爱简收旧衣按件回收前端代码仓库
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.

988 lines
27 KiB

2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
  1. <template>
  2. <view class="container">
  3. <!-- 顶部导航 -->
  4. <view class="nav-bar" >
  5. <view class="back" @tap="goBack">
  6. <uni-icons type="left" size="20"></uni-icons>
  7. </view>
  8. <text class="title">{{ orderDetail && orderDetail.ordeNo ? orderDetail.ordeNo : orderId }}</text>
  9. </view>
  10. <!-- 内容区域 -->
  11. <view class="content">
  12. <!-- 回收流程卡片 -->
  13. <view class="card process-card">
  14. <view class="card-title">回收流程</view>
  15. <view class="process-steps">
  16. <view
  17. v-for="(step, index) in processSteps"
  18. :key="index"
  19. class="step-item"
  20. :class="{ cancel: state === 3 && index === status }"
  21. >
  22. <image :src="step.icon" mode="aspectFit" class="step-icon"></image>
  23. <view
  24. class="step-label"
  25. :class="{
  26. active: status === index && state !== 3,
  27. cancel: state === 3 && index === status
  28. }"
  29. >
  30. <view class="step-label-inner">
  31. <!-- <text class="step-num">{{ ['①','②','③','④'][index] }}</text> -->
  32. <text class="step-text">{{ step.text }}</text>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. <view class="process-divider"></view>
  38. <!-- 状态信息 -->
  39. <view class="status-info" v-if="currentStatus">
  40. <image class="status-icon" :src="currentStatus.icon" mode="aspectFit"></image>
  41. <view class="status-detail">
  42. <text class="status-text" v-if="state === 3">已取消本次预约</text>
  43. <text class="status-text" v-else>{{ currentStatus.text }}</text>
  44. <text class="status-time">{{ currentStatus.time }}</text>
  45. </view>
  46. </view>
  47. <!-- 取消后提示语 -->
  48. <view v-if="state === 3" class="cancel-tip">期待您下次的支持共同为地球减少碳排放出一份力</view>
  49. <!-- 物流公司仅status为01时显示 -->
  50. <view class="express-info" v-if="state !== 3 && status <= 1">
  51. <text class="express-label">物流公司</text>
  52. <view class="express-row">
  53. <text class="express-value">{{ expressCompany }}{{ expressNo }}</text>
  54. <text class="express-copy" @tap="copyExpressNo">复制</text>
  55. </view>
  56. </view>
  57. <view class="info-divider" v-if="state !== 3 && status < 3"></view>
  58. <!-- 地址信息仅非取消和非结款时显示 -->
  59. <view class="pickup-info" v-if="state !== 3 && status < 3">
  60. <view class="info-item" @tap="viewAddress">
  61. <text class="label">取件地址</text>
  62. <view class="value">
  63. <text class="text">{{ address }}</text>
  64. <!-- <text class="arrow">></text> -->
  65. </view>
  66. </view>
  67. <view class="info-item">
  68. <text class="label">{{ timeLabel }}</text>
  69. <view class="value">
  70. <text class="text">{{ appointmentTime }}</text>
  71. <!-- <text class="arrow">></text> -->
  72. </view>
  73. </view>
  74. </view>
  75. </view>
  76. <!-- 订单详情卡片 -->
  77. <view class="order-detail-card">
  78. <text class="order-title">订单详情</text>
  79. <view class="order-row">
  80. <text class="order-label">订单编号</text>
  81. <text class="order-value">{{ orderDetail && orderDetail.ordeNo ? orderDetail.ordeNo : orderId }}</text>
  82. </view>
  83. <view class="order-divider"></view>
  84. <template v-if="status < 2">
  85. <view class="order-row">
  86. <text class="order-label">预估回收</text>
  87. <text class="order-value order-highlight">¥ {{ estimatePrice }}</text>
  88. </view>
  89. </template>
  90. <template v-else-if="status === 3">
  91. <view class="order-row">
  92. <text class="order-label">合格结算</text>
  93. <text class="order-value order-highlight">¥ {{ finalPrice }}</text>
  94. </view>
  95. <view class="order-row">
  96. <text class="order-label">运费扣除</text>
  97. <text class="order-value">¥ 0</text>
  98. </view>
  99. <view class="order-row">
  100. <text class="order-label">结算金额</text>
  101. <text class="order-value order-highlight">¥ {{ finalPrice }}</text>
  102. </view>
  103. </template>
  104. <view class="order-divider"></view>
  105. <view class="goods-list">
  106. <view class="goods-item" v-for="(item, index) in clothesList" :key="index">
  107. <image class="goods-img" :src="item.image" mode="aspectFit"></image>
  108. <view class="goods-info">
  109. <text class="goods-name">{{ item.title }}</text>
  110. <text class="desc">{{ item.pinName }}</text>
  111. <text class="goods-desc">{{ item.details }}</text>
  112. <view class="goods-meta">
  113. <text class="goods-price" v-if="shouldShowSinglePrice(item.estimatedPrice)">¥ {{ item.onePrice }}<text class="goods-unit"> /{{item.unit}}</text></text>
  114. <text class="goods-price" v-else>¥ {{ getSinglePriceRange(item.estimatedPrice, item.num) }}<text class="goods-unit"> /{{item.unit}}</text></text>
  115. <text class="goods-count">x{{ item.num }}</text>
  116. </view>
  117. </view>
  118. <text class="goods-total" v-if="shouldShowSinglePrice(item.estimatedPrice)">¥{{ parseFloat(item.estimatedPrice.split('-')[0]).toFixed(2) }}</text>
  119. <text class="goods-total" v-else>¥{{ item.estimatedPrice.replace('-', '~') }}</text>
  120. </view>
  121. </view>
  122. </view>
  123. <!-- 质检结果卡片仅结款状态显示 -->
  124. <view class="order-detail-card" v-if="status === 3">
  125. <text class="order-title">质检结果</text>
  126. <view class="order-row"><text class="order-label">质检数量</text><text class="order-value">9 </text></view>
  127. <view class="order-row"><text class="order-label">质检合格</text><text class="order-value">7 </text></view>
  128. <view class="order-row"><text class="order-label">质量问题</text><text class="order-value">2 </text></view>
  129. <view class="order-row"><text class="order-label">不可回收</text><text class="order-value">0 </text></view>
  130. <view class="order-row"><text class="order-label">订单重量</text><text class="order-value">2.85 kg</text></view>
  131. <view class="order-divider"></view>
  132. <view class="report-btn" @tap="viewReport">点此查看质检报告详情</view>
  133. </view>
  134. <!-- 详细信息卡片仅结款状态显示 -->
  135. <view class="order-detail-card detail-info-card" v-if="status === 3">
  136. <text class="order-title">详细信息</text>
  137. <view class="order-row">
  138. <text class="order-label">预约时间</text>
  139. <text class="order-value">2025-03-20 11:00~12:00</text>
  140. </view>
  141. <view class="order-row">
  142. <text class="order-label">取件地址</text>
  143. <text class="order-value">{{ address }}</text>
  144. </view>
  145. </view>
  146. </view>
  147. <!-- 底部按钮仅在线预约时显示 -->
  148. <view class="bottom-btns" v-if="(status === 0||(status === 1 && state==0)) && state !== 3 && state !== 4">
  149. <button class="btn cancel-btn" @tap="showCancelModal = true">取消订单</button>
  150. <button class="btn contact-btn" @tap="contactCourier" v-if="status === 1">联系快递员</button>
  151. </view>
  152. <!-- 取消订单弹窗 -->
  153. <view v-if="showCancelModal" class="modal-mask">
  154. <view class="modal-box">
  155. <view class="modal-title">取消订单</view>
  156. <view class="modal-content">确认要取消订单吗</view>
  157. <view class="modal-actions">
  158. <button class="modal-btn modal-cancel" @tap="showCancelModal = false">取消</button>
  159. <button class="modal-btn modal-confirm" @tap="confirmCancelOrder">确认</button>
  160. </view>
  161. </view>
  162. </view>
  163. </view>
  164. </template>
  165. <script>
  166. import pullRefreshMixin from '@/pages/mixins/pullRefreshMixin.js'
  167. export default {
  168. mixins: [pullRefreshMixin],
  169. data() {
  170. return {
  171. orderId: '',
  172. currentStep: 1, // 当前进行到第几步
  173. processSteps: [
  174. ],
  175. address: '',
  176. appointmentTime: '',
  177. estimatePrice: '',
  178. finalPrice: '',
  179. clothesList: [],
  180. currentStatus: {
  181. text: '',
  182. time: '',
  183. icon: ''
  184. },
  185. phone: '',
  186. hasReport: false,
  187. reportTime: '',
  188. showEditButton: true,
  189. expressCompany: '',
  190. expressNo: '',
  191. showCancelModal: false,
  192. statusBarHeight: 0,
  193. orderDetail: null,
  194. status: null, // 订单状态:0:在线预约 1:快递上门 2:透明质检 3:现金打款
  195. state: null // 订单状态:0待取件 1已取件 2已完成 3已取消
  196. }
  197. },
  198. computed: {
  199. timeLabel() {
  200. // 根据状态返回不同的时间标签
  201. if (this.status === 3) {
  202. return '回收到账时间'
  203. } else if (this.status === 2) {
  204. return '质检完成时间'
  205. } else {
  206. return '上门时间'
  207. }
  208. },
  209. showEstimate() {
  210. return this.status < 2
  211. }
  212. },
  213. methods: {
  214. async onRefresh() {
  215. // 模拟刷新数据
  216. await new Promise(resolve => setTimeout(resolve, 1000))
  217. uni.stopPullRefresh()
  218. },
  219. goBack() {
  220. getApp().globalData.shouldClearRecycle = true
  221. uni.navigateBack()
  222. },
  223. showMore() {
  224. // 显示更多选项
  225. },
  226. onShare() {
  227. // 分享功能
  228. },
  229. viewAddress() {
  230. // 查看完整地址
  231. },
  232. viewReport() {
  233. // 查看质检报告,传入orderId
  234. uni.navigateTo({
  235. url: `/pages/subcomponent/inspection-report?orderId=${this.orderId}`
  236. })
  237. },
  238. editOrder() {
  239. // 修改订单
  240. },
  241. // 更新订单状态
  242. updateOrderStatus(status) {
  243. switch(status) {
  244. case 'cancelled':
  245. this.currentStep = 0
  246. this.currentStatus = {
  247. text: '已取消',
  248. time: '',
  249. icon: '/static/my/【待取件】快递员正在赶来.png'
  250. }
  251. this.showEditButton = false
  252. break
  253. case 'processing':
  254. this.currentStep = 2
  255. this.currentStatus = {
  256. text: '【待取件】快递员正在赶来',
  257. time: '2025-04-20 11:00~13:00',
  258. icon: '/static/my/【待取件】快递员正在赶来.png'
  259. }
  260. break
  261. case 'collected':
  262. this.currentStep = 2
  263. this.currentStatus = {
  264. text: '【已取件】快递员正在送至质检',
  265. time: '2025-04-30 11:42',
  266. icon: '/static/my/【上门中】快递员正在赶来.png'
  267. }
  268. this.showEditButton = false
  269. break
  270. case 'inspecting':
  271. this.currentStep = 3
  272. this.currentStatus = {
  273. text: '【质检中】质检员正在质检',
  274. time: '2025-04-20 11:00',
  275. icon: '/static/my/逐件验-配图.png'
  276. }
  277. this.showEditButton = false
  278. break
  279. case 'pending_payment':
  280. this.currentStep = 4
  281. this.currentStatus = {
  282. text: '【待结款】待平台确认结款项',
  283. time: '2025-04-20 12:00',
  284. icon: '/static/my/【已结款】平台已结款至账户.png'
  285. }
  286. this.hasReport = true
  287. this.reportTime = '2025-03-20 11:40'
  288. this.showEditButton = false
  289. break
  290. case 'completed':
  291. this.currentStep = 4
  292. this.currentStatus = {
  293. text: '【已结款】平台已结款至账户',
  294. time: '2025-04-20 12:01',
  295. icon: '/static/my/【已结款】平台已结款至账户.png'
  296. }
  297. this.hasReport = true
  298. this.reportTime = '2025-03-20 11:40'
  299. this.showEditButton = false
  300. break
  301. }
  302. },
  303. copyExpressNo() {
  304. uni.setClipboardData({
  305. data: this.expressCompany + this.expressNo,
  306. success: () => {
  307. uni.showToast({ title: '已复制', icon: 'none' });
  308. }
  309. });
  310. },
  311. confirmCancelOrder() {
  312. this.showCancelModal = false;
  313. // 模拟取消动作
  314. this.currentStep = 0;
  315. // this.currentStatus = {
  316. // text: '已取消',
  317. // time: this.getNowTime(),
  318. // icon: '/static/【待取件】快递员正在赶来.png'
  319. // };
  320. this.$api('cancelOrder', { orderId: this.orderId }, res => {
  321. if (res && res.code === 200) {
  322. console.log('res', res)
  323. uni.showToast({ title: '订单已取消', icon: 'none' });
  324. // 刷新页面数据
  325. this.fetchOrderDetail(this.orderId);
  326. // 通知订单列表页面刷新数据
  327. uni.$emit('orderStatusChanged');
  328. }
  329. })
  330. // uni.showToast({ title: '订单已取消', icon: 'none' });
  331. },
  332. getNowTime() {
  333. const now = new Date();
  334. const y = now.getFullYear();
  335. const m = (now.getMonth() + 1).toString().padStart(2, '0');
  336. const d = now.getDate().toString().padStart(2, '0');
  337. const h = now.getHours().toString().padStart(2, '0');
  338. const min = now.getMinutes().toString().padStart(2, '0');
  339. return `${y}-${m}-${d} ${h}:${min}`;
  340. },
  341. // 判断是否显示单价格(根据estimatedPrice格式判断)
  342. shouldShowSinglePrice(estimatedPrice) {
  343. if (!estimatedPrice || typeof estimatedPrice !== 'string') return true;
  344. // 解析estimatedPrice,格式如"5-0"或"5-10"
  345. const parts = estimatedPrice.split('-');
  346. if (parts.length !== 2) return true;
  347. const maxPrice = parseFloat(parts[1]);
  348. return maxPrice === 0;
  349. },
  350. // 从总价反推单件价格区间
  351. getSinglePriceRange(estimatedPrice, quantity) {
  352. if (!estimatedPrice || typeof estimatedPrice !== 'string' || !quantity) return '';
  353. // 解析estimatedPrice,格式如"25-50"(总价区间)
  354. const parts = estimatedPrice.split('-');
  355. if (parts.length !== 2) return estimatedPrice;
  356. const minTotal = parseFloat(parts[0]);
  357. const maxTotal = parseFloat(parts[1]);
  358. // 计算单件价格区间
  359. const minPrice = (minTotal / quantity).toFixed(2);
  360. const maxPrice = (maxTotal / quantity).toFixed(2);
  361. return `${parseFloat(minPrice)}~${parseFloat(maxPrice)}`;
  362. },
  363. contactCourier() {
  364. // 联系快递员逻辑
  365. if (this.phone) {
  366. uni.makePhoneCall({
  367. phoneNumber: this.phone //仅为示例
  368. });
  369. }else{
  370. uni.showToast({ title: '暂无快递员电话', icon: 'none' });
  371. }
  372. },
  373. fetchOrderDetail(orderId) {
  374. this.$api && this.$api('getOrderDetail', { orderId }, res => {
  375. if (res && res.code === 200 && res.result) {
  376. this.orderDetail = res.result
  377. // 保存状态值
  378. this.status = res.result.status
  379. this.state = res.result.state
  380. // 赋值页面字段
  381. this.address = res.result.address + (res.result.addressDetail || '')
  382. this.appointmentTime = res.result.goTime || ''
  383. this.estimatePrice = res.result.estimatedPrice || ''
  384. this.finalPrice = res.result.price || ''
  385. this.clothesList = res.result.commonOrderList || []
  386. this.expressCompany = res.result.wliu || ''
  387. this.expressNo = res.result.expressNo || ''
  388. this.phone = res.result.deliveryPhone || ''
  389. // 状态判断
  390. this.setOrderStatus(res.result.status, res.result.state, res.result)
  391. }
  392. })
  393. },
  394. setOrderStatus(status, state, data) {
  395. // 0:在线预约 1:快递上门 2:透明质检 3:现金打款
  396. // state:0待取件 1已取件 2已完成 3已取消
  397. if (state == 3) {
  398. this.currentStep = 0
  399. this.currentStatus = {
  400. text: '已取消',
  401. time: '',
  402. icon: '/static/【待取件】快递员正在赶来.png'
  403. }
  404. this.showEditButton = false
  405. return
  406. }
  407. if (status == 0) {
  408. this.currentStep = 1
  409. this.currentStatus = {
  410. text: '【在线预约】',
  411. time: data.goTime || '',
  412. icon: '/static/my/【待取件】快递员正在赶来.png'
  413. }
  414. } else if (status == 1 && state == 0) {
  415. this.currentStep = 2
  416. this.currentStatus = {
  417. text: '【待取件】快递员正在赶来',
  418. time: data.goTime || '',
  419. icon: '/static/my/【待取件】快递员正在赶来.png'
  420. }
  421. } else if (status == 1 && state == 1) {
  422. this.currentStep = 2
  423. this.currentStatus = {
  424. text: '【已取件】快递员正在送至质检',
  425. time: data.goTime || '',
  426. icon: '/static/my/【上门中】快递员正在赶来.png'
  427. }
  428. } else if (status == 2 && state == 1) {
  429. this.currentStep = 3
  430. this.currentStatus = {
  431. text: '【质检中】质检员正在质检',
  432. time: data.goTime || '',
  433. icon: '/static/my/逐件验-配图.png'
  434. }
  435. } else if (status == 3 && state == 1) {
  436. this.currentStep = 4
  437. this.currentStatus = {
  438. text: '【待结款】待平台确认结款项',
  439. time: data.goTime || '',
  440. icon: '/static/my/【已结款】平台已结款至账户.png'
  441. }
  442. this.hasReport = true
  443. this.reportTime = data.updateTime || ''
  444. } else if (status == 3 && state == 2) {
  445. this.currentStep = 4
  446. this.currentStatus = {
  447. text: '【已结款】平台已结款至账户',
  448. time: data.goTime || '',
  449. icon: '/static/my/【已结款】平台已结款至账户.png'
  450. }
  451. this.hasReport = true
  452. this.reportTime = data.updateTime || ''
  453. }
  454. },getAreaList() {
  455. this.$api('getAreaList', {}, (res) => {
  456. console.log(res,'getAreaList');
  457. if (res.code == 200 && Array.isArray(res.result)) {
  458. // 按sort升序排序
  459. const sorted = res.result.slice().sort((a, b) => a.sort - b.sort)
  460. this.processSteps = sorted.map(item => ({
  461. // id: item.id,
  462. icon: item.image,
  463. text: item.title
  464. }))
  465. }
  466. })
  467. },
  468. },
  469. onLoad(options) {
  470. if (options.id) {
  471. this.orderId = options.id
  472. this.fetchOrderDetail(options.id)
  473. }
  474. this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
  475. this.getAreaList()
  476. },
  477. onShow() {
  478. this.getAreaList()
  479. }
  480. }
  481. </script>
  482. <style scoped lang="scss">
  483. .container {
  484. min-height: 100vh;
  485. background: #f4f4f4;
  486. padding-bottom: 120rpx;
  487. }
  488. .card {
  489. background: linear-gradient(180deg, #fffbe6 0%, #fff 90%);
  490. border-radius: 28rpx;
  491. margin: 24rpx 24rpx 0 24rpx;
  492. box-shadow: 0 8rpx 24rpx rgba(255, 156, 0, 0.03);
  493. padding: 40rpx 32rpx;
  494. }
  495. .nav-bar {
  496. display: flex;
  497. align-items: center;
  498. position: fixed;
  499. top: 0;
  500. left: 0;
  501. right: 0;
  502. z-index: 999;
  503. height: calc(150rpx + var(--status-bar-height));
  504. background: #fff;
  505. padding: 0 32rpx;
  506. padding-top: var(--status-bar-height);
  507. box-sizing: border-box;
  508. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  509. .back {
  510. padding: 20rpx;
  511. margin-left: -20rpx;
  512. }
  513. .title {
  514. flex: 1;
  515. text-align: center;
  516. font-size: 34rpx;
  517. font-weight: 500;
  518. }
  519. .right-btns {
  520. display: flex;
  521. align-items: center;
  522. gap: 30rpx;
  523. .more, .target {
  524. font-size: 40rpx;
  525. color: #333;
  526. }
  527. }
  528. }
  529. .card-title, .card-header .title {
  530. font-size: 32rpx;
  531. font-weight: bold;
  532. color: #222;
  533. margin-bottom: 24rpx;
  534. }
  535. .process-card {
  536. background: linear-gradient(180deg, #fffbe6 0%, #fff 35%);
  537. border-radius: 32rpx;
  538. box-shadow: 0 4rpx 16rpx rgba(255, 156, 0, 0.04);
  539. padding: 40rpx 32rpx 32rpx 32rpx;
  540. margin: 24rpx;
  541. }
  542. .card-title {
  543. font-size: 32rpx;
  544. font-weight: bold;
  545. color: #222;
  546. margin-bottom: 24rpx;
  547. text-align: left;
  548. }
  549. .process-steps {
  550. display: flex;
  551. justify-content: space-between;
  552. align-items: flex-start;
  553. margin-bottom: 12rpx;
  554. gap: 18rpx;
  555. }
  556. .step-item {
  557. width: 150%;
  558. height: 150rpx;
  559. background: #fff8ea;
  560. border-radius: 20rpx;
  561. display: flex;
  562. flex-direction: column;
  563. align-items: center;
  564. box-shadow: 0 2rpx 8rpx rgba(255, 156, 0, 0.04);
  565. overflow: hidden;
  566. position: relative;
  567. }
  568. .step-item.cancel {
  569. background: linear-gradient(180deg, #fff0f3 0%, #ffd6df 100%) !important;
  570. }
  571. .step-icon {
  572. width: 86rpx;
  573. height: 86rpx;
  574. margin: 16rpx 0 0 0;
  575. flex-shrink: 0;
  576. }
  577. .step-label {
  578. width: 100%;
  579. height: 44rpx;
  580. background: transparent;
  581. position: absolute;
  582. left: 0;
  583. bottom: 0;
  584. border-radius: 0 0 16rpx 16rpx;
  585. display: flex;
  586. align-items: center;
  587. justify-content: center;
  588. transition: background 0.2s;
  589. overflow: hidden;
  590. }
  591. .step-label.active {
  592. background: linear-gradient(90deg, #ffd01e 0%, #ff8917 100%);
  593. }
  594. .step-label.cancel {
  595. background: linear-gradient(to right, #ff8e8e 0%, #ff5e5e 100%) !important;
  596. }
  597. .step-label.cancel .step-num,
  598. .step-label.cancel .step-text {
  599. color: #fff !important;
  600. }
  601. .step-label-inner {
  602. width: 100%;
  603. height: 100%;
  604. display: flex;
  605. flex-direction: row;
  606. // align-items: center;
  607. justify-content: center;
  608. white-space: nowrap;
  609. }
  610. .step-num,
  611. .step-text {
  612. font-family: PingFang SC;
  613. font-weight: 400;
  614. font-size: 11px;
  615. letter-spacing: 0%;
  616. line-height: 48rpx;
  617. margin: 0;
  618. padding: 0;
  619. color: #9b9b9b;
  620. }
  621. .step-num {
  622. margin-right: 6rpx;
  623. display: flex;
  624. justify-content: center;
  625. align-items: center;
  626. }
  627. .step-label.active .step-num,
  628. .step-label.active .step-text {
  629. font-family: PingFang SC;
  630. font-weight: 500;
  631. font-size: 11px;
  632. letter-spacing: 0%;
  633. color: #fff;
  634. }
  635. .process-divider {
  636. width: 100%;
  637. height: 0;
  638. border-bottom: 1rpx dashed #e6e6e6;
  639. margin: 20rpx 0 0 0;
  640. }
  641. .status-info {
  642. display: flex;
  643. align-items: center;
  644. margin: 24rpx 0;
  645. background: #fafafa;
  646. border-radius: 16rpx;
  647. padding: 16rpx;
  648. }
  649. .status-icon {
  650. width: 60rpx;
  651. height: 60rpx;
  652. margin-right: 16rpx;
  653. }
  654. .status-detail {
  655. display: flex;
  656. flex-direction: column;
  657. flex: 1;
  658. }
  659. .status-text {
  660. font-size: 28rpx;
  661. color: #222;
  662. font-weight: bold;
  663. display: block;
  664. }
  665. .status-time {
  666. font-size: 24rpx;
  667. color: #999;
  668. margin-top: 4rpx;
  669. display: block;
  670. }
  671. .pickup-info .info-item {
  672. display: flex;
  673. // justify-content: space-between;
  674. flex-direction: column;
  675. // align-items: center;
  676. padding: 18rpx 0;
  677. border-bottom: 1px solid #f0f0f0;
  678. margin: 20rpx 0 20rpx 0;
  679. }
  680. .pickup-info .info-item:last-child {
  681. border-bottom: none;
  682. }
  683. .label {
  684. color: #999;
  685. font-size: 26rpx;
  686. }
  687. .value {
  688. color: #222;
  689. font-size: 26rpx;
  690. display: flex;
  691. align-items: center;
  692. }
  693. .value .arrow {
  694. color: #bbb;
  695. margin-left: 8rpx;
  696. }
  697. .order-detail-card {
  698. background: linear-gradient(to bottom, #fff6e3 0%, #fff 20%);
  699. border-radius: 36rpx;
  700. box-shadow: 0 8rpx 32rpx rgba(255, 156, 0, 0.08);
  701. padding: 40rpx 36rpx 32rpx 36rpx;
  702. margin: 24rpx;
  703. margin-bottom: 164rpx;
  704. }
  705. .order-title {
  706. font-size: 36rpx;
  707. font-weight: bold;
  708. color: #222;
  709. margin-bottom: 32rpx;
  710. text-align: left;
  711. display: block;
  712. }
  713. .order-row {
  714. display: flex;
  715. // justify-content: space-between;
  716. align-items: center;
  717. margin-bottom: 18rpx;
  718. }
  719. .order-label {
  720. color: #bcbcbc;
  721. font-size: 26rpx;
  722. margin: 20rpx 0 20rpx 0;
  723. }
  724. .order-value {
  725. color: #222;
  726. font-size: 28rpx;
  727. margin-left: 30rpx;
  728. font-weight: 500;
  729. }
  730. .order-highlight {
  731. color: #ff9c00;
  732. font-size: 30rpx;
  733. font-weight: bold;
  734. }
  735. .order-divider {
  736. width: 100%;
  737. height: 1rpx;
  738. background: #f0f0f0;
  739. margin: 18rpx 0;
  740. }
  741. .goods-list {
  742. margin-top: 10rpx;
  743. display: flex;
  744. flex-direction: column;
  745. gap: 18rpx;
  746. }
  747. .goods-item {
  748. background: #fff;
  749. border-radius: 24rpx;
  750. display: flex;
  751. align-items: center;
  752. padding: 24rpx 20rpx;
  753. box-shadow: 0 2rpx 8rpx rgba(255, 156, 0, 0.04);
  754. position: relative;
  755. }
  756. .goods-img {
  757. width: 90rpx;
  758. height: 90rpx;
  759. border-radius: 18rpx;
  760. margin-right: 20rpx;
  761. // background: #fffbe6;
  762. flex-shrink: 0;
  763. }
  764. .goods-info {
  765. flex: 1;
  766. display: flex;
  767. flex-direction: column;
  768. justify-content: center;
  769. }
  770. .goods-name {
  771. font-size: 30rpx;
  772. color: #222;
  773. font-weight: bold;
  774. margin-bottom: 6rpx;
  775. }
  776. .desc { font-size: 24rpx; color: #999; margin: 4rpx 0 8rpx 0; }
  777. .goods-desc {
  778. font-size: 24rpx;
  779. color: #bcbcbc;
  780. margin-bottom: 10rpx;
  781. }
  782. .goods-meta {
  783. display: flex;
  784. align-items: center;
  785. gap: 10rpx;
  786. }
  787. .goods-price {
  788. color: #ff9c00;
  789. font-size: 26rpx;
  790. font-weight: bold;
  791. }
  792. .goods-unit {
  793. color: #bcbcbc;
  794. font-size: 22rpx;
  795. font-weight: normal;
  796. }
  797. .goods-count {
  798. color: #bcbcbc;
  799. font-size: 24rpx;
  800. margin-left: 8rpx;
  801. }
  802. .goods-total {
  803. color: #222;
  804. font-size: 30rpx;
  805. font-weight: bold;
  806. margin-left: 18rpx;
  807. flex-shrink: 0;
  808. }
  809. .bottom-btns {
  810. position: fixed;
  811. left: 0;
  812. right: 0;
  813. bottom: 0;
  814. z-index: 999;
  815. background: #fff;
  816. display: flex;
  817. justify-content: space-between;
  818. align-items: center;
  819. padding: 24rpx 24rpx calc(env(safe-area-inset-bottom) + 24rpx) 24rpx;
  820. box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.1);
  821. border-top: 1rpx solid #f0f0f0;
  822. gap: 24rpx;
  823. }
  824. .btn {
  825. flex: 1;
  826. height: 78rpx;
  827. font-size: 32rpx;
  828. font-weight: bold;
  829. border-radius: 44rpx;
  830. margin: 0;
  831. padding: 0;
  832. }
  833. .cancel-btn {
  834. color: #ff9c00;
  835. background: #fff0d2;
  836. border: 2rpx solid #ffd01e;
  837. }
  838. .contact-btn {
  839. color: #fff;
  840. background: linear-gradient(90deg, #ffd01e 0%, #ff8917 100%);
  841. border: none;
  842. }
  843. .express-info {
  844. // border: 1rpx solid #ffdca8;
  845. border-radius: 12rpx;
  846. // padding: 18rpx 20rpx 10rpx 20rpx;
  847. margin-bottom: 12rpx;
  848. margin-top: 8rpx;
  849. background: #fff;
  850. position: relative;
  851. }
  852. .express-label {
  853. color: #bcbcbc;
  854. font-size: 24rpx;
  855. margin-bottom: 8rpx;
  856. display: block;
  857. }
  858. .express-row {
  859. display: flex;
  860. justify-content: space-between;
  861. align-items: center;
  862. }
  863. .express-value {
  864. color: #222;
  865. font-size: 28rpx;
  866. font-weight: 500;
  867. word-break: break-all;
  868. }
  869. .express-copy {
  870. color: #ff9c00;
  871. font-size: 26rpx;
  872. font-weight: 500;
  873. margin-left: 16rpx;
  874. }
  875. .modal-mask {
  876. position: fixed;
  877. left: 0; right: 0; top: 0; bottom: 0;
  878. background: rgba(0,0,0,0.35);
  879. z-index: 999;
  880. display: flex;
  881. align-items: center;
  882. justify-content: center;
  883. }
  884. .modal-box {
  885. width: 560rpx;
  886. background: #fff;
  887. border-radius: 32rpx;
  888. box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.08);
  889. padding: 56rpx 0 0 0;
  890. display: flex;
  891. flex-direction: column;
  892. align-items: center;
  893. }
  894. .modal-title {
  895. font-size: 36rpx;
  896. font-weight: bold;
  897. color: #222;
  898. text-align: center;
  899. margin-bottom: 18rpx;
  900. }
  901. .modal-content {
  902. font-size: 28rpx;
  903. color: #222;
  904. text-align: center;
  905. margin-bottom: 48rpx;
  906. }
  907. .modal-actions {
  908. width: 100%;
  909. display: flex;
  910. border-top: 1rpx solid #f0f0f0;
  911. height: 100rpx;
  912. }
  913. .modal-btn {
  914. flex: 1;
  915. border: none;
  916. outline: none;
  917. background: none;
  918. font-size: 32rpx;
  919. font-weight: 500;
  920. border-radius: 0 0 0 32rpx;
  921. height: 100rpx;
  922. line-height: 100rpx;
  923. }
  924. .modal-cancel {
  925. color: #999;
  926. background: #fff;
  927. border-bottom-left-radius: 32rpx;
  928. }
  929. .modal-confirm {
  930. color: #ff9c00;
  931. background: #fff;
  932. border-bottom-right-radius: 32rpx;
  933. }
  934. .cancel-tip {
  935. color: #bcbcbc;
  936. font-size: 26rpx;
  937. text-align: center;
  938. margin: 24rpx 0 0 0;
  939. }
  940. .info-divider {
  941. width: 100%;
  942. height: 1rpx;
  943. background: #f0f0f0;
  944. margin: 0;
  945. }
  946. .report-btn {
  947. width: 100%;
  948. margin: 24rpx 0 0 0;
  949. padding: 0;
  950. height: 80rpx;
  951. line-height: 80rpx;
  952. text-align: center;
  953. color: #ff9c00;
  954. background: #fff;
  955. border: 2rpx solid #ffd01e;
  956. border-radius: 44rpx;
  957. font-size: 28rpx;
  958. font-weight: bold;
  959. }
  960. .detail-info-card {
  961. margin-bottom: 48rpx;
  962. }
  963. .content {
  964. margin-top: calc(150rpx + var(--status-bar-height));
  965. padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
  966. }
  967. </style>