order-detail.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <template>
  2. <view class="order-detail-page">
  3. <!-- 顶部状态栏 -->
  4. <view class="status-header">
  5. <view class="status-text">{{ statusText }}</view>
  6. <view class="status-desc" v-if="orderInfo.status === 2">
  7. 订单编号:{{ orderInfo.orderNo }}
  8. <u-icon name="copy" size="28" @click="copyOrderNo" style="margin-left: 10rpx;"></u-icon>
  9. </view>
  10. <view class="status-desc" v-else-if="orderInfo.status === 3">
  11. 订单编号:{{ orderInfo.orderNo }}
  12. <u-icon name="copy" size="28" @click="copyOrderNo" style="margin-left: 10rpx;"></u-icon>
  13. </view>
  14. <view class="status-desc-block" v-else-if="orderInfo.status === 8">
  15. <view class="status-tip">还剩9天22时18分自动确认收货</view>
  16. <view class="status-desc-row">
  17. 订单编号:{{ orderInfo.orderNo }}
  18. <u-icon name="copy" size="28" @click="copyOrderNo" style="margin-left: 10rpx;"></u-icon>
  19. </view>
  20. </view>
  21. <view class="status-desc" v-else>
  22. 订单编号:{{ orderInfo.orderNo }}
  23. <u-icon name="copy" size="28" @click="copyOrderNo" style="margin-left: 10rpx;"></u-icon>
  24. </view>
  25. </view>
  26. <!-- 地址信息 -->
  27. <view class="info-card address-card">
  28. <view class="icon-box">
  29. <u-icon name="map-fill" color="#ff0000" size="40"></u-icon>
  30. </view>
  31. <view class="address-content">
  32. <view class="user-info">
  33. <text class="name">{{ orderInfo.address && orderInfo.address.name }}</text>
  34. <text class="mobile">{{ orderInfo.address && orderInfo.address.mobile }}</text>
  35. </view>
  36. <view class="address-detail">{{ orderInfo.address && orderInfo.address.detail }}</view>
  37. </view>
  38. <u-icon name="arrow-right" color="#999" size="28"></u-icon>
  39. </view>
  40. <!-- 物流信息 (已发货/已完成/退款) -->
  41. <view class="info-card logistics-card" v-if="[8, 12, 10].includes(orderInfo.status) && orderInfo.logistics">
  42. <view class="icon-box">
  43. <u-icon name="car-fill" color="#38C148" size="40"></u-icon>
  44. </view>
  45. <view class="logistics-content" @click="viewLogistics">
  46. <view class="company-name">{{ orderInfo.logistics.company }} ({{ orderInfo.logistics.no }})</view>
  47. <view class="latest-trace">{{ orderInfo.logistics.trace }}</view>
  48. <view class="update-time">{{ orderInfo.logistics.updateTime }}</view>
  49. </view>
  50. <u-icon name="arrow-right" color="#999" size="28"></u-icon>
  51. </view>
  52. <!-- 商品列表 -->
  53. <view class="info-card goods-card">
  54. <view class="goods-item" v-for="(goods, index) in orderInfo.goodsList" :key="index">
  55. <image :src="goods.cover" mode="aspectFill" class="goods-cover"></image>
  56. <view class="goods-info">
  57. <view class="goods-title">{{ goods.title }}</view>
  58. <view class="goods-quality">品相:{{ goods.quality }}</view>
  59. <view class="price-box">
  60. <text class="price">¥{{ goods.price }}</text>
  61. <text class="num">x{{ goods.num }}</text>
  62. </view>
  63. </view>
  64. <!-- 商品级按钮,如退款 -->
  65. <view class="goods-action" v-if="[3, 8].includes(orderInfo.status)">
  66. <u-button size="mini" shape="circle" plain
  67. custom-style="margin-left: 20rpx; height: 50rpx; line-height: 50rpx;">退款</u-button>
  68. </view>
  69. <view class="goods-action" v-if="[10].includes(orderInfo.status)">
  70. <u-button size="mini" shape="circle" plain disabled
  71. custom-style="margin-left: 20rpx; height: 50rpx; line-height: 50rpx; background: #f5f5f5; color: #999; border: none;">退款成功</u-button>
  72. </view>
  73. </view>
  74. <!-- 价格明细 -->
  75. <view class="price-detail">
  76. <view class="row">
  77. <text>邮费</text>
  78. <text>¥ {{ orderInfo.postage || '0.00' }}</text>
  79. </view>
  80. <view class="row">
  81. <text>商品金额</text>
  82. <text class="goods-total">¥{{ orderInfo.goodsTotalPrice }}</text>
  83. </view>
  84. <view class="row">
  85. <text>优惠金额</text>
  86. <text class="discount">-¥{{ orderInfo.discountPrice || '0.00' }}</text>
  87. </view>
  88. <view class="real-pay-row">
  89. <text>实付款 (微信支付)</text>
  90. <text class="real-price">¥ {{ orderInfo.realPayPrice }}</text>
  91. </view>
  92. </view>
  93. </view>
  94. <!-- 订单时间信息 -->
  95. <view class="info-card time-card">
  96. <view class="row">
  97. <text class="label">下单时间</text>
  98. <text class="value">{{ orderInfo.createTime }}</text>
  99. </view>
  100. <view class="row" v-if="orderInfo.payTime">
  101. <text class="label">付款时间</text>
  102. <text class="value">{{ orderInfo.payTime }}</text>
  103. </view>
  104. <view class="row" v-if="orderInfo.deliveryTime">
  105. <text class="label">发货时间</text>
  106. <text class="value">{{ orderInfo.deliveryTime }}</text>
  107. </view>
  108. <view class="row" v-if="orderInfo.finishTime">
  109. <text class="label">完成时间</text>
  110. <text class="value">{{ orderInfo.finishTime }}</text>
  111. </view>
  112. <view class="row" v-if="orderInfo.closeTime">
  113. <text class="label">关闭时间</text>
  114. <text class="value">{{ orderInfo.closeTime }}</text>
  115. </view>
  116. </view>
  117. <!-- 底部操作栏 -->
  118. <view class="bottom-bar">
  119. <!-- 待付款 -->
  120. <template v-if="orderInfo.status === 2">
  121. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  122. @click="handleAction('addToCart')">加入购物车</u-button>
  123. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  124. @click="handleAction('cancel')">取消订单</u-button>
  125. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  126. @click="handleAction('address')">修改地址</u-button>
  127. <u-button size="mini" shape="circle" :custom-style="themeBtnStyle"
  128. @click="handleAction('pay')">继续付款</u-button>
  129. </template>
  130. <!-- 待发货 -->
  131. <template v-else-if="orderInfo.status === 3">
  132. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  133. @click="handleAction('addToCart')">加入购物</u-button>
  134. <u-button size="mini" shape="circle" type="warning" :custom-style="btnStyle"
  135. @click="handleAction('overtime')">超时发货</u-button>
  136. <u-button size="mini" shape="circle" :custom-style="themeBtnStyle"
  137. @click="handleAction('remind')">催发货</u-button>
  138. </template>
  139. <!-- 已发货 -->
  140. <template v-else-if="orderInfo.status === 8">
  141. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  142. @click="handleAction('addToCart')">加入购物</u-button>
  143. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  144. @click="handleAction('complaint')">投诉</u-button>
  145. <u-button size="mini" shape="circle" type="primary" :custom-style="themeLightBtnStyle"
  146. @click="handleAction('priceMatch')">降价补差</u-button>
  147. <u-button size="mini" shape="circle" :custom-style="themeBtnStyle"
  148. @click="handleAction('confirm')">确认收货</u-button>
  149. </template>
  150. <!-- 交易关闭/已退款 -->
  151. <template v-else-if="orderInfo.status === -1 || orderInfo.status === 10">
  152. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  153. @click="handleAction('addToCart')">加入购物</u-button>
  154. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  155. @click="handleAction('complaint')">投诉</u-button>
  156. <u-button size="mini" shape="circle" :custom-style="themeBtnStyle"
  157. @click="handleAction('moneyWhere')">钱款去向</u-button>
  158. </template>
  159. <!-- 交易完成 -->
  160. <template v-else-if="orderInfo.status === 12">
  161. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  162. @click="handleAction('addToCart')">加入购物</u-button>
  163. <u-button size="mini" shape="circle" plain :custom-style="btnStyle"
  164. @click="handleAction('complaint')">投诉</u-button>
  165. </template>
  166. </view>
  167. <!-- 占位符,防止底部按钮遮挡内容 -->
  168. <view style="height: 120rpx;"></view>
  169. </view>
  170. </template>
  171. <script>
  172. export default {
  173. data() {
  174. return {
  175. orderInfo: {
  176. status: 2,
  177. orderNo: '',
  178. goodsList: [],
  179. address: {}
  180. },
  181. btnStyle: {
  182. marginLeft: '20rpx',
  183. width: '160rpx',
  184. height: '60rpx',
  185. lineHeight: '60rpx',
  186. padding: '0'
  187. },
  188. themeBtnStyle: {
  189. marginLeft: '20rpx',
  190. width: '160rpx',
  191. height: '60rpx',
  192. lineHeight: '60rpx',
  193. padding: '0',
  194. backgroundColor: '#38C148',
  195. color: '#fff',
  196. border: 'none'
  197. },
  198. themeLightBtnStyle: {
  199. marginLeft: '20rpx',
  200. width: '160rpx',
  201. height: '60rpx',
  202. lineHeight: '60rpx',
  203. padding: '0',
  204. backgroundColor: '#5bc0de', // Light blue/green for price match? Or keep simple
  205. color: '#fff',
  206. border: 'none'
  207. }
  208. };
  209. },
  210. computed: {
  211. statusText() {
  212. const map = {
  213. 2: '等待买家付款',
  214. 3: '等待卖家发货',
  215. 8: '已发货',
  216. 12: '交易完成',
  217. 10: '交易关闭', // 退款
  218. '-1': '交易关闭'
  219. };
  220. return map[this.orderInfo.status] || '未知状态';
  221. }
  222. },
  223. onLoad(options) {
  224. if (options.orderNo) {
  225. this.loadOrderDetail(options.orderNo);
  226. } else {
  227. // For testing/preview if no orderNo passed, use a mock default
  228. this.loadOrderDetail('SN_MOCK_DEFAULT');
  229. }
  230. },
  231. methods: {
  232. loadOrderDetail(orderNo) {
  233. // Mock data loading
  234. this.orderInfo = this.getMockData(orderNo);
  235. },
  236. copyOrderNo() {
  237. uni.setClipboardData({
  238. data: this.orderInfo.orderNo,
  239. success: () => {
  240. uni.showToast({ title: '复制成功', icon: 'none' });
  241. }
  242. });
  243. },
  244. viewLogistics() {
  245. uni.navigateTo({
  246. url: `/pages-car/pages/logistics-detail?orderNo=${this.orderInfo.orderNo}`
  247. });
  248. },
  249. handleAction(type) {
  250. if (type === 'complaint') {
  251. uni.setStorageSync('tempComplaintOrder', this.orderInfo);
  252. uni.navigateTo({
  253. url: `/pages-car/pages/complaint?orderId=${this.orderInfo.orderId || this.orderInfo.orderNo}` // Fallback to orderNo if orderId missing in mock
  254. });
  255. return;
  256. }
  257. uni.showToast({ title: `点击了${type}`, icon: 'none' });
  258. // Implement specific logic here similar to my-order.vue
  259. },
  260. getMockData(orderNo) {
  261. // Basic mock structure
  262. return {
  263. status: 2, // Default to pending payment for dev
  264. orderNo: orderNo || '32656+56+5655',
  265. createTime: '2021-07-23 14:50:05',
  266. goodsTotalPrice: '6565',
  267. postage: '0.00',
  268. discountPrice: '55',
  269. realPayPrice: '918.00',
  270. address: {
  271. name: '张三',
  272. mobile: '155****5855',
  273. detail: '四川省成都市高新区XXX街XXX路XXX号XXX小区XXX栋XXXX单元XXX楼XXX'
  274. },
  275. goodsList: [
  276. {
  277. title: '马克思主义基本原理',
  278. quality: '中等',
  279. price: '9.60',
  280. num: 2,
  281. cover: 'https://uviewui.com/album/1.jpg'
  282. },
  283. {
  284. title: '马克思主义基本原理',
  285. quality: '中等',
  286. price: '9.60',
  287. num: 2,
  288. cover: 'https://uviewui.com/album/1.jpg'
  289. }
  290. ]
  291. };
  292. }
  293. }
  294. };
  295. </script>
  296. <style lang="scss" scoped>
  297. .order-detail-page {
  298. min-height: 100vh;
  299. background-color: #F5F5F5;
  300. padding-bottom: 20rpx;
  301. .status-header {
  302. background-color: #d1f2d8; // Light green bg
  303. padding: 40rpx 30rpx;
  304. color: #333;
  305. .status-text {
  306. font-size: 36rpx;
  307. font-weight: bold;
  308. margin-bottom: 10rpx;
  309. }
  310. .status-desc {
  311. font-size: 26rpx;
  312. color: #666;
  313. display: flex;
  314. align-items: center;
  315. }
  316. .status-desc-block {
  317. font-size: 26rpx;
  318. color: #666;
  319. .status-tip {
  320. margin-bottom: 10rpx;
  321. }
  322. .status-desc-row {
  323. display: flex;
  324. align-items: center;
  325. }
  326. }
  327. }
  328. .info-card {
  329. background-color: #fff;
  330. margin: 20rpx;
  331. border-radius: 16rpx;
  332. padding: 30rpx;
  333. display: flex;
  334. &.address-card {
  335. align-items: center;
  336. .icon-box {
  337. margin-right: 20rpx;
  338. }
  339. .address-content {
  340. flex: 1;
  341. margin-right: 20rpx;
  342. .user-info {
  343. font-size: 30rpx;
  344. font-weight: 500;
  345. margin-bottom: 10rpx;
  346. .mobile {
  347. margin-left: 20rpx;
  348. }
  349. }
  350. .address-detail {
  351. font-size: 26rpx;
  352. color: #666;
  353. line-height: 1.4;
  354. }
  355. }
  356. }
  357. &.logistics-card {
  358. align-items: center;
  359. .icon-box {
  360. margin-right: 20rpx;
  361. }
  362. .logistics-content {
  363. flex: 1;
  364. margin-right: 20rpx;
  365. .company-name {
  366. font-size: 28rpx;
  367. color: #38C148;
  368. margin-bottom: 6rpx;
  369. }
  370. .latest-trace {
  371. font-size: 26rpx;
  372. color: #333;
  373. margin-bottom: 6rpx;
  374. display: -webkit-box;
  375. -webkit-box-orient: vertical;
  376. -webkit-line-clamp: 2;
  377. overflow: hidden;
  378. }
  379. .update-time {
  380. font-size: 24rpx;
  381. color: #999;
  382. }
  383. }
  384. }
  385. &.goods-card {
  386. display: block;
  387. .goods-item {
  388. display: flex;
  389. margin-bottom: 30rpx;
  390. .goods-cover {
  391. width: 120rpx;
  392. height: 120rpx;
  393. border-radius: 8rpx;
  394. margin-right: 20rpx;
  395. background-color: #eee;
  396. }
  397. .goods-info {
  398. flex: 1;
  399. .goods-title {
  400. font-size: 28rpx;
  401. color: #333;
  402. margin-bottom: 10rpx;
  403. }
  404. .goods-quality {
  405. font-size: 24rpx;
  406. color: #999;
  407. }
  408. .price-box {
  409. margin-top: 10rpx;
  410. display: flex;
  411. justify-content: space-between;
  412. .price {
  413. font-weight: 500;
  414. }
  415. .num {
  416. color: #999;
  417. }
  418. }
  419. }
  420. .goods-action {
  421. display: flex;
  422. align-items: center;
  423. }
  424. }
  425. .price-detail {
  426. border-top: 1rpx solid #eee;
  427. padding-top: 20rpx;
  428. .row {
  429. display: flex;
  430. justify-content: space-between;
  431. font-size: 26rpx;
  432. color: #666;
  433. margin-bottom: 10rpx;
  434. .goods-total {
  435. color: #38C148;
  436. }
  437. .discount {
  438. color: #38C148;
  439. }
  440. }
  441. .real-pay-row {
  442. display: flex;
  443. justify-content: space-between;
  444. font-size: 30rpx;
  445. font-weight: 500;
  446. margin-top: 20rpx;
  447. .real-price {
  448. color: #38C148;
  449. }
  450. }
  451. }
  452. }
  453. &.time-card {
  454. display: block;
  455. .row {
  456. display: flex;
  457. justify-content: space-between;
  458. font-size: 24rpx;
  459. color: #999;
  460. margin-bottom: 10rpx;
  461. &:last-child {
  462. margin-bottom: 0;
  463. }
  464. }
  465. }
  466. }
  467. .bottom-bar {
  468. position: fixed;
  469. bottom: 0;
  470. left: 0;
  471. right: 0;
  472. background-color: #fff;
  473. padding: 20rpx 30rpx;
  474. padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  475. display: flex;
  476. justify-content: flex-end;
  477. align-items: center;
  478. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  479. }
  480. }
  481. </style>