order-detail.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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. uni.showToast({ title: `点击了${type}`, icon: 'none' });
  251. // Implement specific logic here similar to my-order.vue
  252. },
  253. getMockData(orderNo) {
  254. // Basic mock structure
  255. return {
  256. status: 2, // Default to pending payment for dev
  257. orderNo: orderNo || '32656+56+5655',
  258. createTime: '2021-07-23 14:50:05',
  259. goodsTotalPrice: '6565',
  260. postage: '0.00',
  261. discountPrice: '55',
  262. realPayPrice: '918.00',
  263. address: {
  264. name: '张三',
  265. mobile: '155****5855',
  266. detail: '四川省成都市高新区XXX街XXX路XXX号XXX小区XXX栋XXXX单元XXX楼XXX'
  267. },
  268. goodsList: [
  269. {
  270. title: '马克思主义基本原理',
  271. quality: '中等',
  272. price: '9.60',
  273. num: 2,
  274. cover: 'https://uviewui.com/album/1.jpg'
  275. },
  276. {
  277. title: '马克思主义基本原理',
  278. quality: '中等',
  279. price: '9.60',
  280. num: 2,
  281. cover: 'https://uviewui.com/album/1.jpg'
  282. }
  283. ]
  284. };
  285. }
  286. }
  287. };
  288. </script>
  289. <style lang="scss" scoped>
  290. .order-detail-page {
  291. min-height: 100vh;
  292. background-color: #F5F5F5;
  293. padding-bottom: 20rpx;
  294. .status-header {
  295. background-color: #d1f2d8; // Light green bg
  296. padding: 40rpx 30rpx;
  297. color: #333;
  298. .status-text {
  299. font-size: 36rpx;
  300. font-weight: bold;
  301. margin-bottom: 10rpx;
  302. }
  303. .status-desc {
  304. font-size: 26rpx;
  305. color: #666;
  306. display: flex;
  307. align-items: center;
  308. }
  309. .status-desc-block {
  310. font-size: 26rpx;
  311. color: #666;
  312. .status-tip {
  313. margin-bottom: 10rpx;
  314. }
  315. .status-desc-row {
  316. display: flex;
  317. align-items: center;
  318. }
  319. }
  320. }
  321. .info-card {
  322. background-color: #fff;
  323. margin: 20rpx;
  324. border-radius: 16rpx;
  325. padding: 30rpx;
  326. display: flex;
  327. &.address-card {
  328. align-items: center;
  329. .icon-box {
  330. margin-right: 20rpx;
  331. }
  332. .address-content {
  333. flex: 1;
  334. margin-right: 20rpx;
  335. .user-info {
  336. font-size: 30rpx;
  337. font-weight: 500;
  338. margin-bottom: 10rpx;
  339. .mobile {
  340. margin-left: 20rpx;
  341. }
  342. }
  343. .address-detail {
  344. font-size: 26rpx;
  345. color: #666;
  346. line-height: 1.4;
  347. }
  348. }
  349. }
  350. &.logistics-card {
  351. align-items: center;
  352. .icon-box {
  353. margin-right: 20rpx;
  354. }
  355. .logistics-content {
  356. flex: 1;
  357. margin-right: 20rpx;
  358. .company-name {
  359. font-size: 28rpx;
  360. color: #38C148;
  361. margin-bottom: 6rpx;
  362. }
  363. .latest-trace {
  364. font-size: 26rpx;
  365. color: #333;
  366. margin-bottom: 6rpx;
  367. display: -webkit-box;
  368. -webkit-box-orient: vertical;
  369. -webkit-line-clamp: 2;
  370. overflow: hidden;
  371. }
  372. .update-time {
  373. font-size: 24rpx;
  374. color: #999;
  375. }
  376. }
  377. }
  378. &.goods-card {
  379. display: block;
  380. .goods-item {
  381. display: flex;
  382. margin-bottom: 30rpx;
  383. .goods-cover {
  384. width: 120rpx;
  385. height: 120rpx;
  386. border-radius: 8rpx;
  387. margin-right: 20rpx;
  388. background-color: #eee;
  389. }
  390. .goods-info {
  391. flex: 1;
  392. .goods-title {
  393. font-size: 28rpx;
  394. color: #333;
  395. margin-bottom: 10rpx;
  396. }
  397. .goods-quality {
  398. font-size: 24rpx;
  399. color: #999;
  400. }
  401. .price-box {
  402. margin-top: 10rpx;
  403. display: flex;
  404. justify-content: space-between;
  405. .price {
  406. font-weight: 500;
  407. }
  408. .num {
  409. color: #999;
  410. }
  411. }
  412. }
  413. .goods-action {
  414. display: flex;
  415. align-items: center;
  416. }
  417. }
  418. .price-detail {
  419. border-top: 1rpx solid #eee;
  420. padding-top: 20rpx;
  421. .row {
  422. display: flex;
  423. justify-content: space-between;
  424. font-size: 26rpx;
  425. color: #666;
  426. margin-bottom: 10rpx;
  427. .goods-total {
  428. color: #38C148;
  429. }
  430. .discount {
  431. color: #38C148;
  432. }
  433. }
  434. .real-pay-row {
  435. display: flex;
  436. justify-content: space-between;
  437. font-size: 30rpx;
  438. font-weight: 500;
  439. margin-top: 20rpx;
  440. .real-price {
  441. color: #38C148;
  442. }
  443. }
  444. }
  445. }
  446. &.time-card {
  447. display: block;
  448. .row {
  449. display: flex;
  450. justify-content: space-between;
  451. font-size: 24rpx;
  452. color: #999;
  453. margin-bottom: 10rpx;
  454. &:last-child {
  455. margin-bottom: 0;
  456. }
  457. }
  458. }
  459. }
  460. .bottom-bar {
  461. position: fixed;
  462. bottom: 0;
  463. left: 0;
  464. right: 0;
  465. background-color: #fff;
  466. padding: 20rpx 30rpx;
  467. padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  468. display: flex;
  469. justify-content: flex-end;
  470. align-items: center;
  471. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  472. }
  473. }
  474. </style>