detail.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. <template>
  2. <view class="inventory-detail">
  3. <!-- 导航栏 -->
  4. <u-navbar
  5. :title="pageTitle"
  6. :autoBack="true"
  7. fixed
  8. safe-area-inset-top
  9. placeholder
  10. >
  11. <template #right>
  12. <view class="nav-right">
  13. <u-icon name="search" size="20" color="#333"></u-icon>
  14. </view>
  15. </template>
  16. </u-navbar>
  17. <!-- 基本信息 吸顶 -->
  18. <view class="info-card">
  19. <view class="info-item">
  20. <text class="info-label">盘点单号:</text>
  21. <text class="info-value">{{ inventoryInfo.code }}</text>
  22. </view>
  23. <view class="info-item">
  24. <text class="info-label">盘点人:</text>
  25. <text class="info-value">{{ inventoryInfo.operator }}</text>
  26. </view>
  27. <view class="progress-box">
  28. <text class="progress-label">盘点进度</text>
  29. <view class="progress-bar-wrap">
  30. <u-line-progress
  31. :percentage="getProgressPercentage"
  32. height="4"
  33. :show-text="false"
  34. activeColor="#4080FF"
  35. >
  36. </u-line-progress>
  37. </view>
  38. <text class="progress-value"
  39. >{{ inventoryInfo.progress }}/{{ inventoryInfo.total }}</text
  40. >
  41. </view>
  42. </view>
  43. <!-- 筛选按钮 -->
  44. <u-sticky bgColor="#F5F6F7" :offsetTop="44">
  45. <view class="filter-wrap">
  46. <view class="filter-btn" @click="filterPopupVisible = true">
  47. <text>筛选</text>
  48. <u-icon name="arrow-down" size="12" color="#666"></u-icon>
  49. </view>
  50. </view>
  51. </u-sticky>
  52. <!-- 商品列表 -->
  53. <view class="goods-list">
  54. <view class="goods-item" v-for="(item, index) in goodsList" :key="index">
  55. <view class="location-row">
  56. <view class="location-left">
  57. <text class="location-label">库位:</text>
  58. <text class="location-value">{{ item.location }}</text>
  59. <u-icon name="arrow-right" size="14" color="#4080FF"></u-icon>
  60. </view>
  61. <text class="category-text">{{ item.category }}</text>
  62. </view>
  63. <view class="goods-content">
  64. <image
  65. class="goods-image"
  66. :src="item.image"
  67. mode="aspectFill"
  68. ></image>
  69. <view class="goods-info">
  70. <text class="goods-name u-line-2">{{ item.name }}</text>
  71. <view class="goods-spec">
  72. <text class="spec-label">规格:</text>
  73. <text class="spec-value">{{ item.spec }}</text>
  74. </view>
  75. <view class="check-user">
  76. <text class="check-label">盘点人:</text>
  77. <text class="check-value">{{ item.checkUser }}</text>
  78. </view>
  79. <view class="check-time">
  80. <text class="time-label">盘点时间:</text>
  81. <text class="time-value">{{ item.checkTime }}</text>
  82. </view>
  83. </view>
  84. </view>
  85. <view class="stock-row">
  86. <view class="stock-item">
  87. <text class="stock-label">系统库存</text>
  88. <text class="stock-value">{{ item.systemStock }}瓶</text>
  89. </view>
  90. <view class="stock-item">
  91. <text class="stock-label">已盘库存</text>
  92. <text
  93. class="stock-value"
  94. :class="{
  95. 'stock-value-zero': item.actualStock === '未盘',
  96. 'stock-value-warning': item.actualStock === '0瓶',
  97. }"
  98. >{{ item.actualStock }}</text
  99. >
  100. </view>
  101. </view>
  102. <view class="action-row">
  103. <u-button
  104. type="primary"
  105. size="mini"
  106. @click="handleCheck(item)"
  107. class="action-btn"
  108. >盘点</u-button
  109. >
  110. <u-button
  111. type="primary"
  112. size="mini"
  113. @click="handleRecheck(item)"
  114. class="action-btn"
  115. >重新盘点
  116. </u-button>
  117. <u-button
  118. type="warning"
  119. size="mini"
  120. plain
  121. @click="handleCheck2(item)"
  122. class="action-btn action-btn-secondary"
  123. >盘点2</u-button
  124. >
  125. </view>
  126. </view>
  127. <!-- 加载更多 -->
  128. <u-loadmore :status="loadMoreStatus" @loadmore="onLoadMore" />
  129. </view>
  130. <InventoryFilterPopup
  131. :show.sync="filterPopupVisible"
  132. :defaultValues="defaultFilterValues"
  133. @confirm="handleFilterConfirm"
  134. />
  135. <actionNumPopup :show.sync="actionPop.showNumPop" />
  136. <categoryPopup :show.sync="actionPop.showCategoryPop" />
  137. <error-pop v-model="actionPop.errorShow" isCenter cancelBtnText="取消" confirmBtnText="确定" @close="actionPop.errorShow = false" @confirm="confirm" :content="actionPop.errorText"></error-pop>
  138. </view>
  139. </template>
  140. <script>
  141. import InventoryFilterPopup from "./components/inventoryFilterPopup.vue";
  142. import actionNumPopup from "./components/actionNumPopup.vue";
  143. import categoryPopup from "./components/categoryPopup.vue";
  144. import errorPop from '@/components/error-pop/error-pop.vue'
  145. export default {
  146. components: {
  147. InventoryFilterPopup,
  148. actionNumPopup,
  149. errorPop,
  150. categoryPopup
  151. },
  152. data() {
  153. return {
  154. pageTitle: "2025年中心仓第三季度食品盘点",
  155. isRefreshing: false,
  156. loadMoreStatus: "loadmore",
  157. pageNum: 1,
  158. pageSize: 10,
  159. inventoryInfo: {
  160. code: "2024202244",
  161. operator: "刘双秀",
  162. progress: 105,
  163. total: 604,
  164. },
  165. goodsList: [
  166. {
  167. location: "C6-2-2",
  168. category: "母婴用品-家居旅行",
  169. image: "/static/demo/goods1.png",
  170. name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
  171. spec: "4层-随机",
  172. checkUser: "刘双秀",
  173. checkTime: "2025-04-03",
  174. systemStock: "5瓶",
  175. actualStock: "未盘",
  176. isChecked: false,
  177. },
  178. {
  179. location: "C6-2-2",
  180. category: "母婴用品-家居旅行",
  181. image: "/static/demo/goods1.png",
  182. name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
  183. spec: "4层-随机",
  184. checkUser: "刘双秀",
  185. checkTime: "2025-04-03",
  186. systemStock: "5瓶",
  187. actualStock: "0瓶",
  188. isChecked: true,
  189. },
  190. ],
  191. filterPopupVisible: false,
  192. defaultFilterValues: {
  193. goods: "",
  194. user: "",
  195. category: "",
  196. location: "",
  197. },
  198. actionPop:{
  199. // 盘点数量弹框状态
  200. showNumPop: false,
  201. // 警告提示弹框状态
  202. errorShow: false,
  203. errorText: '是否提交盘点?',
  204. // 修改库位弹框状态
  205. showCategoryPop: false
  206. }
  207. };
  208. },
  209. computed: {
  210. getProgressPercentage() {
  211. return (this.inventoryInfo.progress / this.inventoryInfo.total) * 100;
  212. },
  213. },
  214. onLoad() {
  215. // 初始化数据
  216. this.loadData();
  217. },
  218. onPullDownRefresh() {
  219. // 下拉刷新
  220. this.onRefresh();
  221. },
  222. onReachBottom() {
  223. // 触底加载更多
  224. this.onLoadMore();
  225. },
  226. methods: {
  227. async onRefresh() {
  228. try {
  229. await this.loadData(true);
  230. } finally {
  231. uni.stopPullDownRefresh();
  232. }
  233. },
  234. async onLoadMore() {
  235. if (this.loadMoreStatus !== "loadmore") return;
  236. this.loadMoreStatus = "loading";
  237. try {
  238. await this.loadData();
  239. } catch (e) {
  240. this.loadMoreStatus = "loadmore";
  241. }
  242. },
  243. async loadData(isRefresh = false) {
  244. if (isRefresh) {
  245. this.pageNum = 1;
  246. this.goodsList = [];
  247. }
  248. // 模拟数据加载
  249. await new Promise((resolve) => setTimeout(resolve, 1000));
  250. // 模拟新数据
  251. const mockData = [
  252. {
  253. location: "C6-2-2",
  254. category: "母婴用品-家居旅行",
  255. image: "/static/demo/goods1.png",
  256. name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
  257. spec: "4层-随机",
  258. checkUser: "刘双秀",
  259. checkTime: "2025-04-03",
  260. systemStock: "5瓶",
  261. actualStock: isRefresh ? "未盘" : "0瓶",
  262. isChecked: !isRefresh,
  263. },
  264. ];
  265. this.goodsList = [...this.goodsList, ...mockData];
  266. this.pageNum++;
  267. // 模拟没有更多数据
  268. if (this.pageNum > 3) {
  269. this.loadMoreStatus = "nomore";
  270. } else {
  271. this.loadMoreStatus = "loadmore";
  272. }
  273. },
  274. handleCheck(item) {
  275. uni.showToast({
  276. title: "开始盘点",
  277. icon: "none",
  278. });
  279. },
  280. handleRecheck(item) {
  281. uni.showToast({
  282. title: "开始重新盘点",
  283. icon: "none",
  284. });
  285. },
  286. handleCheck2(item) {
  287. uni.showToast({
  288. title: "开始盘点2",
  289. icon: "none",
  290. });
  291. },
  292. handleFilterConfirm(values) {
  293. this.defaultFilterValues = values;
  294. this.filterPopupVisible = false;
  295. },
  296. },
  297. };
  298. </script>
  299. <style lang="scss">
  300. .inventory-detail {
  301. min-height: 100vh;
  302. background-color: #f0f6fb;
  303. padding-bottom: 40rpx;
  304. .nav-right {
  305. padding: 0 24rpx;
  306. }
  307. .info-card {
  308. background-color: #fff;
  309. border-radius: 16rpx;
  310. padding: 32rpx;
  311. .info-item {
  312. display: flex;
  313. font-size: 28rpx;
  314. margin-bottom: 24rpx;
  315. .info-label {
  316. color: #666;
  317. margin-right: 8rpx;
  318. }
  319. .info-value {
  320. color: #333;
  321. }
  322. }
  323. .progress-box {
  324. .progress-label {
  325. font-size: 28rpx;
  326. color: #666;
  327. display: block;
  328. margin-bottom: 16rpx;
  329. }
  330. .progress-bar-wrap {
  331. margin-bottom: 16rpx;
  332. }
  333. .progress-value {
  334. font-size: 24rpx;
  335. color: #4080ff;
  336. display: block;
  337. text-align: right;
  338. }
  339. }
  340. }
  341. .filter-wrap {
  342. display: flex;
  343. justify-content: flex-end;
  344. padding: 20rpx;
  345. .filter-btn {
  346. display: flex;
  347. align-items: center;
  348. padding: 12rpx 24rpx;
  349. border-radius: 8rpx;
  350. font-size: 24rpx;
  351. color: #666;
  352. .u-icon {
  353. margin-left: 8rpx;
  354. }
  355. }
  356. }
  357. .goods-list {
  358. padding: 0 24rpx;
  359. .goods-item {
  360. background-color: #fff;
  361. border-radius: 16rpx;
  362. margin-bottom: 24rpx;
  363. overflow: hidden;
  364. .location-row {
  365. display: flex;
  366. justify-content: space-between;
  367. align-items: center;
  368. padding: 24rpx 32rpx;
  369. border-bottom: 1rpx solid #f5f6f7;
  370. .location-left {
  371. display: flex;
  372. align-items: center;
  373. .location-label {
  374. font-size: 28rpx;
  375. color: #333;
  376. }
  377. .location-value {
  378. font-size: 28rpx;
  379. color: #4080ff;
  380. margin: 0 8rpx;
  381. }
  382. }
  383. .category-text {
  384. font-size: 24rpx;
  385. color: #999;
  386. }
  387. }
  388. .goods-content {
  389. padding: 24rpx 32rpx;
  390. display: flex;
  391. .goods-image {
  392. width: 160rpx;
  393. height: 160rpx;
  394. border-radius: 8rpx;
  395. background-color: #f5f6f7;
  396. }
  397. .goods-info {
  398. flex: 1;
  399. margin-left: 24rpx;
  400. .goods-name {
  401. font-size: 28rpx;
  402. line-height: 1.4;
  403. color: #333;
  404. margin-bottom: 16rpx;
  405. }
  406. .goods-spec {
  407. font-size: 24rpx;
  408. color: #666;
  409. margin-bottom: 16rpx;
  410. .spec-label {
  411. color: #999;
  412. }
  413. .spec-value {
  414. color: #666;
  415. }
  416. }
  417. .check-user,
  418. .check-time {
  419. font-size: 24rpx;
  420. margin-bottom: 8rpx;
  421. .check-label,
  422. .time-label {
  423. color: #999;
  424. }
  425. .check-value,
  426. .time-value {
  427. color: #666;
  428. }
  429. }
  430. }
  431. }
  432. .stock-row {
  433. display: flex;
  434. padding: 0 32rpx 24rpx;
  435. gap: 48rpx;
  436. .stock-item {
  437. .stock-label {
  438. font-size: 24rpx;
  439. color: #999;
  440. margin-right: 16rpx;
  441. }
  442. .stock-value {
  443. font-size: 24rpx;
  444. color: #333;
  445. &-zero {
  446. color: #999;
  447. }
  448. &-warning {
  449. color: #ff9900;
  450. }
  451. }
  452. }
  453. }
  454. .action-row {
  455. padding: 0 32rpx 32rpx;
  456. display: flex;
  457. justify-content: flex-end;
  458. gap: 24rpx;
  459. .action-btn {
  460. width: 140rpx;
  461. height: 56rpx;
  462. padding: 0;
  463. &-secondary {
  464. background-color: transparent;
  465. border-color: #ff9900;
  466. color: #ff9900;
  467. }
  468. }
  469. }
  470. }
  471. }
  472. }
  473. </style>