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

526 lines
14 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. <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" :class="['category-item', {active: idx === currentCategory}]" @tap="switchCategory(idx)">
  17. <text>{{cat.title}}</text>
  18. <view v-if="cat.badge" class="category-badge">{{cat.badge}}</view>
  19. </view>
  20. </view>
  21. <!-- 右侧商品卡片区 -->
  22. <view class="goods-list">
  23. <view v-for="(item, idx) in currentGoods" :key="item.id" class="goods-card">
  24. <view class="goods-header">
  25. <image :src="item.image" class="goods-img" />
  26. <view class="goods-info">
  27. <view class="goods-title-row">
  28. <text class="goods-name">{{item.name}}</text>
  29. <text class="goods-price">¥ {{item.price}} <text class="goods-unit">/</text></text>
  30. </view>
  31. <text class="goods-desc">{{item.desc}}</text>
  32. </view>
  33. </view>
  34. <view class="goods-row">
  35. <text class="row-label">合格数量</text>
  36. <view class="num-ctrl">
  37. <button class="num-btn" @tap="changeNum(item, 'qualified', -1)">-</button>
  38. <text class="num">{{item.qualified}}</text>
  39. <button class="num-btn" @tap="changeNum(item, 'qualified', 1)">+</button>
  40. </view>
  41. </view>
  42. <view class="goods-row">
  43. <text class="row-label">不合格数量</text>
  44. <view class="num-ctrl">
  45. <button class="num-btn" @tap="changeNum(item, 'unqualified', -1)">-</button>
  46. <text class="num">{{item.unqualified}}</text>
  47. <button class="num-btn" @tap="changeNum(item, 'unqualified', 1)">+</button>
  48. </view>
  49. </view>
  50. <view class="goods-row">
  51. <text class="row-label">总金额</text>
  52. <input class="amount-input" v-model="item.amount" placeholder="请输入金额" />
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <!-- 底部操作按钮 -->
  58. <view class="footer-btns">
  59. <button class="btn-outline" @tap="goBack">返回订单详情</button>
  60. <button class="btn-main" @tap="goNext">下一步</button>
  61. </view>
  62. </view>
  63. </template>
  64. <script>
  65. import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
  66. export default {
  67. mixins: [pullRefreshMixin],
  68. data() {
  69. return {
  70. statusBarHeight: 0,
  71. currentCategory: 0,
  72. allProducts: {}, // { [categoryId]: [商品数组] }
  73. allProductsPage: {}, // { [categoryId]: 当前已加载页码 }
  74. allProductsTotal: {}, // { [categoryId]: 总数 }
  75. pageSize: 10,
  76. loadingMore: false,
  77. finished: false,
  78. }
  79. },
  80. computed: {
  81. categories() {
  82. const list = getApp().globalData.pricePreviewList || []
  83. // 新增不可回收分类
  84. const extra = [{ id: 'unrecyclable', title: '不可回收' }]
  85. return [...list.filter(item => item.pid === '0').sort((a, b) => a.sort - b.sort), ...extra]
  86. },
  87. currentGoods() {
  88. const currentCategoryId = this.categories[this.currentCategory]?.id
  89. // 不可回收分类内容
  90. if (currentCategoryId === 'unrecyclable') {
  91. return [{
  92. id: 'unrecyclable-1',
  93. image: '/static/回收/衣物.png',
  94. name: '不可回收品类',
  95. price: '—',
  96. desc: '允许脏破烂,160码以上',
  97. quantity: 2,
  98. amount: ''
  99. }]
  100. }
  101. return this.allProducts[currentCategoryId] || []
  102. }
  103. },
  104. methods: {
  105. fetchGoodsList(categoryId, page = 1, callback) {
  106. this.$api('getClassGoodsList', {
  107. classId: categoryId,
  108. pageNo: page,
  109. pageSize: this.pageSize
  110. }, res => {
  111. if (res.code === 200 && res.result && Array.isArray(res.result.records)) {
  112. const oldList = this.allProducts[categoryId] || []
  113. const newList = page === 1 ? res.result.records : oldList.concat(res.result.records)
  114. this.$set(this.allProducts, categoryId, newList)
  115. this.$set(this.allProductsPage, categoryId, page)
  116. this.$set(this.allProductsTotal, categoryId, res.result.total)
  117. }
  118. if (callback) callback()
  119. })
  120. },
  121. goBack() {
  122. uni.navigateBack()
  123. },
  124. goNext() {
  125. // 跳转到下一步页面,带上质检数据
  126. uni.navigateTo({
  127. url: '/pages/manager/inspect-result'
  128. })
  129. },
  130. switchCategory(idx) {
  131. this.currentCategory = idx
  132. this.loadingMore = false
  133. this.finished = false
  134. const categoryId = this.categories[idx]?.id
  135. if (categoryId === 'unrecyclable') {
  136. // 切换到不可回收时重置默认数据
  137. this.$set(this.allProducts, 'unrecyclable', [{
  138. id: 'unrecyclable-1',
  139. image: '/static/回收/衣物.png',
  140. name: '不可回收品类',
  141. price: '—',
  142. desc: '允许脏破烂,160码以上',
  143. quantity: 2,
  144. amount: ''
  145. }])
  146. this.$forceUpdate && this.$forceUpdate()
  147. return
  148. }
  149. if (!this.allProducts[categoryId]) {
  150. this.fetchGoodsList(categoryId, 1)
  151. }
  152. },
  153. changeNum(item, key, delta) {
  154. if (key === 'qualified') {
  155. item.qualified = Math.max(0, (item.qualified || 0) + delta)
  156. } else {
  157. item.unqualified = Math.max(0, (item.unqualified || 0) + delta)
  158. }
  159. },
  160. refreshData() {
  161. // 可根据实际需求刷新商品数据、分类等
  162. // 例如重新请求接口或重置数据
  163. },
  164. async onRefresh() {
  165. await this.refreshData && this.refreshData()
  166. }
  167. },
  168. created() {
  169. this.currentCategory = 0
  170. this.$nextTick(() => {
  171. if (this.categories.length > 0) {
  172. const firstCategoryId = this.categories[0]?.id
  173. if (firstCategoryId) {
  174. this.fetchGoodsList(firstCategoryId, 1)
  175. }
  176. }
  177. })
  178. },
  179. onLoad() {
  180. this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
  181. },
  182. onPullDownRefresh() {
  183. this.refreshData && this.refreshData()
  184. uni.stopPullDownRefresh()
  185. }
  186. }
  187. </script>
  188. <style lang="scss" scoped>
  189. .inspect-container {
  190. min-height: 100vh;
  191. background: #f8f8f8;
  192. display: flex;
  193. flex-direction: column;
  194. }
  195. .nav-bar {
  196. display: flex;
  197. align-items: center;
  198. height: calc(150rpx + var(--status-bar-height));
  199. padding: 0 32rpx;
  200. padding-top: var(--status-bar-height);
  201. background: #fff;
  202. position: fixed;
  203. top: 0;
  204. left: 0;
  205. right: 0;
  206. z-index: 999;
  207. box-sizing: border-box;
  208. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  209. .back {
  210. padding: 20rpx;
  211. margin-left: -20rpx;
  212. }
  213. .nav-title {
  214. flex: 1;
  215. text-align: center;
  216. font-size: 32rpx;
  217. font-weight: 500;
  218. color: #222;
  219. }
  220. .nav-icons {
  221. display: flex;
  222. align-items: center;
  223. gap: 12px;
  224. }
  225. }
  226. .main-content {
  227. margin-top: calc(150rpx + var(--status-bar-height));
  228. display: flex;
  229. background: none;
  230. }
  231. .category-nav {
  232. width: 80px;
  233. background: #fff;
  234. border-radius: 24px 0 0 24px;
  235. padding: 24px 0;
  236. display: flex;
  237. flex-direction: column;
  238. align-items: center;
  239. box-shadow: 0 2px 8px rgba(0,0,0,0.03);
  240. height: 100%;
  241. overflow-y: auto;
  242. position: relative;
  243. z-index: 2;
  244. .category-item {
  245. width: 64px;
  246. height: 44px;
  247. border-radius: 16px 0 0 16px;
  248. display: flex;
  249. align-items: center;
  250. justify-content: flex-start;
  251. font-size: 16px;
  252. color: #222;
  253. margin-bottom: 12px;
  254. background: #fff;
  255. position: relative;
  256. transition: background 0.2s, color 0.2s, font-weight 0.2s;
  257. padding-left: 12px;
  258. &.active {
  259. background: linear-gradient(90deg, #fff7e6 80%, #fff 100%);
  260. color: #ffb400;
  261. font-weight: bold;
  262. &::before {
  263. content: '';
  264. position: absolute;
  265. left: 0;
  266. top: 30%;
  267. height: 40%;
  268. width: 2px;
  269. border-radius: 4px;
  270. background: #ffb400;
  271. bottom: auto;
  272. }
  273. }
  274. .category-badge {
  275. position: absolute;
  276. top: 6px;
  277. right: 10px;
  278. background: #ff4d4f;
  279. color: #fff;
  280. font-size: 12px;
  281. border-radius: 50%;
  282. width: 18px;
  283. height: 18px;
  284. display: flex;
  285. align-items: center;
  286. justify-content: center;
  287. }
  288. }
  289. }
  290. .goods-list {
  291. flex: 1;
  292. height: calc(100vh - 110rpx - var(--status-bar-height) - 80px);
  293. padding: 0 0 0 16px;
  294. overflow-y: auto;
  295. background: none;
  296. }
  297. .goods-card {
  298. background: #fff;
  299. border-radius: 24px;
  300. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  301. margin-bottom: 18px;
  302. padding: 18px 18px 0 18px;
  303. &.unrecycle-card {
  304. background: #fff;
  305. border-radius: 24px;
  306. box-shadow: 0 4px 24px rgba(0,0,0,0.06);
  307. margin-bottom: 18px;
  308. padding: 18px 18px 0 18px;
  309. .goods-header {
  310. display: flex;
  311. align-items: center;
  312. margin-bottom: 12px;
  313. .goods-img {
  314. width: 56px;
  315. height: 56px;
  316. border-radius: 16px;
  317. margin-right: 12px;
  318. background: #f8f8f8;
  319. object-fit: contain;
  320. }
  321. .goods-info {
  322. flex: 1;
  323. display: flex;
  324. flex-direction: column;
  325. justify-content: center;
  326. min-width: 0;
  327. .goods-title-row {
  328. display: flex;
  329. align-items: baseline;
  330. .goods-name {
  331. font-size: 16px;
  332. font-weight: bold;
  333. color: #222;
  334. margin-right: 8px;
  335. }
  336. .goods-price {
  337. font-size: 15px;
  338. color: #ffb400;
  339. font-weight: bold;
  340. .goods-unit {
  341. font-size: 13px;
  342. color: #bbb;
  343. }
  344. }
  345. }
  346. .goods-desc {
  347. font-size: 13px;
  348. color: #999;
  349. margin-top: 4px;
  350. }
  351. }
  352. }
  353. .goods-row {
  354. display: flex;
  355. align-items: center;
  356. margin-bottom: 12px;
  357. .row-label {
  358. font-size: 14px;
  359. color: #888;
  360. width: 80px;
  361. flex-shrink: 0;
  362. }
  363. .num-ctrl {
  364. display: flex;
  365. align-items: center;
  366. .num-btn {
  367. width: 32px;
  368. height: 32px;
  369. border-radius: 50%;
  370. background: #f6f6f6;
  371. color: #bbb;
  372. font-size: 20px;
  373. border: none;
  374. display: flex;
  375. align-items: center;
  376. justify-content: center;
  377. margin: 0 6px;
  378. }
  379. .num {
  380. font-size: 16px;
  381. color: #222;
  382. width: 28px;
  383. text-align: center;
  384. }
  385. }
  386. .amount-input {
  387. flex: 1;
  388. height: 32px;
  389. border-radius: 12px;
  390. background: #f6f6f6;
  391. border: none;
  392. font-size: 15px;
  393. color: #222;
  394. padding-left: 10px;
  395. margin-left: 8px;
  396. }
  397. }
  398. }
  399. }
  400. .goods-header {
  401. display: flex;
  402. align-items: center;
  403. margin-bottom: 12px;
  404. .goods-img {
  405. width: 56px;
  406. height: 56px;
  407. border-radius: 16px;
  408. margin-right: 12px;
  409. background: #f8f8f8;
  410. object-fit: contain;
  411. }
  412. .goods-info {
  413. flex: 1;
  414. display: flex;
  415. flex-direction: column;
  416. justify-content: center;
  417. min-width: 0;
  418. .goods-title-row {
  419. display: flex;
  420. align-items: baseline;
  421. .goods-name {
  422. font-size: 16px;
  423. font-weight: bold;
  424. color: #222;
  425. margin-right: 8px;
  426. }
  427. .goods-price {
  428. font-size: 15px;
  429. color: #ffb400;
  430. font-weight: bold;
  431. .goods-unit {
  432. font-size: 13px;
  433. color: #bbb;
  434. }
  435. }
  436. }
  437. .goods-desc {
  438. font-size: 13px;
  439. color: #999;
  440. margin-top: 4px;
  441. }
  442. }
  443. }
  444. .goods-row {
  445. display: flex;
  446. align-items: center;
  447. margin-bottom: 12px;
  448. .row-label {
  449. font-size: 14px;
  450. color: #888;
  451. width: 80px;
  452. flex-shrink: 0;
  453. }
  454. .num-ctrl {
  455. display: flex;
  456. align-items: center;
  457. .num-btn {
  458. width: 32px;
  459. height: 32px;
  460. border-radius: 50%;
  461. background: #f6f6f6;
  462. color: #bbb;
  463. font-size: 20px;
  464. border: none;
  465. display: flex;
  466. align-items: center;
  467. justify-content: center;
  468. margin: 0 6px;
  469. }
  470. .num {
  471. font-size: 16px;
  472. color: #222;
  473. width: 28px;
  474. text-align: center;
  475. }
  476. }
  477. .amount-input {
  478. flex: 1;
  479. height: 32px;
  480. border-radius: 12px;
  481. background: #f6f6f6;
  482. border: none;
  483. font-size: 15px;
  484. color: #222;
  485. padding-left: 10px;
  486. margin-left: 8px;
  487. }
  488. }
  489. .footer-btns {
  490. position: fixed;
  491. left: 0;
  492. right: 0;
  493. bottom: 0;
  494. background: #fff;
  495. display: flex;
  496. gap: 16px;
  497. padding: 12px 16px 24px 16px;
  498. z-index: 101;
  499. .btn-outline {
  500. flex: 1;
  501. height: 40px;
  502. border-radius: 16px;
  503. border: 1px solid #ffe09a;
  504. color: #ffb400;
  505. background: #fff0d2;
  506. font-size: 15px;
  507. font-weight: 500;
  508. box-shadow: none;
  509. padding: 0 18px;
  510. }
  511. .btn-main {
  512. flex: 1;
  513. height: 40px;
  514. border-radius: 16px;
  515. background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
  516. color: #fff;
  517. border: none;
  518. font-size: 15px;
  519. font-weight: 500;
  520. box-shadow: none;
  521. padding: 0 18px;
  522. }
  523. }
  524. </style>