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

1013 lines
28 KiB

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