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

995 lines
30 KiB

2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view class="inspect-result-container" :class="{ 'popup-open': isPopupOpen }">
  3. <!-- 顶部导航栏 -->
  4. <view class="nav-bar">
  5. <view class="back" @tap="goBack">
  6. <uni-icons type="left" size="20" color="#222" />
  7. </view>
  8. <text class="nav-title">步骤二合格质检</text>
  9. <view class="nav-icons">
  10. <uni-icons type="more" size="24" color="#222" />
  11. </view>
  12. </view>
  13. <view class="main-content">
  14. <!-- 合格产品卡片 -->
  15. <view v-if="hasQualifiedItems" class="result-card">
  16. <view class="card-title">合格产品</view>
  17. <view v-for="item in qualifiedList" :key="item.id" class="result-row">
  18. <view class="row-main">
  19. <view class="goods-name-section">
  20. <text class="goods-name">{{getItemName(item.id)}}</text>
  21. <text class="goods-brand">{{getItemBrand(item.id)}}</text>
  22. </view>
  23. <text class="row-price">¥ {{item.price}} <text class="row-unit">/</text></text>
  24. <text class="row-count">x{{item.count}}</text>
  25. <text class="row-total">¥{{item.total}}</text>
  26. </view>
  27. <view class="row-reason">
  28. <text class="reason-label">{{getItemName(item.id)}}</text>
  29. <view class="reason-select" @tap="selectReasonForQualified(item)">
  30. <text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
  31. {{ hasSelectedReason(item) ? '已选择' : '请选择理由(选填)' }}
  32. </text>
  33. <uni-icons type="right" size="18" color="#bbb" />
  34. </view>
  35. </view>
  36. </view>
  37. </view>
  38. <!-- 不合格产品卡片 -->
  39. <view v-if="hasUnqualifiedItems" class="result-card">
  40. <view class="card-title">不合格产品</view>
  41. <view v-for="group in unqualifiedGroups" :key="group.name" class="result-group">
  42. <view class="row-main">
  43. <view class="goods-name-section">
  44. <text class="goods-name">{{getItemName(group.id)}}</text>
  45. <text class="goods-brand">{{getItemBrand(group.id)}}</text>
  46. </view>
  47. <text class="row-price">¥ {{group.price}} <text class="row-unit">/</text></text>
  48. <text class="row-total">¥{{group.total}}</text>
  49. </view>
  50. <view v-for="item in group.items" :key="item.id" class="row-reason">
  51. <text class="reason-label">{{item.name}}</text>
  52. <view class="reason-select" @tap="selectReason(item)">
  53. <text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
  54. {{ hasSelectedReason(item) ? '已选择' : '请选择理由' }}
  55. </text>
  56. <uni-icons type="right" size="18" color="#bbb" />
  57. </view>
  58. </view>
  59. </view>
  60. </view>
  61. <!-- 不可回收产品卡片 -->
  62. <view v-if="hasUnrecyclableItems" class="result-card">
  63. <view class="card-title">不可回收产品</view>
  64. <view v-for="item in unrecyclableList" :key="item.id" class="result-row">
  65. <view class="row-main">
  66. <view class="goods-name-section">
  67. <text class="goods-name">{{getItemName(item.id)}}</text>
  68. <text class="goods-brand">{{getItemBrand(item.id)}}</text>
  69. </view>
  70. <text class="row-price">¥ {{item.price || '—'}} <text class="row-unit">/</text></text>
  71. <text class="row-count">x{{item.count}}</text>
  72. <text class="row-total">¥{{item.total}}</text>
  73. </view>
  74. <view class="row-reason">
  75. <text class="reason-label">{{getItemName(item.id)}}</text>
  76. <view class="reason-select" @tap="selectReasonForUnrecyclable(item)">
  77. <text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
  78. {{ hasSelectedReason(item) ? '已选择' : '请选择理由(选填)' }}
  79. </text>
  80. <uni-icons type="right" size="18" color="#bbb" />
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. <!-- 回收信息卡片 -->
  86. <view class="result-card info-card">
  87. <view class="card-title-row">
  88. <text class="card-title">回收信息</text>
  89. <view class="status-tag">待质检</view>
  90. </view>
  91. <view class="info-row">
  92. <text class="info-label">订单编号</text>
  93. <text class="info-value copy-btn">{{ order?.ordeNo || 'RE82738127861525' }} 复制</text>
  94. </view>
  95. <view class="info-row">
  96. <text class="info-label">取件时间</text>
  97. <text class="info-value">{{ order?.goTime || '2025-03-20 11:00' }}</text>
  98. </view>
  99. </view>
  100. </view>
  101. <!-- 底部操作按钮 -->
  102. <view class="footer-btns">
  103. <button class="btn-outline" @tap="goPrev">上一步</button>
  104. <button class="btn-main" @tap="finishInspect">完成质检</button>
  105. </view>
  106. <!-- 理由弹窗 -->
  107. <uni-popup ref="reasonPopup" type="bottom" :mask-click="false" :safe-area="false" class="reason-popup-wrapper">
  108. <view class="reason-popup">
  109. <view class="popup-header">
  110. <text class="popup-close" @tap="closeReasonPopup">关闭</text>
  111. <text class="popup-title">{{ currentReasonTitle }}</text>
  112. </view>
  113. <scroll-view class="popup-content" scroll-y="true">
  114. <view class="popup-section">
  115. <text class="section-label">上传图片</text>
  116. <view class="img-list">
  117. <view class="img-item add" @tap="addReasonImg">
  118. <uni-icons type="plusempty" size="32" color="#bbb" />
  119. </view>
  120. <view v-for="(img, idx) in reasonImages" :key="idx" class="img-item">
  121. <image :src="img" class="img" />
  122. <view class="img-del" @tap="removeReasonImg(idx)">×</view>
  123. </view>
  124. </view>
  125. </view>
  126. <view class="popup-section">
  127. <text class="section-label">选择理由</text>
  128. <view v-for="(item, index) in reasonOptions" :key="item.id" class="reason-row" @tap="toggleReason(index)">
  129. <view :class="['checkbox', {checked: reasonChecked[index]}]" />
  130. <text class="reason-text">{{ item.reason }}</text>
  131. </view>
  132. </view>
  133. </scroll-view>
  134. <button class="popup-save-btn" @tap="saveReason">保存</button>
  135. </view>
  136. </uni-popup>
  137. </view>
  138. </template>
  139. <script>
  140. import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
  141. import OSS from '@/utils/oss-upload/oss/index.js'
  142. export default {
  143. mixins: [pullRefreshMixin],
  144. data() {
  145. return {
  146. inspectData: null, // 从步骤一传过来的质检数据
  147. order: null, // 订单数据
  148. qualifiedList: [],
  149. unqualifiedGroups: [],
  150. unrecyclableList: [],
  151. reasonPopupVisible: false,
  152. currentReasonTitle: '',
  153. reasonImages: [],
  154. reasonOptions: [],
  155. reasonChecked: [],
  156. currentReasonItem: null,
  157. isPopupOpen: false // 控制弹窗状态
  158. }
  159. },
  160. computed: {
  161. hasQualifiedItems() {
  162. return this.qualifiedList && this.qualifiedList.length > 0
  163. },
  164. hasUnqualifiedItems() {
  165. return this.unqualifiedGroups && this.unqualifiedGroups.length > 0
  166. },
  167. hasUnrecyclableItems() {
  168. return this.unrecyclableList && this.unrecyclableList.length > 0
  169. }
  170. },
  171. onLoad(options) {
  172. // 接收质检数据和订单数据
  173. if (options && options.resultData) {
  174. try {
  175. const resultData = JSON.parse(decodeURIComponent(options.resultData))
  176. this.inspectData = resultData.inspectResult
  177. this.order = resultData.order
  178. console.log('接收到的质检数据:', this.inspectData)
  179. console.log('接收到的订单数据:', this.order)
  180. this.processInspectData()
  181. } catch (error) {
  182. console.error('解析数据失败:', error)
  183. }
  184. }
  185. // 兼容旧的参数格式
  186. if (options && options.inspectData && !options.resultData) {
  187. try {
  188. this.inspectData = JSON.parse(decodeURIComponent(options.inspectData))
  189. console.log('接收到的质检数据:', this.inspectData)
  190. this.processInspectData()
  191. } catch (error) {
  192. console.error('解析质检数据失败:', error)
  193. }
  194. }
  195. },
  196. methods: {
  197. processInspectData() {
  198. if (!this.inspectData || !this.inspectData.list) return
  199. this.qualifiedList = []
  200. this.unqualifiedGroups = []
  201. this.unrecyclableList = []
  202. this.inspectData.list.forEach(item => {
  203. // 跳过不可回收分类
  204. if (item.id === 'unrecyclable') return
  205. // 从order中获取对应的商品信息
  206. const orderItem = this.order?.commonOrderList?.find(orderGoods => orderGoods.id == item.id)
  207. if (!orderItem) return
  208. const itemName = orderItem.title || '未知商品'
  209. const itemBrand = orderItem.pinName || ''
  210. const displayName = itemBrand ? `${itemName} ${itemBrand}` : itemName
  211. const itemNames = itemBrand ? `${itemName}` : itemName
  212. const itemPrice = orderItem.onePrice || 0
  213. // 统计各种状态的数量
  214. let qualifiedCount = 0
  215. let unqualifiedCount = 0
  216. let unrecyclableCount = 0
  217. console.log('item', item)
  218. item.commonOrderList.forEach(commonItem => {
  219. if (commonItem.testingStatus === 0) {
  220. qualifiedCount++
  221. } else if (commonItem.testingStatus === 1) {
  222. unqualifiedCount++
  223. } else if (commonItem.testingStatus === 2) {
  224. unrecyclableCount++
  225. }
  226. })
  227. // 处理合格产品
  228. if (qualifiedCount > 0) {
  229. // 获取合格商品的理由和图片信息
  230. const qualifiedCommonItem = item.commonOrderList.find(commonItem => commonItem.testingStatus === 0)
  231. const savedImages = qualifiedCommonItem?.testingImages ? qualifiedCommonItem.testingImages.split(',').filter(img => img) : []
  232. const savedReasons = this.parseTestingInstructions(qualifiedCommonItem?.testingInstructions || '')
  233. this.qualifiedList.push({
  234. id: item.id,
  235. name: displayName,
  236. shopClass: this.getShopClass(item.id),
  237. shopId: item.shopId,
  238. price: itemPrice,
  239. count: qualifiedCount,
  240. total: item.price || 0, // 使用质检时填写的总金额
  241. reason: '',
  242. images: savedImages,
  243. reasons: savedReasons
  244. })
  245. }
  246. // 处理不合格产品
  247. if (unqualifiedCount > 0) {
  248. const unqualifiedItems = []
  249. let index = 1
  250. item.commonOrderList.forEach(commonItem => {
  251. if (commonItem.testingStatus === 1) {
  252. const savedImages = commonItem.testingImages ? commonItem.testingImages.split(',').filter(img => img) : []
  253. const savedReasons = this.parseTestingInstructions(commonItem.testingInstructions || '')
  254. unqualifiedItems.push({
  255. id: commonItem.id,
  256. name: `${itemNames}${index}`,
  257. shopClass: this.getShopClass(item.id),
  258. shopId: item.shopId,
  259. reason: '',
  260. images: savedImages,
  261. reasons: savedReasons
  262. })
  263. index++
  264. }
  265. })
  266. if (unqualifiedItems.length > 0) {
  267. this.unqualifiedGroups.push({
  268. id: item.id,
  269. name: displayName,
  270. shopClass: this.getShopClass(item.id),
  271. shopId: item.shopId,
  272. price: itemPrice,
  273. total: 0, // 不合格产品总价为0
  274. items: unqualifiedItems
  275. })
  276. }
  277. }
  278. // 处理不可回收产品
  279. if (unrecyclableCount > 0) {
  280. // 获取不可回收商品的理由和图片信息
  281. const unrecyclableCommonItem = item.commonOrderList.find(commonItem => commonItem.testingStatus === 2)
  282. const savedImages = unrecyclableCommonItem?.testingImages ? unrecyclableCommonItem.testingImages.split(',').filter(img => img) : []
  283. const savedReasons = this.parseTestingInstructions(unrecyclableCommonItem?.testingInstructions || '')
  284. this.unrecyclableList.push({
  285. id: item.id,
  286. name: displayName,
  287. shopClass: item.shopClass,
  288. shopId: item.shopId,
  289. price: '', // 不可回收产品不显示价格
  290. count: unrecyclableCount,
  291. total: 0,
  292. reason: '',
  293. images: savedImages,
  294. reasons: savedReasons
  295. })
  296. }
  297. })
  298. console.log('处理后的数据:', {
  299. qualifiedList: this.qualifiedList,
  300. unqualifiedGroups: this.unqualifiedGroups,
  301. unrecyclableList: this.unrecyclableList
  302. })
  303. },
  304. goBack() {
  305. uni.navigateBack()
  306. },
  307. goPrev() {
  308. uni.navigateBack()
  309. },
  310. finishInspect() {
  311. // 这里可以将最终的inspectData提交到服务器
  312. this.inspectData["list"]=JSON.stringify(this.inspectData["list"], null, 2)
  313. console.log('最终的质检数据:', this.inspectData);
  314. // 可以调用API提交数据
  315. this.$api('submitQualityInfo', this.inspectData , res => {
  316. if (res && res.code === 200) {
  317. uni.showToast({ title: '质检完成', icon: 'success' })
  318. // 关闭其余页面回到首页
  319. uni.reLaunch({
  320. url: '/pages/component/home'
  321. })
  322. }
  323. })
  324. uni.showToast({ title: '完成质检', icon: 'success' })
  325. },
  326. selectReasonForUnqualified(item,type) {
  327. this.$api('getcheckoutReasons', {
  328. classId: item.shopClass,
  329. type: type
  330. }, res => {
  331. console.log('res', res)
  332. if(res.code == 200){
  333. this.reasonOptions = res.result;
  334. }
  335. })
  336. },
  337. selectReason(item) {
  338. console.log('item', item)
  339. this.currentReasonItem = item
  340. this.currentReasonTitle = item.name
  341. this.reasonImages = item.images || []
  342. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  343. this.selectReasonForUnqualified(item,0)
  344. this.lockScroll()
  345. this.$refs.reasonPopup.open()
  346. },
  347. selectReasonForQualified(item) {
  348. this.currentReasonItem = item
  349. this.currentReasonTitle = this.getItemName(item.id)
  350. this.reasonImages = item.images || []
  351. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  352. this.selectReasonForUnqualified(item,1)
  353. this.lockScroll()
  354. this.$refs.reasonPopup.open()
  355. },
  356. selectReasonForUnrecyclable(item) {
  357. console.log('item', item)
  358. this.currentReasonItem = item
  359. this.currentReasonTitle = this.getItemName(item.id)
  360. this.reasonImages = item.images || []
  361. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  362. this.selectReasonForUnqualified(item,2)
  363. this.lockScroll()
  364. this.$refs.reasonPopup.open()
  365. },
  366. closeReasonPopup() {
  367. this.unlockScroll()
  368. this.$refs.reasonPopup.close()
  369. },
  370. addReasonImg() {
  371. // 检查是否已达到最大数量限制
  372. if (this.reasonImages.length >= 3) {
  373. uni.showToast({
  374. title: '最多只能上传3张图片',
  375. icon: 'none'
  376. })
  377. return
  378. }
  379. uni.chooseMedia({
  380. count: 3 - this.reasonImages.length, // 剩余可选择数量
  381. mediaType: ['image'], // 只选择图片
  382. sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机
  383. maxDuration: 30,
  384. camera: 'back',
  385. success: (res) => {
  386. console.log('选择的图片:', res.tempFiles)
  387. // 显示上传进度
  388. uni.showLoading({
  389. title: '上传中...'
  390. })
  391. // 处理选择的图片
  392. const uploadPromises = res.tempFiles.map(file => {
  393. return this.uploadImageToOSS(file.tempFilePath)
  394. })
  395. // 批量上传
  396. Promise.all(uploadPromises).then(urls => {
  397. this.reasonImages = this.reasonImages.concat(urls)
  398. uni.hideLoading()
  399. uni.showToast({
  400. title: '上传成功',
  401. icon: 'success'
  402. })
  403. }).catch(error => {
  404. console.error('上传失败:', error)
  405. uni.hideLoading()
  406. uni.showToast({
  407. title: '上传失败,请重试',
  408. icon: 'none'
  409. })
  410. })
  411. },
  412. fail: (error) => {
  413. console.error('选择图片失败:', error)
  414. uni.showToast({
  415. title: '选择图片失败',
  416. icon: 'none'
  417. })
  418. }
  419. })
  420. },
  421. async uploadImageToOSS(filePath) {
  422. try {
  423. // 使用项目中的OSS上传工具
  424. const url = await OSS.ossUpload(filePath)
  425. return url
  426. } catch (error) {
  427. console.error('OSS上传失败:', error)
  428. throw error
  429. }
  430. },
  431. removeReasonImg(idx) {
  432. this.reasonImages.splice(idx, 1)
  433. },
  434. toggleReason(idx) {
  435. console.log
  436. this.$set(this.reasonChecked, idx, !this.reasonChecked[idx])
  437. },
  438. saveReason() {
  439. // 保存到当前item
  440. if (this.currentReasonItem) {
  441. this.currentReasonItem.images = [...this.reasonImages]
  442. this.currentReasonItem.reasons = [...this.reasonChecked]
  443. // console.log('this.currentReasonItem', this.currentReasonItem)
  444. // 更新inspectData中的数据
  445. this.updateInspectData()
  446. }
  447. this.closeReasonPopup()
  448. },
  449. updateInspectData() {
  450. if (!this.inspectData || !this.currentReasonItem) return
  451. // 获取选中的理由ID(假设理由选项的索引就是ID)
  452. const selectedReasonIds = []
  453. this.reasonChecked.forEach((checked, index) => {
  454. if (checked) {
  455. selectedReasonIds.push(this.reasonOptions[index].reason.toString())
  456. }
  457. })
  458. // 将理由ID用逗号分割保存
  459. const testingInstructions = selectedReasonIds.join(',')
  460. // 将图片URL用逗号分割保存
  461. const testingImages = this.reasonImages.join(',')
  462. // 根据当前选择的商品类型,找到对应的inspectData项进行更新
  463. if (this.isQualifiedItem(this.currentReasonItem)) {
  464. this.updateQualifiedItemInspectData(testingInstructions, testingImages)
  465. } else if (this.isUnqualifiedItem(this.currentReasonItem)) {
  466. this.updateUnqualifiedItemInspectData(testingInstructions, testingImages)
  467. } else if (this.isUnrecyclableItem(this.currentReasonItem)) {
  468. this.updateUnrecyclableItemInspectData(testingInstructions, testingImages)
  469. }
  470. console.log('更新后的inspectData:', JSON.stringify(this.inspectData, null, 2))
  471. },
  472. isQualifiedItem(item) {
  473. return this.qualifiedList.some(qualified => qualified.id === item.id)
  474. },
  475. isUnqualifiedItem(item) {
  476. return this.unqualifiedGroups.some(group =>
  477. group.items.some(unqualified => unqualified.id === item.id)
  478. )
  479. },
  480. isUnrecyclableItem(item) {
  481. return this.unrecyclableList.some(unrecyclable => unrecyclable.id === item.id)
  482. },
  483. updateQualifiedItemInspectData(testingInstructions, testingImages) {
  484. const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
  485. if (inspectItem && inspectItem.commonOrderList) {
  486. // 为合格的商品更新所有状态为0的项
  487. inspectItem.commonOrderList.forEach(commonItem => {
  488. if (commonItem.testingStatus === 0) {
  489. commonItem.testingInstructions = testingInstructions
  490. commonItem.testingImages = testingImages
  491. }
  492. })
  493. }
  494. },
  495. updateUnqualifiedItemInspectData(testingInstructions, testingImages) {
  496. // 对于不合格商品,需要根据具体的commonOrderList项ID来更新
  497. this.unqualifiedGroups.forEach(group => {
  498. const targetItem = group.items.find(item => item.id === this.currentReasonItem.id)
  499. if (targetItem) {
  500. // 找到对应的inspectData项
  501. const inspectItem = this.inspectData.list.find(item => item.id == group.id)
  502. if (inspectItem && inspectItem.commonOrderList) {
  503. // 根据不合格项的ID找到对应的commonOrderList项
  504. const commonItem = inspectItem.commonOrderList.find(common => common.id === targetItem.id)
  505. if (commonItem) {
  506. commonItem.testingInstructions = testingInstructions
  507. commonItem.testingImages = testingImages
  508. }
  509. }
  510. }
  511. })
  512. },
  513. updateUnrecyclableItemInspectData(testingInstructions, testingImages) {
  514. const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
  515. if (inspectItem && inspectItem.commonOrderList) {
  516. // 为不可回收的商品更新所有状态为2的项
  517. inspectItem.commonOrderList.forEach(commonItem => {
  518. if (commonItem.testingStatus === 2) {
  519. commonItem.testingInstructions = testingInstructions
  520. commonItem.testingImages = testingImages
  521. }
  522. })
  523. }
  524. },
  525. lockScroll() {
  526. // 禁用页面滚动
  527. this.isPopupOpen = true
  528. },
  529. unlockScroll() {
  530. // 恢复页面滚动
  531. this.isPopupOpen = false
  532. },
  533. async onRefresh() {
  534. await this.refreshData && this.refreshData()
  535. },
  536. refreshData() {
  537. // 可根据实际需求刷新质检结果数据
  538. // 例如重新请求接口或重置数据
  539. },
  540. getItemName(id) {
  541. if (this.order && this.order.commonOrderList) {
  542. const orderItem = this.order.commonOrderList.find(item => item.id == id)
  543. return orderItem ? (orderItem.title || '未知商品') : '未知商品'
  544. }
  545. return '未知商品'
  546. },
  547. getShopClass(id) {
  548. if (this.order && this.order.commonOrderList) {
  549. // console.log('this.order', ShopClass)
  550. const ShopClass = this.order.commonOrderList.find(item => item.id == id)
  551. // console.log('ShopClass', ShopClass)
  552. return ShopClass ? ShopClass.shopClass: ''
  553. }
  554. return ''
  555. },
  556. getItemBrand(id) {
  557. if (this.order && this.order.commonOrderList) {
  558. const orderItem = this.order.commonOrderList.find(item => item.id == id)
  559. return orderItem ? (orderItem.pinName || '') : ''
  560. }
  561. return ''
  562. },
  563. parseTestingInstructions(instructions) {
  564. // 解析理由ID字符串,返回布尔数组
  565. const reasonArray = Array(this.reasonOptions.length).fill(false)
  566. if (instructions) {
  567. const selectedIds = instructions.split(',').map(id => id.trim()).filter(id => id)
  568. selectedIds.forEach(id => {
  569. const index = parseInt(id)
  570. if (index >= 0 && index < reasonArray.length) {
  571. reasonArray[index] = true
  572. }
  573. })
  574. }
  575. return reasonArray
  576. },
  577. hasSelectedReason(item) {
  578. // 检查该商品是否已选择理由或上传图片
  579. return (item.reasons && item.reasons.some(checked => checked)) ||
  580. (item.images && item.images.length > 0)
  581. }
  582. }
  583. }
  584. </script>
  585. <style lang="scss" scoped>
  586. .inspect-result-container {
  587. min-height: 100vh;
  588. background: #f8f8f8;
  589. display: flex;
  590. flex-direction: column;
  591. &.popup-open {
  592. overflow: hidden;
  593. position: fixed;
  594. width: 100%;
  595. height: 100vh;
  596. }
  597. }
  598. .nav-bar {
  599. display: flex;
  600. align-items: center;
  601. height: calc(150rpx + var(--status-bar-height));
  602. padding: 0 32rpx;
  603. padding-top: var(--status-bar-height);
  604. background: #fff;
  605. position: fixed;
  606. top: 0;
  607. left: 0;
  608. right: 0;
  609. z-index: 999;
  610. box-sizing: border-box;
  611. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  612. .back {
  613. padding: 20rpx;
  614. margin-left: -20rpx;
  615. }
  616. .nav-title {
  617. flex: 1;
  618. text-align: center;
  619. font-size: 32rpx;
  620. font-weight: 500;
  621. color: #222;
  622. }
  623. .nav-icons {
  624. display: flex;
  625. align-items: center;
  626. gap: 12px;
  627. }
  628. }
  629. .main-content {
  630. margin-top: calc(200rpx + var(--status-bar-height));
  631. display: flex;
  632. flex-direction: column;
  633. background: none;
  634. padding-bottom: 120px;
  635. }
  636. .result-card {
  637. background: #fff;
  638. border-radius: 24px;
  639. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  640. margin: 0 24px 24px 24px;
  641. padding: 24px 24px 0 24px;
  642. }
  643. .card-title {
  644. font-size: 16px;
  645. font-weight: bold;
  646. color: #222;
  647. margin-bottom: 18px;
  648. }
  649. .card-title-row {
  650. display: flex;
  651. align-items: center;
  652. justify-content: space-between;
  653. margin-bottom: 18px;
  654. }
  655. .status-tag {
  656. background: #fff7e6;
  657. color: #ffb400;
  658. font-size: 12px;
  659. border-radius: 12px;
  660. padding: 2px 14px;
  661. font-weight: 400;
  662. height: 22px;
  663. display: flex;
  664. align-items: center;
  665. }
  666. .result-row, .result-group {
  667. margin-bottom: 18px;
  668. }
  669. .row-main {
  670. display: flex;
  671. align-items: center;
  672. .goods-name-section {
  673. display: flex;
  674. flex-direction: column;
  675. margin-right: 8px;
  676. .goods-name {
  677. font-size: 14px;
  678. font-weight: bold;
  679. color: #222;
  680. line-height: 1.2;
  681. }
  682. .goods-brand {
  683. font-size: 11px;
  684. color: #999;
  685. font-weight: normal;
  686. line-height: 1.2;
  687. margin-top: 2px;
  688. }
  689. }
  690. .row-name {
  691. font-size: 14px;
  692. font-weight: bold;
  693. color: #222;
  694. margin-right: 8px;
  695. }
  696. .row-price {
  697. font-size: 13px;
  698. color: #ffb400;
  699. font-weight: bold;
  700. margin-right: 8px;
  701. .row-unit {
  702. font-size: 11px;
  703. color: #bbb;
  704. }
  705. }
  706. .row-count {
  707. font-size: 13px;
  708. color: #888;
  709. margin-right: 8px;
  710. }
  711. .row-total {
  712. font-size: 14px;
  713. color: #222;
  714. font-weight: bold;
  715. margin-left: auto;
  716. }
  717. }
  718. .row-reason {
  719. display: flex;
  720. align-items: center;
  721. margin-top: 8px;
  722. .reason-label {
  723. font-size: 13px;
  724. color: #bbb;
  725. min-width: 80px;
  726. }
  727. .reason-input {
  728. flex: 1;
  729. height: 36px;
  730. border-radius: 12px;
  731. background: #f6f6f6;
  732. border: none;
  733. font-size: 14px;
  734. color: #222;
  735. padding-left: 12px;
  736. margin-left: 8px;
  737. }
  738. .reason-select {
  739. flex: 1;
  740. display: flex;
  741. align-items: center;
  742. height: 36px;
  743. border-radius: 12px;
  744. background: #f6f6f6;
  745. font-size: 14px;
  746. color: #bbb;
  747. padding-left: 12px;
  748. margin-left: 8px;
  749. justify-content: flex-end;
  750. }
  751. .reason-placeholder {
  752. color: #bbb;
  753. font-size: 14px;
  754. &.selected {
  755. color: #52c41a;
  756. font-weight: 500;
  757. }
  758. }
  759. }
  760. .info-card {
  761. background: #fff;
  762. border-radius: 24px;
  763. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  764. margin: 0 24px 24px 24px;
  765. padding: 24px 24px 0 24px;
  766. }
  767. .info-row {
  768. display: flex;
  769. align-items: center;
  770. margin-bottom: 16px;
  771. .info-label {
  772. font-size: 13px;
  773. color: #bbb;
  774. min-width: 80px;
  775. }
  776. .info-value {
  777. font-size: 13px;
  778. color: #222;
  779. margin-left: 8px;
  780. }
  781. .copy-btn {
  782. color: #ffb400;
  783. margin-left: 8px;
  784. }
  785. }
  786. .footer-btns {
  787. position: fixed;
  788. left: 0;
  789. right: 0;
  790. bottom: 0;
  791. background: #fff;
  792. display: flex;
  793. gap: 16px;
  794. padding: 12px 16px 24px 16px;
  795. z-index: 101;
  796. .btn-outline {
  797. flex: 1;
  798. height: 40px;
  799. border-radius: 16px;
  800. border: 1px solid #ffe09a;
  801. color: #ffb400;
  802. background: #fff0d2;
  803. font-size: 15px;
  804. font-weight: 500;
  805. box-shadow: none;
  806. padding: 0 18px;
  807. }
  808. .btn-main {
  809. flex: 1;
  810. height: 40px;
  811. border-radius: 16px;
  812. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  813. color: #fff;
  814. border: none;
  815. font-size: 15px;
  816. font-weight: 500;
  817. box-shadow: none;
  818. padding: 0 18px;
  819. }
  820. }
  821. .reason-popup-wrapper {
  822. z-index: 10000 !important;
  823. }
  824. .reason-popup-wrapper .uni-popup__wrapper {
  825. z-index: 10000 !important;
  826. }
  827. .reason-popup {
  828. background: #fff;
  829. border-radius: 24px 24px 0 0;
  830. padding: 0;
  831. height: 75vh;
  832. position: relative;
  833. z-index: 9999;
  834. .popup-header {
  835. display: flex;
  836. align-items: center;
  837. justify-content: center;
  838. height: 60px;
  839. border-bottom: 1px solid #f0f0f0;
  840. position: relative;
  841. .popup-close {
  842. position: absolute;
  843. left: 20px;
  844. color: #666;
  845. font-size: 16px;
  846. }
  847. .popup-title {
  848. font-size: 18px;
  849. font-weight: 600;
  850. color: #222;
  851. }
  852. }
  853. .popup-content {
  854. height: calc(75vh - 60px - 82px);
  855. overflow-y: auto;
  856. }
  857. .popup-section {
  858. padding: 0 20px 24px 20px;
  859. &:first-child {
  860. padding-top: 24px;
  861. }
  862. .section-label {
  863. font-size: 16px;
  864. color: #222;
  865. margin-bottom: 16px;
  866. display: block;
  867. font-weight: 500;
  868. }
  869. .img-list {
  870. display: flex;
  871. gap: 12px;
  872. margin-bottom: 32px;
  873. .img-item {
  874. width: 80px;
  875. height: 80px;
  876. border-radius: 12px;
  877. background: #f8f8f8;
  878. position: relative;
  879. .img {
  880. width: 100%;
  881. height: 100%;
  882. border-radius: 12px;
  883. object-fit: cover;
  884. }
  885. .img-del {
  886. position: absolute;
  887. top: -6px;
  888. right: -6px;
  889. width: 24px;
  890. height: 24px;
  891. background: rgba(0,0,0,0.6);
  892. color: #fff;
  893. border-radius: 50%;
  894. text-align: center;
  895. line-height: 24px;
  896. font-size: 16px;
  897. font-weight: bold;
  898. }
  899. &.add {
  900. display: flex;
  901. align-items: center;
  902. justify-content: center;
  903. background: #f8f8f8;
  904. border: 2px dashed #ddd;
  905. color: #bbb;
  906. }
  907. }
  908. }
  909. .reason-row {
  910. display: flex;
  911. align-items: center;
  912. padding: 16px 0;
  913. border-bottom: 1px solid #f0f0f0;
  914. &:last-child {
  915. border-bottom: none;
  916. }
  917. .checkbox {
  918. width: 20px;
  919. height: 20px;
  920. border-radius: 4px;
  921. border: 2px solid #ddd;
  922. margin-right: 12px;
  923. background: #fff;
  924. position: relative;
  925. &.checked {
  926. border-color: #ffb400;
  927. background: #ffb400;
  928. &::after {
  929. content: '✓';
  930. position: absolute;
  931. top: 50%;
  932. left: 50%;
  933. transform: translate(-50%, -50%);
  934. color: #fff;
  935. font-size: 12px;
  936. font-weight: bold;
  937. }
  938. }
  939. }
  940. .reason-text {
  941. font-size: 16px;
  942. color: #222;
  943. line-height: 1.4;
  944. }
  945. }
  946. }
  947. .popup-save-btn {
  948. position: fixed;
  949. bottom: 34px;
  950. left: 20px;
  951. right: 20px;
  952. height: 48px;
  953. border-radius: 24px;
  954. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  955. color: #fff;
  956. font-size: 18px;
  957. font-weight: 600;
  958. border: none;
  959. display: flex;
  960. align-items: center;
  961. justify-content: center;
  962. box-shadow: 0 4px 12px rgba(255, 172, 4, 0.3);
  963. }
  964. }
  965. </style>