lisy 2 هفته پیش
والد
کامیت
127e8923bc

+ 3 - 27
src/plant/processing/processing-depstock/index.vue

@@ -142,16 +142,11 @@ const rules = reactive({
 const selectedSeeds = ref<any[]>([]);
 const showSelectDialog = ref(false);
 
-// 处理种子选择确认
-const handleSeedConfirm = (ids: number[]) => {
-    // 根据 ID 过滤出选中的种子
-    selectedSeeds.value = seedList.value.filter((item) => ids.includes(item.id));
-    console.log(selectedSeeds.value, 'ids');
+// 处理种子选择确认(直接接收完整数据)
+const handleSeedConfirm = (items: any[]) => {
+    selectedSeeds.value = items;
 };
 
-// 种子列表(用于过滤)
-const seedList = ref<any[]>([]);
-
 // 删除种子
 const deleteSeed = (index: number) => {
     selectedSeeds.value.splice(index, 1);
@@ -242,25 +237,6 @@ const generateBatchCode = async () => {
     }
 };
 
-// 监听弹窗打开,获取种子列表用于后续过滤
-watch(
-    () => showSelectDialog.value,
-    async (val) => {
-        if (val) {
-            try {
-                const res = await useClientRequest.get('/plt-api/app/processOutPut/pageList', {
-                    pageNum: 1,
-                    pageSize: 100,
-                });
-                if (res && res.code === 200) {
-                    seedList.value = res.rows || [];
-                }
-            } catch (error) {
-                console.error(error);
-            }
-        }
-    },
-);
 const processId = ref<any>();
 onLoad((optins: any) => {
     processId.value = optins?.processId;

+ 7 - 6
src/plant/processing/processing-depstock/models/select-seed-dialog.vue

@@ -15,8 +15,8 @@
                 </view>
                 <!-- 底部按钮 -->
                 <view class="w-700 bg-#fff h-100 d-flex a-c gap-20 pt-24 pb-24 bottom-btns z-index-20" style="position: fixed; bottom: 0; right: 0">
-                    <up-button @click="handleCancel" :customStyle="{ flex: 1, marginRight: '10rpx' }">取消</up-button>
-                    <up-button @click="handleConfirm" type="primary" :customStyle="{ flex: 1, marginLeft: '10rpx' }">确认选择</up-button>
+                    <up-button @click="handleCancel" :customStyle="{ flex: 1, marginRight: '10rpx', marginLeft: '10rpx' }">取消</up-button>
+                    <up-button @click="handleConfirm" type="primary" :customStyle="{ flex: 1, marginRight: '10rpx', marginLeft: '10rpx' }">确认选择</up-button>
                 </view>
             </scroll-view>
         </view>
@@ -40,7 +40,7 @@ const props = defineProps({
 
 const emit = defineEmits<{
     'update:modelValue': [value: boolean];
-    confirm: [ids: number[]];
+    confirm: [items: any[]];
 }>();
 const top = ref(0);
 const visible = computed({
@@ -93,11 +93,13 @@ const handleConfirm = () => {
         });
         return;
     }
-    emit('confirm', selectedIds.value);
+    // 返回选中的完整对象数据
+    const selectedItems = list.value.filter((item) => selectedIds.value.includes(item.id));
+    emit('confirm', selectedItems);
     visible.value = false;
 };
 
-// 监听弹窗打开,加载数据
+// 监听弹窗打开,加载数据(弹窗打开时)
 watch(
     () => visible.value,
     (val) => {
@@ -105,7 +107,6 @@ watch(
             getList();
         }
     },
-    { immediate: true },
 );
 onMounted(() => {
     const querys = uni.createSelectorQuery().in(instance?.proxy);

+ 25 - 14
src/plant/processing/processing-detail-list/index.vue

@@ -59,11 +59,11 @@
             </view>
             <!-- Tab 切换 -->
             <view class="d-flex a-c bg-#f7f7f7 mb-16">
-                <ut-tabs v-model="activeTab" :tabs="tabs" @change="onTabChange"></ut-tabs>
+                <up-tabs :list="tabs" @change="onTabChange" :current="activeTab" lineWidth="60"></up-tabs>
             </view>
             <!-- 原料信息列表 -->
-            <view v-if="activeTab == '0'">
-                <view v-if="list.length === 0 && activeTab == '0'" class="d-flex flex-cln a-c pd-40">
+            <view v-if="+activeTab == 0">
+                <view v-if="list.length === 0 && +activeTab == 0" class="d-flex flex-cln a-c pd-40">
                     <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="goAssociate">去关联原料信息</up-button>
                 </view>
@@ -178,15 +178,15 @@ const taskId = ref('');
 const taskDetail = ref<any>({});
 const outputList = ref<any[]>([]);
 
-const activeTab = ref('0');
+const activeTab = ref(0);
 const tabs = [
     {
-        label: '原料信息',
-        value: '0',
+        name: '原料信息',
+        value: 0,
     },
     {
-        label: '产出信息',
-        value: '1',
+        name: '产出信息',
+        value: 1,
     },
 ];
 // 加载任务详情
@@ -231,8 +231,9 @@ const goAssociate = () => {
     });
 };
 // Tab 切换
-const onTabChange = () => {
-    if (activeTab.value === '1') {
+const onTabChange = (tabItem: any) => {
+    activeTab.value = tabItem?.value;
+    if (+activeTab.value === 1) {
         // 切换到产出信息,加载产出信息列表
         getOutputList();
     } else {
@@ -250,6 +251,7 @@ const getOutputList = async () => {
         if (res && res.rows) {
             outputList.value = res.rows;
         }
+        return res;
     } catch (error) {
         console.error('加载产出信息失败:', error);
         outputList.value = [];
@@ -277,7 +279,7 @@ const gotoDetail = () => {
 // 监听修改成功事件,重新加载任务详情
 const handleUpdateTaskDetail = () => {
     loadTaskDetail(); // 重新加载任务详情
-    if (activeTab.value === '0') {
+    if (+activeTab.value === 0) {
         paging.value?.reload(); // 刷新原料列表
     } else {
         getOutputList(); // 刷新产出列表
@@ -291,6 +293,10 @@ onLoad((options: any) => {
     if (taskId.value) {
         loadTaskDetail();
     }
+    if (options?.output) {
+        activeTab.value = 1;
+        getOutputList();
+    }
 });
 
 // 离开页面时卸载事件监听
@@ -309,6 +315,7 @@ const withdraw = async () => {
         const delRes = await useClientRequest.get(`/plt-api/app/processInputMaterial/callbackInput/${list.value?.[0]?.id}`);
         if (delRes && delRes.code === 200) {
             uni.showToast({ title: '删除成功', icon: 'none' });
+            uni.$emit(`updatesupervise-${taskId.value}`, []);
             paging.value?.reload();
         }
     }
@@ -326,8 +333,11 @@ const handleShowOutputModel = () => {
 };
 
 // 处理添加/修改成功
-const handleOutputConfirm = () => {
-    getOutputList();
+const handleOutputConfirm = async () => {
+    const res: any = await getOutputList();
+    console.log(res, 'res˝');
+
+    uni.$emit(`updateoutList-${taskId.value}`, res?.rows || []);
 };
 
 // 处理产出项点击
@@ -389,7 +399,8 @@ const handleDeleteOutput = async (outPutId: string | number, item: any) => {
         const delRes = await useClientRequest.get(`/plt-api/app/processOutPut/removeOutPut/${outPutId}`);
         if (delRes && delRes.code === 200) {
             uni.showToast({ title: '删除成功', icon: 'none' });
-            getOutputList();
+            const data = await getOutputList();
+            uni.$emit(`updateoutList-${taskId.value}`, data?.rows || []);
         }
     } catch (error) {
         console.error('删除失败:', error);

+ 178 - 57
src/plant/processing/processing-index/index.vue

@@ -4,16 +4,16 @@
             <up-navbar title="加工及包装赋码任务" :fixed="false"> </up-navbar>
         </template>
         <template>
-            <view class="pd3-24-24-0">
-                <view class="">
-                    <ut-tabs mode="subsection" v-model="form.restFlag" :tabs="tabs" @change="onRefresh"></ut-tabs>
-                </view>
-            </view>
             <view class="d-flex a-c pd-24 pb-0 bg-#f7f7f7">
-                <view class="min-w-170 flex1">
-                    <ut-action-sheet v-model="form.taskType" :tabs="[{ label: '全部', value: '' }, ...pt_process_type]" @change="onRefresh" title="选择原料类型">
+                <view class="min-w-220 flex1">
+                    <ut-action-sheet v-model="form.processType" :tabs="[{ label: '全部', value: '' }, ...pt_process_type]" @change="onRefresh" title="选择原料类型">
                         <view class="d-flex search-select-item a-c">
-                            <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ selectDictLabel(pt_process_type, form.taskType) || '全部' }}</view>
+                            <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no d-flex a-c j-c">
+                                <view class="w-s-no">{{ selectDictLabel(pt_process_type, form.processType) || '全部' }}</view>
+                                <template v-for="(item, index) in processCountList" :key="index">
+                                    <view class="" v-if="form.processType == item?.type">({{ item?.num }})</view>
+                                </template>
+                            </view>
                             <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="mr-5"></up-icon>
                         </view>
                     </ut-action-sheet>
@@ -23,53 +23,59 @@
                 </view>
             </view>
             <view class="pd-24">
-                <template v-for="(item, index) in list" :key="index">
-                    <view class="bg-#fff b-radius pd-24 p-rtv mb-16">
-                        <view v-if="+item?.processType == 1 && +item?.processMedType == 1" class="bg-#91C747 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">种子初加工</view>
-                        <view v-if="+item?.processType == 1 && +item?.processMedType == 2" class="bg-#C7A262 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">药材初加工</view>
-                        <view v-if="+item?.processType == 2" class="bg-#37A954 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">趁鲜切制</view>
-                        <view v-if="item?.processingDate || item?.processingDateEnd" class="d-flex a-c j-ed">
-                            <view class="c-#999 f-s-24">{{ item?.processingDate }} 至 {{ item?.processingDateEnd }}</view>
-                        </view>
-                        <view class="mb-10 d-flex a-c" @click="gotodetaillist(item)">
-                            <view class="">
-                                <span v-if="item?.variety" class="f-s-34 c-#333 f-w-500 mr-10">{{ item?.variety }}</span>
-                                <span v-else class="f-s-34 c-#333 f-w-500 mr-10">{{ item?.medicineName }}(鲜制)</span>
-                                <span class="f-s-24 c-#666" v-if="+item?.processMedType == 1">{{ selectDictLabel(pt_stock_type, item?.processMedType) }}</span>
+                <up-swipe-action>
+                    <up-swipe-action-item v-for="(item, index) in list" :key="index" :name="item?.id" :options="swipeOptions" class="mb-16" @click="handleSwipeClick">
+                        <template #default>
+                            <view class="bg-#fff b-radius pd-24 p-rtv">
+                                <view v-if="+item?.processType == 1 && +item?.processMedType == 1" class="bg-#91C747 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">种子初加工</view>
+                                <view v-if="+item?.processType == 1 && +item?.processMedType == 2" class="bg-#C7A262 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">药材初加工</view>
+                                <view v-if="+item?.processType == 2" class="bg-#37A954 c-#fff f-w-5 pd-10 pt-4 pb-4 f-s-20" style="border-radius: 16rpx 0 16rpx 0; width: max-content; position: absolute; top: 0rpx; left: 0rpx">趁鲜切制</view>
+                                <view v-if="item?.processingDate || item?.processingDateEnd" class="d-flex a-c j-ed">
+                                    <view class="c-#999 f-s-24">{{ item?.processingDate }} 至 {{ item?.processingDateEnd }}</view>
+                                </view>
+                                <view class="" @click="gotodetaillist(item)">
+                                    <view class="mb-10 d-flex a-c">
+                                        <view class="">
+                                            <span v-if="item?.variety" class="f-s-34 c-#333 f-w-500 mr-10">{{ item?.variety }}</span>
+                                            <span v-else class="f-s-34 c-#333 f-w-500 mr-10">{{ item?.medicineName }}(鲜制)</span>
+                                            <span class="f-s-24 c-#666" v-if="+item?.processMedType == 1">{{ selectDictLabel(pt_stock_type, item?.processMedType) }}</span>
+                                        </view>
+                                        <view class="flex1"></view>
+                                        <up-icon name="arrow-right" size="26rpx"></up-icon>
+                                    </view>
+                                    <view class="pd2-4-0 f-s-28">
+                                        <span class="c-#666">加工批号:</span>
+                                        <span class="c-#333 f-w-500">{{ item?.processCode }}</span>
+                                    </view>
+                                    <view v-if="+item?.processType == 1" class="pd2-4-0 f-s-28">
+                                        <span class="c-#666">执行标准:</span>
+                                        <span class="c-#333 f-w-500">{{ selectDictLabel(pt_standard_type, item?.standardType) }}</span>
+                                        <span class="c-#666" v-if="item?.standardDetailName">({{ item?.standardDetailName }})</span>
+                                    </view>
+                                    <view v-else class="pd2-4-0 f-s-28">
+                                        <span class="c-#666">执行标准:</span>
+                                        <span class="c-#666" v-if="item?.standardDetailName">{{ item?.standardDetailName }}</span>
+                                    </view>
+                                    <view class="pd2-4-0 f-s-28">
+                                        <span class="c-#666">加工工艺:</span>
+                                        <template v-for="(items, indexs) in item?.ptech?.split(',')" v-if="item?.ptech" :key="indexs">
+                                            <span v-if="indexs !== 0" class="c-#999 f-s-32 ml-10 mr-10">→ </span>
+                                            <span class="f-s-32">{{ items }}</span>
+                                        </template>
+                                        <template v-else>
+                                            <span class="c-#999 f-s-32">-</span>
+                                        </template>
+                                    </view>
+                                    <view class="pd2-4-0 f-s-28">
+                                        <span class="c-#666">加工负责人:</span>
+                                        <span class="c-#333 f-w-500">{{ item?.contactName }}</span>
+                                    </view>
+                                </view>
+                                <Output :data="item" />
                             </view>
-                            <view class="flex1"></view>
-                            <up-icon name="arrow-right" size="26rpx"></up-icon>
-                        </view>
-                        <view class="pd2-4-0 f-s-28">
-                            <span class="c-#666">加工批号:</span>
-                            <span class="c-#333 f-w-500">{{ item?.processCode }}</span>
-                        </view>
-                        <view v-if="+item?.processType == 1" class="pd2-4-0 f-s-28">
-                            <span class="c-#666">执行标准:</span>
-                            <span class="c-#333 f-w-500">{{ selectDictLabel(pt_standard_type, item?.standardType) }}</span>
-                            <span class="c-#666" v-if="item?.standardDetailName">({{ item?.standardDetailName }})</span>
-                        </view>
-                        <view v-else class="pd2-4-0 f-s-28">
-                            <span class="c-#666">执行标准:</span>
-                            <span class="c-#666" v-if="item?.standardDetailName">{{ item?.standardDetailName }}</span>
-                        </view>
-                        <view class="pd2-4-0 f-s-28">
-                            <span class="c-#666">加工工艺:</span>
-                            <template v-for="(items, indexs) in item?.ptech?.split(',')" v-if="item?.ptech" :key="indexs">
-                                <span v-if="indexs !== 0" class="c-#999 f-s-32 ml-10 mr-10">→ </span>
-                                <span class="f-s-32">{{ items }}</span>
-                            </template>
-                            <template v-else>
-                                <span class="c-#999 f-s-32">-</span>
-                            </template>
-                        </view>
-                        <view class="pd2-4-0 f-s-28">
-                            <span class="c-#666">加工负责人:</span>
-                            <span class="c-#333 f-w-500">{{ item?.contactName }}</span>
-                        </view>
-                        <Output :data="item" />
-                    </view>
-                </template>
+                        </template>
+                    </up-swipe-action-item>
+                </up-swipe-action>
             </view>
         </template>
         <view class="h-210" v-if="list?.length"></view>
@@ -91,10 +97,10 @@
         <view class="" v-for="item in pt_process_type" :key="item?.value">
             <view style="border: 1rpx solid" :style="{ backgroundColor: item?.value == basetype ? '#EBF6EE' : '#f7f7f7', borderColor: item?.value == basetype ? '#37A954' : 'transparent' }" class="pr-30 d-flex a-c mb-20 radius-100" @click="handlechose(item.value)">
                 <view class="radius-50% mg-8 bg-#F0F0F0" v-if="item?.value == '1'">
-                    <up-avatar size="90rpx" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/port/TaskType_plant.png"></up-avatar>
+                    <up-avatar size="90rpx" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/port/processType_plant.png"></up-avatar>
                 </view>
                 <view class="radius-50% mg-8 bg-#F0F0F0" v-if="item?.value == '2'">
-                    <up-avatar size="90rpx" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/port/TaskType_breeding.png"></up-avatar>
+                    <up-avatar size="90rpx" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/port/processType_breeding.png"></up-avatar>
                 </view>
                 <view class="c-#333 f-s-34">
                     {{ item?.label }}
@@ -123,6 +129,7 @@ sus.value.left = systemInfo.windowWidth - 10;
 sus.value.bottom = systemInfo.windowHeight - 200;
 const showDeleteDialog = ref(false);
 const basetype = ref();
+const processCountList = ref<any>();
 const handlechose = (item: string) => {
     basetype.value = item;
 };
@@ -140,7 +147,7 @@ const handlechoseConfirm = () => {
         });
         return;
     }
-    uni.$u.route({ type: 'navigateTo', url: '/plant/processing/processing-create/index', params: { taskType: basetype.value } });
+    uni.$u.route({ type: 'navigateTo', url: '/plant/processing/processing-create/index', params: { processType: basetype.value } });
 };
 const paging = ref();
 const list = ref<any[]>([]);
@@ -156,7 +163,108 @@ const tabs = [
 ];
 const form = ref({
     storageType: '4',
+    processType: '',
+    keyword: '',
 });
+
+// 滑动操作选项
+const swipeOptions = reactive([
+    {
+        text: '复制',
+        style: {
+            backgroundColor: '#37A954',
+            width: '80rpx',
+            fontSize: '28rpx',
+        },
+    },
+    {
+        text: '修改',
+        style: {
+            backgroundColor: '#18BECA',
+            width: '80rpx',
+            fontSize: '28rpx',
+        },
+    },
+    {
+        text: '删除',
+        style: {
+            backgroundColor: '#F74C30',
+            width: '80rpx',
+            fontSize: '28rpx',
+        },
+    },
+]);
+
+// 处理滑动按钮点击
+const handleSwipeClick = async (event: any) => {
+    const { name, index } = event;
+    const item = list.value[index];
+
+    if (index === 0) {
+        // 点击复制
+        handleCopy(name, item);
+    } else if (index === 1) {
+        // 点击修改
+        handleEdit(item);
+    } else if (index === 2) {
+        // 点击删除
+        handleDelete(name, item);
+    }
+};
+
+// 处理复制
+const handleCopy = async (processId: string | number, item: any) => {
+    try {
+        const res = await uni.showModal({
+            title: '复制提示',
+            content: '确定复制该加工任务吗?',
+            confirmColor: '#37A954',
+        });
+        if (!res.confirm) return;
+
+        const copyRes = await useClientRequest.get(`/plt-api/app/processe/copyProcess/${processId}`);
+        if (copyRes && copyRes.code === 200) {
+            uni.showToast({ title: '复制成功', icon: 'success' });
+            paging.value?.reload();
+        }
+    } catch (error) {
+        console.error('复制失败:', error);
+    }
+};
+
+// 处理修改
+const handleEdit = (item: any) => {
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/plant/processing/processing-create/index',
+        params: { id: item?.id, edit: 1 },
+    });
+};
+
+// 处理删除
+const handleDelete = async (processId: 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/processe/deleteProcess/${processId}`);
+        if (delRes && delRes.code === 200) {
+            uni.showToast({ title: '删除成功', icon: 'none' });
+            paging.value?.reload();
+        }
+    } catch (error) {
+        console.error('删除失败:', error);
+    }
+};
+
+const changeSeach = () => {
+    paging.value.reload();
+};
+
 const query = async (pageNum: number, pageSize: number) => {
     const params = {
         pageNum,
@@ -176,6 +284,16 @@ const gotodetaillist = (item: any) => {
         params: { id: item?.id },
     });
 };
+//获取所选类型的数量
+const selectNumber = async () => {
+    const res = await useClientRequest.get('/plt-api/app/processe/processCountList');
+    if (res) {
+        console.log(res);
+        processCountList.value = res?.data;
+        return res;
+    }
+};
+
 const onRefresh = () => {
     paging.value?.reload();
 };
@@ -184,6 +302,9 @@ onMounted(() => {
         paging.value?.reload();
     });
 });
+onShow(() => {
+    selectNumber();
+});
 </script>
 <style scoped lang="scss">
 .search-select-item {

+ 86 - 22
src/plant/processing/processing-index/models/output.vue

@@ -8,7 +8,7 @@
             <view class="d-flex flex1 f-s-26">
                 <view class="c-#999 ml-16"> 暂无关联原料信息 </view>
                 <view class="flex1"></view>
-                <view class="c-primary d-flex a-c" @click="goAssociate">
+                <view class="c-primary d-flex a-c" @click.stop="goAssociate">
                     <view>去关联</view>
                     <up-icon name="arrow-right" size="26rpx"></up-icon>
                 </view>
@@ -26,19 +26,19 @@
                     </view>
                 </ut-col>
                 <ut-col class="d-flex a-c c-#666" :span="10">{{ inputList?.quantity }}{{ inputList?.unit }}</ut-col>
-                <ut-col class="d-flex a-c j-ed" :span="5" @click.stop="withdraw">
+                <ut-col class="d-flex a-c j-ed" :span="5" @click.stop="handleWithdrawClick">
                     <span class="c-#666">撤回</span>
                     <up-icon name="arrow-right" size="26rpx"></up-icon>
                 </ut-col>
             </ut-row>
         </view>
     </view>
-    <view class="radius-10 bg-#f7f7f7 d-flex">
+    <view class="radius-10 bg-#f7f7f7 d-flex" @click="gotodetaillist(processId)">
         <view class="bg-#EBF4FD w-50 d-flex flex-cln a-c j-c c-#2289E0 f-w-5 f-s-24">
             <view class="">产</view>
             <view class="">出</view>
         </view>
-        <view class="bg-#F6FAFE flex1 d-flex a-c" v-if="data?.length === 0">
+        <view class="bg-#F6FAFE flex1 d-flex a-c h-110" v-if="outputList?.length === 0">
             <view class="d-flex flex1 f-s-26">
                 <view class="c-#999 ml-16"> 暂无产出信息 </view>
                 <view class="flex1"></view>
@@ -49,42 +49,73 @@
             </view>
         </view>
         <view class="bg-#F6FAFE flex1 f-s-22 pd-16" v-else>
-            <ut-row gap="10rpx">
-                <ut-col class="d-flex a-c c-#666" :span="2">01</ut-col>
-                <ut-col class="d-flex flex-cln j-c" :span="8">
-                    <span class="c-#666">统货2</span>
-                    <span class="c-#999">1mm极薄片</span>
-                </ut-col>
-                <ut-col class="d-flex a-c c-#666" :span="8">19999kg</ut-col>
-                <ut-col class="d-flex a-c" :span="3">
-                    <span class="c-#F74C30">未检</span>
-                    <span class="c-primary">已检</span>
-                </ut-col>
-                <ut-col class="d-flex a-c j-ed" :span="9">
-                    <span class="c-#666">已入药材库</span>
-                    <span class="c-#666">未入库</span>
-                    <up-icon name="arrow-right" size="26rpx"></up-icon>
-                </ut-col>
-            </ut-row>
-            <view class="d-flex a-c j-c pd-16 radius-10" style="border: 1rpx dashed #2289e0">
+            <view v-for="(item, index) in outputList" :key="item?.id || index" class="mb-6">
+                <ut-row gap="10rpx">
+                    <ut-col class="d-flex a-c c-#666" :span="2">{{ String(Number(index) + 1).padStart(2, '0') }}</ut-col>
+                    <ut-col class="d-flex flex-cln j-c" :span="8">
+                        <span class="c-#666">{{ item?.specnLevel }}</span>
+                        <span class="c-#999">{{ item?.finalSpecn }}{{ item?.finalUnit }}{{ selectDictLabel(pt_final_form_type, item?.finalFormType) }}</span>
+                    </ut-col>
+                    <ut-col class="d-flex a-c c-#666" :span="8">{{ item?.capacity }}{{ item?.unit }}</ut-col>
+                    <ut-col class="d-flex a-c" :span="3">
+                        <span v-if="item?.examinReport?.length > 0" class="c-primary">已检</span>
+                        <span v-else class="c-#F74C30">未检</span>
+                    </ut-col>
+                    <ut-col class="d-flex a-c j-ed" :span="9">
+                        <span v-if="Number(item?.status) !== 0" class="c-#37a954">已入药材库</span>
+                        <span v-else class="c-#666">未入库</span>
+                        <up-icon name="arrow-right" size="26rpx"></up-icon>
+                    </ut-col>
+                </ut-row>
+            </view>
+            <view class="d-flex a-c j-c pd-16 radius-10" style="border: 1rpx dashed #2289e0" @click.stop="handleShowOutputModel">
                 <up-icon name="plus" size="26rpx" color="#2289E0"></up-icon>
                 <span class="c-#2289E0 f-s-26">添加产出物</span>
             </view>
         </view>
     </view>
+    <!-- 添加/修改产出信息弹框 -->
+    <root-portal>
+        <OutputInfo v-if="showOutputModel" v-model:show="showOutputModel" :type="processType" :processId="processId" :isEdit="isEditOutput" :editData="editOutputData" @confirm="handleOutputConfirm" />
+    </root-portal>
 </template>
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';
+import OutputInfo from './outputInfo.vue';
+
 const props = defineProps<{
     data: any;
 }>();
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_final_form_type } = toRefs<any>(proxy?.useDict('pt_final_form_type'));
+
+// 从 data 中获取 processId 和 processType
+const processId = computed(() => props.data?.id);
+const processType = computed(() => props.data?.processType || 1);
+
+// 字典标签选择函数
+const selectDictLabel = (dict: any[], value: string | number) => {
+    const item = dict.find((item) => item.value == value);
+    return item ? item.label : '';
+};
+
 watch(
     () => props.data,
     (val) => {
         inputList.value = val?.inputList[0] || {};
+        outputList.value = val?.outputList || [];
     },
 );
+
 const inputList = ref<any>(props?.data?.inputList[0] || {});
+const outputList = ref<any>(props?.data?.outputList || []);
+
+// 弹框状态管理
+const showOutputModel = ref(false);
+const isEditOutput = ref(false); // 是否编辑模式
+const editOutputData = ref<any>({}); // 编辑的数据
+
 const goAssociate = () => {
     uni.$u.route({
         type: 'navigateTo',
@@ -92,9 +123,29 @@ const goAssociate = () => {
         params: { id: props?.data?.id, processMedType: props?.data?.processMedType },
     });
 };
+const gotodetaillist = (id: any) => {
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/plant/processing/processing-detail-list/index',
+        params: { id: id, output: true },
+    });
+};
 uni.$on(`updatesupervise-${props?.data?.id}`, function (data) {
+    console.log(data, 'data');
+
     inputList.value = data;
 });
+uni.$on(`updateoutList-${props?.data?.id}`, function (data) {
+    outputList.value = data;
+});
+// 处理撤回按钮点击,阻止事件冒泡
+const handleWithdrawClick = (event: any) => {
+    if (event) {
+        event.stopPropagation();
+    }
+    withdraw();
+};
+
 const withdraw = async () => {
     // 删除
     const res = await uni.showModal({
@@ -111,4 +162,17 @@ const withdraw = async () => {
         }
     }
 };
+
+// 显示添加产出信息弹框
+const handleShowOutputModel = () => {
+    isEditOutput.value = false;
+    editOutputData.value = {};
+    showOutputModel.value = true;
+};
+
+// 处理添加/修改成功回调
+const handleOutputConfirm = async () => {
+    const res = await useClientRequest.get(`/plt-api/app/processOutPut/pageList?processId=${processId?.value}`);
+    outputList.value = res?.rows || [];
+};
 </script>

+ 354 - 0
src/plant/processing/processing-index/models/outputInfo.vue

@@ -0,0 +1,354 @@
+<template>
+    <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-16">{{ getTitle() }}</view>
+            <scroll-view scroll-y class="h-0 flex1">
+                <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 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="pt_out_put_unit" 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>
+                            <!-- 产出物图片 -->
+                            <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 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="pt_out_put_unit" 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="#37A954" 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="#37A954" name="arrow-down-fill"></up-icon>
+                                    </template>
+                                </up-form-item>
+                            </ut-action-sheet>
+                            <!-- 具体切制形态 -->
+                            <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="#37A954" 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 pd-24">
+                <up-button plain type="info" @click="handleClose">取消</up-button>
+                <up-button type="primary" @click="handleSubmit">确认</up-button>
+            </view>
+        </view>
+    </up-popup>
+</template>
+
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_final_form_type, pt_final_unit, pt_out_put_unit } = toRefs<any>(proxy?.useDict('pt_final_form_type', 'pt_final_unit', 'pt_out_put_unit'));
+
+// 字典标签选择函数
+const selectDictLabel = (dict: any[], value: string | number) => {
+    const item = dict.find((item) => item.value == value);
+    return item ? item.label : '';
+};
+const props = defineProps<{
+    show: boolean;
+    type: number; // 1: 初加工,2: 趁鲜切制
+    processId: string | number; // 加工任务 ID
+    isEdit: boolean; // 是否编辑模式
+    editData: any; // 要编辑的数据
+}>();
+const emit = defineEmits<{
+    'update:show': [value: boolean];
+    confirm: [data: any];
+}>();
+
+const formRef = ref();
+
+// 表单数据
+const formData = ref({
+    specnLevel: '',
+    capacity: '',
+    unit: '',
+    imgs: [] as any[],
+    examinReport: [] as any[],
+    finalFormType: '',
+    finalFormOther: '',
+    finalSpecn: '',
+    finalUnit: '',
+    id: '', // 编辑模式需要 id
+});
+
+// 监听 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 = {
+        specnLevel: '',
+        capacity: '',
+        unit: '',
+        imgs: [],
+        examinReport: [],
+        finalFormType: '',
+        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 {
+        const valid = await formRef.value?.validate();
+        if (!valid) return;
+
+        // 准备提交数据
+        const submitData = {
+            processId: props.processId,
+            specnLevel: formData.value.specnLevel,
+            capacity: Number(formData.value.capacity),
+            unit: formData.value.unit,
+            imgs: formData.value.imgs.map((item: any) => item.url).join(','),
+            examinReport: formData.value.examinReport.map((item: any) => ({
+                fileName: item.fileName || '',
+                url: item.url || '',
+                fileSize: item.fileSize || 0,
+            })),
+            finalFormType: formData.value.finalFormType,
+            finalFormOther: formData.value.finalFormOther,
+            finalSpecn: formData.value.finalSpecn,
+            finalUnit: formData.value.finalUnit,
+        };
+
+        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: props.isEdit ? '修改成功' : '添加成功', icon: 'success' });
+            handleClose();
+            emit('confirm', res.data);
+        }
+    } catch (error) {
+        console.error('提交失败:', error);
+    }
+};
+</script>
+
+<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>