建材商城系统20241014
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

468 lines
15 KiB

1 year ago
  1. <template>
  2. <view class="hand-firm">
  3. <navbar
  4. title="确定下单"
  5. leftClick
  6. @leftClick="$utils.navigateBack"
  7. />
  8. <!-- 商品信息 -->
  9. <view class="content-wrapper">
  10. <view class="section-wrapper">
  11. <view class="section-title">
  12. <view class="title-bar"></view>
  13. <text>商品信息</text>
  14. </view>
  15. <view class="product-card">
  16. <image class="product-image" :src="productInfo.image &&
  17. productInfo.image.split(',')[0]" mode="aspectFit"></image>
  18. <view class="product-details">
  19. <view class="product-name">{{productInfo.name || ''}}</view>
  20. <view class="product-tags">
  21. <text class="tag">{{productInfo.categoryName || ''}}</text>
  22. <text class="tag">快速下单</text>
  23. </view>
  24. <view class="product-price">
  25. <text class="price-value">¥{{productInfo.price || ''}}</text>
  26. <text class="price-unit">/{{productInfo.unit || ''}}</text>
  27. </view>
  28. </view>
  29. </view>
  30. </view>
  31. <!-- 个人信息 -->
  32. <view class="section-wrapper">
  33. <view class="section-title">
  34. <view class="title-bar"></view>
  35. <text>填写个人信息</text>
  36. </view>
  37. <view class="address-section">
  38. <view v-if="addressTotal > 0" class="has-address">
  39. <view class="address-info" @click="openAddress">
  40. <view class="address-user">
  41. <text class="name">{{address.name}}</text>
  42. <text class="phone">{{address.phone}}</text>
  43. </view>
  44. <view class="address-detail">
  45. {{address.address}} {{address.addressDetails}}
  46. </view>
  47. <view class="address-action">
  48. <text class="address-tip">已添加过的地址</text>
  49. <view class="arrow-right"></view>
  50. </view>
  51. </view>
  52. <view class="address-tag">
  53. <text>已添加过的地址</text>
  54. </view>
  55. </view>
  56. <!-- 地址表单 -->
  57. <view v-else class="no-address">
  58. <redact-address-form
  59. ref="addressForm"
  60. @saveOrUpdate="handleAddressSave"
  61. ></redact-address-form>
  62. </view>
  63. </view>
  64. </view>
  65. </view>
  66. <!-- 底部按钮 -->
  67. <view class="order-submit">
  68. <button class="submit-btn" @click="submitOrder">快捷下单</button>
  69. </view>
  70. <!-- 地址选择弹窗 -->
  71. <uv-popup ref="addressPopup" :round="30" style="padding-bottom: 90rpx;">
  72. <addressList ref="addressList" height="60vh" @select="selectAddress" />
  73. <view class="add-btn">
  74. <view @click="$utils.navigateTo('/pages_order/mine/address?type=back')" class="button-submit">新增地址</view>
  75. </view>
  76. </uv-popup>
  77. <kefu/>
  78. </view>
  79. </template>
  80. <script>
  81. import redactAddressForm from '../components/address/redactAddressForm.vue';
  82. import addressList from '../components/address/addressList.vue';
  83. export default {
  84. components: {
  85. redactAddressForm,
  86. addressList
  87. },
  88. data() {
  89. return {
  90. productInfo: {}, // 商品信息
  91. orderId: '', // 订单ID
  92. address: {
  93. name: '请选择地址',
  94. address: '',
  95. phone: ''
  96. },
  97. addressTotal: 0,
  98. orderInfo: [],
  99. isLoading: false, // 加载状态
  100. shouldSubmitOrder: false // 标记是否应该在获取地址后自动提交订单
  101. };
  102. },
  103. onLoad(options) {
  104. // 获取订单ID
  105. if (options.orderId) {
  106. this.orderId = options.orderId;
  107. this.getOrderInfo();
  108. }
  109. },
  110. onShow() {
  111. // 获取地址列表
  112. this.getAddressList();
  113. },
  114. methods: {
  115. // 获取订单信息
  116. getOrderInfo() {
  117. this.$api('getOrderInfo', res => {
  118. if (res.code === 200 && res.result[0]) {
  119. // 如果返回商品信息,则设置商品信息
  120. if (res.result[0].commonShop) {
  121. this.productInfo = res.result[0].commonShop;
  122. }
  123. }
  124. });
  125. },
  126. // 获取地址列表
  127. getAddressList() {
  128. // 调用地址列表组件获取地址
  129. this.$refs.addressList.getAddressList().then(res => {
  130. if (res && res.total) {
  131. this.addressTotal = res.total;
  132. // 查找默认地址
  133. if (res.records && res.records.length > 0) {
  134. const defaultAddress = res.records.find(addr => addr.defaultFlag === '1');
  135. if (defaultAddress) {
  136. this.address = defaultAddress;
  137. } else {
  138. // 如果没有默认地址,使用第一个地址
  139. this.address = res.records[0];
  140. }
  141. // 如果标记为需要自动提交订单
  142. if (this.shouldSubmitOrder) {
  143. this.shouldSubmitOrder = false; // 重置标记
  144. this.submitOrder(true); // 执行提交订单,传入true表示不再验证地址
  145. }
  146. }
  147. } else {
  148. this.addressTotal = 0;
  149. }
  150. // 完成加载
  151. this.isLoading = false;
  152. }).catch(err => {
  153. console.error('获取地址列表失败', err);
  154. this.addressTotal = 0;
  155. this.isLoading = false;
  156. });
  157. },
  158. // 打开地址选择弹窗
  159. openAddress() {
  160. this.$refs.addressPopup.open('bottom');
  161. },
  162. // 选择地址
  163. selectAddress(address) {
  164. this.address = address;
  165. this.$refs.addressPopup.close();
  166. },
  167. // 处理地址保存
  168. handleAddressSave(address) {
  169. // 显示加载状态
  170. this.isLoading = true;
  171. // 保存地址
  172. this.$api('saveOrUpdateAddress', address, res => {
  173. if (res.code === 200) {
  174. uni.showToast({
  175. title: '地址保存成功',
  176. icon: 'success'
  177. });
  178. // 标记需要在获取地址后自动提交订单
  179. this.shouldSubmitOrder = true;
  180. // 重新获取地址列表
  181. this.getAddressList();
  182. } else {
  183. uni.showToast({
  184. title: res.message || '保存失败',
  185. icon: 'none'
  186. });
  187. this.isLoading = false;
  188. }
  189. });
  190. },
  191. // 提交订单
  192. submitOrder(skipAddressCheck = false) {
  193. if (!skipAddressCheck && this.addressTotal === 0) {
  194. const addressForm = this.$refs.addressForm;
  195. // 验证地址表单
  196. const isValid = addressForm.parameterVerification(addressForm.addressDetail);
  197. if (!isValid.auth) {
  198. uni.showToast({
  199. title: isValid.title,
  200. icon: 'none'
  201. });
  202. return;
  203. }
  204. // 显示加载状态
  205. this.isLoading = true;
  206. // 保存地址并继续
  207. addressForm.onSubmit();
  208. return;
  209. }
  210. // 显示加载中
  211. uni.showLoading({
  212. title: '提交订单中...'
  213. });
  214. // 创建订单
  215. this.$api('createOrder', {
  216. addressId: this.address.id,
  217. productId: this.productInfo.id,
  218. num : 1,
  219. payType: 1, // 默认微信支付
  220. orderId: this.orderId
  221. }, res => {
  222. uni.hideLoading();
  223. if (res.code === 200) {
  224. uni.showToast({
  225. title: '下单成功',
  226. icon: 'success',
  227. duration: 1500,
  228. success: () => {
  229. setTimeout(() => {
  230. // 跳转到订单列表页
  231. this.$utils.redirectTo('/pages_order/order/orderList');
  232. }, 1500);
  233. }
  234. });
  235. } else {
  236. uni.showToast({
  237. title: res.message || '下单失败',
  238. icon: 'none'
  239. });
  240. }
  241. });
  242. }
  243. }
  244. }
  245. </script>
  246. <style scoped lang="scss">
  247. .hand-firm {
  248. min-height: 100vh;
  249. background-color: #f6f6f6;
  250. padding-bottom: 120rpx;
  251. .content-wrapper {
  252. padding: 20rpx;
  253. }
  254. .section-wrapper {
  255. margin-bottom: 20rpx;
  256. border-radius: 12rpx;
  257. overflow: hidden;
  258. background-color: #fff;
  259. }
  260. .section-title {
  261. display: flex;
  262. align-items: center;
  263. padding: 30rpx;
  264. border-bottom: 1rpx solid #f0f0f0;
  265. .title-bar {
  266. width: 6rpx;
  267. height: 30rpx;
  268. background-color: #D03F25;
  269. margin-right: 15rpx;
  270. border-radius: 3rpx;
  271. }
  272. text {
  273. font-size: 32rpx;
  274. font-weight: 500;
  275. color: #333;
  276. }
  277. }
  278. .product-card {
  279. display: flex;
  280. padding: 30rpx;
  281. .product-image {
  282. width: 180rpx;
  283. height: 180rpx;
  284. margin-right: 30rpx;
  285. background-color: #f9f9f9;
  286. border-radius: 8rpx;
  287. }
  288. .product-details {
  289. flex: 1;
  290. display: flex;
  291. flex-direction: column;
  292. justify-content: space-between;
  293. .product-name {
  294. font-size: 32rpx;
  295. font-weight: 500;
  296. color: #333;
  297. margin-bottom: 15rpx;
  298. }
  299. .product-tags {
  300. display: flex;
  301. margin-bottom: 20rpx;
  302. .tag {
  303. font-size: 24rpx;
  304. color: #D03F25;
  305. padding: 4rpx 12rpx;
  306. background-color: rgba(208, 63, 37, 0.1);
  307. border-radius: 4rpx;
  308. margin-right: 15rpx;
  309. }
  310. }
  311. .product-price {
  312. font-size: 28rpx;
  313. color: #666;
  314. .price-value {
  315. font-size: 40rpx;
  316. font-weight: 600;
  317. color: #D03F25;
  318. }
  319. }
  320. }
  321. }
  322. .address-section {
  323. .has-address {
  324. position: relative;
  325. .address-info {
  326. padding: 30rpx;
  327. .address-user {
  328. margin-bottom: 15rpx;
  329. .name {
  330. font-size: 32rpx;
  331. font-weight: 500;
  332. color: #333;
  333. margin-right: 30rpx;
  334. }
  335. .phone {
  336. font-size: 28rpx;
  337. color: #666;
  338. }
  339. }
  340. .address-detail {
  341. font-size: 28rpx;
  342. color: #666;
  343. line-height: 1.5;
  344. margin-bottom: 20rpx;
  345. }
  346. .address-action {
  347. display: flex;
  348. justify-content: space-between;
  349. align-items: center;
  350. padding-top: 20rpx;
  351. border-top: 1px solid #eee;
  352. .address-tip {
  353. font-size: 28rpx;
  354. color: #D03F25;
  355. }
  356. .arrow-right {
  357. width: 16rpx;
  358. height: 16rpx;
  359. border-top: 2rpx solid #D03F25;
  360. border-right: 2rpx solid #D03F25;
  361. transform: rotate(45deg);
  362. }
  363. }
  364. }
  365. .address-tag {
  366. position: absolute;
  367. top: 20rpx;
  368. right: 0;
  369. background-color: #D03F25;
  370. color: #fff;
  371. font-size: 24rpx;
  372. padding: 8rpx 20rpx;
  373. border-radius: 30rpx 0 0 30rpx;
  374. }
  375. }
  376. .no-address {
  377. padding: 20rpx;
  378. }
  379. }
  380. .order-submit {
  381. position: fixed;
  382. bottom: 0;
  383. left: 0;
  384. right: 0;
  385. padding: 20rpx 30rpx;
  386. background-color: #fff;
  387. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  388. .submit-btn {
  389. width: 100%;
  390. height: 90rpx;
  391. line-height: 90rpx;
  392. text-align: center;
  393. background-color: #D03F25;
  394. color: #fff;
  395. font-size: 32rpx;
  396. border-radius: 45rpx;
  397. border: none;
  398. }
  399. }
  400. .add-btn {
  401. padding: 30rpx;
  402. .button-submit {
  403. display: flex;
  404. align-items: center;
  405. justify-content: center;
  406. width: 100%;
  407. height: 90rpx;
  408. background-color: #D03F25;
  409. color: #fff;
  410. font-size: 32rpx;
  411. border-radius: 45rpx;
  412. }
  413. }
  414. }
  415. </style>