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

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
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
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
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">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>