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

1487 lines
48 KiB

3 months ago
3 months ago
3 months ago
2 weeks ago
3 months ago
2 weeks ago
3 months ago
2 weeks ago
3 months ago
3 months ago
3 months ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
3 months ago
3 months ago
2 weeks ago
2 weeks ago
3 months ago
2 weeks ago
2 weeks ago
2 weeks ago
3 months ago
3 months 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
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
3 months ago
3 months ago
2 weeks ago
2 weeks ago
3 months ago
2 weeks ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
2 weeks ago
  1. <template>
  2. <view class="inspect-container">
  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="scan" size="24" color="#222" />
  11. </view>
  12. </view>
  13. <view class="main-content">
  14. <!-- 左侧分类导航 -->
  15. <view class="category-nav">
  16. <view v-for="(cat, idx) in categories" :key="cat.title"
  17. :class="['category-item', { active: idx === currentCategory }]" @tap="switchCategory(idx)">
  18. <text>{{ cat.title }}</text>
  19. <view v-if="cat.badge" class="category-badge">{{ cat.badge }}</view>
  20. </view>
  21. </view>
  22. <!-- 右侧商品卡片区 -->
  23. <scroll-view class="goods-list" scroll-y @scrolltolower="loadMoreGoods">
  24. <view v-for="(item, idx) in currentGoods" :key="item.id" class="goods-card">
  25. <view class="goods-header">
  26. <view class="goods-img-container">
  27. <image :src="item.image" class="goods-img" />
  28. <!-- 品牌标签 -->
  29. <view class="brand-tag" v-if="item.isPin === 'Y'">品牌</view>
  30. </view>
  31. <view class="goods-info">
  32. <view class="goods-title-row">
  33. <text class="goods-name">{{ item.name }}</text>
  34. <text class="goods-price">
  35. {{ formatPrice(item) }}
  36. <text class="goods-unit" v-if="item.unit">/{{item.unit}}</text>
  37. </text>
  38. </view>
  39. <text class="goods-desc">{{ item.desc }}</text>
  40. <!-- 显示已选择的品牌款式信息 -->
  41. <view v-if="getSelectedBrandStyles(item).length > 0" class="selected-styles">
  42. <view v-for="style in getSelectedBrandStyles(item)" :key="style.uniqueKey" class="style-item">
  43. <text class="style-text">{{ style.brandName }} - {{ style.styleName }} x{{ style.quantity }}</text>
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. <view class="goods-row">
  49. <text class="row-label">合格数量</text>
  50. <view class="num-ctrl">
  51. <button class="num-btn" @tap="updateQuantity(idx, -1)">-</button>
  52. <text class="num">{{ getItemTotalQuantity(item) }}</text>
  53. <button class="num-btn" @tap="updateQuantity(idx, 1)">+</button>
  54. </view>
  55. </view>
  56. </view>
  57. <view v-if="loadingMore" class="loading-more">加载中...</view>
  58. <view v-else-if="finished" class="loading-more">没有更多了</view>
  59. </scroll-view>
  60. </view>
  61. <!-- 底部操作按钮 -->
  62. <view class="footer-btns">
  63. <button class="btn-outline" @tap="goBack">返回订单详情</button>
  64. <button class="btn-main" @tap="goNext">下一步</button>
  65. </view>
  66. <!-- 品牌选择组件 -->
  67. <brand-selector ref="brandSelector" @brand-confirm="onBrandConfirm" @reduce-select="onReduceSelect"
  68. @close="onBrandSelectorClose" @get-existing-quantities="getExistingQuantities"></brand-selector>
  69. </view>
  70. </template>
  71. <script>
  72. import brandSelector from '../../compoent/recycle/brand-selector.vue'
  73. export default {
  74. components: {
  75. brandSelector
  76. },
  77. data() {
  78. return {
  79. statusBarHeight: 0,
  80. currentCategory: 0,
  81. orderId: '',
  82. order: null, // 订单数据
  83. currentGoods: [], // 当前显示的商品列表
  84. inspectResult: {}, // 质检结果对象,按照新的数据格式
  85. allProducts: {}, // { [categoryId]: [商品数组] }
  86. allProductsPage: {}, // { [categoryId]: 当前已加载页码 }
  87. allProductsTotal: {}, // { [categoryId]: 总数 }
  88. pageSize: 10,
  89. loadingMore: false,
  90. finished: false,
  91. // 品牌选择相关
  92. pendingBrandIndex: null,
  93. reduceItem: null, // 待减少数量的商品
  94. brandStyleCache: {}, // 全局品牌款式缓存
  95. // brandIndexList 改为 computed
  96. }
  97. },
  98. computed: {
  99. categories() {
  100. const list = getApp().globalData.pricePreviewList || []
  101. console.log('categories计算 - pricePreviewList:', list.length)
  102. // 显示所有分类,不再根据订单数据筛选
  103. const allCategories = list.filter(item => item.pid === '0').sort((a, b) => a.sort - b.sort)
  104. console.log('categories计算 - allCategories:', allCategories.length)
  105. // 为每个分类计算数量
  106. const categoriesWithCount = allCategories.map(category => {
  107. const count = this.getCategoryItemCountDirect(category.id)
  108. return {
  109. ...category,
  110. badge: count > 0 ? count : null
  111. }
  112. })
  113. // 新增不可回收和质量问题分类
  114. const extra = [
  115. { id: 'unrecyclable', title: '不可回收', badge: this.getUnrecyclableCount() },
  116. { id: 'quality_issue', title: '质量问题', badge: this.getQualityIssueCount() }
  117. ]
  118. const result = [...categoriesWithCount, ...extra]
  119. console.log('categories计算 - 最终结果:', result.map(c => ({ id: c.id, title: c.title, badge: c.badge })))
  120. return result
  121. },
  122. },
  123. methods: {
  124. initInspectResult() {
  125. // 只初始化空的list
  126. this.inspectResult = {
  127. id: this.order ? this.order.id : '',
  128. list: []
  129. }
  130. },
  131. // 获取分类商品数量(直接方法,避免递归)
  132. getCategoryItemCountDirect(categoryId) {
  133. if (categoryId === 'unrecyclable') {
  134. return this.getUnrecyclableCount()
  135. }
  136. if (categoryId === 'quality_issue') {
  137. return this.getQualityIssueCount()
  138. }
  139. let totalCount = 0
  140. if (this.inspectResult.list && this.inspectResult.list.length > 0) {
  141. this.inspectResult.list.forEach(inspectItem => {
  142. if (inspectItem.categoryId === categoryId) {
  143. totalCount += inspectItem.qualifiedNum || 0
  144. }
  145. })
  146. }
  147. return totalCount
  148. },
  149. // 获取当前分类ID(避免递归)
  150. getCurrentCategoryId() {
  151. const list = getApp().globalData.pricePreviewList || []
  152. const allCategories = list.filter(item => item.pid === '0').sort((a, b) => a.sort - b.sort)
  153. const extra = [
  154. { id: 'unrecyclable', title: '不可回收' },
  155. { id: 'quality_issue', title: '质量问题' }
  156. ]
  157. const allCategoriesWithExtra = [...allCategories, ...extra]
  158. return allCategoriesWithExtra[this.currentCategory]?.id
  159. },
  160. // 获取分类商品数量(保持原有方法名兼容性)
  161. getCategoryItemCount(categoryId) {
  162. return this.getCategoryItemCountDirect(categoryId)
  163. },
  164. // 获取不可回收数量
  165. getUnrecyclableCount() {
  166. // 从inspectResult中获取不可回收的数量
  167. const unrecyclableItem = this.inspectResult.list?.find(item => item.id === 'unrecyclable')
  168. return unrecyclableItem ? unrecyclableItem.unrecyclable : 0
  169. },
  170. // 获取质量问题数量
  171. getQualityIssueCount() {
  172. // 从inspectResult中获取质量问题的数量
  173. const qualityIssueItem = this.inspectResult.list?.find(item => item.id === 'quality_issue')
  174. return qualityIssueItem ? qualityIssueItem.noQualifiedNum : 0
  175. },
  176. fetchGoodsList(categoryId, page = 1, callback) {
  177. this.$api('getClassGoodsList', {
  178. classId: categoryId,
  179. pageNo: page,
  180. pageSize: this.pageSize
  181. }, res => {
  182. if (res.code === 200 && res.result && Array.isArray(res.result.records)) {
  183. const oldList = this.allProducts[categoryId] || []
  184. const newList = page === 1 ? res.result.records : oldList.concat(res.result.records)
  185. this.$set(this.allProducts, categoryId, newList)
  186. this.$set(this.allProductsPage, categoryId, page)
  187. this.$set(this.allProductsTotal, categoryId, res.result.total)
  188. this.updateCurrentGoods()
  189. }
  190. if (callback) callback()
  191. })
  192. },
  193. updateCurrentGoods() {
  194. const currentCategoryId = this.categories[this.currentCategory]?.id
  195. // 不可回收分类内容
  196. if (currentCategoryId === 'unrecyclable') {
  197. // 从inspectResult中获取不可回收的数量
  198. const unrecyclableItem = this.inspectResult.list?.find(item => item.id === 'unrecyclable')
  199. const unrecyclableCount = unrecyclableItem ? unrecyclableItem.unrecyclable : 0
  200. this.currentGoods = [{
  201. id: 'unrecyclable-1',
  202. image: '/static/回收/衣物.png',
  203. name: '不可回收品类',
  204. price: '—',
  205. desc: '允许脏破烂,160码以上',
  206. qualified: unrecyclableCount,
  207. amount: '',
  208. originalNum: 0 // 不设置最大数量限制
  209. }]
  210. return
  211. }
  212. // 质量问题分类内容
  213. if (currentCategoryId === 'quality_issue') {
  214. // 从inspectResult中获取质量问题的数量
  215. const qualityIssueItem = this.inspectResult.list?.find(item => item.id === 'quality_issue')
  216. const qualityIssueCount = qualityIssueItem ? qualityIssueItem.noQualifiedNum : 0
  217. this.currentGoods = [{
  218. id: 'quality-issue-1',
  219. image: '/static/回收/衣物.png',
  220. name: '质量问题品类',
  221. price: '—',
  222. desc: '存在质量问题,无法正常回收',
  223. qualified: qualityIssueCount,
  224. amount: '',
  225. originalNum: 0 // 不设置最大数量限制
  226. }]
  227. return
  228. }
  229. // 从API获取的商品数据
  230. const categoryGoods = this.allProducts[currentCategoryId] || []
  231. // 将API商品数据转换为质检页面格式,并合并inspectResult.list中已选状态(shopId和id双向查找)
  232. const goodsList = categoryGoods.map((item, index) => {
  233. // 从订单数据中查找对应的商品
  234. const orderItem = this.getOrderItemByProductId(item.id)
  235. let itemId = item.id
  236. if (orderItem && orderItem.id) {
  237. itemId = orderItem.id
  238. }
  239. const inspectItem = this.inspectResult.list?.find(listItem =>
  240. listItem.shopId == item.id || listItem.shopId == itemId || listItem.id == item.id || listItem.id == itemId
  241. )
  242. // 恢复品牌款式数据 - 从所有分类的商品中查找
  243. const brandStyleQuantities = {}
  244. const styleCache = {}
  245. let totalQuantity = 0
  246. // 查找所有分类中是否有相同商品的品牌款式数据
  247. Object.values(this.allProducts).forEach(categoryProducts => {
  248. const existingProduct = categoryProducts.find(p => p.id === item.id)
  249. if (existingProduct && this.currentGoods) {
  250. const existingGoodsItem = this.currentGoods.find(g => g.id === item.id)
  251. if (existingGoodsItem && existingGoodsItem.brandStyleQuantities) {
  252. Object.assign(brandStyleQuantities, existingGoodsItem.brandStyleQuantities)
  253. Object.assign(styleCache, existingGoodsItem.styleCache)
  254. totalQuantity = Object.values(existingGoodsItem.brandStyleQuantities).reduce((sum, qty) => sum + qty, 0)
  255. }
  256. }
  257. })
  258. // 如果没有找到现有数据,尝试从全局状态中恢复
  259. if (totalQuantity === 0 && this.brandStyleCache && this.brandStyleCache[item.id]) {
  260. Object.assign(brandStyleQuantities, this.brandStyleCache[item.id].brandStyleQuantities || {})
  261. Object.assign(styleCache, this.brandStyleCache[item.id].styleCache || {})
  262. totalQuantity = Object.values(brandStyleQuantities).reduce((sum, qty) => sum + qty, 0)
  263. }
  264. // 如果没有品牌款式数据,使用普通数量
  265. const finalQuantity = totalQuantity > 0 ? 0 : (inspectItem ? inspectItem.qualifiedNum : 0)
  266. return {
  267. id: item.id,
  268. image: item.image || '/static/回收/衣物.png',
  269. name: item.name,
  270. price: item.price || 0,
  271. maxPrice: item.maxPrice || 0,
  272. desc: item.service || '允许脏破烂,160码以上',
  273. qualified: inspectItem ? inspectItem.qualifiedNum : 0,
  274. originalNum: 0,
  275. estimatedPrice: orderItem ? orderItem.estimatedPrice : 0,
  276. originalId: item.id,
  277. isPin: item.isPin || 'N',
  278. orderItem: orderItem,
  279. unit: item.unit || '件',
  280. // 品牌款式相关数据
  281. brandStyleQuantities: brandStyleQuantities,
  282. styleCache: styleCache,
  283. quantity: finalQuantity
  284. }
  285. })
  286. this.currentGoods = goodsList
  287. },
  288. // 根据商品ID从订单数据中查找对应商品
  289. getOrderItemByProductId(productId) {
  290. if (!this.order || !this.order.commonOrderList) {
  291. return null
  292. }
  293. // 支持id和shopId双向查找
  294. return this.order.commonOrderList.find(item => item.id == productId || item.shopId == productId)
  295. },
  296. goBack() {
  297. uni.navigateBack()
  298. },
  299. goNext() {
  300. // 检测是否所有商品都已完成质检和填写价格
  301. const validationResult = this.validateInspectData()
  302. if (!validationResult.isValid) {
  303. uni.showToast({
  304. title: validationResult.message,
  305. icon: 'none',
  306. duration: 2000
  307. })
  308. return
  309. }
  310. // 将品牌款式数据转换为独立的质检对象
  311. const processedInspectResult = this.processInspectResultForBrandStyles()
  312. // 构造传递给步骤二的完整数据
  313. const resultData = {
  314. inspectResult: processedInspectResult,
  315. order: this.order // 同时传递订单信息
  316. }
  317. console.log('resultDataStr:', resultData)
  318. const resultDataStr = encodeURIComponent(JSON.stringify(resultData))
  319. uni.navigateTo({
  320. url: `/pages/manager/inspect-result?resultData=${resultDataStr}`
  321. })
  322. },
  323. // 处理品牌款式数据,将每个品牌款式组合生成独立的质检对象
  324. processInspectResultForBrandStyles() {
  325. const processedList = []
  326. // 遍历当前的质检结果
  327. this.inspectResult.list.forEach(inspectItem => {
  328. // 不可回收和质量问题直接保留
  329. if (inspectItem.id === 'unrecyclable' || inspectItem.id === 'quality_issue') {
  330. processedList.push(inspectItem)
  331. return
  332. }
  333. // 从全局缓存中查找品牌款式数据
  334. const cachedBrandStyleData = this.findBrandStyleDataFromCache(inspectItem.shopId)
  335. if (cachedBrandStyleData && Object.keys(cachedBrandStyleData.brandStyleQuantities).length > 0) {
  336. // 如果有品牌款式数据,为每个品牌款式创建独立对象
  337. Object.entries(cachedBrandStyleData.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
  338. if (quantity > 0 && cachedBrandStyleData.styleCache && cachedBrandStyleData.styleCache[uniqueKey]) {
  339. const { brandInfo, styleInfo } = cachedBrandStyleData.styleCache[uniqueKey]
  340. // 为每个品牌款式组合创建独立的质检对象
  341. const brandStyleInspectItem = {
  342. ...inspectItem,
  343. qualifiedNum: quantity,
  344. shopId: inspectItem.shopId,
  345. pinId: brandInfo.id,
  346. styleId: styleInfo.id,
  347. brandName: brandInfo.name,
  348. styleName: styleInfo.name,
  349. brandImage: brandInfo.logo,
  350. styleImage: styleInfo.image,
  351. uniqueKey: uniqueKey,
  352. commonOrderList: [{
  353. testingInstructions: '',
  354. testingImages: '',
  355. testingStatus: 0
  356. }]
  357. }
  358. processedList.push(brandStyleInspectItem)
  359. }
  360. })
  361. } else {
  362. // 没有品牌款式数据,保留原始对象
  363. processedList.push(inspectItem)
  364. }
  365. })
  366. return {
  367. id: this.inspectResult.id,
  368. list: processedList
  369. }
  370. },
  371. // 根据shopId查找当前商品
  372. findCurrentGoodsByShopId(shopId) {
  373. return this.currentGoods.find(item => {
  374. const orderItem = this.getOrderItemByProductId(item.id)
  375. const itemId = orderItem ? (orderItem.shopId || orderItem.id) : item.id
  376. return itemId == shopId
  377. })
  378. },
  379. // 从全局缓存和所有分类商品中查找品牌款式数据
  380. findBrandStyleDataFromCache(shopId) {
  381. // 首先从全局缓存中查找
  382. const productId = this.getProductIdFromShopId(shopId)
  383. if (productId && this.brandStyleCache[productId]) {
  384. return this.brandStyleCache[productId]
  385. }
  386. // 从所有分类的商品中查找
  387. for (const categoryId in this.allProducts) {
  388. const categoryProducts = this.allProducts[categoryId]
  389. for (const product of categoryProducts) {
  390. const orderItem = this.getOrderItemByProductId(product.id)
  391. const itemId = orderItem ? (orderItem.shopId || orderItem.id) : product.id
  392. if (itemId == shopId && this.brandStyleCache[product.id]) {
  393. return this.brandStyleCache[product.id]
  394. }
  395. }
  396. }
  397. return null
  398. },
  399. // 根据shopId获取productId
  400. getProductIdFromShopId(shopId) {
  401. // 从订单数据中查找
  402. if (this.order && this.order.commonOrderList) {
  403. const orderItem = this.order.commonOrderList.find(item =>
  404. item.shopId == shopId || item.id == shopId
  405. )
  406. if (orderItem) {
  407. return orderItem.shopId || orderItem.id
  408. }
  409. }
  410. // 从所有分类商品中查找
  411. for (const categoryId in this.allProducts) {
  412. const categoryProducts = this.allProducts[categoryId]
  413. const product = categoryProducts.find(p => {
  414. const orderItem = this.getOrderItemByProductId(p.id)
  415. const itemId = orderItem ? (orderItem.shopId || orderItem.id) : p.id
  416. return itemId == shopId
  417. })
  418. if (product) {
  419. return product.id
  420. }
  421. }
  422. return shopId
  423. },
  424. validateInspectData() {
  425. if (!this.inspectResult.list || this.inspectResult.list.length === 0) {
  426. return {
  427. isValid: false,
  428. message: '没有质检数据'
  429. }
  430. }
  431. for (const item of this.inspectResult.list) {
  432. // 不可回收和质量问题不需要校验金额
  433. if (item.id === 'unrecyclable' || item.id === 'quality_issue') {
  434. continue
  435. }
  436. // 只判断是否填写了commonOrderList(即有质检结果)
  437. if (!item.commonOrderList || item.commonOrderList.length === 0) {
  438. return {
  439. isValid: false,
  440. message: '有商品未完成质检选择'
  441. }
  442. }
  443. // 检查是否有空的testingStatus
  444. const hasEmptyStatus = item.commonOrderList.some(commonItem =>
  445. commonItem.testingStatus === '' || commonItem.testingStatus === null || commonItem.testingStatus === undefined
  446. )
  447. if (hasEmptyStatus) {
  448. return {
  449. isValid: false,
  450. message: '有商品未完成质检选择'
  451. }
  452. }
  453. // 不再校验价格,价格将在下一步填写
  454. }
  455. return {
  456. isValid: true,
  457. message: ''
  458. }
  459. },
  460. switchCategory(idx) {
  461. this.currentCategory = idx
  462. this.loadingMore = false
  463. this.finished = false
  464. const categoryId = this.categories[idx]?.id
  465. if (categoryId === 'unrecyclable' || categoryId === 'quality_issue') {
  466. // 不可回收和质量问题分类直接更新商品列表
  467. this.updateCurrentGoods()
  468. return
  469. }
  470. // 如果该分类的商品还没有加载,调用API获取
  471. if (!this.allProducts[categoryId]) {
  472. this.fetchGoodsList(categoryId, 1)
  473. } else {
  474. // 已有数据,直接更新显示
  475. this.updateCurrentGoods()
  476. }
  477. },
  478. // 更新商品数量
  479. updateQuantity(index, delta) {
  480. const categoryId = this.categories[this.currentCategory]?.id
  481. const item = this.currentGoods[index]
  482. if (!item) return
  483. // 处理不可回收和质量问题
  484. if (item.id === 'unrecyclable-1' || item.id === 'quality-issue-1') {
  485. const newQualified = Math.max(0, (item.qualified || 0) + delta)
  486. this.$set(item, 'qualified', newQualified)
  487. this.updateInspectResult(item, 'qualified', delta, categoryId)
  488. // 更新商品列表以同步显示
  489. this.updateCurrentGoods()
  490. this.$forceUpdate()
  491. return
  492. }
  493. // 如果是减少数量且delta为负数
  494. if (delta < 0) {
  495. // 检查是否有多个品牌款式
  496. if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 1) {
  497. // 有多个品牌款式,显示选择弹窗
  498. this.reduceItem = { item, index, delta }
  499. const reduceStyleList = Object.entries(item.brandStyleQuantities)
  500. .filter(([uniqueKey, quantity]) => quantity > 0)
  501. .map(([uniqueKey, quantity]) => {
  502. const cacheInfo = item.styleCache[uniqueKey]
  503. return {
  504. uniqueKey,
  505. quantity,
  506. name: cacheInfo ? `${cacheInfo.brandInfo.name} - ${cacheInfo.styleInfo.name}` : '未知款式',
  507. logo: cacheInfo ? cacheInfo.brandInfo.logo : ''
  508. }
  509. })
  510. this.$refs.brandSelector.openReducePopup(reduceStyleList)
  511. return
  512. } else if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length === 1) {
  513. // 只有一个品牌款式,直接减少
  514. const uniqueKey = Object.keys(item.brandStyleQuantities)[0]
  515. const currentQty = item.brandStyleQuantities[uniqueKey] || 0
  516. const newQty = Math.max(0, currentQty + delta)
  517. this.$set(item.brandStyleQuantities, uniqueKey, newQty)
  518. // 如果数量为0,删除该品牌款式
  519. if (newQty === 0) {
  520. delete item.brandStyleQuantities[uniqueKey]
  521. if (item.styleCache && item.styleCache[uniqueKey]) {
  522. delete item.styleCache[uniqueKey]
  523. }
  524. }
  525. this.updateInspectResultFromBrandStyle(item)
  526. return
  527. } else {
  528. // 没有品牌数量,使用原来的逻辑
  529. let newQuantity = (item.quantity || 0) + delta
  530. if (newQuantity < 0) newQuantity = 0
  531. this.$set(item, 'quantity', newQuantity)
  532. this.updateInspectResultFromQuantity(item)
  533. return
  534. }
  535. }
  536. // 品牌商品且数量为0且加一时,打开品牌选择
  537. if (item.isPin === 'Y' && (this.getItemTotalQuantity(item) === 0) && delta > 0) {
  538. this.pendingBrandIndex = index
  539. this.$refs.brandSelector.open(item.id)
  540. return
  541. }
  542. // 品牌商品且已有数量时,继续增加到现有品牌款式
  543. if (item.isPin === 'Y' && this.getItemTotalQuantity(item) > 0 && delta > 0) {
  544. // 如果只有一个品牌款式,直接增加
  545. if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length === 1) {
  546. const uniqueKey = Object.keys(item.brandStyleQuantities)[0]
  547. const currentQty = item.brandStyleQuantities[uniqueKey] || 0
  548. this.$set(item.brandStyleQuantities, uniqueKey, currentQty + delta)
  549. this.updateInspectResultFromBrandStyle(item)
  550. return
  551. } else {
  552. // 有多个品牌款式,打开品牌选择
  553. this.pendingBrandIndex = index
  554. this.$refs.brandSelector.open(item.id)
  555. return
  556. }
  557. }
  558. // 无品牌商品,直接加减数量
  559. if (item.isPin !== 'Y') {
  560. let newQuantity = (item.quantity || 0) + delta
  561. if (newQuantity < 0) newQuantity = 0
  562. this.$set(item, 'quantity', newQuantity)
  563. this.updateInspectResultFromQuantity(item)
  564. return
  565. }
  566. },
  567. // 获取商品的总数量(所有品牌款式)
  568. getItemTotalQuantity(item) {
  569. // 特殊处理不可回收和质量问题
  570. if (item.id === 'unrecyclable-1' || item.id === 'quality-issue-1') {
  571. return item.qualified || 0
  572. }
  573. if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
  574. return Object.values(item.brandStyleQuantities).reduce((sum, qty) => sum + qty, 0)
  575. }
  576. return item.quantity || 0
  577. },
  578. // 获取已选择的品牌款式信息
  579. getSelectedBrandStyles(item) {
  580. const styles = []
  581. if (item.brandStyleQuantities && item.styleCache) {
  582. Object.entries(item.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
  583. if (quantity > 0 && item.styleCache[uniqueKey]) {
  584. const { brandInfo, styleInfo } = item.styleCache[uniqueKey]
  585. styles.push({
  586. uniqueKey,
  587. quantity,
  588. brandName: brandInfo.name,
  589. styleName: styleInfo.name
  590. })
  591. }
  592. })
  593. }
  594. return styles
  595. },
  596. // 处理品牌确认事件
  597. onBrandConfirm(data) {
  598. if (this.pendingBrandIndex !== null) {
  599. const item = this.currentGoods[this.pendingBrandIndex]
  600. if (item && data.selectedStyles && data.selectedStyles.length > 0) {
  601. // 初始化品牌款式数量对象
  602. if (!item.brandStyleQuantities) {
  603. this.$set(item, 'brandStyleQuantities', {})
  604. }
  605. // 清理当前品牌的所有款式数据
  606. const brandPrefix = `${data.brandInfo.id}_`
  607. Object.keys(item.brandStyleQuantities).forEach(key => {
  608. if (key.startsWith(brandPrefix)) {
  609. delete item.brandStyleQuantities[key]
  610. if (item.styleCache && item.styleCache[key]) {
  611. delete item.styleCache[key]
  612. }
  613. }
  614. })
  615. // 为每个选中的款式设置数量(只保存有数量的款式)
  616. data.selectedStyles.forEach(style => {
  617. if (style.quantity > 0) {
  618. const uniqueKey = `${data.brandInfo.id}_${style.id}`
  619. this.$set(item.brandStyleQuantities, uniqueKey, style.quantity)
  620. // 缓存款式信息用于后续显示
  621. if (!item.styleCache) {
  622. this.$set(item, 'styleCache', {})
  623. }
  624. this.$set(item.styleCache, uniqueKey, {
  625. brandInfo: data.brandInfo,
  626. styleInfo: style
  627. })
  628. }
  629. })
  630. // 清除原来的quantity
  631. if (item.quantity) {
  632. this.$set(item, 'quantity', 0)
  633. }
  634. // 更新质检结果
  635. this.updateInspectResultFromBrandStyle(item)
  636. // 保存到全局缓存
  637. this.$set(this.brandStyleCache, item.id, {
  638. brandStyleQuantities: { ...item.brandStyleQuantities },
  639. styleCache: { ...item.styleCache }
  640. })
  641. }
  642. this.pendingBrandIndex = null
  643. }
  644. },
  645. // 处理减少品牌选择事件
  646. onReduceSelect(selectInfo) {
  647. const { item, index, delta } = this.reduceItem
  648. if (selectInfo.uniqueKey) {
  649. // 品牌款式减少逻辑
  650. const currentQty = item.brandStyleQuantities[selectInfo.uniqueKey] || 0
  651. const newQty = Math.max(0, currentQty + delta)
  652. this.$set(item.brandStyleQuantities, selectInfo.uniqueKey, newQty)
  653. // 如果数量为0,删除该品牌款式
  654. if (newQty === 0) {
  655. delete item.brandStyleQuantities[selectInfo.uniqueKey]
  656. if (item.styleCache && item.styleCache[selectInfo.uniqueKey]) {
  657. delete item.styleCache[selectInfo.uniqueKey]
  658. }
  659. }
  660. this.updateInspectResultFromBrandStyle(item)
  661. // 更新全局缓存
  662. this.$set(this.brandStyleCache, item.id, {
  663. brandStyleQuantities: { ...item.brandStyleQuantities },
  664. styleCache: { ...item.styleCache }
  665. })
  666. }
  667. this.reduceItem = null
  668. },
  669. // 处理品牌选择器关闭事件
  670. onBrandSelectorClose() {
  671. this.pendingBrandIndex = null
  672. },
  673. // 获取已有的款式数量
  674. getExistingQuantities(brandId, callback) {
  675. if (this.pendingBrandIndex !== null) {
  676. const item = this.currentGoods[this.pendingBrandIndex]
  677. if (item && item.brandStyleQuantities) {
  678. // 过滤出当前品牌的款式数量
  679. const existingQuantities = {}
  680. Object.entries(item.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
  681. if (uniqueKey.startsWith(`${brandId}_`)) {
  682. existingQuantities[uniqueKey] = quantity
  683. }
  684. })
  685. callback(existingQuantities)
  686. } else {
  687. callback({})
  688. }
  689. } else {
  690. callback({})
  691. }
  692. },
  693. // 从品牌款式数据更新质检结果
  694. updateInspectResultFromBrandStyle(item) {
  695. const totalQuantity = this.getItemTotalQuantity(item)
  696. // 如果总数量为0,移除质检结果
  697. if (totalQuantity === 0) {
  698. this.removeInspectItem(item)
  699. return
  700. }
  701. // 更新或创建质检结果项
  702. const categoryId = this.categories[this.currentCategory]?.id
  703. const orderItem = this.getOrderItemByProductId(item.id)
  704. const itemId = orderItem ? (orderItem.shopId || orderItem.id) : item.id
  705. let inspectItem = this.inspectResult.list?.find(listItem => listItem.shopId == itemId)
  706. if (!inspectItem) {
  707. inspectItem = {
  708. price: 0,
  709. qualifiedNum: totalQuantity,
  710. noQualifiedNum: 0,
  711. unrecyclable: 0,
  712. shopId: itemId,
  713. pinId: '',
  714. categoryId: categoryId || '',
  715. commonOrderList: [{
  716. testingInstructions: '',
  717. testingImages: '',
  718. testingStatus: 0
  719. }]
  720. }
  721. this.inspectResult.list.push(inspectItem)
  722. } else {
  723. inspectItem.qualifiedNum = totalQuantity
  724. }
  725. },
  726. // 从普通数量更新质检结果
  727. updateInspectResultFromQuantity(item) {
  728. const quantity = item.quantity || 0
  729. // 如果数量为0,移除质检结果
  730. if (quantity === 0) {
  731. this.removeInspectItem(item)
  732. return
  733. }
  734. // 更新或创建质检结果项
  735. const categoryId = this.categories[this.currentCategory]?.id
  736. const orderItem = this.getOrderItemByProductId(item.id)
  737. const itemId = orderItem ? (orderItem.shopId || orderItem.id) : item.id
  738. let inspectItem = this.inspectResult.list?.find(listItem => listItem.shopId == itemId)
  739. if (!inspectItem) {
  740. inspectItem = {
  741. price: 0,
  742. qualifiedNum: quantity,
  743. noQualifiedNum: 0,
  744. unrecyclable: 0,
  745. shopId: itemId,
  746. pinId: '',
  747. categoryId: categoryId || '',
  748. commonOrderList: [{
  749. testingInstructions: '',
  750. testingImages: '',
  751. testingStatus: 0
  752. }]
  753. }
  754. this.inspectResult.list.push(inspectItem)
  755. } else {
  756. inspectItem.qualifiedNum = quantity
  757. }
  758. },
  759. // 修改:移除商品对象方法,支持不可回收和质量问题
  760. removeInspectItem(item) {
  761. // 判断不可回收和质量问题
  762. if (item.id === 'unrecyclable-1' || item.id === 'unrecyclable') {
  763. const idx = this.inspectResult.list.findIndex(listItem => listItem.id === 'unrecyclable')
  764. if (idx !== -1) {
  765. this.inspectResult.list.splice(idx, 1)
  766. }
  767. return
  768. }
  769. if (item.id === 'quality-issue-1' || item.id === 'quality_issue') {
  770. const idx = this.inspectResult.list.findIndex(listItem => listItem.id === 'quality_issue')
  771. if (idx !== -1) {
  772. this.inspectResult.list.splice(idx, 1)
  773. }
  774. return
  775. }
  776. let itemId = item.originalId || item.id
  777. const orderItem = this.getOrderItemByProductId(itemId)
  778. if (orderItem && orderItem.id) {
  779. itemId = orderItem.id
  780. }
  781. // shopId 匹配
  782. const idx = this.inspectResult.list.findIndex(listItem => listItem.shopId == (orderItem ? (orderItem.shopId || orderItem.id) : itemId))
  783. if (idx !== -1) {
  784. this.inspectResult.list.splice(idx, 1)
  785. }
  786. },
  787. updateInspectResult(item, type, delta, currentCategoryId) {
  788. // 处理不可回收分类
  789. if (item.id === 'unrecyclable-1') {
  790. let inspectItem = this.inspectResult.list.find(listItem => listItem.id === 'unrecyclable')
  791. if (!inspectItem && delta > 0) {
  792. inspectItem = {
  793. id: 'unrecyclable',
  794. price: 0,
  795. qualifiedNum: 0,
  796. noQualifiedNum: 0,
  797. unrecyclable: 0, // 初始值为0
  798. shopId: '',
  799. pinId: '',
  800. categoryId: '',
  801. commonOrderList: [] // 初始为空数组
  802. }
  803. this.inspectResult.list.push(inspectItem)
  804. }
  805. if (!inspectItem) return
  806. if (type === 'qualified' && delta > 0) {
  807. inspectItem.unrecyclable++
  808. // 增加一个commonOrderList对象
  809. inspectItem.commonOrderList.push({
  810. testingInstructions: '',
  811. testingImages: '',
  812. testingStatus: 2
  813. })
  814. } else if (type === 'qualified' && delta < 0) {
  815. inspectItem.unrecyclable = Math.max(0, inspectItem.unrecyclable - 1)
  816. // 减少一个commonOrderList对象
  817. if (inspectItem.commonOrderList.length > 0) {
  818. inspectItem.commonOrderList.pop()
  819. }
  820. // 新增:如果减到0,移除该对象
  821. if (inspectItem.unrecyclable === 0) {
  822. const idx = this.inspectResult.list.findIndex(listItem => listItem === inspectItem)
  823. if (idx !== -1) {
  824. this.inspectResult.list.splice(idx, 1)
  825. }
  826. return
  827. }
  828. }
  829. console.log('不可回收对象:', inspectItem)
  830. return
  831. }
  832. if (item.id === 'quality-issue-1') {
  833. let inspectItem = this.inspectResult.list.find(listItem => listItem.id === 'quality_issue')
  834. if (!inspectItem && delta > 0) {
  835. inspectItem = {
  836. id: 'quality_issue',
  837. price: 0,
  838. qualifiedNum: 0,
  839. noQualifiedNum: 0, // 初始值为0
  840. unrecyclable: 0,
  841. shopId: '',
  842. pinId: '',
  843. categoryId: '',
  844. commonOrderList: [] // 初始为空数组
  845. }
  846. this.inspectResult.list.push(inspectItem)
  847. }
  848. if (!inspectItem) return
  849. if (type === 'qualified' && delta > 0) {
  850. inspectItem.noQualifiedNum++
  851. // 增加一个commonOrderList对象
  852. inspectItem.commonOrderList.push({
  853. testingInstructions: '',
  854. testingImages: '',
  855. testingStatus: 1
  856. })
  857. } else if (type === 'qualified' && delta < 0) {
  858. inspectItem.noQualifiedNum = Math.max(0, inspectItem.noQualifiedNum - 1)
  859. // 减少一个commonOrderList对象
  860. if (inspectItem.commonOrderList.length > 0) {
  861. inspectItem.commonOrderList.pop()
  862. }
  863. // 新增:如果减到0,移除该对象
  864. if (inspectItem.noQualifiedNum === 0) {
  865. const idx = this.inspectResult.list.findIndex(listItem => listItem === inspectItem)
  866. if (idx !== -1) {
  867. this.inspectResult.list.splice(idx, 1)
  868. }
  869. return
  870. }
  871. }
  872. console.log('质量问题对象:', inspectItem)
  873. return
  874. }
  875. let itemId = item.originalId || item.id
  876. const orderItem = this.getOrderItemByProductId(itemId)
  877. if (orderItem && orderItem.id) {
  878. itemId = orderItem.id
  879. }
  880. let inspectItem = this.inspectResult.list.find(listItem => listItem.shopId == (orderItem ? (orderItem.shopId || orderItem.id) : itemId))
  881. if (!inspectItem && delta > 0) {
  882. inspectItem = {
  883. price: 0,
  884. qualifiedNum: 0,
  885. noQualifiedNum: 0,
  886. unrecyclable: 0,
  887. shopId: orderItem ? (orderItem.shopId || orderItem.id) : itemId,
  888. pinId: '',
  889. categoryId: currentCategoryId || '', // 直接用当前分类id
  890. commonOrderList: [{
  891. testingInstructions: '',
  892. testingImages: '',
  893. testingStatus: 0
  894. }] // 合格产品固定一个commonOrderList项
  895. }
  896. this.inspectResult.list.push(inspectItem)
  897. }
  898. if (!inspectItem) return
  899. if (type === 'qualified' && delta > 0) {
  900. inspectItem.qualifiedNum++
  901. // 合格产品不需要动态增加commonOrderList,保持固定一个
  902. } else if (type === 'qualified' && delta < 0) {
  903. inspectItem.qualifiedNum = Math.max(0, inspectItem.qualifiedNum - 1)
  904. // 合格产品不需要动态减少commonOrderList
  905. // 新增:如果减到0,移除该商品对象
  906. if (inspectItem.qualifiedNum === 0) {
  907. const idx = this.inspectResult.list.findIndex(listItem => listItem === inspectItem)
  908. if (idx !== -1) {
  909. this.inspectResult.list.splice(idx, 1)
  910. }
  911. return
  912. }
  913. }
  914. console.log('更新后的inspectResult:', JSON.stringify(this.inspectResult, null, 2))
  915. },
  916. loadMoreGoods() {
  917. const categoryId = this.categories[this.currentCategory]?.id
  918. // 不可回收和质量问题分类不支持加载更多
  919. if (categoryId === 'unrecyclable' || categoryId === 'quality_issue') {
  920. return
  921. }
  922. const page = (this.allProductsPage[categoryId] || 1) + 1
  923. const total = this.allProductsTotal[categoryId] || 0
  924. const loaded = (this.allProducts[categoryId] || []).length
  925. if (this.loadingMore || this.finished) return
  926. if (loaded < total) {
  927. this.loadingMore = true
  928. this.fetchGoodsList(categoryId, page, () => {
  929. this.loadingMore = false
  930. // 判断是否加载完
  931. const newLoaded = (this.allProducts[categoryId] || []).length
  932. this.finished = newLoaded >= (this.allProductsTotal[categoryId] || 0)
  933. })
  934. } else {
  935. this.finished = true
  936. }
  937. },
  938. // 格式化价格显示
  939. formatPrice(item) {
  940. const price = item.price
  941. const maxPrice = item.maxPrice
  942. // 如果两个价格都没有或都为0,显示占位符
  943. if ((!price || price === 0) && (!maxPrice || maxPrice === 0)) {
  944. return '¥ —'
  945. }
  946. // 如果只有一个价格有值
  947. if (price && (!maxPrice || maxPrice === 0)) {
  948. return `¥ ${price}`
  949. }
  950. if (maxPrice && (!price || price === 0)) {
  951. return `¥ ${maxPrice}`
  952. }
  953. // 如果两个价格都有值且不相等,显示价格范围
  954. if (price && maxPrice && price !== maxPrice) {
  955. const minPrice = Math.min(price, maxPrice)
  956. const maxPriceValue = Math.max(price, maxPrice)
  957. return `¥ ${minPrice} - ${maxPriceValue}`
  958. }
  959. // 如果两个价格相等,只显示一个
  960. return `¥ ${price || maxPrice}`
  961. },
  962. },
  963. created() {
  964. this.currentCategory = 0
  965. },
  966. onLoad(options) {
  967. // 接收订单数据
  968. if (options && options.orderData) {
  969. try {
  970. this.order = JSON.parse(decodeURIComponent(options.orderData))
  971. console.log('接收到的订单数据:', this.order)
  972. // 订单数据加载完成后初始化质检结果
  973. this.$nextTick(() => {
  974. this.initInspectResult()
  975. })
  976. } catch (error) {
  977. console.error('解析订单数据失败:', error)
  978. }
  979. }
  980. if (options && options.orderId) {
  981. this.orderId = options.orderId
  982. }
  983. // 初始化加载第一个分类的商品
  984. this.$nextTick(() => {
  985. // 确保categories已经计算完成
  986. if (this.categories.length > 0) {
  987. const firstCategoryId = this.categories[0]?.id
  988. console.log('第一个分类ID:', firstCategoryId, '所有分类:', this.categories.map(c => c.id))
  989. if (firstCategoryId && firstCategoryId !== 'unrecyclable' && firstCategoryId !== 'quality_issue') {
  990. this.fetchGoodsList(firstCategoryId, 1)
  991. } else if (firstCategoryId === 'unrecyclable' || firstCategoryId === 'quality_issue') {
  992. this.updateCurrentGoods()
  993. }
  994. } else {
  995. console.log('categories为空,等待数据加载')
  996. // 如果categories为空,等待一下再尝试
  997. setTimeout(() => {
  998. if (this.categories.length > 0) {
  999. const firstCategoryId = this.categories[0]?.id
  1000. if (firstCategoryId && firstCategoryId !== 'unrecyclable' && firstCategoryId !== 'quality_issue') {
  1001. this.fetchGoodsList(firstCategoryId, 1)
  1002. } else if (firstCategoryId === 'unrecyclable' || firstCategoryId === 'quality_issue') {
  1003. this.updateCurrentGoods()
  1004. }
  1005. }
  1006. }, 500)
  1007. }
  1008. })
  1009. console.log(this.orderId, 'orderId')
  1010. },
  1011. onShow() {
  1012. // 确保在页面显示时categories已经正确计算
  1013. console.log('onShow - categories:', this.categories.map(c => ({ id: c.id, title: c.title, badge: c.badge })))
  1014. // 强制更新视图,确保所有分类都显示
  1015. this.$nextTick(() => {
  1016. console.log('分类导航应该显示的分类数量:', this.categories.length)
  1017. this.categories.forEach((cat, index) => {
  1018. console.log(`分类 ${index}: ${cat.title} (${cat.id})`)
  1019. })
  1020. })
  1021. },
  1022. }
  1023. </script>
  1024. <style lang="scss" scoped>
  1025. .inspect-container {
  1026. min-height: 100vh;
  1027. background: #f8f8f8;
  1028. display: flex;
  1029. flex-direction: column;
  1030. }
  1031. .nav-bar {
  1032. display: flex;
  1033. align-items: center;
  1034. height: calc(150rpx + var(--status-bar-height));
  1035. padding: 0 32rpx;
  1036. padding-top: var(--status-bar-height);
  1037. background: #fff;
  1038. position: fixed;
  1039. top: 0;
  1040. left: 0;
  1041. right: 0;
  1042. z-index: 999;
  1043. box-sizing: border-box;
  1044. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
  1045. .back {
  1046. padding: 20rpx;
  1047. margin-left: -20rpx;
  1048. }
  1049. .nav-title {
  1050. flex: 1;
  1051. text-align: center;
  1052. font-size: 32rpx;
  1053. font-weight: 500;
  1054. color: #222;
  1055. }
  1056. .nav-icons {
  1057. display: flex;
  1058. align-items: center;
  1059. gap: 12px;
  1060. }
  1061. }
  1062. .main-content {
  1063. margin-top: calc(200rpx + var(--status-bar-height));
  1064. display: flex;
  1065. background: none;
  1066. height: calc(100vh - 200rpx - var(--status-bar-height));
  1067. min-height: calc(100vh - 200rpx - var(--status-bar-height));
  1068. }
  1069. .category-nav {
  1070. width: 160rpx;
  1071. background: #fff;
  1072. border-radius: 48rpx 0 0 48rpx;
  1073. // padding: 48rpx 0;
  1074. display: flex;
  1075. flex-direction: column;
  1076. align-items: center;
  1077. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
  1078. height: calc(100vh - 200rpx - var(--status-bar-height) - 160rpx);
  1079. max-height: calc(100vh - 200rpx - var(--status-bar-height) - 160rpx);
  1080. overflow-y: scroll;
  1081. overflow-x: hidden;
  1082. position: relative;
  1083. z-index: 2;
  1084. -webkit-overflow-scrolling: touch;
  1085. scrollbar-width: thin;
  1086. scrollbar-color: #ddd transparent;
  1087. &::-webkit-scrollbar {
  1088. width: 8rpx;
  1089. }
  1090. &::-webkit-scrollbar-track {
  1091. background: transparent;
  1092. }
  1093. &::-webkit-scrollbar-thumb {
  1094. background: #ddd;
  1095. border-radius: 4rpx;
  1096. }
  1097. &::-webkit-scrollbar-thumb:hover {
  1098. background: #ccc;
  1099. }
  1100. .category-item {
  1101. width: 128rpx;
  1102. height: 88rpx;
  1103. border-radius: 32rpx 0 0 32rpx;
  1104. display: flex;
  1105. align-items: center;
  1106. justify-content: flex-start;
  1107. font-size: 32rpx;
  1108. color: #222;
  1109. margin-bottom: 24rpx;
  1110. background: #fff;
  1111. position: relative;
  1112. transition: background 0.2s, color 0.2s, font-weight 0.2s;
  1113. padding-left: 24rpx;
  1114. &.active {
  1115. background: linear-gradient(90deg, #fff7e6 80%, #fff 100%);
  1116. color: #ffb400;
  1117. font-weight: bold;
  1118. &::before {
  1119. content: '';
  1120. position: absolute;
  1121. left: 0;
  1122. top: 30%;
  1123. height: 40%;
  1124. width: 4rpx;
  1125. border-radius: 8rpx;
  1126. background: #ffb400;
  1127. bottom: auto;
  1128. }
  1129. }
  1130. .category-badge {
  1131. position: absolute;
  1132. top: 12rpx;
  1133. right: 20rpx;
  1134. background: #ff4d4f;
  1135. color: #fff;
  1136. font-size: 24rpx;
  1137. border-radius: 50%;
  1138. width: 36rpx;
  1139. height: 36rpx;
  1140. display: flex;
  1141. align-items: center;
  1142. justify-content: center;
  1143. }
  1144. }
  1145. }
  1146. .goods-list {
  1147. flex: 1;
  1148. height: calc(100vh - 200rpx - var(--status-bar-height) - 160rpx);
  1149. padding: 0 0 0 32rpx;
  1150. overflow-y: auto;
  1151. background: none;
  1152. }
  1153. .goods-card {
  1154. background: #fff;
  1155. border-radius: 48rpx;
  1156. box-shadow: 0 8rpx 48rpx rgba(0, 0, 0, 0.06);
  1157. margin-bottom: 36rpx;
  1158. padding: 36rpx 36rpx 18rpx 36rpx;
  1159. }
  1160. .goods-header {
  1161. display: flex;
  1162. align-items: center;
  1163. margin-bottom: 24rpx;
  1164. .goods-img-container {
  1165. position: relative;
  1166. width: 112rpx;
  1167. height: 112rpx;
  1168. margin-right: 24rpx;
  1169. flex-shrink: 0;
  1170. }
  1171. .goods-img {
  1172. width: 100%;
  1173. height: 100%;
  1174. border-radius: 32rpx;
  1175. background: #f8f8f8;
  1176. object-fit: contain;
  1177. }
  1178. .brand-tag {
  1179. position: absolute;
  1180. top: 0rpx;
  1181. left: 0rpx;
  1182. background: rgba(0, 0, 0, 0.8);
  1183. color: #fff;
  1184. font-size: 20rpx;
  1185. padding: 4rpx 8rpx;
  1186. border-radius: 8rpx;
  1187. z-index: 2;
  1188. }
  1189. .goods-info {
  1190. flex: 1;
  1191. display: flex;
  1192. flex-direction: column;
  1193. justify-content: center;
  1194. min-width: 0;
  1195. .goods-title-row {
  1196. display: flex;
  1197. align-items: baseline;
  1198. justify-content: space-between;
  1199. .goods-name {
  1200. font-size: 28rpx;
  1201. font-weight: bold;
  1202. color: #222;
  1203. margin-right: 16rpx;
  1204. flex: 1;
  1205. overflow: hidden;
  1206. text-overflow: ellipsis;
  1207. white-space: nowrap;
  1208. }
  1209. .goods-price {
  1210. font-size: 30rpx;
  1211. color: #ffb400;
  1212. font-weight: bold;
  1213. white-space: nowrap;
  1214. flex-shrink: 0;
  1215. .goods-unit {
  1216. font-size: 26rpx;
  1217. color: #bbb;
  1218. }
  1219. }
  1220. }
  1221. .goods-desc {
  1222. font-size: 26rpx;
  1223. color: #999;
  1224. margin-top: 8rpx;
  1225. }
  1226. }
  1227. }
  1228. .goods-row {
  1229. display: flex;
  1230. align-items: center;
  1231. margin-bottom: 24rpx;
  1232. .row-label {
  1233. font-size: 28rpx;
  1234. color: #888;
  1235. width: 160rpx;
  1236. flex-shrink: 0;
  1237. }
  1238. .num-ctrl {
  1239. display: flex;
  1240. align-items: center;
  1241. .num-btn {
  1242. width: 60rpx;
  1243. height: 60rpx;
  1244. padding: 0;
  1245. margin: 0;
  1246. display: flex;
  1247. align-items: center;
  1248. justify-content: center;
  1249. font-size: 28rpx;
  1250. color: #666;
  1251. background: #ffffff;
  1252. border: none;
  1253. border-radius: 50%;
  1254. &::after {
  1255. border: none;
  1256. }
  1257. &:active {
  1258. opacity: 0.8;
  1259. }
  1260. }
  1261. .num {
  1262. width: 80rpx;
  1263. text-align: center;
  1264. font-size: 32rpx;
  1265. color: #333;
  1266. }
  1267. }
  1268. .amount-input {
  1269. flex: 1;
  1270. height: 64rpx;
  1271. border-radius: 24rpx;
  1272. background: #f6f6f6;
  1273. border: none;
  1274. font-size: 30rpx;
  1275. color: #222;
  1276. padding-left: 20rpx;
  1277. margin-left: 16rpx;
  1278. }
  1279. }
  1280. .footer-btns {
  1281. position: fixed;
  1282. left: 0;
  1283. right: 0;
  1284. bottom: 0;
  1285. background: #fff;
  1286. display: flex;
  1287. gap: 32rpx;
  1288. padding: 24rpx 32rpx 48rpx 32rpx;
  1289. z-index: 101;
  1290. .btn-outline {
  1291. flex: 1;
  1292. height: 80rpx;
  1293. border-radius: 32rpx;
  1294. border: 2rpx solid #ffe09a;
  1295. color: #ffb400;
  1296. background: #fff0d2;
  1297. font-size: 30rpx;
  1298. font-weight: 500;
  1299. box-shadow: none;
  1300. padding: 0 36rpx;
  1301. }
  1302. .btn-main {
  1303. flex: 1;
  1304. height: 80rpx;
  1305. border-radius: 32rpx;
  1306. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  1307. color: #fff;
  1308. border: none;
  1309. font-size: 30rpx;
  1310. font-weight: 500;
  1311. box-shadow: none;
  1312. padding: 0 36rpx;
  1313. }
  1314. }
  1315. .loading-more {
  1316. text-align: center;
  1317. color: #999;
  1318. padding: 20rpx 0;
  1319. font-size: 26rpx;
  1320. }
  1321. // 品牌款式显示样式
  1322. .selected-styles {
  1323. margin-top: 8rpx;
  1324. .style-item {
  1325. margin-bottom: 4rpx;
  1326. .style-text {
  1327. font-size: 22rpx;
  1328. color: #ff9c00;
  1329. background: #fff7e6;
  1330. padding: 2rpx 8rpx;
  1331. border-radius: 8rpx;
  1332. display: inline-block;
  1333. }
  1334. }
  1335. }
  1336. </style>