Selaa lähdekoodia

Merge branch 'master' of http://git.yujin.shuziyunyao.com/yujin/forestry-wx

huangxw 2 viikkoa sitten
vanhempi
säilyke
ac19566061

+ 8 - 0
src/pages.json

@@ -552,6 +552,14 @@
                     "style": {
                         "navigationBarTitleText": "选择加工原料"
                     }
+                },
+                // 选择规格等级
+                {
+                    "path": "specification-level/index",
+                    "style": {
+                        "navigationBarTitleText": "选择规格等级",
+                        "navigationStyle": "custom"
+                    }
                 }
             ]
         },

+ 1 - 1
src/pages/plant/port/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" safe-area-inset-bottom hide-no-more-inside>
+    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" hide-no-more-inside>
         <template #top>
             <ut-navbar title="种养殖任务" :fixed="false">
                 <template #left><view class=""></view></template>

+ 45 - 45
src/plant/port/port-create/index.vue

@@ -108,14 +108,14 @@
                         </up-form-item>
                         <view class="h-1" id="plantpppp"></view>
                         <up-form-item label="养殖量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd">
                                     <up-form-item prop="plantingMgAmount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.plantingMgAmount" placeholder="请输入养殖量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.plantingMgUnit" :tabs="pt_planting_mg_unit" title="选择单位">
                                         <up-form-item prop="unit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -127,8 +127,8 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <up-form-item borderBottom label="备注" prop="remark" id="remarkpppp">
                             <up-input v-model="form.remark" placeholder="请输入备注" border="none"></up-input>
@@ -241,14 +241,14 @@
                         </up-form-item>
                         <view class="h-1" id="plantpppp"></view>
                         <up-form-item label="养殖量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd" id="plantingMgAmountpppp">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd" id="plantingMgAmountpppp">
                                     <up-form-item prop="plantingMgAmount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.plantingMgAmount" placeholder="请输入养殖量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5" id="plantingMgUnitpppp"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5" id="plantingMgUnitpppp"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.plantingMgUnit" :tabs="pt_planting_mg_unit" title="选择单位">
                                         <up-form-item prop="plantingMgUnit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -260,8 +260,8 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <up-form-item borderBottom label="备注" prop="remark" id="remarkpppp">
                             <up-input v-model="form.remark" placeholder="请输入备注" border="none"></up-input>
@@ -342,14 +342,14 @@
                             </view>
                         </up-form-item>
                         <up-form-item label="种植量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd" id="plantingMgAmountpppp">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd" id="plantingMgAmountpppp">
                                     <up-form-item prop="plantingMgAmount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.plantingMgAmount" placeholder="请输入种植量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5" id="plantingMgUnitpppp"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5" id="plantingMgUnitpppp"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.plantingMgUnit" :tabs="pt_area_unit" title="选择单位">
                                         <up-form-item prop="unit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -361,8 +361,8 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <view class="h-1" id="queryType6pppp"></view>
                         <up-form-item :borderBottom="false" label="种植时间" required prop="queryType6">
@@ -558,14 +558,14 @@
                             </view>
                         </up-form-item>
                         <up-form-item v-if="+deawerData?.data[0]?.landType == 3" label="接种数量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd" id="plantingMgAmountpppp">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd" id="plantingMgAmountpppp">
                                     <up-form-item prop="inoculationAmount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.inoculationAmount" placeholder="请输入接种数量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5" id="plantingMgUnitpppp"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5" id="plantingMgUnitpppp"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.inoculationUnit" :tabs="pt_inoculation_unit" title="选择单位">
                                         <up-form-item prop="unit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -577,18 +577,18 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <up-form-item v-if="+deawerData?.data[0]?.landType == 3" label="接种剂量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd">
                                     <up-form-item prop="inoculationDosage" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.inoculationDosage" placeholder="请输入接种剂量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.inoculationDosageUnit" :tabs="pt_inoculation_dosage_unit" title="选择单位">
                                         <up-form-item prop="specUnit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -600,9 +600,9 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                                <div class="pd2-0-10 c-#ccc d-flex d-c a-c">/</div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd2-0-10 c-#ccc d-flex d-c a-c">/</view>
+                                <view class="min-w-200">
                                     <up-form-item prop="unit" border-bottom class="form-item-top-padding-0">
                                         <view class="flex1" style="line-height: 24px">
                                             <view v-if="form.inoculationUnit" class="f-s-30 c-333 f-w-5 text-center">{{ selectDictLabel(pt_inoculation_unit, form.inoculationUnit) }}</view>
@@ -612,8 +612,8 @@
                                             <up-icon size="22rpx" color="#fff" name="arrow-down-fill"></up-icon>
                                         </template>
                                     </up-form-item>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <view class="h-1" id="plantpppp"></view>
                         <up-form-item v-if="+deawerData?.data[0]?.landType == 3" borderBottom label="繁育量" prop="plant">
@@ -633,14 +633,14 @@
                             </ut-action-sheet>
                         </up-form-item> -->
                         <up-form-item v-else label="繁育量" required class="form-item-bottom-padding-0">
-                            <div class="flex1 d-flex">
-                                <div class="flex1 ov-hd" id="plantingMgAmountpppp">
+                            <view class="flex1 d-flex">
+                                <view class="flex1 ov-hd" id="plantingMgAmountpppp">
                                     <up-form-item prop="plantingMgAmount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.plantingMgAmount" placeholder="请输入繁育量" border="none" clearable></up-input>
                                     </up-form-item>
-                                </div>
-                                <div class="pd-5" id="plantingMgUnitpppp"></div>
-                                <div class="min-w-200">
+                                </view>
+                                <view class="pd-5" id="plantingMgUnitpppp"></view>
+                                <view class="min-w-200">
                                     <ut-action-sheet v-model="form.plantingMgUnit" :tabs="pt_feed_amount_unit" title="选择单位">
                                         <up-form-item prop="plantingMgUnit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
