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

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