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

711 lines
19 KiB

2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
  1. <template>
  2. <view class="inspection-detail-page">
  3. <!-- 顶部导航栏 -->
  4. <view class="nav-bar" :style="{ height: navBarTotalHeight + 'px', paddingTop: statusBarHeight + 'px' }">
  5. <view class="nav-bar-left" @tap="navigateBack">
  6. <uni-icons type="left" size="22" color="#222" />
  7. </view>
  8. <view class="nav-bar-title">质检详情</view>
  9. <view class="nav-bar-right">
  10. <uni-icons type="more-filled" size="22" color="#222" />
  11. <uni-icons type="camera" size="22" color="#222" style="margin-left: 12rpx;" />
  12. </view>
  13. </view>
  14. <scroll-view scroll-y class="main-content safe-area-inset-bottom" :style="{ marginTop: navBarTotalHeight + 'px' }">
  15. <!-- 质检合格列表 -->
  16. <view v-if="qualifiedList.length > 0" class="section">
  17. <view class="section-title">
  18. <view class="dot dot-green"></view>
  19. <text class="title-text">质检合格</text>
  20. </view>
  21. <view v-for="(item, index) in qualifiedList" :key="'qualified-' + index" class="card card-qualified">
  22. <view v-if="item.qualityLevel" class="quality-level-badge">{{ item.qualityLevel }}</view>
  23. <view class="card-header">
  24. <view class="goods-info">
  25. <image :src="item.img" class="goods-img" mode="aspectFit" />
  26. <view class="goods-detail">
  27. <text class="goods-name">{{ item.name }}</text>
  28. <text class="goods-desc">{{ item.desc }}</text>
  29. <text v-if="item.styleName" class="goods-style">款式{{ item.styleName }}</text>
  30. <view class="goods-price-row">
  31. <text class="goods-price" v-if="item.price">{{ (item.price / item.count).toFixed(2) }}/</text>
  32. <text class="goods-count">x{{ item.count }}</text>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. <view class="timeline">
  38. <view class="timeline-item">
  39. <view class="timeline-dot"></view>
  40. <view class="timeline-content">
  41. <view class="timeline-title-row">
  42. <text class="timeline-title">质检说明</text>
  43. <text class="timeline-time">{{ item.testingTime }}</text>
  44. </view>
  45. <view class="problem-block">
  46. <view class="problem-title">质检图片</view>
  47. <view class="problem-divider"></view>
  48. <view class="problem-images" v-if="item.imagesArr && item.imagesArr.length > 0">
  49. <view v-for="(img, i) in item.imagesArr" :key="i" class="img-lock-wrap"
  50. @tap="isSelf && previewImage(img, i)">
  51. <image :src="img" class="problem-img" mode="aspectFill" />
  52. <view v-if="!isSelf" class="img-lock-mask">
  53. <image src="/static/lock.png" class="lock-icon" />
  54. <view class="lock-tip">为保护用户隐私衣物照片仅本人可见您无权限查看</view>
  55. </view>
  56. </view>
  57. </view>
  58. <view v-else class="no-images">暂无质检图片</view>
  59. </view>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. </view>
  65. <!-- 不可回收列表 -->
  66. <view v-if="unrecyclableList.length > 0" class="section">
  67. <view class="section-title">
  68. <view class="dot dot-orange"></view>
  69. <text class="title-text">不可回收</text>
  70. </view>
  71. <view v-for="(item, index) in unrecyclableList" :key="'unrecyclable-' + index" class="card card-problem">
  72. <view v-if="item.qualityLevel" class="quality-level-badge">{{ item.qualityLevel }}</view>
  73. <view class="card-header">
  74. <view class="goods-info">
  75. <image :src="item.img || bkhs_image" class="goods-img" mode="aspectFit" />
  76. <view class="goods-detail">
  77. <text class="goods-name">{{ item.name }}</text>
  78. <text class="goods-desc">{{ item.desc }}</text>
  79. <text v-if="item.styleName" class="goods-style">款式{{ item.styleName }}</text>
  80. <view class="goods-price-row">
  81. <text class="goods-price" v-if="item.price">{{ (item.price / item.count).toFixed(2) }}/</text>
  82. <text class="goods-count">x{{ item.count }}</text>
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. <view class="timeline">
  88. <view class="timeline-item">
  89. <view class="timeline-dot"></view>
  90. <view class="timeline-content">
  91. <view class="timeline-title-row">
  92. <text class="timeline-title">质检说明</text>
  93. <text class="timeline-time">{{ item.testingTime }}</text>
  94. </view>
  95. <view class="problem-block">
  96. <view class="problem-title">{{ item.problemDesc || '不可回收' }}</view>
  97. <view class="problem-divider"></view>
  98. <view class="problem-label">质检实拍</view>
  99. <view class="problem-images" v-if="item.imagesArr && item.imagesArr.length > 0">
  100. <view v-for="(img, i) in item.imagesArr" :key="i" class="img-lock-wrap"
  101. @tap="isSelf && previewImage(img, i)">
  102. <image :src="img" class="problem-img" mode="aspectFill" />
  103. <view v-if="!isSelf" class="img-lock-mask">
  104. <image src="/static/lock.png" class="lock-icon" />
  105. <view class="lock-tip">为保护用户隐私衣物照片仅本人可见您无权限查看</view>
  106. </view>
  107. </view>
  108. </view>
  109. <view v-else class="no-images">暂无质检图片</view>
  110. </view>
  111. </view>
  112. </view>
  113. </view>
  114. </view>
  115. </view>
  116. <!-- 质量问题列表 -->
  117. <view v-if="problemList.length > 0" class="section">
  118. <view class="section-title">
  119. <view class="dot dot-orange"></view>
  120. <text class="title-text">质量问题</text>
  121. </view>
  122. <view v-for="(item, index) in problemList" :key="'problem-' + index" class="card card-problem">
  123. <view v-if="item.qualityLevel" class="quality-level-badge">{{ item.qualityLevel }}</view>
  124. <view class="card-header">
  125. <view class="goods-info">
  126. <image :src="item.img || zlwt_image" class="goods-img" mode="aspectFit" />
  127. <view class="goods-detail">
  128. <text class="goods-name">{{ item.name }}</text>
  129. <text class="goods-desc">{{ item.desc }}</text>
  130. <text v-if="item.styleName" class="goods-style">款式{{ item.styleName }}</text>
  131. <view class="goods-price-row">
  132. <text class="goods-price" v-if="item.price">{{ (item.price / item.count).toFixed(2) }}/</text>
  133. <text class="goods-count">x{{ item.count }}</text>
  134. </view>
  135. </view>
  136. </view>
  137. </view>
  138. <view class="timeline">
  139. <view class="timeline-item">
  140. <view class="timeline-dot"></view>
  141. <view class="timeline-content">
  142. <view class="timeline-title-row">
  143. <text class="timeline-title">质检说明</text>
  144. <text class="timeline-time">{{ item.testingTime }}</text>
  145. </view>
  146. <view class="problem-block">
  147. <view class="problem-title">{{ item.problemDesc || '质量问题' }}</view>
  148. <view class="problem-divider"></view>
  149. <view class="problem-label">质量问题实拍</view>
  150. <view class="problem-images" v-if="item.imagesArr && item.imagesArr.length > 0">
  151. <view v-for="(img, i) in item.imagesArr" :key="i" class="img-lock-wrap"
  152. @tap="isSelf && previewImage(img, i)">
  153. <image :src="img" class="problem-img" mode="aspectFill" />
  154. <view v-if="!isSelf" class="img-lock-mask">
  155. <image src="/static/lock.png" class="lock-icon" />
  156. <view class="lock-tip">为保护用户隐私衣物照片仅本人可见您无权限查看</view>
  157. </view>
  158. </view>
  159. </view>
  160. <view v-else class="no-images">暂无质检图片</view>
  161. </view>
  162. </view>
  163. </view>
  164. </view>
  165. </view>
  166. </view>
  167. </scroll-view>
  168. </view>
  169. </template>
  170. <script>
  171. export default {
  172. data() {
  173. return {
  174. statusBarHeight: 0,
  175. navBarHeight: 44,
  176. navBarTotalHeight: 44,
  177. orderId: '',
  178. qualifiedList: [],
  179. problemList: [],
  180. unrecyclableList: [],
  181. isSelf: true,
  182. }
  183. },
  184. computed: {
  185. bkhs_image() {//不可回收图片
  186. const item = getApp().globalData.configData.find(i => i.keyName === 'bkhs_image')
  187. return item ? item.keyContent : ''
  188. },
  189. zlwt_image() {//质量问题图片
  190. const item = getApp().globalData.configData.find(i => i.keyName === 'zlwt_image')
  191. return item ? item.keyContent : ''
  192. },
  193. },
  194. onLoad(options) {
  195. // 适配顶部安全区
  196. const sysInfo = uni.getSystemInfoSync()
  197. this.statusBarHeight = sysInfo.statusBarHeight
  198. this.navBarHeight = 44
  199. this.navBarTotalHeight = this.statusBarHeight + this.navBarHeight
  200. // 获取订单ID
  201. if (options && options.orderId) {
  202. this.orderId = options.orderId
  203. this.fetchOrderDetail()
  204. }
  205. // 判断是否为本人或管理员
  206. if (options.isSelf) {
  207. this.isSelf = true
  208. }
  209. },
  210. methods: {
  211. async fetchOrderDetail() {
  212. this.$api && this.$api('getOrderDetail', {
  213. orderId: this.orderId
  214. }, res => {
  215. if (res && res.code === 200 && res.result) {
  216. this.parseOrderData(res.result)
  217. }
  218. })
  219. },
  220. parseOrderData(orderData) {
  221. this.qualifiedList = []
  222. this.problemList = []
  223. this.unrecyclableList = []
  224. if (orderData.orderCheckList && orderData.orderCheckList.length > 0) {
  225. orderData.orderCheckList.forEach(item => {
  226. // 合格商品
  227. if (Number(item.qualifiedNum) > 0) {
  228. const imagesArr = item.commonOrderList && item.commonOrderList[0] && item.commonOrderList[0].testingImages
  229. ? item.commonOrderList[0].testingImages.split(',').filter(img => img.trim() !== '')
  230. : []
  231. this.qualifiedList.push({
  232. img: item.image || '/static/default-goods.png',
  233. name: item.title || '未知品类',
  234. desc: item.pinName ? `${item.pinName}` : '',
  235. styleName: item.styleName || '',
  236. price: item.price || 0,
  237. count: item.qualifiedNum,
  238. qualityLevel: item.qualityLevel || '',
  239. testingTime: item.commonOrderList && item.commonOrderList[0] && item.commonOrderList[0].testingTime || '',
  240. imagesArr: imagesArr
  241. })
  242. }
  243. // 质量问题和不可回收
  244. if (Array.isArray(item.commonOrderList)) {
  245. item.commonOrderList.forEach(sub => {
  246. const imagesArr = sub.testingImages ? sub.testingImages.split(',').filter(img => img.trim() !== '') : []
  247. // 质量问题
  248. if (sub.testingStatus == 1) {
  249. this.problemList.push({
  250. img: item.image,
  251. name: item.title || '未知品类',
  252. desc: item.pinName ? `${item.pinName}` : '',
  253. styleName: item.styleName || '',
  254. price: (item.price || 0) / (item.noQualifiedNum || 1),
  255. count: sub.num || 1,
  256. qualityLevel: sub.qualityLevel || '',
  257. testingTime: sub.testingTime || '',
  258. problemDesc: sub.testingInstructions || '',
  259. imagesArr: imagesArr
  260. })
  261. }
  262. // 不可回收
  263. if (sub.testingStatus == 2) {
  264. this.unrecyclableList.push({
  265. img: item.image,
  266. name: item.title || '未知品类',
  267. desc: item.pinName ? `${item.pinName}` : '',
  268. styleName: item.styleName || '',
  269. price: (item.price || 0) / (item.unrecyclable || 1),
  270. count: sub.num || 1,
  271. qualityLevel: sub.qualityLevel || '',
  272. testingTime: sub.testingTime || '',
  273. problemDesc: sub.testingInstructions || '',
  274. imagesArr: imagesArr
  275. })
  276. }
  277. })
  278. }
  279. })
  280. }
  281. },
  282. navigateBack() {
  283. uni.navigateBack()
  284. },
  285. previewImage(img, i) {
  286. // 获取当前点击图片所在的列表
  287. let allImages = []
  288. this.qualifiedList.forEach(item => {
  289. if (item.imagesArr) allImages = allImages.concat(item.imagesArr)
  290. })
  291. this.problemList.forEach(item => {
  292. if (item.imagesArr) allImages = allImages.concat(item.imagesArr)
  293. })
  294. this.unrecyclableList.forEach(item => {
  295. if (item.imagesArr) allImages = allImages.concat(item.imagesArr)
  296. })
  297. uni.previewImage({
  298. current: img,
  299. urls: allImages.length > 0 ? allImages : [img]
  300. })
  301. }
  302. }
  303. }
  304. </script>
  305. <style lang="scss" scoped>
  306. .inspection-detail-page {
  307. min-height: 100vh;
  308. background: #f7f7f7;
  309. box-sizing: border-box;
  310. display: flex;
  311. flex-direction: column;
  312. align-items: center;
  313. }
  314. .nav-bar {
  315. position: fixed;
  316. left: 0;
  317. top: 0;
  318. right: 0;
  319. z-index: 1000;
  320. background: #fff;
  321. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
  322. display: flex;
  323. align-items: center;
  324. justify-content: space-between;
  325. height: 100rpx;
  326. padding: 0 24rpx;
  327. .nav-bar-left,
  328. .nav-bar-right {
  329. display: flex;
  330. align-items: center;
  331. min-width: 60rpx;
  332. }
  333. .nav-bar-title {
  334. flex: 1;
  335. text-align: center;
  336. font-size: 34rpx;
  337. font-weight: bold;
  338. color: #222;
  339. }
  340. max-width: 750rpx;
  341. margin: 0 auto;
  342. width: 100%;
  343. box-sizing: border-box;
  344. }
  345. .main-content {
  346. padding: 32rpx 24rpx 0 24rpx;
  347. width: 100%;
  348. max-width: 750rpx;
  349. margin: 0 auto;
  350. box-sizing: border-box;
  351. height: calc(100vh - var(--nav-bar-height));
  352. }
  353. .section {
  354. margin-bottom: 40rpx;
  355. }
  356. .section-title {
  357. display: flex;
  358. align-items: center;
  359. margin-bottom: 24rpx;
  360. padding: 0 16rpx;
  361. }
  362. .title-text {
  363. font-size: 32rpx;
  364. font-weight: bold;
  365. color: #222;
  366. }
  367. .goods-info {
  368. display: flex;
  369. align-items: center;
  370. margin-bottom: 16rpx;
  371. }
  372. .goods-img {
  373. width: 80rpx;
  374. height: 80rpx;
  375. border-radius: 16rpx;
  376. margin-right: 20rpx;
  377. background: #f5f5f5;
  378. }
  379. .goods-detail {
  380. flex: 1;
  381. display: flex;
  382. flex-direction: column;
  383. }
  384. .goods-name {
  385. font-size: 28rpx;
  386. font-weight: bold;
  387. color: #222;
  388. margin-bottom: 4rpx;
  389. }
  390. .goods-desc {
  391. font-size: 24rpx;
  392. color: #999;
  393. margin-bottom: 4rpx;
  394. }
  395. .goods-style {
  396. font-size: 24rpx;
  397. color: #666;
  398. margin-bottom: 4rpx;
  399. }
  400. .goods-price-row {
  401. display: flex;
  402. align-items: baseline;
  403. justify-content: space-between;
  404. }
  405. .goods-price {
  406. font-size: 24rpx;
  407. color: #ff6600;
  408. font-weight: bold;
  409. }
  410. .goods-count {
  411. font-size: 24rpx;
  412. color: #666;
  413. }
  414. .no-images {
  415. color: #999;
  416. font-size: 24rpx;
  417. text-align: center;
  418. padding: 20rpx;
  419. background: #f8f8f8;
  420. border-radius: 12rpx;
  421. }
  422. .safe-area-inset-bottom {
  423. padding-bottom: constant(safe-area-inset-bottom);
  424. padding-bottom: env(safe-area-inset-bottom);
  425. }
  426. .card {
  427. margin: 0 24rpx;
  428. border-radius: 32rpx;
  429. padding: 32rpx 32rpx 24rpx 32rpx;
  430. box-shadow: 0 4rpx 24rpx rgba(60, 167, 250, 0.08);
  431. background: #fff;
  432. max-width: 700rpx;
  433. width: calc(100% - 30rpx);
  434. box-sizing: border-box;
  435. position: relative;
  436. }
  437. .quality-level-badge {
  438. position: absolute;
  439. top: 16rpx;
  440. right: 16rpx;
  441. width: 48rpx;
  442. height: 48rpx;
  443. border-radius: 50%;
  444. background: #ffb400;
  445. color: #fff;
  446. font-size: 24rpx;
  447. font-weight: bold;
  448. display: flex;
  449. align-items: center;
  450. justify-content: center;
  451. z-index: 10;
  452. box-shadow: 0 2rpx 8rpx rgba(255, 180, 0, 0.3);
  453. }
  454. .card-problem {
  455. background: linear-gradient(180deg, #fff7e6 0%, #fff 40%);
  456. }
  457. .card-qualified {
  458. background: linear-gradient(180deg, #e8ffe0 0%, #fff 100%);
  459. }
  460. .card-header {
  461. display: flex;
  462. align-items: center;
  463. margin-bottom: 12rpx;
  464. }
  465. .dot {
  466. width: 16rpx;
  467. height: 16rpx;
  468. border-radius: 50%;
  469. margin-right: 12rpx;
  470. &.dot-orange {
  471. background: #ffa800;
  472. }
  473. &.dot-green {
  474. background: #13ac47;
  475. }
  476. &.gray {
  477. background: #bbb;
  478. }
  479. }
  480. .card-title {
  481. font-size: 30rpx;
  482. font-weight: bold;
  483. }
  484. .card-title-orange {
  485. color: #ffa800;
  486. }
  487. .card-title-green {
  488. color: #13ac47;
  489. }
  490. .card-desc {
  491. font-size: 24rpx;
  492. color: #888;
  493. margin-bottom: 24rpx;
  494. line-height: 1.7;
  495. margin-left: 32rpx + 16rpx;
  496. }
  497. .card-desc-orange {
  498. color: #888;
  499. }
  500. .card-desc-green {
  501. color: #888;
  502. }
  503. .timeline {
  504. position: relative;
  505. margin-left: 0;
  506. padding-left: 0;
  507. }
  508. .timeline:before {
  509. content: '';
  510. position: absolute;
  511. left: 8rpx;
  512. top: 0;
  513. bottom: 0;
  514. width: 2rpx;
  515. background: #eee;
  516. z-index: 0;
  517. }
  518. .timeline-item {
  519. display: flex;
  520. align-items: flex-start;
  521. margin-bottom: 32rpx;
  522. position: relative;
  523. }
  524. .timeline-dot {
  525. width: 16rpx;
  526. height: 16rpx;
  527. border-radius: 50%;
  528. background: #bbb;
  529. margin-right: 16rpx;
  530. margin-top: 8rpx;
  531. flex-shrink: 0;
  532. position: relative;
  533. z-index: 1;
  534. }
  535. .timeline-dot.dot-orange {
  536. background: #ffa800;
  537. }
  538. .timeline-dot.dot-green {
  539. background: #13ac47;
  540. }
  541. .timeline-dot.gray {
  542. background: #bbb;
  543. }
  544. .timeline-content {
  545. flex: 1;
  546. min-width: 0;
  547. }
  548. .timeline-title-row {
  549. display: flex;
  550. align-items: center;
  551. margin-bottom: 12rpx;
  552. }
  553. .timeline-title {
  554. font-size: 26rpx;
  555. color: #222;
  556. font-weight: bold;
  557. margin-right: 16rpx;
  558. }
  559. .timeline-time {
  560. font-size: 22rpx;
  561. color: #bbb;
  562. }
  563. .problem-block {
  564. background: #f7f8fa;
  565. border-radius: 20rpx;
  566. padding: 24rpx 20rpx 16rpx 20rpx;
  567. margin-bottom: 20rpx;
  568. max-width: 100%;
  569. box-sizing: border-box;
  570. }
  571. .problem-index {
  572. font-size: 22rpx;
  573. color: #bbb;
  574. margin-bottom: 6rpx;
  575. }
  576. .problem-title {
  577. font-size: 26rpx;
  578. color: #222;
  579. font-weight: bold;
  580. margin-bottom: 8rpx;
  581. }
  582. .problem-divider {
  583. border-bottom: 2rpx dashed #ddd;
  584. margin: 12rpx 0 10rpx 0;
  585. }
  586. .problem-label {
  587. font-size: 22rpx;
  588. color: #bbb;
  589. margin-bottom: 8rpx;
  590. }
  591. .problem-images {
  592. display: flex;
  593. flex-wrap: wrap;
  594. gap: 12rpx;
  595. max-width: 100%;
  596. }
  597. .problem-img {
  598. width: 120rpx;
  599. height: 120rpx;
  600. border-radius: 12rpx;
  601. background: #eee;
  602. max-width: 40vw;
  603. max-height: 40vw;
  604. }
  605. .timeline-desc {
  606. font-size: 24rpx;
  607. color: #888;
  608. margin-top: 8rpx;
  609. line-height: 1.7;
  610. }
  611. .img-lock-wrap {
  612. position: relative;
  613. display: inline-block;
  614. }
  615. .img-lock-mask {
  616. position: absolute;
  617. left: 0;
  618. top: 0;
  619. right: 0;
  620. bottom: 0;
  621. background: rgba(0, 0, 0, 0.45);
  622. display: flex;
  623. flex-direction: column;
  624. align-items: center;
  625. justify-content: center;
  626. border-radius: 12rpx;
  627. z-index: 2;
  628. }
  629. .lock-icon {
  630. width: 48rpx;
  631. height: 48rpx;
  632. margin-bottom: 8rpx;
  633. }
  634. .lock-tip {
  635. color: #fff;
  636. font-size: 20rpx;
  637. text-align: center;
  638. padding: 0 8rpx;
  639. }
  640. </style>