@@ -652,8 +652,8 @@
                                             </template>
                                         </up-form-item>
                                     </ut-action-sheet>
-                                </div>
-                            </div>
+                                </view>
+                            </view>
                         </up-form-item>
                         <up-form-item borderBottom label="培养基配方" prop="cultureMediumFormula" id="cultureMediumFormulapppp">
                             <Go_button v-if="!Biological" @click="gotoTorganism(1)" title="请选择培养基配方" style="flex: 1" />

+ 65 - 7
src/plant/processing/processing-create/index.vue

@@ -144,7 +144,7 @@
         </view>
         <template #bottom>
             <view class="pd-24 d-flex j-c gap-20 base-bottom-wrap">
-                <up-button type="primary" @click="save()">确认创建</up-button>
+                <up-button type="primary" @click="save()">{{ isEdit ? '确认修改' : '确认创建' }}</up-button>
             </view>
         </template>
     </z-paging>
@@ -161,6 +161,8 @@ const { pt_process_type, pt_stock_type, pt_standard_type, yes_no } = toRefs<any>
 
 const infoStore = useInfoStore();
 const pageTitle = ref('创建初加工任务');
+const isEdit = ref(false); // 是否为修改模式
+const processId = ref(''); // 加工任务 ID
 
 // 表单数据
 const form = ref({
@@ -293,14 +295,17 @@ const save = () => {
 
                 const params = {
                     ...form.value,
+                    id: processId.value,
                 };
 
                 console.log('提交参数:', params);
 
-                const res = await useClientRequest.post('/plt-api/app/processe/create', params);
+                // 根据模式调用不同的接口
+                const url = isEdit.value ? '/plt-api/app/processe/updateProcess' : '/plt-api/app/processe/create';
+                const res = await useClientRequest.post(url, params);
                 if (res.code == 200) {
                     uni.showToast({
-                        title: '创建成功',
+                        title: isEdit.value ? '修改成功' : '创建成功',
                         icon: 'success',
                         duration: 2000,
                     });
@@ -326,6 +331,47 @@ const save = () => {
         true,
     );
 };
+
+// 查询加工任务详情
+const getDetail = async () => {
+    try {
+        const res = await useClientRequest.get(`/plt-api/app/processe/getInfoById/${processId.value}`);
+        if (res && res.data) {
+            const data = res.data;
+            // 回显表单数据
+            form.value.processType = data.processType || '';
+            form.value.processMedType = data.processMedType || '';
+            form.value.varietyId = data.varietyId || null;
+            form.value.medicineCode = data.medicineCode || null;
+            form.value.varietyName = data.variety || data?.medicineName;
+            form.value.processingDate = data.processingDate || '';
+            form.value.processingDateEnd = data.processingDateEnd || '';
+            form.value.processCode = data.processCode || '';
+            form.value.standardType = data.standardType || '';
+            form.value.standardDetailName = data.standardDetailName || '';
+            form.value.contactName = data.contactName || infoStore.userInfo?.name || '';
+            form.value.ptech = data.ptech || '';
+            form.value.freshCatalogueStatus = data.freshCatalogueStatus !== undefined ? data.freshCatalogueStatus : null;
+            // 处理图片回显
+            form.value.imgs = data.processImages || null;
+            // 处理视频回显
+            form.value.videos = data.processVideos || null;
+
+            // 根据加工方式设置页面标题
+            if (+data.processType == 2) {
+                pageTitle.value = '修改趁鲜切制任务';
+            } else {
+                pageTitle.value = '修改初加工任务';
+            }
+        }
+    } catch (error) {
+        console.error('加载任务详情失败:', error);
+        uni.showToast({
+            title: '加载任务详情失败',
+            icon: 'none',
+        });
+    }
+};
 const selectMedicine = () => {
     if (form.value.processMedType == '1') {
         uni.$once('updateBiologicalname', function (data) {
@@ -350,10 +396,22 @@ const selectMedicine = () => {
     }
 };
 onLoad((options: any) => {
-    form.value.processType = options?.taskType;
-    if (+options?.taskType == 2) {
-        pageTitle.value = '创建趁鲜切制任务';
-        form.value.processMedType = '2';
+    // 判断是否为修改模式
+    isEdit.value = options?.edit == '1';
+    processId.value = options?.id || '';
+
+    if (isEdit.value) {
+        // 修改模式:加载任务详情
+        if (processId.value) {
+            getDetail();
+        }
+    } else {
+        // 创建模式
+        form.value.processType = options?.taskType;
+        if (+options?.taskType == 2) {
+            pageTitle.value = '创建趁鲜切制任务';
+            form.value.processMedType = '2';
+        }
     }
 });
 </script>

+ 105 - 26
src/plant/processing/processing-detail-list/index.vue

@@ -36,7 +36,7 @@
                     <view class="c-#666">加工工艺:</view>
                     <view class="c-#333 f-w-5 flex1 d-flex a-c" style="justify-content: flex-start">
                         <template v-for="(item, index) in (taskDetail?.ptech || '').split(',')" :key="index">
-                            <span v-if="+index > 0 && item" class="c-#999 mx-10">→</span>
+                            <span v-if="+index > 0 && item" class="c-#999 ml-10 mr-10">→</span>
                             <span v-if="item">{{ item }}</span>
                         </template>
                         <span v-if="!taskDetail?.ptech" class="c-#999">-</span>
@@ -144,40 +144,31 @@
                     <ut-empty color="#ccc" size="28rpx" image="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/noEmpty.png">暂无产出信息</ut-empty>
                     <up-button type="primary" @click="handleShowOutputModel">去添加产出信息</up-button>
                 </view>
-                <view v-for="(item, index) in outputList" :key="index" class="bg-#fff b-radius pd-24 mb-16">
-                    <!-- 序号 -->
-                    <view class="d-flex a-c mb-12">
-                        <view class="bg-#2289E0 c-#fff f-s-20 f-w-5 pd-10 pt-4 pb-4 radius-8 mr-10">{{ String(index + 1).padStart(2, '0') }}</view>
-                        <view class="f-s-32 f-w-5 c-#333">{{ item?.specnLevel || '统货' }}</view>
-                    </view>
-                    <!-- 规格 -->
-                    <view class="d-flex mb-12 f-s-28">
-                        <view class="c-#666">规格:</view>
-                        <view class="c-#333 f-w-5 flex1">{{ item?.specn || '-' }}</view>
-                    </view>
-                    <!-- 产能 -->
-                    <view class="d-flex mb-12 f-s-28">
-                        <view class="c-#666">产能:</view>
-                        <view class="c-#333 f-w-5 flex1">{{ item?.capacity || 0 }}{{ item?.unit }}</view>
-                    </view>
-                    <!-- 状态 -->
-                    <view class="d-flex a-c j-end mt-16">
-                        <view v-if="item?.examinReport?.length > 0" class="c-#37A954 f-s-24 bg-#EDF7F0 pd-8 radius-8">已检</view>
-                        <view v-else class="c-#F74C30 f-s-24 bg-#FEF3E8 pd-8 radius-8">未检</view>
-                    </view>
+                <view v-else class="d-flex a-c mb-16">
+                    <view class="c-#999 f-s-28">产出物:</view>
+                    <view class="c-#999 f-s-28">{{ outputList.length }}个</view>
+                    <view class="flex1"></view>
+                    <up-button color="#18BECA" style="width: 210rpx; height: 60rpx; margin-right: 20rpx">单个/批量入库</up-button>
+                    <up-button type="primary" style="width: 160rpx; height: 60rpx" @click="handleShowOutputModel">添加产出</up-button>
                 </view>
+                <up-swipe-action>
+                    <up-swipe-action-item v-for="(item, index) in outputList" :key="index" :name="item?.id" :options="swipeOptions" class="mb-16" @click="handleSwipeClick">
+                        <ProcessingOutputItem :item="item" :index="index" :selectable="false" @click="handleOutputItemClick" />
+                    </up-swipe-action-item>
+                </up-swipe-action>
             </view>
         </view>
     </z-paging>
 
-    <!-- 添加产出信息弹框 -->
-    <OutputInfo v-if="showOutputModel" v-model:show="showOutputModel" :type="taskDetail?.processType" :processId="taskId" @confirm="handleOutputConfirm" />
+    <!-- 添加/修改产出信息弹框 -->
+    <OutputInfo v-if="showOutputModel" v-model:show="showOutputModel" :type="taskDetail?.processType" :processId="taskId" :isEdit="isEditOutput" :editData="editOutputData" @confirm="handleOutputConfirm" />
 </template>
 
 <script setup lang="ts">
 import { getStorageRoomNames } from '@/utils/common';
 import { useClientRequest } from '@/utils/request';
 import OutputInfo from './models/outputInfo.vue';
+import ProcessingOutputItem from './models/processing-output-item.vue';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { pt_stock_type, pt_standard_type, pt_fresh_instore_type, pt_final_form_type } = toRefs<any>(proxy?.useDict('pt_stock_type', 'pt_standard_type', 'pt_fresh_instore_type', 'pt_final_form_type'));
 
@@ -273,12 +264,29 @@ const goEdit = () => {
     });
 };
 
+// 监听修改成功事件,重新加载任务详情
+const handleUpdateTaskDetail = () => {
+    loadTaskDetail(); // 重新加载任务详情
+    if (activeTab.value === '0') {
+        paging.value?.reload(); // 刷新原料列表
+    } else {
+        getOutputList(); // 刷新产出列表
+    }
+};
+
 onLoad((options: any) => {
     taskId.value = options?.id || '';
+    // 监听修改成功事件
+    uni.$on('updateprocesstasklist', handleUpdateTaskDetail);
     if (taskId.value) {
         loadTaskDetail();
     }
 });
+
+// 离开页面时卸载事件监听
+onUnload(() => {
+    uni.$off('updateprocesstasklist');
+});
 const withdraw = async () => {
     // 删除
     const res = await uni.showModal({
@@ -288,7 +296,7 @@ const withdraw = async () => {
     });
     console.log(res);
     if (res.confirm) {
-        const delRes = await useClientRequest.get(`/plt-api/app/processInputMaterial/callbackInput/${taskDetail.value?.id}`);
+        const delRes = await useClientRequest.get(`/plt-api/app/processInputMaterial/callbackInput/${list.value?.[0]?.id}`);
         if (delRes && delRes.code === 200) {
             uni.showToast({ title: '删除成功', icon: 'none' });
             paging.value?.reload();
@@ -298,14 +306,85 @@ const withdraw = async () => {
 
 // 显示添加产出信息弹框
 const showOutputModel = ref(false);
+const isEditOutput = ref(false); // 是否编辑模式
+const editOutputData = ref<any>({}); // 编辑的数据
+
 const handleShowOutputModel = () => {
+    isEditOutput.value = false;
+    editOutputData.value = {};
     showOutputModel.value = true;
 };
 
-// 处理添加成功
+// 处理添加/修改成功
 const handleOutputConfirm = () => {
     getOutputList();
 };
+
+// 处理产出项点击
+const handleOutputItemClick = (item: any) => {
+    console.log('点击产出项:', item);
+};
+
+// 滑动操作选项
+const swipeOptions = reactive([
+    {
+        text: '修改',
+        style: {
+            backgroundColor: '#18BECA',
+            width: '100rpx',
+            fontSize: '28rpx',
+        },
+    },
+    {
+        text: '删除',
+        style: {
+            backgroundColor: '#F74C30',
+            width: '100rpx',
+            fontSize: '28rpx',
+        },
+    },
+]);
+
+// 处理滑动按钮点击
+const handleSwipeClick = async (event: any) => {
+    const { name, index } = event;
+    const item = outputList.value[index];
+
+    if (index === 0) {
+        // 点击修改
+        handleEditOutput(item);
+    } else if (index === 1) {
+        // 点击删除
+        handleDeleteOutput(name, item);
+    }
+};
+
+// 处理修改产出
+const handleEditOutput = (item: any) => {
+    isEditOutput.value = true;
+    editOutputData.value = item;
+    showOutputModel.value = true;
+};
+
+// 处理删除产出
+const handleDeleteOutput = async (outPutId: string | number, item: any) => {
+    try {
+        const res = await uni.showModal({
+            title: '删除提示',
+            content: '删除后不可恢复,请谨慎操作!',
+            confirmColor: '#F74C30',
+        });
+        if (!res.confirm) return;
+
+        const delRes = await useClientRequest.get(`/plt-api/app/processOutPut/removeOutPut/${outPutId}`);
+        if (delRes && delRes.code === 200) {
+            uni.showToast({ title: '删除成功', icon: 'none' });
+            getOutputList();
+        }
+    } catch (error) {
+        console.error('删除失败:', error);
+    }
+};
 </script>
 
 <style scoped lang="scss">

+ 247 - 85
src/plant/processing/processing-detail-list/models/outputInfo.vue

@@ -1,75 +1,129 @@
 <template>
-    <up-popup :show="show" mode="bottom" @close="handleClose" :round="20" closeable style="height: 70vh">
-        <view class="d-flex flex-cln h-100% pd-24 bg-#fff p-rtv" style="max-height: 70vh">
-            <view class="f-s-34 f-w-5">添加产出信息</view>
+    <up-popup :show="show" mode="bottom" @close="handleClose" :round="20" closeable>
+        <view class="d-flex flex-cln h-100%" style="max-height: 70vh">
+            <view class="f-s-34 f-w-5 pd-24 pb-0">{{ getTitle() }}</view>
             <scroll-view scroll-y class="h-0 flex1">
-                <up-form ref="formRef" :model="formData" :rules="rules" labelPosition="top" labelWidth="auto">
-                    <template v-if="+type == 1">
-                        <!-- 规格等级 -->
-                        <up-form-item borderBottom label="规格等级" required prop="specnLevel">
-                            <ut-action-sheet v-model="formData.specnLevel" :tabs="specnLevelList" title="选择规格等级">
-                                <template #right>
-                                    <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                                </template>
-                            </ut-action-sheet>
-                        </up-form-item>
-                        <!-- 产量 -->
-                        <up-form-item borderBottom label="产量" prop="capacity" required>
-                            <view class="d-flex a-c w-100%">
-                                <up-input v-model="formData.capacity" type="number" placeholder="请输入产量" border="none" clearable></up-input>
-                                <ut-action-sheet v-model="formData.unit" :tabs="unitList" title="选择单位" style="margin-left: 10rpx"></ut-action-sheet>
-                            </view>
-                        </up-form-item>
-
-                        <!-- 产出物图片 -->
-                        <up-form-item borderBottom label="产出物图片">
-                            <ut-upload v-model="formData.imgs" :max-count="6" valueType="array" accept="image" width="210rpx" height="210rpx" style="card"></ut-upload>
-                        </up-form-item>
-
-                        <!-- 检验报告 -->
-                        <up-form-item borderBottom label="检验报告">
-                            <ut-upload v-model="formData.examinReport" :max-count="50" valueType="array" accept="image,file" width="260rpx" height="260rpx" style="card" uploadImageText="上传图片" uploadFileText="上传 PDF"></ut-upload>
-                        </up-form-item>
-                    </template>
-
-                    <!-- 类型 2 特有字段 -->
-                    <template v-if="+type == 2">
-                        <!-- 切制形态 -->
-                        <up-form-item borderBottom label="切制形态" prop="finalFormType" required>
-                            <ut-action-sheet v-model="formData.finalFormType" :tabs="finalFormTypeList" title="选择切制形态">
-                                <template #right>
-                                    <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
-                                </template>
+                <view class="pd-24">
+                    <up-form ref="formRef" :model="formData" :rules="rules" labelPosition="top" labelWidth="auto">
+                        <template v-if="+type == 1">
+                            <!-- 规格等级 -->
+                            <up-form-item label="规格等级" required prop="specnLevel">
+                                <view class="flex1" @click="goToSpecLevel">
+                                    <up-input readonly v-model="formData.specnLevel" type="number" placeholder="请选择规格等级" style="padding-left: 0; padding-right: 0" border="bottom" clearable suffixIcon="arrow-down-fill" suffixIconStyle="color: #2A6D52;font-size: 22rpx"> </up-input>
+                                </view>
+                                <view class="ml-20">
+                                    <up-checkbox :customStyle="{ marginBottom: '8px' }" label="统货" name="agree" usedAlone :checked="formData.specnLevel == '统货'" @change="handleSpecnLevelChange"> </up-checkbox>
+                                </view>
+                            </up-form-item>
+                            <!-- 产量 -->
+                            <up-form-item borderBottom label="产量" prop="capacity" required>
+                                <view class="d-flex a-c w-100%">
+                                    <up-input v-model="formData.capacity" type="number" placeholder="请输入产量" border="none" clearable></up-input>
+                                    <ut-action-sheet v-model="formData.unit" :tabs="unitList" title="选择单位" style="margin-left: 10rpx"></ut-action-sheet>
+                                </view>
+                            </up-form-item>
+
+                            <!-- 产出物图片 -->
+                            <up-form-item borderBottom label="产出物图片">
+                                <ut-upload v-model="formData.imgs" :max-count="6" valueType="array" accept="image" width="210rpx" height="210rpx" style="card"></ut-upload>
+                            </up-form-item>
+
+                            <!-- 检验报告 -->
+                            <up-form-item borderBottom label="加工检验报告">
+                                <ut-upload v-model="formData.examinReport" :max-count="50" valueType="array" accept="image,file" width="210rpx" height="210rpx" style="card"></ut-upload>
+                            </up-form-item>
+                        </template>
+
+                        <!-- 类型 2 特有字段 -->
+                        <template v-else>
+                            <!-- 规格等级 -->
+                            <up-form-item label="规格等级" required prop="specnLevel">
+                                <view class="flex1" @click="goToSpecLevel">
+                                    <up-input readonly v-model="formData.specnLevel" type="number" placeholder="请选择规格等级" style="padding-left: 0; padding-right: 0" border="bottom" clearable suffixIcon="arrow-down-fill" suffixIconStyle="color: #2A6D52;font-size: 22rpx"> </up-input>
+                                </view>
+                                <view class="ml-20">
+                                    <up-checkbox :customStyle="{ marginBottom: '8px' }" label="统货" name="agree" usedAlone :checked="formData.specnLevel == '统货'" @change="handleSpecnLevelChange"> </up-checkbox>
+                                </view>
+                            </up-form-item>
+                            <!-- 产量 -->
+                            <up-form-item borderBottom label="产量" prop="capacity" required>
+                                <view class="flex1 d-flex">
+                                    <view class="flex1 ov-hd" id="capacitypppp">
+                                        <up-form-item border-bottom prop="capacity" class="form-item-top-padding-0">
+                                            <up-input v-model="formData.capacity" type="number" placeholder="请输入产量" border="none" clearable></up-input>
+                                        </up-form-item>
+                                    </view>
+                                    <view class="pd-5"></view>
+                                    <view class="min-w-100">
+                                        <ut-action-sheet v-model="formData.unit" :tabs="unitList" title="选择单位">
+                                            <up-form-item border-bottom prop="unit" class="form-item-top-padding-0">
+                                                <view class="flex1" style="line-height: 24px">
+                                                    <view v-if="formData?.unit" class="f-s-30 c-#333 f-w-5 flex1">{{ formData?.unit }}</view>
+                                                    <view v-else class="f-s-30 c-ccc f-w-4 flex1">单位</view>
+                                                </view>
+                                                <template #right>
+                                                    <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                                                </template>
+                                            </up-form-item>
+                                        </ut-action-sheet>
+                                    </view>
+                                </view>
+                            </up-form-item>
+                            <!-- 切制形态 -->
+                            <ut-action-sheet v-model="formData.finalFormType" :tabs="pt_final_form_type" title="选择切制形态">
+                                <up-form-item borderBottom label="切制形态" prop="finalFormType" required>
+                                    <view v-if="formData?.finalFormType" class="f-s-30 c-#333 f-w-5 flex1">{{ selectDictLabel(pt_final_form_type, formData?.finalFormType) }}</view>
+                                    <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择切制形态</view>
+                                    <template #right>
+                                        <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                                    </template>
+                                </up-form-item>
                             </ut-action-sheet>
-                        </up-form-item>
-
-                        <!-- 具体切制形态 -->
-                        <up-form-item borderBottom label="具体切制形态" prop="finalFormOther">
-                            <up-input v-model="formData.finalFormOther" placeholder="请输入具体切制形态" border="none" clearable></up-input>
-                        </up-form-item>
-
-                        <!-- 切制尺寸 -->
-                        <up-form-item borderBottom label="切制尺寸" prop="finalUnit">
-                            <view class="d-flex a-c w-100%">
-                                <up-input v-model="formData.finalSpecn" type="number" placeholder="请输入切制尺寸" border="none" clearable></up-input>
-                                <view class="ml-10" style="font-size: 28rpx; font-weight: 500; color: #333">mm</view>
-                            </view>
-                        </up-form-item>
-                        <!-- 产出物图片 -->
-                        <up-form-item borderBottom label="产出物图片">
-                            <ut-upload v-model="formData.imgs" :max-count="6" valueType="array" accept="image" width="210rpx" height="210rpx" style="card"></ut-upload>
-                        </up-form-item>
-
-                        <!-- 检验报告 -->
-                        <up-form-item borderBottom label="检验报告">
-                            <ut-upload v-model="formData.examinReport" :max-count="50" valueType="array" accept="image,file" width="260rpx" height="260rpx" style="card" uploadImageText="上传图片" uploadFileText="上传 PDF"></ut-upload>
-                        </up-form-item>
-                    </template>
-                </up-form>
+                            <!-- 具体切制形态 -->
+                            <up-form-item borderBottom label="具体切制形态" prop="finalFormOther" required>
+                                <up-input v-model="formData.finalFormOther" placeholder="请输入具体切制形态" border="none" clearable></up-input>
+                            </up-form-item>
+
+                            <!-- 切制尺寸 -->
+                            <up-form-item label="切制尺寸" required>
+                                <view class="flex1 d-flex">
+                                    <view class="flex1 ov-hd" id="finalSpecnpppp">
+                                        <up-form-item border-bottom prop="finalSpecn" class="form-item-top-padding-0">
+                                            <up-input v-model="formData.finalSpecn" type="number" placeholder="请输入切制尺寸" border="none" clearable></up-input>
+                                        </up-form-item>
+                                    </view>
+                                    <view class="pd-5"></view>
+                                    <view class="min-w-100">
+                                        <ut-action-sheet v-model="formData.finalUnit" :tabs="pt_final_unit" title="选择切制单位">
+                                            <up-form-item border-bottom prop="finalUnit" class="form-item-top-padding-0">
+                                                <view class="flex1" style="line-height: 24px">
+                                                    <view v-if="formData?.finalUnit" class="f-s-30 c-#333 f-w-5 flex1">{{ selectDictLabel(pt_final_unit, formData?.finalUnit) }}</view>
+                                                    <view v-else class="f-s-30 c-ccc f-w-4 flex1">单位</view>
+                                                </view>
+                                                <template #right>
+                                                    <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                                                </template>
+                                            </up-form-item>
+                                        </ut-action-sheet>
+                                    </view>
+                                </view>
+                            </up-form-item>
+                            <!-- 产出物图片 -->
+                            <up-form-item borderBottom label="产出物图片">
+                                <ut-upload v-model="formData.imgs" :max-count="6" valueType="array" accept="image" width="210rpx" height="210rpx" style="card"></ut-upload>
+                            </up-form-item>
+
+                            <!-- 检验报告 -->
+                            <up-form-item borderBottom label="加工检验报告">
+                                <ut-upload v-model="formData.examinReport" :max-count="50" valueType="array" accept="image,file" width="210rpx" height="210rpx" style="card"></ut-upload>
+                            </up-form-item>
+                        </template>
+                    </up-form>
+                </view>
             </scroll-view>
 
             <!-- 底部按钮 -->
-            <view class="d-flex gap-20">
+            <view class="d-flex gap-20 pd-24">
                 <up-button plain type="info" @click="handleClose">取消</up-button>
                 <up-button type="primary" @click="handleSubmit">确认</up-button>
             </view>
@@ -79,22 +133,34 @@
 
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_final_form_type, pt_final_unit } = toRefs<any>(proxy?.useDict('pt_final_form_type', 'pt_final_unit'));
 const props = defineProps<{
     show: boolean;
     type: number; // 1: 初加工,2: 趁鲜切制
     processId: string | number; // 加工任务 ID
+    isEdit: boolean; // 是否编辑模式
+    editData: any; // 要编辑的数据
 }>();
-console.log(props.type, 'type');
-
 const emit = defineEmits<{
     'update:show': [value: boolean];
     confirm: [data: any];
 }>();
-
+setTimeout(() => {
+    console.log(pt_final_unit);
+}, 2000);
 const formRef = ref();
-const specnLevelList = ref<any[]>([]); // 规格等级列表(先空着)
-const unitList = ref<any[]>([]); // 单位列表(先空着)
-const finalFormTypeList = ref<any[]>([]); // 切制形态列表 pt_final_form_type
+const unitList = ref<any[]>([
+    {
+        label: 'kg',
+        value: 'kg',
+    },
+    {
+        label: '吨',
+        value: '吨',
+    },
+]); // 单位列表(先空着)
+const finalFormTypeList = ref<any[]>([]); // 切制形态列表 (pt_final_form_type)
 
 // 表单数据
 const formData = ref({
@@ -107,25 +173,81 @@ const formData = ref({
     finalFormOther: '',
     finalSpecn: '',
     finalUnit: '',
+    id: '', // 编辑模式需要 id
 });
 
-// 表单验证规则
-const rules = {
-    specnLevel: [{ required: true, message: '请选择规格等级', trigger: 'change' }],
-    capacity: [
-        { required: true, message: '请输入产量', trigger: 'blur' },
-        { type: 'number', message: '产量必须为数字', trigger: 'blur' },
-    ],
-    unit: [{ required: true, message: '请选择单位', trigger: 'change' }],
-    finalFormType: [{ required: true, message: '请选择切制形态', trigger: 'change' }],
+// 监听 editData 变化,初始化表单数据
+watch(
+    () => props.editData,
+    (newVal) => {
+        if (newVal && props.isEdit) {
+            formData.value = {
+                specnLevel: newVal?.specnLevel || '',
+                capacity: newVal?.capacity || '',
+                unit: newVal?.unit || '',
+                imgs: newVal?.imgs ? newVal.imgs.split(',').map((url: string) => ({ url })) : [],
+                examinReport: newVal?.examinReport || [],
+                finalFormType: newVal?.finalFormType || '',
+                finalFormOther: newVal?.finalFormOther || '',
+                finalSpecn: newVal?.finalSpecn || '',
+                finalUnit: newVal?.finalUnit || '',
+                id: newVal?.id || '',
+            };
+        }
+    },
+    { immediate: true },
+);
+
+// 动态生成校验规则
+const getRules = () => {
+    const baseRules = {
+        specnLevel: [{ required: true, message: '请选择规格等级', trigger: 'change' }],
+        capacity: [
+            { required: true, message: '请输入产量', trigger: 'blur' },
+            { type: 'number', message: '产量必须为数字', trigger: 'blur' },
+        ],
+        unit: [{ required: true, message: '请选择单位', trigger: 'change' }],
+    };
+
+    if (type.value === 2) {
+        // 类型 2(趁鲜切制)所有字段必填
+        return {
+            ...baseRules,
+            finalFormType: [{ required: true, message: '请选择切制形态', trigger: 'change' }],
+            finalFormOther: [{ required: true, message: '请输入具体切制形态', trigger: 'blur' }],
+            finalSpecn: [{ required: true, message: '请输入切制尺寸', trigger: 'blur' }],
+            finalUnit: [{ required: true, message: '请选择切制单位', trigger: 'change' }],
+        };
+    } else {
+        // 类型 1(初加工)只有前三个必填
+        return baseRules;
+    }
 };
 
+// 根据 type 动态设置校验规则
+const type = ref(+props.type);
+const rules = ref(getRules());
+
+// 监听 type 变化,重新生成规则
+watch(
+    () => props.type,
+    (newVal) => {
+        type.value = newVal;
+        rules.value = getRules();
+    },
+);
+
 // 关闭弹框
 const handleClose = () => {
     emit('update:show', false);
     resetForm();
 };
 
+// 获取标题
+const getTitle = () => {
+    return props.isEdit ? '修改产出信息' : '添加产出信息';
+};
+
 // 重置表单
 const resetForm = () => {
     formData.value = {
@@ -138,10 +260,32 @@ const resetForm = () => {
         finalFormOther: '',
         finalSpecn: '',
         finalUnit: '',
+        id: '',
     };
     formRef.value?.clearValidate();
 };
 
+// 处理统货 checkbox 点击事件
+const handleSpecnLevelChange = (checked: boolean) => {
+    if (checked) {
+        formData.value.specnLevel = '统货';
+    } else {
+        formData.value.specnLevel = '';
+    }
+};
+
+// 跳转到规格等级选择页面
+const goToSpecLevel = () => {
+    uni.$once('updateSpecificationLevel', (res) => {
+        if (res?.data) {
+            formData.value.specnLevel = res.data;
+        }
+    });
+    uni.navigateTo({
+        url: '/tools/specification-level/index',
+    });
+};
+
 // 提交表单
 const handleSubmit = async () => {
     try {
@@ -166,11 +310,18 @@ const handleSubmit = async () => {
             finalUnit: formData.value.finalUnit,
         };
 
-        // 调用接口
-        const res: any = await useClientRequest.post('/plt-api/app/processOutPut/output', submitData);
+        let res: any;
+        // 编辑模式调用修改接口
+        if (props.isEdit && formData.value.id) {
+            (submitData as any).id = formData.value.id;
+            res = await useClientRequest.post('/plt-api/app/processOutPut/outputEdit', submitData);
+        } else {
+            // 新增模式调用新增接口
+            res = await useClientRequest.post('/plt-api/app/processOutPut/output', submitData);
+        }
 
         if (res && res.code === 200) {
-            uni.showToast({ title: '添加成功', icon: 'success' });
+            uni.showToast({ title: props.isEdit ? '修改成功' : '添加成功', icon: 'success' });
             handleClose();
             emit('confirm', res.data);
         }
@@ -180,4 +331,15 @@ const handleSubmit = async () => {
 };
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.search-select-item {
+    height: 86rpx;
+    background-color: #fff;
+    border-radius: 10rpx;
+    box-sizing: border-box;
+    padding-left: 16rpx;
+    padding-right: 16rpx;
+    padding-top: 14rpx;
+    padding-bottom: 14rpx;
+}
+</style>

+ 82 - 0
src/plant/processing/processing-detail-list/models/processing-output-item.vue

@@ -0,0 +1,82 @@
+<template>
+    <view class="relative bg-#fff b-radius pd-24 d-flex a-c" :class="{ 'bg-#EDF7F0': selected && selectable }" @click="handleClick">
+        <!-- 序号标签 -->
+        <view v-if="showIndex" class="absolute top-0 left-0 w-60 h-60 c-#fff f-s-20 f-w-5 pd-4 pt-4 pb-4 z-index-10" style="border-radius: 16rpx 0 0rpx 0; background: linear-gradient(135deg, #22c55e 50%, transparent 50%)">
+            <span class="w-30 h-30 f-s-24 f-w-5" style="transform: rotate(-45deg); display: block">{{ String(index + 1).padStart(2, '0') }}</span>
+        </view>
+        <!-- 图片 -->
+        <view class="w-100 h-100 radius-8 ov-hd mr-24" style="flex-shrink: 0">
+            <up-image :src="item?.imgs?.split(',')?.[0]" mode="aspectFill" width="100%" height="100%"></up-image>
+        </view>
+        <!-- 信息区域 -->
+        <view class="flex-1 flex a-c j-sb">
+            <!-- 左侧:品名和规格 -->
+            <view class="flex flex-cln">
+                <view class="f-s-34 f-w-5 c-#333 mb-4">{{ item?.specnLevel }}</view>
+                <view class="f-s-24 c-#999">{{ item?.finalSpecn }}{{ item?.finalUnit }}{{ item?.finalFormType }}</view>
+            </view>
+            <!-- 中间:重量和检验状态 -->
+            <view class="flex flex-cln a-c">
+                <view class="f-s-34 f-w-5 c-#333">{{ item?.capacity }}{{ item?.unit }}</view>
+                <view v-if="item?.examinReport?.length > 0" class="f-s-24 mt-8 c-#37a954">已检验</view>
+                <view v-else class="f-s-24 mt-8 c-#f74c30">未检验</view>
+            </view>
+            <!-- 右侧:入库状态 -->
+            <view class="flex a-c">
+                <view v-if="+item?.status !== 0" class="f-s-24 c-#37a954" style="text-decoration: underline">已入种源库</view>
+                <view v-else class="f-s-24 c-#999">未入库</view>
+            </view>
+        </view>
+        <!-- 选中对勾图标 -->
+        <view v-if="selected && selectable" class="absolute bottom-24 right-24 w-40 h-40 bg-#37a954 d-flex a-c j-c radius-8">
+            <up-icon name="checkmark" color="#fff" size="24rpx"></up-icon>
+        </view>
+    </view>
+</template>
+
+<script setup lang="ts">
+const props = defineProps({
+    // 单个产出项数据
+    item: {
+        type: Object,
+        default: () => ({}),
+    },
+    // 序号(用于显示)
+    index: {
+        type: Number,
+        default: 0,
+    },
+    // 是否支持点击选中
+    selectable: {
+        type: Boolean,
+        default: false,
+    },
+    // 是否已选中
+    selected: {
+        type: Boolean,
+        default: false,
+    },
+    // 是否显示序号标签
+    showIndex: {
+        type: Boolean,
+        default: true,
+    },
+});
+
+const emit = defineEmits<{
+    click: [item: any];
+    'update:selected': [value: boolean];
+}>();
+
+// 处理点击事件
+const handleClick = () => {
+    if (props.selectable) {
+        emit('update:selected', !props.selected);
+    }
+    emit('click', props.item);
+};
+</script>
+
+<style scoped lang="scss">
+// 组件样式使用 UnoCSS 原子类,无需额外样式
+</style>

+ 167 - 0
src/tools/specification-level/index.vue

@@ -0,0 +1,167 @@
+<template>
+    <z-paging ref="paging" safe-area-inset-bottom v-model="list">
+        <template #top>
+            <ut-navbar title="请选择/填写规格等级" :fixed="false"></ut-navbar>
+            <view class="">
+                <up-tabs :list="list1" @change="changeType" lineWidth="30" :current="activetab"></up-tabs>
+            </view>
+        </template>
+        <view class="">
+            <view class="pd-24 pt-0 d-flex flex-cln">
+                <!-- 常用标签页 -->
+                <template v-if="+activetab == 0">
+                    <view v-if="commonly?.length > 0" class="pt-16 d-flex flex-wrap gap-16" style="justify-content: start">
+                        <view v-for="(item, idnex) in commonly" :key="idnex" class="bg-#fff c-#333 radius-10 pd4-16-24-16-24 mb-16" @click="selectItem(item)">
+                            {{ item }}
+                        </view>
+                    </view>
+                    <template v-else>
+                        <ut-empty class="mg-at mt-30" color="#ccc" size="28rpx">暂无常用规格等级</ut-empty>
+                    </template>
+                </template>
+                <!-- 规格等级库标签页 -->
+                <template v-if="+activetab == 1">
+                    <view class="d-flex flex-cln" style="justify-content: start">
+                        <view v-for="(item, idnexs) in ptechData" :key="idnexs">
+                            <view class="pt-16 pb-16 f-s-28 f-w-5 c-#666">{{ item?.dictTypeLabel }}</view>
+                            <view class="d-flex flex-wrap gap-16">
+                                <view v-for="(items, idnex) in item?.childVos" :key="idnex" class="bg-#fff c-#333 radius-10 pd4-16-24-16-24 mb-10" @click="selectItem(items?.dictLabel)">
+                                    {{ items?.dictLabel }}
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                </template>
+                <!-- 自行填写标签页 -->
+                <template v-if="+activetab == 2">
+                    <view class="d-flex flex-cln">
+                        <view class="pt-16 f-s-28 c-#333">规格等级</view>
+                        <view class="d-flex flex-wrap gap-16 f-s-28 mt-16">
+                            <up-input v-model="temPtech" clearable border="bottom" placeholder="请输入规格等级">
+                                <template #suffix>
+                                    <up-button type="primary" @click="confirmAdd()" style="height: 60rpx; width: 120rpx; font-size: 22rpx">确认添加</up-button>
+                                </template>
+                            </up-input>
+                        </view>
+                    </view>
+                </template>
+            </view>
+        </view>
+    </z-paging>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+
+const list = ref<any>();
+const activetab = ref<number>(0);
+const STORAGE_KEY = 'specification-level-cache';
+const temPtech = ref<string>('');
+
+const list1 = reactive([
+    { name: '常用', value: 0 },
+    { name: '规格等级库', value: 1 },
+    { name: '自行填写', value: 2 },
+]);
+
+const changeType = (tabItem: any) => {
+    activetab.value = tabItem?.value;
+};
+
+const commonly = ref<string[]>([]);
+const ptechData = ref<any[]>([]);
+
+// 选中项并返回
+const selectItem = (item: string) => {
+    if (!item) return;
+
+    // 添加到常用缓存
+    let cached = uni.getStorageSync(STORAGE_KEY) || '';
+    let items = cached ? cached.split(',') : [];
+
+    // 去重
+    const index = items.indexOf(item);
+    if (index > -1) {
+        items.splice(index, 1);
+    }
+    items.push(item);
+
+    // 限制最多 40 个
+    const MAX_ITEMS = 40;
+    if (items.length > MAX_ITEMS) {
+        items.splice(0, items.length - MAX_ITEMS);
+    }
+
+    // 更新缓存
+    const newCached = items.join(',');
+    uni.setStorageSync(STORAGE_KEY, newCached);
+    commonly.value = items;
+
+    // 返回选择结果
+    uni?.$emit('updateSpecificationLevel', {
+        data: item,
+    });
+
+    setTimeout(() => {
+        uni.navigateBack({
+            delta: 1,
+        });
+    }, 300);
+};
+
+// 确认添加(自行填写)
+const confirmAdd = () => {
+    if (!temPtech.value) {
+        uni.showToast({
+            title: '请输入规格等级',
+            icon: 'none',
+        });
+        return;
+    }
+
+    // 添加到常用缓存
+    let cached = uni.getStorageSync(STORAGE_KEY) || '';
+    let items = cached ? cached.split(',') : [];
+
+    // 去重
+    const index = items.indexOf(temPtech.value);
+    if (index > -1) {
+        items.splice(index, 1);
+    }
+    items.push(temPtech.value);
+
+    // 限制最多 40 个
+    const MAX_ITEMS = 40;
+    if (items.length > MAX_ITEMS) {
+        items.splice(0, items.length - MAX_ITEMS);
+    }
+
+    // 更新缓存
+    const newCached = items.join(',');
+    uni.setStorageSync(STORAGE_KEY, newCached);
+    commonly.value = items;
+
+    // 返回选择结果
+    uni?.$emit('updateSpecificationLevel', {
+        data: temPtech.value,
+    });
+
+    setTimeout(() => {
+        uni.navigateBack({
+            delta: 1,
+        });
+    }, 300);
+};
+
+const query = async () => {
+    const res = await useClientRequest.get(`/plt-api/app/process/tech/listAllGroup`, {
+        groupType: 'specn_level',
+    });
+    ptechData.value = res?.data;
+};
+
+onLoad(() => {
+    query();
+    let cached = uni.getStorageSync(STORAGE_KEY) || '';
+    commonly.value = cached ? cached.split(',') : [];
+});
+</script>