建材商城系统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.

465 lines
15 KiB

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