Browse Source

feat: 去盘点、盘点详情页面

maliang 2 days ago
parent
commit
6200208054

+ 19 - 3
components/error-pop/error-pop.vue

@@ -5,10 +5,10 @@
 				<view class="flex_box flex_row_center">
 					<u-image src="@/static/image/error-img.png" width="112rpx" height="112rpx"></u-image>
 				</view>
-				<view class="tips-value">{{content}}</view>
+				<view :class="['tips-value',{'is-center': isCenter}]">{{content}}</view>
 				<view class="btn-box">
-					<u-button class="no-btn" type="primary" :plain="true" text="否" @click="closeClick"></u-button>
-					<u-button class="yes-btn" type="primary" text="是" @click="confirmClick"></u-button>
+					<u-button class="no-btn" type="primary" :plain="true" :text="cancelBtnText" @click="closeClick"></u-button>
+					<u-button class="yes-btn" type="primary" :text="confirmBtnText" @click="confirmClick"></u-button>
 				</view>
 			</view>
 		</u-popup>
@@ -25,6 +25,18 @@
 			content: {
 				type:String,
 				default:''
+			},
+			cancelBtnText: {
+			    type:String,
+				default:'否'
+			},
+			confirmBtnText: {
+			    type:String,
+				default:'是'
+			},
+			isCenter: {
+				type:Boolean,
+				default:false
 			}
 		},
 		watch:{
@@ -62,6 +74,10 @@
 		font-style: normal;
 		font-weight: bold;
 		margin-top: 32rpx;
+
+		&.is-center{
+			text-align: center;
+		}
 	}
 	.btn-box {
 		display: flex;

+ 24 - 0
pages.json

@@ -84,6 +84,30 @@
 			"style": {
 				"navigationBarTitleText": ""
 			}
+		},
+		{
+			"path" : "pages/inventory-task/taskDetail",
+			"style" : 
+			{
+				"navigationBarTitleText" : "",
+				"enablePullDownRefresh": true,
+				"onReachBottomDistance": 50,
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
+		},
+		{
+			"path" : "pages/inventory-task/detail",
+			"style" : 
+			{
+				"navigationBarTitleText" : "",
+				"enablePullDownRefresh": true,
+				"onReachBottomDistance": 50,
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
 		}
 	],
 	/* 分包预载配置 */

+ 176 - 0
pages/inventory-task/components/actionNumPopup.vue

@@ -0,0 +1,176 @@
+<template>
+  <u-popup
+    :show="show"
+    mode="center"
+    @close="close"
+    @open="open"
+    :round="10"
+    :closeOnClickOverlay="false"
+  >
+    <view class="action-num-popup">
+      <view class="icon-wrapper">
+					<u-image src="@/static/image/error-img.png" width="112rpx" height="112rpx"></u-image>
+				</view>
+      <view class="title">请确认该商品盘点数量</view>
+      <view class="num-box">
+        <u-number-box v-model="count">
+          <view slot="minus" class="minus">
+            <u-icon name="minus" color="#0256FF" size="12"></u-icon>
+          </view>
+          <text slot="input" class="input">{{count}}</text>
+          <view slot="plus" class="plus">
+            <u-icon name="plus" color="#ffffff" size="12"></u-icon>
+          </view>
+        </u-number-box>
+      </view>
+      <view class="btn-group">
+        <u-button 
+          class="btn cancel-btn" 
+          :plain="true" 
+          shape="square" 
+          @click="onCancel"
+        >取消</u-button>
+        <u-button 
+          class="btn confirm-btn" 
+          type="primary" 
+          shape="square" 
+          @click="onConfirm"
+        >确认</u-button>
+      </view>
+    </view>
+  </u-popup>
+</template>
+
+<script>
+export default {
+  name: "actionNumPopup",
+  props: {
+    show: {
+      type: Boolean,
+      default: false,
+    },
+    defaultCount: {
+      type: [Number, String],
+      default: 1
+    },
+    minCount: {
+      type: Number,
+      default: 0
+    },
+    maxCount: {
+      type: Number,
+      default: 9999
+    }
+  },
+  data() {
+    return {
+      count: 2,
+    };
+  },
+  watch: {
+    show(newVal) {
+      if (newVal) {
+        this.count = this.defaultCount || 2;
+      }
+    },
+    defaultCount: {
+      immediate: true,
+      handler(val) {
+        this.count = val || 2;
+      }
+    }
+  },
+  methods: {
+    close() {
+      this.$emit('update:show', false);
+    },
+    open() {},
+    onNumberChange(value) {
+      this.count = value;
+    },
+    onCancel() {
+      this.close();
+      this.$emit('cancel');
+    },
+    onConfirm() {
+      this.close();
+      this.$emit('confirm', this.count);
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.action-num-popup {
+  padding: 40rpx 30rpx;
+	width: 580rpx;
+  
+  .icon-wrapper {
+    display: flex;
+    justify-content: center;
+    margin-bottom: 20rpx;
+  }
+  
+  .title {
+    font-size: 32rpx;
+    color: #333;
+    text-align: center;
+    font-weight: 500;
+    margin-bottom: 40rpx;
+  }
+  
+  .num-box {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin: 30rpx 0;
+		.input {
+			width: 112rpx;
+			text-align: center;
+			border-bottom: 1px solid #0256FF;
+			margin: 0 8rpx;
+		}
+		.minus {
+			width: 40rpx;
+			height: 40rpx;
+			border-radius: 8rpx;
+			border: 1px solid #0256FF;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+		.plus {
+			width: 40rpx;
+			height: 40rpx;
+			border-radius: 8rpx;
+			background-color: #0256FF;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+	}
+
+  .btn-group {
+    display: flex;
+    justify-content: space-between;
+    
+    .btn {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 32rpx;
+      
+      &.cancel-btn {
+        margin-right: 20rpx;
+        color: #666;
+        border-color: #ddd;
+      }
+      
+      &.confirm-btn {
+        background-color: #2979ff;
+      }
+    }
+  }
+}
+</style>

+ 187 - 0
pages/inventory-task/components/categoryPopup.vue

@@ -0,0 +1,187 @@
+<template>
+    <u-popup
+      :show="show"
+      mode="center"
+      @close="close"
+      @open="open"
+      :round="10"
+      :closeOnClickOverlay="false"
+      width="580rpx"
+    >
+      <view class="location-edit-popup">
+        <view class="popup-header">
+          <text class="popup-title">修改库位</text>
+          <u-icon name="close" size="28" @click="close"></u-icon>
+        </view>
+        
+        <u--form 
+          :model="formData" 
+          ref="locationForm"
+          :rules="rules"
+          labelPosition="top"
+          labelWidth="100%"
+          :borderBottom="false"
+        >
+          <u-form-item
+            label="原库位"
+            prop="originLocation"
+            :borderBottom="false"
+          >
+            <u--input
+              v-model="formData.originLocation"
+              border="surround"
+              placeholder="请输入原库位"
+              height="80rpx"
+              clearable
+              fontSize="28rpx"
+              color="#333333"
+            ></u--input>
+          </u-form-item>
+          
+          <u-form-item
+            label="新库位"
+            prop="newLocation"
+            :borderBottom="false"
+            class="mt-20"
+          >
+            <u--input
+              v-model="formData.newLocation"
+              border="surround"
+              placeholder="请输入新库位"
+              height="80rpx"
+              clearable
+              fontSize="28rpx"
+              color="#333333"
+            ></u--input>
+          </u-form-item>
+        </u--form>
+        
+        <view class="btn-group">
+          <u-button 
+            class="btn cancel-btn" 
+            :plain="true" 
+            shape="square" 
+            @click="onCancel"
+          >取消</u-button>
+          <u-button 
+            class="btn confirm-btn" 
+            type="primary" 
+            shape="square" 
+            @click="onConfirm"
+          >确认</u-button>
+        </view>
+      </view>
+    </u-popup>
+  </template>
+  
+  <script>
+  export default {
+    name: "locationEditPopup",
+    props: {
+      show: {
+        type: Boolean,
+        default: false
+      },
+      originalLocation: {
+        type: String,
+        default: ''
+      }
+    },
+    data() {
+      return {
+        formData: {
+          originLocation: '',
+          newLocation: ''
+        },
+        rules: {
+          newLocation: {
+            type: 'string',
+            required: true,
+            message: '请输入新库位',
+            trigger: ['blur', 'change']
+          }
+        }
+      };
+    },
+    watch: {
+      show(newVal) {
+        if (newVal) {
+          this.formData.originLocation = this.originalLocation
+          this.formData.newLocation = '';
+        }
+      },
+      originalLocation(val) {
+        this.formData.originLocation = val
+      }
+    },
+    methods: {
+      close() {
+        this.$emit('update:show', false);
+      },
+      open() {},
+      onCancel() {
+        this.close();
+        this.$emit('cancel');
+      },
+      onConfirm() {
+        this.$refs.locationForm.validate(valid => {
+          if (valid) {
+            this.close();
+            this.$emit('confirm', this.formData.newLocation);
+          }
+        });
+      }
+    }
+  };
+  </script>
+  
+  <style lang="scss" scoped>
+  .location-edit-popup {
+    padding: 30rpx;
+	width: 580rpx;
+    
+    .popup-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 30rpx;
+      
+      .popup-title {
+        font-size: 36rpx;
+        font-weight: 500;
+        color: #333333;
+      }
+    }
+    
+    .mt-20 {
+      margin-top: 20rpx;
+    }
+    
+    
+    .btn-group {
+      display: flex;
+      justify-content: space-between;
+      margin-top: 40rpx;
+      
+      .btn {
+        flex: 1;
+        height: 88rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 32rpx;
+        
+        &.cancel-btn {
+          margin-right: 20rpx;
+          color: #666666;
+          border-color: #dddddd;
+        }
+        
+        &.confirm-btn {
+          background-color: #2979ff;
+        }
+      }
+    }
+  }
+  </style>
+  

+ 496 - 0
pages/inventory-task/components/inventoryFilterPopup.vue

@@ -0,0 +1,496 @@
+<template>
+  <u-popup
+    :show="show"
+    mode="bottom"
+    @close="handleClose"
+    :closeOnClickOverlay="false"
+    closeable
+    :safeAreaInsetBottom="true"
+    :round="20"
+  >
+    <view class="filter-popup">
+      <view class="filter-header">
+        <u-tabs
+          :list="tabList"
+          :current="currentTab"
+          @change="tabChange"
+          :activeStyle="{
+            color: '#4080FF',
+            fontWeight: 'bold',
+          }"
+          :inactiveStyle="{
+            color: '#333333',
+          }"
+          itemStyle="padding-left: 30rpx; padding-right: 30rpx; height: 100rpx;"
+        ></u-tabs>
+      </view>
+      <view class="filter-content">
+        <!-- 货物选项 -->
+        <scroll-view scroll-y class="filter-scroll" v-if="currentTab === 0">
+          <view
+            v-for="(item, index) in goodsOptions"
+            :key="index"
+            class="filter-item"
+            :class="{ active: selectedValues.goods === item.value }"
+            @click="selectFilter('goods', item.value)"
+          >
+            <text>{{ item.label }}</text>
+            <u-icon
+              v-if="selectedValues.goods === item.value"
+              name="checkbox-mark"
+              color="#4080FF"
+              size="20"
+            ></u-icon>
+          </view>
+        </scroll-view>
+
+        <!-- 盘点人选项 -->
+        <scroll-view scroll-y class="filter-scroll" v-if="currentTab === 1">
+          <view
+            v-for="(item, index) in userOptions"
+            :key="index"
+            class="filter-item"
+            :class="{ active: selectedValues.user === item.value }"
+            @click="selectFilter('user', item.value)"
+          >
+            <text>{{ item.label }}</text>
+            <u-icon
+              v-if="selectedValues.user === item.value"
+              name="checkbox-mark"
+              color="#4080FF"
+              size="20"
+            ></u-icon>
+          </view>
+        </scroll-view>
+
+        <!-- 类目选项 - 左右布局实现二级联动 -->
+        <view class="category-container" v-if="currentTab === 2">
+          <view class="category-sidebar">
+            <scroll-view scroll-y style="height: 100%">
+              <view
+                v-for="(item, index) in categorySidebarList"
+                :key="index"
+                class="sidebar-item"
+                :class="{ active: currentCategoryIndex === index }"
+                @click="changeCategoryIndex(index)"
+              >
+                <text>{{ item.name }}</text>
+              </view>
+            </scroll-view>
+          </view>
+          <view class="category-content">
+            <scroll-view scroll-y style="height: 100%">
+              <u-checkbox-group
+                v-model="selectedValues.category"
+                placement="column"
+                @change="onCategoryChange"
+              >
+                <view
+                  v-for="(item, index) in categoryContentList"
+                  :key="index"
+                  class="checkbox-item"
+                >
+                  <u-checkbox
+                    :name="item.value"
+                    shape="circle"
+                    activeColor="#4080FF"
+                    :label="item.label"
+                    size="20"
+                  >
+                  </u-checkbox>
+                </view>
+              </u-checkbox-group>
+            </scroll-view>
+          </view>
+        </view>
+
+        <!-- 库位选项 - 左右布局实现二级联动 -->
+        <view class="category-container" v-if="currentTab === 3">
+          <view class="category-sidebar">
+            <scroll-view scroll-y style="height: 100%">
+              <view
+                v-for="(item, index) in locationSidebarList"
+                :key="index"
+                class="sidebar-item"
+                :class="{ active: currentLocationIndex === index }"
+                @click="changeLocationIndex(index)"
+              >
+                <text>{{ item.name }}</text>
+              </view>
+            </scroll-view>
+          </view>
+          <view class="category-content">
+            <scroll-view scroll-y style="height: 100%">
+              <u-checkbox-group
+                v-model="selectedValues.location"
+                placement="column"
+                @change="onLocationChange"
+              >
+                <view
+                  v-for="(item, index) in locationContentList"
+                  :key="index"
+                  class="checkbox-item"
+                >
+                  <u-checkbox
+                    :name="item.value"
+                    shape="circle"
+                    activeColor="#4080FF"
+                    :label="item.label"
+                    size="20"
+                  >
+                  </u-checkbox>
+                </view>
+              </u-checkbox-group>
+            </scroll-view>
+          </view>
+        </view>
+      </view>
+      <view class="filter-footer">
+        <u-button
+          text="重置"
+          :plain="true"
+          shape="circle"
+          @click="resetFilter"
+          class="footer-btn"
+        ></u-button>
+        <u-button
+          text="确定"
+          type="primary"
+          shape="circle"
+          @click="confirmFilter"
+          class="footer-btn"
+        ></u-button>
+      </view>
+    </view>
+  </u-popup>
+</template>
+
+<script>
+export default {
+  name: "InventoryFilterPopup",
+  props: {
+    show: {
+      type: Boolean,
+      default: false,
+    },
+    // 初始选中值
+    defaultValues: {
+      type: Object,
+      default: () => ({
+        goods: "",
+        user: "",
+        category: [],
+        location: [],
+      }),
+    },
+  },
+  data() {
+    return {
+      currentTab: 0,
+      tabList: [
+        { name: "未盘" },
+        { name: "盘点人" },
+        { name: "类目" },
+        { name: "库位" },
+      ],
+      // 货物选项
+      goodsOptions: [
+        { label: "全部", value: "" },
+        { label: "未盘", value: "unchecked" },
+        { label: "盘盈", value: "overflow" },
+        { label: "盘亏", value: "loss" },
+        { label: "无差异", value: "normal" },
+      ],
+      // 盘点人选项
+      userOptions: [
+        { label: "全部", value: "" },
+        { label: "刘双秀", value: "刘双秀" },
+      ],
+      // 类目树形数据
+      categoryTree: [
+        {
+          id: "all",
+          name: "全部",
+          children: [
+            { label: "生活用品", value: "daily" },
+            { label: "厨房餐具", value: "kitchen" },
+            { label: "个人洗护", value: "personal" },
+          ],
+        },
+        {
+          id: "summer",
+          name: "夏季热卖",
+          children: [
+            { label: "防晒", value: "summer_sunscreen" },
+            { label: "泳衣", value: "summer_swimwear" },
+          ],
+        },
+        {
+          id: "disposable",
+          name: "一次用品",
+          children: [
+            { label: "餐具", value: "disposable_tableware" },
+            { label: "纸巾", value: "disposable_tissue" },
+          ],
+        },
+        {
+          id: "swimming",
+          name: "游泳运动",
+          children: [
+            { label: "泳镜", value: "swimming_goggles" },
+            { label: "泳帽", value: "swimming_caps" },
+          ],
+        },
+        {
+          id: "cleaning",
+          name: "家庭清洁",
+          children: [
+            { label: "洗衣液", value: "cleaning_detergent" },
+            { label: "清洁剂", value: "cleaning_agent" },
+          ],
+        },
+      ],
+      // 当前选中的类目侧边栏索引
+      currentCategoryIndex: 0,
+
+      // 库位树形数据
+      locationTree: [
+        {
+          id: "all",
+          name: "全部",
+          children: [],
+        },
+        {
+          id: "zone_a",
+          name: "A区",
+          children: [
+            { label: "A1-1-1", value: "A1-1-1" },
+            { label: "A1-1-2", value: "A1-1-2" },
+            { label: "A1-2-1", value: "A1-2-1" },
+          ],
+        },
+        {
+          id: "zone_b",
+          name: "B区",
+          children: [
+            { label: "B2-1-1", value: "B2-1-1" },
+            { label: "B2-1-2", value: "B2-1-2" },
+            { label: "B2-2-1", value: "B2-2-1" },
+          ],
+        },
+        {
+          id: "zone_c",
+          name: "C区",
+          children: [
+            { label: "C6-2-2", value: "C6-2-2" },
+            { label: "C6-3-1", value: "C6-3-1" },
+            { label: "C6-3-2", value: "C6-3-2" },
+          ],
+        },
+      ],
+      // 当前选中的库位侧边栏索引
+      currentLocationIndex: 0,
+
+      // 选中的筛选值
+      selectedValues: {
+        goods: "",
+        user: "",
+        category: [],
+        location: [],
+      },
+    };
+  },
+  computed: {
+    // 类目侧边栏列表
+    categorySidebarList() {
+      return this.categoryTree.map((item) => ({
+        name: item.name,
+        id: item.id,
+      }));
+    },
+    // 当前显示的类目内容
+    categoryContentList() {
+      return this.categoryTree[this.currentCategoryIndex]?.children || [];
+    },
+    // 库位侧边栏列表
+    locationSidebarList() {
+      return this.locationTree.map((item) => ({
+        name: item.name,
+        id: item.id,
+      }));
+    },
+    // 当前显示的库位内容
+    locationContentList() {
+      return this.locationTree[this.currentLocationIndex]?.children || [];
+    },
+  },
+  created() {
+    // 初始化选中值
+    this.selectedValues = {
+      goods: this.defaultValues.goods || "",
+      user: this.defaultValues.user || "",
+      category: this.defaultValues.category || [],
+      location: this.defaultValues.location || [],
+    };
+  },
+  methods: {
+    // 标签切换
+    tabChange({ index }) {
+      this.currentTab = index;
+    },
+    // 选择筛选项(单选)
+    selectFilter(type, value) {
+      this.selectedValues[type] = value;
+    },
+    // 切换类目侧边栏
+    changeCategoryIndex(index) {
+      // 如果切换了侧边栏,则重置该类别下的选择状态
+      if (this.currentCategoryIndex !== index) {
+        this.currentCategoryIndex = index;
+        // 重置当前类别的选择状态
+        this.selectedValues.category = [];
+      }
+    },
+    // 切换库位侧边栏
+    changeLocationIndex(index) {
+      // 如果切换了侧边栏,则重置该类别下的选择状态
+      if (this.currentLocationIndex !== index) {
+        this.currentLocationIndex = index;
+        // 重置当前库位的选择状态
+        this.selectedValues.location = [];
+      }
+    },
+    // 重置筛选
+    resetFilter() {
+      this.selectedValues = {
+        goods: "",
+        user: "",
+        category: [],
+        location: [],
+      };
+    },
+    // 确认筛选
+    confirmFilter() {
+      this.$emit("confirm", { ...this.selectedValues });
+      this.handleClose();
+    },
+    // 关闭弹窗
+    handleClose() {
+      this.$emit("update:show", false);
+      this.$emit("close");
+    },
+    // 处理类目选择变化
+    onCategoryChange(value) {
+      this.selectedValues.category = value;
+    },
+    // 处理库位选择变化
+    onLocationChange(value) {
+      this.selectedValues.location = value;
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.filter-popup {
+  display: flex;
+  flex-direction: column;
+  height: 70vh;
+
+  .filter-header {
+    border-bottom: 1rpx solid #f5f6f7;
+  }
+
+  .filter-content {
+    flex: 1;
+    overflow: hidden;
+
+    .filter-scroll {
+      height: 100%;
+    }
+
+    .filter-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 30rpx;
+      font-size: 28rpx;
+      color: #333;
+      border-bottom: 1rpx solid #f5f6f7;
+
+      &.active {
+        background-color: #f0f6fb;
+      }
+
+      &:last-child {
+        border-bottom: none;
+      }
+    }
+
+    // 类目和库位二级联动样式
+    .category-container {
+      display: flex;
+      height: 100%;
+
+      .category-sidebar {
+        width: 200rpx;
+        height: 100%;
+        background-color: #f5f7fa;
+
+        .sidebar-item {
+          padding: 30rpx 20rpx;
+          font-size: 28rpx;
+          color: #333;
+          text-align: center;
+
+          &.active {
+            background-color: #ffffff;
+            color: #4080ff;
+            position: relative;
+            font-weight: 500;
+
+            &::before {
+              content: "";
+              position: absolute;
+              left: 0;
+              top: 30%;
+              height: 40%;
+              width: 6rpx;
+              background-color: #4080ff;
+              border-radius: 3rpx;
+            }
+          }
+        }
+      }
+
+      .category-content {
+        flex: 1;
+        height: 100%;
+        background-color: #ffffff;
+        padding: 0 30rpx;
+
+        .checkbox-item {
+          padding: 30rpx 0;
+          font-size: 28rpx;
+          border-bottom: 1rpx solid #f5f6f7;
+
+          &:last-child {
+            border-bottom: none;
+          }
+        }
+      }
+    }
+  }
+
+  .filter-footer {
+    display: flex;
+    padding: 30rpx;
+    border-top: 1rpx solid #f5f6f7;
+
+    .footer-btn {
+      flex: 1;
+      margin: 0 16rpx;
+    }
+  }
+}
+</style>

+ 521 - 0
pages/inventory-task/detail.vue

@@ -0,0 +1,521 @@
+<template>
+  <view class="inventory-detail">
+    <!-- 导航栏 -->
+    <u-navbar
+      :title="pageTitle"
+      :autoBack="true"
+      fixed
+      safe-area-inset-top
+      placeholder
+    >
+      <template #right>
+        <view class="nav-right">
+          <u-icon name="search" size="20" color="#333"></u-icon>
+        </view>
+      </template>
+    </u-navbar>
+
+    <!-- 基本信息 吸顶 -->
+    <view class="info-card">
+      <view class="info-item">
+        <text class="info-label">盘点单号:</text>
+        <text class="info-value">{{ inventoryInfo.code }}</text>
+      </view>
+      <view class="info-item">
+        <text class="info-label">盘点人:</text>
+        <text class="info-value">{{ inventoryInfo.operator }}</text>
+      </view>
+      <view class="progress-box">
+        <text class="progress-label">盘点进度</text>
+        <view class="progress-bar-wrap">
+          <u-line-progress
+            :percentage="getProgressPercentage"
+            height="4"
+            :show-text="false"
+            activeColor="#4080FF"
+          >
+          </u-line-progress>
+        </view>
+        <text class="progress-value"
+          >{{ inventoryInfo.progress }}/{{ inventoryInfo.total }}</text
+        >
+      </view>
+    </view>
+    <!-- 筛选按钮 -->
+    <u-sticky bgColor="#F5F6F7" :offsetTop="44">
+      <view class="filter-wrap">
+        <view class="filter-btn" @click="filterPopupVisible = true">
+          <text>筛选</text>
+          <u-icon name="arrow-down" size="12" color="#666"></u-icon>
+        </view>
+      </view>
+    </u-sticky>
+
+    <!-- 商品列表 -->
+    <view class="goods-list">
+      <view class="goods-item" v-for="(item, index) in goodsList" :key="index">
+        <view class="location-row">
+          <view class="location-left">
+            <text class="location-label">库位:</text>
+            <text class="location-value">{{ item.location }}</text>
+            <u-icon name="arrow-right" size="14" color="#4080FF"></u-icon>
+          </view>
+          <text class="category-text">{{ item.category }}</text>
+        </view>
+
+        <view class="goods-content">
+          <image
+            class="goods-image"
+            :src="item.image"
+            mode="aspectFill"
+          ></image>
+          <view class="goods-info">
+            <text class="goods-name u-line-2">{{ item.name }}</text>
+            <view class="goods-spec">
+              <text class="spec-label">规格:</text>
+              <text class="spec-value">{{ item.spec }}</text>
+            </view>
+            <view class="check-user">
+              <text class="check-label">盘点人:</text>
+              <text class="check-value">{{ item.checkUser }}</text>
+            </view>
+            <view class="check-time">
+              <text class="time-label">盘点时间:</text>
+              <text class="time-value">{{ item.checkTime }}</text>
+            </view>
+          </view>
+        </view>
+
+        <view class="stock-row">
+          <view class="stock-item">
+            <text class="stock-label">系统库存</text>
+            <text class="stock-value">{{ item.systemStock }}瓶</text>
+          </view>
+          <view class="stock-item">
+            <text class="stock-label">已盘库存</text>
+            <text
+              class="stock-value"
+              :class="{
+                'stock-value-zero': item.actualStock === '未盘',
+                'stock-value-warning': item.actualStock === '0瓶',
+              }"
+              >{{ item.actualStock }}</text
+            >
+          </view>
+        </view>
+
+        <view class="action-row">
+          <u-button
+            type="primary"
+            size="mini"
+            @click="handleCheck(item)"
+            class="action-btn"
+            >盘点</u-button
+          >
+          <u-button
+            type="primary"
+            size="mini"
+            @click="handleRecheck(item)"
+            class="action-btn"
+            >重新盘点
+          </u-button>
+          <u-button
+            type="warning"
+            size="mini"
+            plain
+            @click="handleCheck2(item)"
+            class="action-btn action-btn-secondary"
+            >盘点2</u-button
+          >
+        </view>
+      </view>
+
+      <!-- 加载更多 -->
+      <u-loadmore :status="loadMoreStatus" @loadmore="onLoadMore" />
+    </view>
+    <InventoryFilterPopup
+      :show.sync="filterPopupVisible"
+      :defaultValues="defaultFilterValues"
+      @confirm="handleFilterConfirm"
+    />
+    <actionNumPopup :show.sync="actionPop.showNumPop" />
+    <categoryPopup :show.sync="actionPop.showCategoryPop" />
+		<error-pop v-model="actionPop.errorShow" isCenter cancelBtnText="取消" confirmBtnText="确定" @close="actionPop.errorShow = false" @confirm="confirm" :content="actionPop.errorText"></error-pop>
+  </view>
+</template>
+
+<script>
+import InventoryFilterPopup from "./components/inventoryFilterPopup.vue";
+import actionNumPopup from "./components/actionNumPopup.vue";
+import categoryPopup from "./components/categoryPopup.vue";
+import errorPop from '@/components/error-pop/error-pop.vue'
+export default {
+  components: {
+    InventoryFilterPopup,
+    actionNumPopup,
+    errorPop,
+    categoryPopup
+  },
+  data() {
+    return {
+      pageTitle: "2025年中心仓第三季度食品盘点",
+      isRefreshing: false,
+      loadMoreStatus: "loadmore",
+      pageNum: 1,
+      pageSize: 10,
+      inventoryInfo: {
+        code: "2024202244",
+        operator: "刘双秀",
+        progress: 105,
+        total: 604,
+      },
+      goodsList: [
+        {
+          location: "C6-2-2",
+          category: "母婴用品-家居旅行",
+          image: "/static/demo/goods1.png",
+          name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
+          spec: "4层-随机",
+          checkUser: "刘双秀",
+          checkTime: "2025-04-03",
+          systemStock: "5瓶",
+          actualStock: "未盘",
+          isChecked: false,
+        },
+        {
+          location: "C6-2-2",
+          category: "母婴用品-家居旅行",
+          image: "/static/demo/goods1.png",
+          name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
+          spec: "4层-随机",
+          checkUser: "刘双秀",
+          checkTime: "2025-04-03",
+          systemStock: "5瓶",
+          actualStock: "0瓶",
+          isChecked: true,
+        },
+      ],
+      filterPopupVisible: false,
+      defaultFilterValues: {
+        goods: "",
+        user: "",
+        category: "",
+        location: "",
+      },
+      actionPop:{
+        // 盘点数量弹框状态
+        showNumPop: false,
+        // 警告提示弹框状态
+        errorShow: false,
+        errorText: '是否提交盘点?',
+        // 修改库位弹框状态
+        showCategoryPop: false
+      }
+    };
+  },
+  computed: {
+    getProgressPercentage() {
+      return (this.inventoryInfo.progress / this.inventoryInfo.total) * 100;
+    },
+  },
+  onLoad() {
+    // 初始化数据
+    this.loadData();
+  },
+  onPullDownRefresh() {
+    // 下拉刷新
+    this.onRefresh();
+  },
+  onReachBottom() {
+    // 触底加载更多
+    this.onLoadMore();
+  },
+  methods: {
+    async onRefresh() {
+      try {
+        await this.loadData(true);
+      } finally {
+        uni.stopPullDownRefresh();
+      }
+    },
+    async onLoadMore() {
+      if (this.loadMoreStatus !== "loadmore") return;
+      this.loadMoreStatus = "loading";
+      try {
+        await this.loadData();
+      } catch (e) {
+        this.loadMoreStatus = "loadmore";
+      }
+    },
+    async loadData(isRefresh = false) {
+      if (isRefresh) {
+        this.pageNum = 1;
+        this.goodsList = [];
+      }
+
+      // 模拟数据加载
+      await new Promise((resolve) => setTimeout(resolve, 1000));
+
+      // 模拟新数据
+      const mockData = [
+        {
+          location: "C6-2-2",
+          category: "母婴用品-家居旅行",
+          image: "/static/demo/goods1.png",
+          name: "4层汗巾儿童全棉幼儿类吸汗巾婴儿纱布毛巾1条装",
+          spec: "4层-随机",
+          checkUser: "刘双秀",
+          checkTime: "2025-04-03",
+          systemStock: "5瓶",
+          actualStock: isRefresh ? "未盘" : "0瓶",
+          isChecked: !isRefresh,
+        },
+      ];
+
+      this.goodsList = [...this.goodsList, ...mockData];
+      this.pageNum++;
+
+      // 模拟没有更多数据
+      if (this.pageNum > 3) {
+        this.loadMoreStatus = "nomore";
+      } else {
+        this.loadMoreStatus = "loadmore";
+      }
+    },
+    handleCheck(item) {
+      uni.showToast({
+        title: "开始盘点",
+        icon: "none",
+      });
+    },
+    handleRecheck(item) {
+      uni.showToast({
+        title: "开始重新盘点",
+        icon: "none",
+      });
+    },
+    handleCheck2(item) {
+      uni.showToast({
+        title: "开始盘点2",
+        icon: "none",
+      });
+    },
+    handleFilterConfirm(values) {
+      this.defaultFilterValues = values;
+      this.filterPopupVisible = false;
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.inventory-detail {
+  min-height: 100vh;
+  background-color: #f0f6fb;
+  padding-bottom: 40rpx;
+
+  .nav-right {
+    padding: 0 24rpx;
+  }
+
+  .info-card {
+    background-color: #fff;
+    border-radius: 16rpx;
+    padding: 32rpx;
+
+    .info-item {
+      display: flex;
+      font-size: 28rpx;
+      margin-bottom: 24rpx;
+
+      .info-label {
+        color: #666;
+        margin-right: 8rpx;
+      }
+
+      .info-value {
+        color: #333;
+      }
+    }
+
+    .progress-box {
+      .progress-label {
+        font-size: 28rpx;
+        color: #666;
+        display: block;
+        margin-bottom: 16rpx;
+      }
+
+      .progress-bar-wrap {
+        margin-bottom: 16rpx;
+      }
+
+      .progress-value {
+        font-size: 24rpx;
+        color: #4080ff;
+        display: block;
+        text-align: right;
+      }
+    }
+  }
+
+  .filter-wrap {
+    display: flex;
+    justify-content: flex-end;
+    padding: 20rpx;
+
+    .filter-btn {
+      display: flex;
+      align-items: center;
+      padding: 12rpx 24rpx;
+      border-radius: 8rpx;
+      font-size: 24rpx;
+      color: #666;
+
+      .u-icon {
+        margin-left: 8rpx;
+      }
+    }
+  }
+
+  .goods-list {
+    padding: 0 24rpx;
+
+    .goods-item {
+      background-color: #fff;
+      border-radius: 16rpx;
+      margin-bottom: 24rpx;
+      overflow: hidden;
+
+      .location-row {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 24rpx 32rpx;
+        border-bottom: 1rpx solid #f5f6f7;
+
+        .location-left {
+          display: flex;
+          align-items: center;
+
+          .location-label {
+            font-size: 28rpx;
+            color: #333;
+          }
+
+          .location-value {
+            font-size: 28rpx;
+            color: #4080ff;
+            margin: 0 8rpx;
+          }
+        }
+
+        .category-text {
+          font-size: 24rpx;
+          color: #999;
+        }
+      }
+
+      .goods-content {
+        padding: 24rpx 32rpx;
+        display: flex;
+
+        .goods-image {
+          width: 160rpx;
+          height: 160rpx;
+          border-radius: 8rpx;
+          background-color: #f5f6f7;
+        }
+
+        .goods-info {
+          flex: 1;
+          margin-left: 24rpx;
+
+          .goods-name {
+            font-size: 28rpx;
+            line-height: 1.4;
+            color: #333;
+            margin-bottom: 16rpx;
+          }
+
+          .goods-spec {
+            font-size: 24rpx;
+            color: #666;
+            margin-bottom: 16rpx;
+
+            .spec-label {
+              color: #999;
+            }
+
+            .spec-value {
+              color: #666;
+            }
+          }
+
+          .check-user,
+          .check-time {
+            font-size: 24rpx;
+            margin-bottom: 8rpx;
+
+            .check-label,
+            .time-label {
+              color: #999;
+            }
+
+            .check-value,
+            .time-value {
+              color: #666;
+            }
+          }
+        }
+      }
+
+      .stock-row {
+        display: flex;
+        padding: 0 32rpx 24rpx;
+        gap: 48rpx;
+
+        .stock-item {
+          .stock-label {
+            font-size: 24rpx;
+            color: #999;
+            margin-right: 16rpx;
+          }
+
+          .stock-value {
+            font-size: 24rpx;
+            color: #333;
+
+            &-zero {
+              color: #999;
+            }
+
+            &-warning {
+              color: #ff9900;
+            }
+          }
+        }
+      }
+
+      .action-row {
+        padding: 0 32rpx 32rpx;
+        display: flex;
+        justify-content: flex-end;
+        gap: 24rpx;
+
+        .action-btn {
+          width: 140rpx;
+          height: 56rpx;
+          padding: 0;
+
+          &-secondary {
+            background-color: transparent;
+            border-color: #ff9900;
+            color: #ff9900;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 213 - 0
pages/inventory-task/taskDetail.vue

@@ -0,0 +1,213 @@
+<template>
+  <view class="inventory-task-detail">
+    <!-- 导航栏 -->
+    <u-navbar
+      title="盘点任务详情"
+      :autoBack="true"
+      fixed
+      safe-area-inset-top
+      placeholder
+      bgColor="#FFFFFF"
+    ></u-navbar>
+
+    <!-- 任务信息卡片 -->
+    <view class="info-card">
+      <view class="task-title">
+        {{ taskInfo.title }}
+        <view
+          class="task-status"
+          :class="{ 'status-completed': taskInfo.status === '已完成' }"
+        >
+          {{ taskInfo.status }}
+        </view>
+      </view>
+
+      <view class="task-number"> 盘点单号:{{ taskInfo.number }} </view>
+
+      <!-- 统计信息 -->
+      <view class="statistics">
+        <view class="stat-item">
+          <view class="stat-label">盘点商品</view>
+          <view class="stat-value highlight">
+            {{ taskInfo.inventoryCount }}/{{ taskInfo.totalCount }}
+          </view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-label">差异率</view>
+          <view class="stat-value">{{ taskInfo.differenceRate }}</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-label">准确率</view>
+          <view class="stat-value">{{ taskInfo.accuracyRate }}</view>
+        </view>
+      </view>
+
+      <!-- 详情按钮 -->
+      <view class="action-btn" @click="viewDetail"> 查看盘点详情 </view>
+
+      <!-- 详细信息列表 -->
+      <view class="info-list">
+        <view class="info-item">
+          <text class="info-label">盘点类型</text>
+          <text class="info-value">{{ taskInfo.type }}</text>
+        </view>
+        <view class="info-item">
+          <text class="info-label">盘点仓库</text>
+          <text class="info-value">{{ taskInfo.warehouse }}</text>
+        </view>
+        <view class="info-item">
+          <text class="info-label">盘点范围</text>
+          <text class="info-value">{{ taskInfo.scope }}</text>
+        </view>
+        <view class="info-item">
+          <text class="info-label">参与人员</text>
+          <text class="info-value">{{ taskInfo.participants }}</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      taskInfo: {
+        title: "2023年中心仓第三季度食品盘点",
+        status: "已完成",
+        number: "2024202244",
+        inventoryCount: "604",
+        totalCount: "604",
+        differenceRate: "6.29%",
+        accuracyRate: "97.80%",
+        type: "盘点类型",
+        warehouse: "中心仓",
+        scope: "A区-B区",
+        participants: "张三、李四",
+      },
+    };
+  },
+  methods: {
+    viewDetail() {
+      // 跳转到盘点详情页面
+      uni.navigateTo({
+        url: "/pages/inventory-task/inventory-detail",
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.inventory-task-detail {
+  min-height: 100vh;
+  background-color: #f5f7fa;
+  padding-bottom: 30rpx;
+
+  .info-card {
+    padding: 30rpx;
+    background-color: #ffffff;
+    border-radius: 20rpx;
+    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+
+    .task-title {
+      font-size: 32rpx;
+      font-weight: 500;
+      color: #333333;
+      line-height: 44rpx;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .task-status {
+        font-size: 24rpx;
+        padding: 4rpx 16rpx;
+        background-color: #e3f2fd;
+        color: #2196f3;
+        border-radius: 20rpx;
+        font-weight: normal;
+
+        &.status-completed {
+          background-color: #e8f5e9;
+          color: #4caf50;
+        }
+      }
+    }
+
+    .task-number {
+      font-size: 28rpx;
+      color: #666666;
+      margin-top: 16rpx;
+      margin-bottom: 30rpx;
+    }
+
+    .statistics {
+      display: flex;
+      justify-content: space-between;
+      background-color: #f7f8fa;
+      border-radius: 10rpx;
+      padding: 30rpx 0;
+      margin-bottom: 30rpx;
+
+      .stat-item {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+
+        .stat-label {
+          font-size: 24rpx;
+          color: #999999;
+          margin-bottom: 10rpx;
+        }
+
+        .stat-value {
+          font-size: 28rpx;
+          color: #333333;
+          font-weight: 500;
+
+          &.highlight {
+            color: #4080ff;
+          }
+        }
+      }
+    }
+
+    .action-btn {
+      height: 88rpx;
+      background-color: #4080ff;
+      border-radius: 16rpx;
+      color: #ffffff;
+      font-size: 30rpx;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 40rpx;
+    }
+
+    .info-list {
+      padding: 20rpx;
+
+      .info-item {
+        display: flex;
+        justify-content: space-between;
+        padding: 20rpx 0;
+
+        &:last-child {
+          border-bottom: none;
+        }
+
+        .info-label {
+          font-size: 28rpx;
+          color: #666666;
+        }
+
+        .info-value {
+          font-size: 28rpx;
+          color: #333333;
+        }
+      }
+    }
+  }
+}
+</style>