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

1037 lines
29 KiB

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