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

992 lines
30 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month 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. uni.navigateBack()
  319. }
  320. })
  321. uni.showToast({ title: '完成质检', icon: 'success' })
  322. },
  323. selectReasonForUnqualified(item,type) {
  324. this.$api('getcheckoutReasons', {
  325. classId: item.shopClass,
  326. type: type
  327. }, res => {
  328. console.log('res', res)
  329. if(res.code == 200){
  330. this.reasonOptions = res.result;
  331. }
  332. })
  333. },
  334. selectReason(item) {
  335. console.log('item', item)
  336. this.currentReasonItem = item
  337. this.currentReasonTitle = item.name
  338. this.reasonImages = item.images || []
  339. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  340. this.selectReasonForUnqualified(item,0)
  341. this.lockScroll()
  342. this.$refs.reasonPopup.open()
  343. },
  344. selectReasonForQualified(item) {
  345. this.currentReasonItem = item
  346. this.currentReasonTitle = this.getItemName(item.id)
  347. this.reasonImages = item.images || []
  348. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  349. this.selectReasonForUnqualified(item,1)
  350. this.lockScroll()
  351. this.$refs.reasonPopup.open()
  352. },
  353. selectReasonForUnrecyclable(item) {
  354. console.log('item', item)
  355. this.currentReasonItem = item
  356. this.currentReasonTitle = this.getItemName(item.id)
  357. this.reasonImages = item.images || []
  358. this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
  359. this.selectReasonForUnqualified(item,2)
  360. this.lockScroll()
  361. this.$refs.reasonPopup.open()
  362. },
  363. closeReasonPopup() {
  364. this.unlockScroll()
  365. this.$refs.reasonPopup.close()
  366. },
  367. addReasonImg() {
  368. // 检查是否已达到最大数量限制
  369. if (this.reasonImages.length >= 3) {
  370. uni.showToast({
  371. title: '最多只能上传3张图片',
  372. icon: 'none'
  373. })
  374. return
  375. }
  376. uni.chooseMedia({
  377. count: 3 - this.reasonImages.length, // 剩余可选择数量
  378. mediaType: ['image'], // 只选择图片
  379. sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机
  380. maxDuration: 30,
  381. camera: 'back',
  382. success: (res) => {
  383. console.log('选择的图片:', res.tempFiles)
  384. // 显示上传进度
  385. uni.showLoading({
  386. title: '上传中...'
  387. })
  388. // 处理选择的图片
  389. const uploadPromises = res.tempFiles.map(file => {
  390. return this.uploadImageToOSS(file.tempFilePath)
  391. })
  392. // 批量上传
  393. Promise.all(uploadPromises).then(urls => {
  394. this.reasonImages = this.reasonImages.concat(urls)
  395. uni.hideLoading()
  396. uni.showToast({
  397. title: '上传成功',
  398. icon: 'success'
  399. })
  400. }).catch(error => {
  401. console.error('上传失败:', error)
  402. uni.hideLoading()
  403. uni.showToast({
  404. title: '上传失败,请重试',
  405. icon: 'none'
  406. })
  407. })
  408. },
  409. fail: (error) => {
  410. console.error('选择图片失败:', error)
  411. uni.showToast({
  412. title: '选择图片失败',
  413. icon: 'none'
  414. })
  415. }
  416. })
  417. },
  418. async uploadImageToOSS(filePath) {
  419. try {
  420. // 使用项目中的OSS上传工具
  421. const url = await OSS.ossUpload(filePath)
  422. return url
  423. } catch (error) {
  424. console.error('OSS上传失败:', error)
  425. throw error
  426. }
  427. },
  428. removeReasonImg(idx) {
  429. this.reasonImages.splice(idx, 1)
  430. },
  431. toggleReason(idx) {
  432. console.log
  433. this.$set(this.reasonChecked, idx, !this.reasonChecked[idx])
  434. },
  435. saveReason() {
  436. // 保存到当前item
  437. if (this.currentReasonItem) {
  438. this.currentReasonItem.images = [...this.reasonImages]
  439. this.currentReasonItem.reasons = [...this.reasonChecked]
  440. // console.log('this.currentReasonItem', this.currentReasonItem)
  441. // 更新inspectData中的数据
  442. this.updateInspectData()
  443. }
  444. this.closeReasonPopup()
  445. },
  446. updateInspectData() {
  447. if (!this.inspectData || !this.currentReasonItem) return
  448. // 获取选中的理由ID(假设理由选项的索引就是ID)
  449. const selectedReasonIds = []
  450. this.reasonChecked.forEach((checked, index) => {
  451. if (checked) {
  452. selectedReasonIds.push(this.reasonOptions[index].reason.toString())
  453. }
  454. })
  455. // 将理由ID用逗号分割保存
  456. const testingInstructions = selectedReasonIds.join(',')
  457. // 将图片URL用逗号分割保存
  458. const testingImages = this.reasonImages.join(',')
  459. // 根据当前选择的商品类型,找到对应的inspectData项进行更新
  460. if (this.isQualifiedItem(this.currentReasonItem)) {
  461. this.updateQualifiedItemInspectData(testingInstructions, testingImages)
  462. } else if (this.isUnqualifiedItem(this.currentReasonItem)) {
  463. this.updateUnqualifiedItemInspectData(testingInstructions, testingImages)
  464. } else if (this.isUnrecyclableItem(this.currentReasonItem)) {
  465. this.updateUnrecyclableItemInspectData(testingInstructions, testingImages)
  466. }
  467. console.log('更新后的inspectData:', JSON.stringify(this.inspectData, null, 2))
  468. },
  469. isQualifiedItem(item) {
  470. return this.qualifiedList.some(qualified => qualified.id === item.id)
  471. },
  472. isUnqualifiedItem(item) {
  473. return this.unqualifiedGroups.some(group =>
  474. group.items.some(unqualified => unqualified.id === item.id)
  475. )
  476. },
  477. isUnrecyclableItem(item) {
  478. return this.unrecyclableList.some(unrecyclable => unrecyclable.id === item.id)
  479. },
  480. updateQualifiedItemInspectData(testingInstructions, testingImages) {
  481. const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
  482. if (inspectItem && inspectItem.commonOrderList) {
  483. // 为合格的商品更新所有状态为0的项
  484. inspectItem.commonOrderList.forEach(commonItem => {
  485. if (commonItem.testingStatus === 0) {
  486. commonItem.testingInstructions = testingInstructions
  487. commonItem.testingImages = testingImages
  488. }
  489. })
  490. }
  491. },
  492. updateUnqualifiedItemInspectData(testingInstructions, testingImages) {
  493. // 对于不合格商品,需要根据具体的commonOrderList项ID来更新
  494. this.unqualifiedGroups.forEach(group => {
  495. const targetItem = group.items.find(item => item.id === this.currentReasonItem.id)
  496. if (targetItem) {
  497. // 找到对应的inspectData项
  498. const inspectItem = this.inspectData.list.find(item => item.id == group.id)
  499. if (inspectItem && inspectItem.commonOrderList) {
  500. // 根据不合格项的ID找到对应的commonOrderList项
  501. const commonItem = inspectItem.commonOrderList.find(common => common.id === targetItem.id)
  502. if (commonItem) {
  503. commonItem.testingInstructions = testingInstructions
  504. commonItem.testingImages = testingImages
  505. }
  506. }
  507. }
  508. })
  509. },
  510. updateUnrecyclableItemInspectData(testingInstructions, testingImages) {
  511. const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
  512. if (inspectItem && inspectItem.commonOrderList) {
  513. // 为不可回收的商品更新所有状态为2的项
  514. inspectItem.commonOrderList.forEach(commonItem => {
  515. if (commonItem.testingStatus === 2) {
  516. commonItem.testingInstructions = testingInstructions
  517. commonItem.testingImages = testingImages
  518. }
  519. })
  520. }
  521. },
  522. lockScroll() {
  523. // 禁用页面滚动
  524. this.isPopupOpen = true
  525. },
  526. unlockScroll() {
  527. // 恢复页面滚动
  528. this.isPopupOpen = false
  529. },
  530. async onRefresh() {
  531. await this.refreshData && this.refreshData()
  532. },
  533. refreshData() {
  534. // 可根据实际需求刷新质检结果数据
  535. // 例如重新请求接口或重置数据
  536. },
  537. getItemName(id) {
  538. if (this.order && this.order.commonOrderList) {
  539. const orderItem = this.order.commonOrderList.find(item => item.id == id)
  540. return orderItem ? (orderItem.title || '未知商品') : '未知商品'
  541. }
  542. return '未知商品'
  543. },
  544. getShopClass(id) {
  545. if (this.order && this.order.commonOrderList) {
  546. // console.log('this.order', ShopClass)
  547. const ShopClass = this.order.commonOrderList.find(item => item.id == id)
  548. // console.log('ShopClass', ShopClass)
  549. return ShopClass ? ShopClass.shopClass: ''
  550. }
  551. return ''
  552. },
  553. getItemBrand(id) {
  554. if (this.order && this.order.commonOrderList) {
  555. const orderItem = this.order.commonOrderList.find(item => item.id == id)
  556. return orderItem ? (orderItem.pinName || '') : ''
  557. }
  558. return ''
  559. },
  560. parseTestingInstructions(instructions) {
  561. // 解析理由ID字符串,返回布尔数组
  562. const reasonArray = Array(this.reasonOptions.length).fill(false)
  563. if (instructions) {
  564. const selectedIds = instructions.split(',').map(id => id.trim()).filter(id => id)
  565. selectedIds.forEach(id => {
  566. const index = parseInt(id)
  567. if (index >= 0 && index < reasonArray.length) {
  568. reasonArray[index] = true
  569. }
  570. })
  571. }
  572. return reasonArray
  573. },
  574. hasSelectedReason(item) {
  575. // 检查该商品是否已选择理由或上传图片
  576. return (item.reasons && item.reasons.some(checked => checked)) ||
  577. (item.images && item.images.length > 0)
  578. }
  579. }
  580. }
  581. </script>
  582. <style lang="scss" scoped>
  583. .inspect-result-container {
  584. min-height: 100vh;
  585. background: #f8f8f8;
  586. display: flex;
  587. flex-direction: column;
  588. &.popup-open {
  589. overflow: hidden;
  590. position: fixed;
  591. width: 100%;
  592. height: 100vh;
  593. }
  594. }
  595. .nav-bar {
  596. display: flex;
  597. align-items: center;
  598. height: calc(150rpx + var(--status-bar-height));
  599. padding: 0 32rpx;
  600. padding-top: var(--status-bar-height);
  601. background: #fff;
  602. position: fixed;
  603. top: 0;
  604. left: 0;
  605. right: 0;
  606. z-index: 999;
  607. box-sizing: border-box;
  608. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  609. .back {
  610. padding: 20rpx;
  611. margin-left: -20rpx;
  612. }
  613. .nav-title {
  614. flex: 1;
  615. text-align: center;
  616. font-size: 32rpx;
  617. font-weight: 500;
  618. color: #222;
  619. }
  620. .nav-icons {
  621. display: flex;
  622. align-items: center;
  623. gap: 12px;
  624. }
  625. }
  626. .main-content {
  627. margin-top: calc(200rpx + var(--status-bar-height));
  628. display: flex;
  629. flex-direction: column;
  630. background: none;
  631. padding-bottom: 120px;
  632. }
  633. .result-card {
  634. background: #fff;
  635. border-radius: 24px;
  636. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  637. margin: 0 24px 24px 24px;
  638. padding: 24px 24px 0 24px;
  639. }
  640. .card-title {
  641. font-size: 16px;
  642. font-weight: bold;
  643. color: #222;
  644. margin-bottom: 18px;
  645. }
  646. .card-title-row {
  647. display: flex;
  648. align-items: center;
  649. justify-content: space-between;
  650. margin-bottom: 18px;
  651. }
  652. .status-tag {
  653. background: #fff7e6;
  654. color: #ffb400;
  655. font-size: 12px;
  656. border-radius: 12px;
  657. padding: 2px 14px;
  658. font-weight: 400;
  659. height: 22px;
  660. display: flex;
  661. align-items: center;
  662. }
  663. .result-row, .result-group {
  664. margin-bottom: 18px;
  665. }
  666. .row-main {
  667. display: flex;
  668. align-items: center;
  669. .goods-name-section {
  670. display: flex;
  671. flex-direction: column;
  672. margin-right: 8px;
  673. .goods-name {
  674. font-size: 14px;
  675. font-weight: bold;
  676. color: #222;
  677. line-height: 1.2;
  678. }
  679. .goods-brand {
  680. font-size: 11px;
  681. color: #999;
  682. font-weight: normal;
  683. line-height: 1.2;
  684. margin-top: 2px;
  685. }
  686. }
  687. .row-name {
  688. font-size: 14px;
  689. font-weight: bold;
  690. color: #222;
  691. margin-right: 8px;
  692. }
  693. .row-price {
  694. font-size: 13px;
  695. color: #ffb400;
  696. font-weight: bold;
  697. margin-right: 8px;
  698. .row-unit {
  699. font-size: 11px;
  700. color: #bbb;
  701. }
  702. }
  703. .row-count {
  704. font-size: 13px;
  705. color: #888;
  706. margin-right: 8px;
  707. }
  708. .row-total {
  709. font-size: 14px;
  710. color: #222;
  711. font-weight: bold;
  712. margin-left: auto;
  713. }
  714. }
  715. .row-reason {
  716. display: flex;
  717. align-items: center;
  718. margin-top: 8px;
  719. .reason-label {
  720. font-size: 13px;
  721. color: #bbb;
  722. min-width: 80px;
  723. }
  724. .reason-input {
  725. flex: 1;
  726. height: 36px;
  727. border-radius: 12px;
  728. background: #f6f6f6;
  729. border: none;
  730. font-size: 14px;
  731. color: #222;
  732. padding-left: 12px;
  733. margin-left: 8px;
  734. }
  735. .reason-select {
  736. flex: 1;
  737. display: flex;
  738. align-items: center;
  739. height: 36px;
  740. border-radius: 12px;
  741. background: #f6f6f6;
  742. font-size: 14px;
  743. color: #bbb;
  744. padding-left: 12px;
  745. margin-left: 8px;
  746. justify-content: flex-end;
  747. }
  748. .reason-placeholder {
  749. color: #bbb;
  750. font-size: 14px;
  751. &.selected {
  752. color: #52c41a;
  753. font-weight: 500;
  754. }
  755. }
  756. }
  757. .info-card {
  758. background: #fff;
  759. border-radius: 24px;
  760. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  761. margin: 0 24px 24px 24px;
  762. padding: 24px 24px 0 24px;
  763. }
  764. .info-row {
  765. display: flex;
  766. align-items: center;
  767. margin-bottom: 16px;
  768. .info-label {
  769. font-size: 13px;
  770. color: #bbb;
  771. min-width: 80px;
  772. }
  773. .info-value {
  774. font-size: 13px;
  775. color: #222;
  776. margin-left: 8px;
  777. }
  778. .copy-btn {
  779. color: #ffb400;
  780. margin-left: 8px;
  781. }
  782. }
  783. .footer-btns {
  784. position: fixed;
  785. left: 0;
  786. right: 0;
  787. bottom: 0;
  788. background: #fff;
  789. display: flex;
  790. gap: 16px;
  791. padding: 12px 16px 24px 16px;
  792. z-index: 101;
  793. .btn-outline {
  794. flex: 1;
  795. height: 40px;
  796. border-radius: 16px;
  797. border: 1px solid #ffe09a;
  798. color: #ffb400;
  799. background: #fff0d2;
  800. font-size: 15px;
  801. font-weight: 500;
  802. box-shadow: none;
  803. padding: 0 18px;
  804. }
  805. .btn-main {
  806. flex: 1;
  807. height: 40px;
  808. border-radius: 16px;
  809. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  810. color: #fff;
  811. border: none;
  812. font-size: 15px;
  813. font-weight: 500;
  814. box-shadow: none;
  815. padding: 0 18px;
  816. }
  817. }
  818. .reason-popup-wrapper {
  819. z-index: 10000 !important;
  820. }
  821. .reason-popup-wrapper .uni-popup__wrapper {
  822. z-index: 10000 !important;
  823. }
  824. .reason-popup {
  825. background: #fff;
  826. border-radius: 24px 24px 0 0;
  827. padding: 0;
  828. height: 75vh;
  829. position: relative;
  830. z-index: 9999;
  831. .popup-header {
  832. display: flex;
  833. align-items: center;
  834. justify-content: center;
  835. height: 60px;
  836. border-bottom: 1px solid #f0f0f0;
  837. position: relative;
  838. .popup-close {
  839. position: absolute;
  840. left: 20px;
  841. color: #666;
  842. font-size: 16px;
  843. }
  844. .popup-title {
  845. font-size: 18px;
  846. font-weight: 600;
  847. color: #222;
  848. }
  849. }
  850. .popup-content {
  851. height: calc(75vh - 60px - 82px);
  852. overflow-y: auto;
  853. }
  854. .popup-section {
  855. padding: 0 20px 24px 20px;
  856. &:first-child {
  857. padding-top: 24px;
  858. }
  859. .section-label {
  860. font-size: 16px;
  861. color: #222;
  862. margin-bottom: 16px;
  863. display: block;
  864. font-weight: 500;
  865. }
  866. .img-list {
  867. display: flex;
  868. gap: 12px;
  869. margin-bottom: 32px;
  870. .img-item {
  871. width: 80px;
  872. height: 80px;
  873. border-radius: 12px;
  874. background: #f8f8f8;
  875. position: relative;
  876. .img {
  877. width: 100%;
  878. height: 100%;
  879. border-radius: 12px;
  880. object-fit: cover;
  881. }
  882. .img-del {
  883. position: absolute;
  884. top: -6px;
  885. right: -6px;
  886. width: 24px;
  887. height: 24px;
  888. background: rgba(0,0,0,0.6);
  889. color: #fff;
  890. border-radius: 50%;
  891. text-align: center;
  892. line-height: 24px;
  893. font-size: 16px;
  894. font-weight: bold;
  895. }
  896. &.add {
  897. display: flex;
  898. align-items: center;
  899. justify-content: center;
  900. background: #f8f8f8;
  901. border: 2px dashed #ddd;
  902. color: #bbb;
  903. }
  904. }
  905. }
  906. .reason-row {
  907. display: flex;
  908. align-items: center;
  909. padding: 16px 0;
  910. border-bottom: 1px solid #f0f0f0;
  911. &:last-child {
  912. border-bottom: none;
  913. }
  914. .checkbox {
  915. width: 20px;
  916. height: 20px;
  917. border-radius: 4px;
  918. border: 2px solid #ddd;
  919. margin-right: 12px;
  920. background: #fff;
  921. position: relative;
  922. &.checked {
  923. border-color: #ffb400;
  924. background: #ffb400;
  925. &::after {
  926. content: '✓';
  927. position: absolute;
  928. top: 50%;
  929. left: 50%;
  930. transform: translate(-50%, -50%);
  931. color: #fff;
  932. font-size: 12px;
  933. font-weight: bold;
  934. }
  935. }
  936. }
  937. .reason-text {
  938. font-size: 16px;
  939. color: #222;
  940. line-height: 1.4;
  941. }
  942. }
  943. }
  944. .popup-save-btn {
  945. position: fixed;
  946. bottom: 34px;
  947. left: 20px;
  948. right: 20px;
  949. height: 48px;
  950. border-radius: 24px;
  951. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  952. color: #fff;
  953. font-size: 18px;
  954. font-weight: 600;
  955. border: none;
  956. display: flex;
  957. align-items: center;
  958. justify-content: center;
  959. box-shadow: 0 4px 12px rgba(255, 172, 4, 0.3);
  960. }
  961. }
  962. </style>