Bläddra i källkod

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

lisy 1 vecka sedan
förälder
incheckning
9dae761c9a
34 ändrade filer med 1289 tillägg och 165 borttagningar
  1. 18 0
      package-lock.json
  2. 1 0
      package.json
  3. 7 0
      src/assets/styles/uview-plus.ts
  4. 14 0
      src/pages.json
  5. 1 1
      src/plant/base/gap-base-info-edit/index.vue
  6. 1 1
      src/plant/base/mark-base/index.vue
  7. 1 1
      src/plant/contact-unit/unit-edit/index.vue
  8. 15 4
      src/plant/export-print/export/index.vue
  9. 65 0
      src/plant/export-print/models/code-checked-logos.vue
  10. 113 35
      src/plant/export-print/models/code-style-tem.vue
  11. 212 55
      src/plant/export-print/models/export-print-confirm.vue
  12. 308 0
      src/plant/packaging/batch-link/index.vue
  13. 1 1
      src/plant/packaging/create/index.vue
  14. 8 3
      src/plant/packaging/detail/index.vue
  15. 2 0
      src/plant/packaging/detail/models/pack-test-info.vue
  16. 52 10
      src/plant/packaging/detail/models/print-info-page.vue
  17. 231 0
      src/plant/packaging/detail/models/relate-info-page.vue
  18. 1 1
      src/plant/packaging/list/index.vue
  19. 1 1
      src/plant/processing/processing-depstock/index.vue
  20. 4 4
      src/plant/storage/agro-product/add/index.vue
  21. 1 1
      src/plant/storage/agro-product/info-edit/index.vue
  22. 4 4
      src/plant/storage/agro-product/info-update/index.vue
  23. 4 4
      src/plant/storage/fresh-goods/add/index.vue
  24. 1 1
      src/plant/storage/fresh-goods/info-edit/index.vue
  25. 6 6
      src/plant/storage/fresh-goods/info-update/index.vue
  26. 1 1
      src/plant/storage/loss-register/index.vue
  27. 4 4
      src/plant/storage/seed-source/add/index.vue
  28. 8 8
      src/plant/storage/seed-source/info-edit/index.vue
  29. 17 17
      src/plant/storage/seed-source/info-update/index.vue
  30. 1 1
      src/plant/storage/storage-room/edit/index.vue
  31. 152 0
      src/tools/select-code-section/index.vue
  32. 1 1
      src/tools/select-gap-info/index.vue
  33. 7 0
      src/utils/common.ts
  34. 26 0
      src/utils/propTypes.ts

+ 18 - 0
package-lock.json

@@ -35,6 +35,7 @@
                 "uview-plus": "^3.6.4",
                 "vue": "3.5.26",
                 "vue-i18n": "9.14.5",
+                "vue-types": "^6.0.0",
                 "z-paging": "^2.8.7"
             },
             "devDependencies": {
@@ -10876,6 +10877,23 @@
                 "node": ">=10"
             }
         },
+        "node_modules/vue-types": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmmirror.com/vue-types/-/vue-types-6.0.0.tgz",
+            "integrity": "sha512-fBgCA4nrBrB8SCU/AN40tFq8HUxLGBvU2ds7a5+SEDse6dYc+TJyvy8mWiwwL8oWIC/aGS/8nTqmhwxApgU5eA==",
+            "license": "MIT",
+            "engines": {
+                "node": ">=14.0.0"
+            },
+            "peerDependencies": {
+                "vue": "^3.0.0"
+            },
+            "peerDependenciesMeta": {
+                "vue": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/vue/node_modules/@vue/compiler-core": {
             "version": "3.5.26",
             "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.26.tgz",

+ 1 - 0
package.json

@@ -64,6 +64,7 @@
         "uview-plus": "^3.6.4",
         "vue": "3.5.26",
         "vue-i18n": "9.14.5",
+        "vue-types": "^6.0.0",
         "z-paging": "^2.8.7"
     },
     "devDependencies": {

+ 7 - 0
src/assets/styles/uview-plus.ts

@@ -13,4 +13,11 @@ export const formItemBtnListStyle = {
     lineHeight: '68rpx',
     borderRadius: '10rpx',
     padding: '0 20rpx',
+};
+export const formItemBtnCardStyle = {
+    height: '78rpx',
+    fontSize: '36rpx',
+    lineHeight: '78rpx',
+    borderRadius: '10rpx',
+    padding: '0 20rpx',
 };

+ 14 - 0
src/pages.json

@@ -478,6 +478,13 @@
                     "style": {
                         "navigationBarTitleText": "选择包装对象"
                     }
+                },
+                // 批量关联
+                {
+                    "path": "batch-link/index",
+                    "style": {
+                        "navigationBarTitleText": "批量关联"
+                    }
                 }
             ]
         },
@@ -666,6 +673,13 @@
                         "navigationBarTitleText": "view-html页面",
                         "navigationStyle": "custom"
                     }
+                },
+                // 选择追溯码码段
+                {
+                    "path": "select-code-section/index",
+                    "style": {
+                        "navigationBarTitleText": "选择追溯码码段"
+                    }
                 }
             ]
         },

+ 1 - 1
src/plant/base/gap-base-info-edit/index.vue

@@ -180,7 +180,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/base/mark-base/index.vue

@@ -169,7 +169,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/contact-unit/unit-edit/index.vue

@@ -198,7 +198,7 @@ const submit = async () => {
     try {
         await upFormRef.value?.validate();
     } catch (error: any) {
-        const firstErrorField = error && error[0].prop + 'pppp';
+        const firstErrorField = error && error[0].field + 'pppp';
         paging.value?.scrollIntoViewById(firstErrorField, 30, true);
         return;
     }

+ 15 - 4
src/plant/export-print/export/index.vue

@@ -14,7 +14,15 @@
             </view>
             <view v-show="currentStep === 'export'">
                 <!-- 业务组件确认数量 -->
-                <export-print-confirm v-if="opts" :opts="opts" :infoData="info" :info="stepsObject[currentStep]"></export-print-confirm>
+                <export-print-confirm :paging="paging" v-if="opts" :opts="opts" prevStepValue="check" @prev="prevSteps" :infoData="info" :info="stepsObject[currentStep]">
+                    <template #fileType><view class="h-1" id="fileTypepppp"></view></template>
+                    <template #logos><view class="h-1" id="logospppp"></view></template>
+                    <template #fields><view class="h-1" id="fieldspppp"></view></template>
+                    <template #layoutType><view class="h-1" id="layoutTypepppp"></view></template>
+                    <template #printCount><view class="h-1" id="printCountpppp"></view></template>
+                    <template #email><view class="h-1" id="emailpppp"></view></template>
+                    <template #fileFormat><view class="h-1" id="fileFormatpppp"></view></template>
+                </export-print-confirm>
             </view>
             
         </view>
@@ -25,7 +33,8 @@
 import CheckInfoPack from '@/plant/print/models/check-info-pack.vue';
 import { useClientRequest } from '@/utils/request';
 import ExportPrintConfirm from '@/plant/export-print/models/export-print-confirm.vue';
-const currentStep = ref('export');
+const paging = ref<any>(null);
+const currentStep = ref('check');
 const stepsObject = reactive<any>({
     check: {
         title: '核对信息',
@@ -48,10 +57,9 @@ const info =ref<any>(null);
 const getDetailInfo = (data: any) => {
    info.value = data;
 };
+// 根据id获取详情form信息
 // 如果是 30x30
 const nextSteps = (data: any) => {
-    console.log(data);
-    
     if (!data.info || !data?.info?.value) return;
     stepsObject[data?.info?.value] = {
         ...data.info,
@@ -59,5 +67,8 @@ const nextSteps = (data: any) => {
     stepsObject[data?.nextStepValue].status = 'in-progress';
     currentStep.value = data?.nextStepValue;
 };
+const prevSteps = (data: any) => {
+    currentStep.value = data?.prevStepValue;
+};
 </script>
 <style lang="scss" scoped></style>

+ 65 - 0
src/plant/export-print/models/code-checked-logos.vue

@@ -0,0 +1,65 @@
+<template>
+    <view>
+        <up-checkbox-group v-model="checked" @change="changeLogos" placement="column">
+            <template v-for="(item, index) in logos" :key="index">
+                <up-checkbox :name="item.logo" :disabled="disabledFn(item)">
+                    <template #label>
+                        <view class="a-c logo-item" style="display: inline-flex;" :class="{ 'disabled': disabledFn(item) }">
+                            <view class="w-74 h-74 d-flex a-c j-c mr-16 radius-8 border-#C5C5C5">
+                                <image :src="item.logo" class="w-68 h-68" mode="aspectFit"></image>
+                            </view>
+                            <view class="flex1 ov-hd">
+                                <view class="f-s-30 f-w-5 c-#333">{{ item?.logoName }}</view>
+                                <view v-if="item?.remark" class="f-s-24 c-#999">{{ item?.remark }}</view>
+                            </view>
+                        </view>
+                    </template>
+                </up-checkbox>
+            </template>
+        </up-checkbox-group>
+    </view>
+</template>
+<script lang="ts" setup>
+import { propTypes } from '@/utils/propTypes';
+import { useClientRequest } from '@/utils/request';
+import type { PropType } from 'vue';
+
+const props = defineProps(
+    {
+        modelValue: propTypes.any.def([]),
+    }
+)
+const logos = ref<any[]>([])
+const checked = ref<any>(props.modelValue)
+const emit = defineEmits(['change', 'update:modelValue'])
+// 获取logos数据
+const getLogos = async () => {
+    const res = await useClientRequest.get('/plt-api/app/printLog/getLogoList');
+    if (!res || res.code !== 200) return
+    logos.value = res.data || [];
+}
+const changeLogos = (val: string[]) => {
+    emit('update:modelValue', val)
+    emit('change', val)
+}
+const disabledFn = (item: any) => {
+    if (!item.logo) return true;
+    if (!checked.value?.includes(item.logo) && checked.value?.length >= 2) {
+        return true;
+    }
+    return false;
+}
+onMounted(() => {
+    getLogos()
+})
+watch(() => props.modelValue, (val) => {
+    checked.value = val as string[]
+})
+</script>
+<style lang="scss" scoped>
+.logo-item {
+    &.disabled {
+        opacity: 0.7;
+    }
+}
+</style>

+ 113 - 35
src/plant/export-print/models/code-style-tem.vue

@@ -1,63 +1,70 @@
 <template>
-   <view v-if="layoutType == '2'" class="w-640 tem-wrapper-table">
+    <view v-if="layoutType == '2'" class="w-640 tem-wrapper-table">
         <view class="table-tr">
-            <view class="table-td flex1"></view>
+            <view class="table-td flex1 d-flex flex-cln j-c a-c">
+                <view class="f-s-36 f-w-6 c-#000 mb-30 pt-30">中药材标签</view>
+                <view class="d-flex j-c gap-60 mb-30">
+                     <template v-for="(item, index) in logos" :key="index">
+                          <image class="w-160 h-160" :src="item" mode="widthFix" />
+                     </template>
+                </view>
+            </view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('proName')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">品名</view>
             </view>
             <view class="table-td flex1">{{ info?.proName || '-' }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('genusName')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">基原</view>
             </view>
-            <view class="table-td flex1">三七</view>
+            <view class="table-td flex1">{{ info?.varietyInfo?.varietyName + info?.varietyInfo?.latinName || '-' }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('batchSn')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">批号</view>
             </view>
             <view class="table-td flex1">{{ info?.batchSn || '-' }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('proLevel')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">规格等级</view>
             </view>
             <view class="table-td flex1">{{ info?.proLevel || '-' }}</view>
-        </view>
-        <view class="table-tr">
+        </view>  
+        <view v-if="(fields as string[])?.includes('proAdcodeDesc')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">产地</view>
             </view>
             <view class="table-td flex1">{{ info?.proAdcodeDesc || '-' }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('specn')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">数量/重量</view>
             </view>
             <view class="table-td flex1">{{ info?.specn }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('harvestDate')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">采收日期</view>
             </view>
             <view class="table-td flex1">{{ getDateRangeFrt(info?.harvestDate, info?.harvestDateEnd) }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('packagingDate')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">包装日期</view>
             </view>
             <view class="table-td flex1">{{ getDateRangeFrt(info?.packagingDateStart, info?.packagingDateStart) }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('expireDate')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">保质期</view>
             </view>
             <view class="table-td flex1">{{ info?.expireDate }}{{ info?.expireDateUnit }}</view>
         </view>
-        <view class="table-tr">
+        <view v-if="(fields as string[])?.includes('cpyName')" class="table-tr">
             <view class="table-td w-160">
                 <view class="table-label flex1">企业名称</view>
             </view>
@@ -67,31 +74,102 @@
             <view class="table-td w-160">
                 <view class="table-label flex1">追溯码</view>
             </view>
-            <view class="table-td flex1">三七</view>
+            <view class="table-td flex1 d-flex">
+                 <view class="d-flex j-c a-c flex-cln flex1">
+                    <image class="w-140 h-140" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/code_logo_export.png" mode="widthFix" />
+                    <view class="f-s-26">xxxx</view>
+                    <view v-if="(fields as string[])?.includes('gapFlag')" class="f-s-26">药材符合GAP要求</view>
+                </view>
+            </view>
         </view>
-   </view>
+    </view>
+    <view v-if="layoutType == '1'" class="w-640 tem-wrapper-b;okk">
+        <view class="pd2-10-40">
+            <view class="d-flex flex-cln j-c a-c">
+                <view class="f-s-36 f-w-6 c-#000 mb-30 pt-30">中药材标签</view>
+                <view class="d-flex j-c gap-60 mb-30">
+                     <template v-for="(item, index) in logos" :key="index">
+                          <image class="w-160 h-160" :src="item" mode="widthFix" />
+                     </template>
+                </view>
+            </view>
+            <view v-if="(fields as string[])?.includes('proName')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>品名:</span>
+                <span>{{ info?.proName || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('genusName')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>基原:</span>
+                <span>{{ info?.varietyInfo?.varietyName + info?.varietyInfo?.latinName || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('batchSn')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>批号:</span>
+                <span>{{ info?.batchSn || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('proSpecn')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>规格等级:</span>
+                <span>{{ info?.proLevel || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('proAdcodeDesc')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>产地:</span>
+                <span>{{ info?.proAdcodeDesc || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('specn')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>数量/重量:</span>
+                <span>{{ info?.specn || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('harvestDate')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>采收日期:</span>
+                <span>{{ getDateRangeFrt(info?.harvestDate, info?.harvestDateEnd) }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('packagingDate')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>包装日期:</span>
+                <span>{{ getDateRangeFrt(info?.packagingDateStart, info?.packagingDateStart) }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('expireDate')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>保质期:</span>
+                <span>{{ (info?.expireDate || '') + (info?.expireDateUnit || '') || '-' }}</span>
+            </view>
+            <view v-if="(fields as string[])?.includes('cpyName')" class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <span>企业名称:</span>
+                <span>{{ info?.cpyName || '-' }}</span>
+            </view>
+            <view class="f-s-30 c-#000 f-w-5 pd2-8-0">
+                <view class="mb-20">溯源码:</view>
+                <view class="d-flex j-c a-c flex-cln">
+                    <image class="w-140 h-140" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/code_logo_export.png" mode="widthFix" />
+                    <view class="f-s-26">xxxx</view>
+                </view>
+            </view>
+            <view class="h-2 bg-#000 mg2-10-0"></view>
+            <view v-if="(fields as string[])?.includes('gapFlag')" class="text-center f-s-40 c-#000 f-w-5">药材符合GAP要求</view>
+        </view>
+    </view>
 </template>
 
 <script lang="ts" setup>
 const props = defineProps({
-   fields: {
-       type: Array,
-       default: () => []
-   },
-   layoutType: {
-       type: String,
-       default: ''
-   },
-   hasBorder: { // 新增属性:控制是否显示边框
-       type: Boolean,
-       default: false
-   },
-   info: {
-       type: Object,
-       default: () => null
-   },
-})
-
+    fields: {
+        type: Array,
+        default: () => [],
+    },
+    layoutType: {
+        type: String,
+        default: '',
+    },
+    hasBorder: {
+        // 新增属性:控制是否显示边框
+        type: Boolean,
+        default: false,
+    },
+    info: {
+        type: Object,
+        default: () => null,
+    },
+    logos: {
+        type: Array,
+        default: () => [],
+    },
+});
 </script>
 
 <style lang="scss" scoped>
@@ -122,4 +200,4 @@ const props = defineProps({
     /*兼容ie*/
     text-justify: distribute-all-lines;
 }
-</style>
+</style>

+ 212 - 55
src/plant/export-print/models/export-print-confirm.vue

@@ -2,57 +2,105 @@
     <view class="pd-24 bg-fff">
         <up-form class="p-rtv bg-#fff" labelPosition="top" :model="form" errorType="toast" :rules="rules" labelWidth="auto" ref="upFormUpRef">
             <view class="f-s-24 c-#999">导出追溯码仅支持导出追溯码地址用于喷印或排版好追溯码PDF文件直接打印。如有疑问,请。如有疑问,请<span class="c-primary">点击此处联系客服</span>。</view>
-            <view class="h-1" id="fileTypepppp"></view>
-            <ut-action-sheet v-model="form.extraInfo.fileType" :tabs="pt_code_export_type" @change="changeExtraFileType" mode="custom" title="请选择导出类型">
+            <slot name="fileType"></slot>
+            <template v-if="opts.id">
                 <up-form-item borderBottom label="导出类型" required prop="extraInfo.fileType">
                     <view v-if="form.extraInfo?.fileType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_code_export_type, form.extraInfo.fileType) }}</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>
-            <!-- 导出格式 -->
-            <view class="h-1" id="fileFormatpppp"></view>
+            </template>
+            <template v-else>
+                <ut-action-sheet v-model="form.extraInfo.fileType" :tabs="pt_code_export_type" @change="changeExtraFileType" mode="custom" title="请选择导出类型">
+                    <up-form-item borderBottom label="导出类型" required prop="extraInfo.fileType">
+                        <view v-if="form.extraInfo?.fileType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_code_export_type, form.extraInfo.fileType) }}</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>
+            </template>
+
+            <template v-if="form.extraInfo.fileType == '2'">
+                <slot name="logos"></slot>
+                <up-form-item borderBottom prop="extraInfo.logos">
+                    <view class="flex1">
+                        <view class="p-rtv mb-20">
+                            <span class="form-item-label_required">*</span>
+                            <span class="f-s-30 c-#333">打印logo</span>
+                            <span class="f-s-24 c-#999">(最多2种)</span>
+                        </view>
+                        <codeCheckedLogos v-model="form.extraInfo.logos"></codeCheckedLogos>
+                    </view>
+                </up-form-item>
+                <slot name="fields"></slot>
+                <up-form-item prop="extraInfo.fields" borderBottom>
+                    <view class="flex1">
+                        <view class="p-rtv mb-20">
+                            <span class="form-item-label_required">*</span>
+                            <span class="f-s-30 c-#333">导出信息</span>
+                            <span class="f-s-24 c-#999">(已默认勾选必打字段,如需其他字段可自行选择)</span>
+                        </view>
+                        <up-checkbox-group v-model="form.extraInfo.fields">
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="品名" name="proName"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="基原" name="genusName"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="批号" name="batchSn"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="规格等级" name="proLevel"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="产地" name="proAdcodeDesc"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="数量(重量)" name="specn"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="采收日期" name="harvestDate"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="包装日期" name="packagingDate"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="保质期" name="expireDate"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="企业名称" name="cpyName"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="溯源码码值" name="code"></up-checkbox>
+                            <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="溯源码图" name="qrcode"></up-checkbox>
+                            <up-checkbox v-if="+info?.gapFlag" :customStyle="{ marginBottom: '8px' }" label="是否符合GAP要求" name="gapFlag"></up-checkbox>
+                        </up-checkbox-group>
+                    </view>
+                </up-form-item>
+
+                <slot name="layoutType"></slot>
+                <up-form-item props="extraInfo.layoutType" label="排版类型" required borderBottom>
+                    <view class="flex1">
+                        <ut-radio v-model="form.extraInfo.layoutType" :options="pt_code_export_layout_type"></ut-radio>
+                        <view class="d-flex j-c a-c pd-24">
+                            <codeStyleTem :fields="form.extraInfo.fields" :logos="form.extraInfo.logos" :info="infoData" :layoutType="form.extraInfo.layoutType"></codeStyleTem>
+                        </view>
+                    </view>
+                </up-form-item>
+                <!-- 导出数量 -->
+
+                <slot name="printCount"></slot>
+                <template v-if="opts.id">
+                    <up-form-item :label="`导出数量`" prop="printCount" required borderBottom>
+                        <up-input v-model="form.printCount" readonly placeholder="请输入导出数量" border="none" clearable></up-input>
+                        <template #right>
+                            <span class="f-s-30 f-w-5 c-#333">{{ opts?.unit || form?.unit || 'kg' }}</span>
+                        </template>
+                    </up-form-item>
+                </template>
+                <template v-else>
+                    <up-form-item :label="`导出数量`" prop="printCount" required borderBottom>
+                        <up-input v-model="form.printCount" placeholder="请输入导出数量" border="none" clearable></up-input>
+                        <template #right>
+                            <span class="f-s-30 f-w-5 c-#333">{{ opts?.unit || form?.unit || 'kg' }}</span>
+                        </template>
+                    </up-form-item>
+                </template>
+                <!-- 邮箱 -->
+                <slot name="email"></slot>
+                <up-form-item borderBottom required label="邮箱" prop="extraInfo.email">
+                    <up-input v-model="form.extraInfo.email" placeholder="请输入邮箱" border="none" clearable></up-input>
+                </up-form-item>
+            </template>
+
+            <slot name="fileFormat"></slot>
             <up-form-item borderBottom label="导出格式" required prop="extraInfo.fileFormat">
                 <view v-if="form.extraInfo?.fileFormat" class="f-s-30 c-333 f-w-5 flex1">
                     {{ selectDictLabel(pt_code_export_format, form.extraInfo?.fileFormat) }}
                 </view>
                 <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择导出格式</view>
             </up-form-item>
-            <view class="h-1" id="fieldspppp"></view>
-            <up-form-item prop="extraInfo.fields" borderBottom>
-                <view class="flex1">
-                    <view class="p-rtv mb-20">
-                        <span class="form-item-label_required">*</span>
-                        <span class="f-s-30 c-#333">导出信息</span>
-                        <span class="f-s-24 c-#999">(已默认勾选必打字段,如需其他字段可自行选择)</span>
-                    </view>
-                    <up-checkbox-group v-model="form.extraInfo.fields">
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="品名" name="proName"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="基原" name="genusName"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="批号" name="batchSn"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="规格等级" name="proSpecn"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="产地" name="proAdcodeDesc"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="数量(重量)" name="specn"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="采收日期" name="harvestDate"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="包装日期" name="packagingDate"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="保质期" name="expireDate"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="企业名称" name="cpyName"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" label="溯源码码值" name="code"></up-checkbox>
-                        <up-checkbox :customStyle="{ width: '33%', marginBottom: '8px' }" disabled label="溯源码图" name="qrcode"></up-checkbox>
-                        <up-checkbox :customStyle="{ marginBottom: '8px' }" label="是否符合GAP要求" name="gapFlag"></up-checkbox>
-                    </up-checkbox-group>
-                </view>
-            </up-form-item>
-            <up-form-item props="extraInfo.layoutType" label="排版类型" required borderBottom>
-                <view class="flex1">
-                    <ut-radio v-model="form.extraInfo.layoutType" :options="pt_code_export_layout_type"></ut-radio>
-                    <view class="d-flex j-c a-c pd-24">
-                        <codeStyleTem :fields="form.extraInfo.fields" :info="infoData" :layoutType="form.extraInfo.layoutType"></codeStyleTem>
-                    </view>
-                </view>
-            </up-form-item>
             <up-form-item :label="`导出人`" required borderBottom>
                 <up-input v-model="form.printPerson" placeholder="请输入导出人" readonly border="none" clearable></up-input>
             </up-form-item>
@@ -60,12 +108,14 @@
     </view>
     <view class="pd3-40-24-30 d-flex">
         <up-button class="mr-30" type="primary" plain @click="prevSteps">上一步</up-button>
-        <up-button type="primary" @click="submitForm">下一步</up-button>
+        <up-button type="primary" @click="submitForm">确认导出</up-button>
     </view>
 </template>
 <script setup lang="ts">
 import { useInfoStore } from '@/store';
 import codeStyleTem from './code-style-tem.vue';
+import codeCheckedLogos from './code-checked-logos.vue';
+import { useClientRequest } from '@/utils/request';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { pt_code_export_type, pt_code_export_format, pt_code_export_layout_type } = toRefs<any>(proxy?.useDict('pt_code_export_type', 'pt_code_export_format', 'pt_code_export_layout_type'));
 const infoStore = useInfoStore();
@@ -95,46 +145,153 @@ const props = defineProps({
         type: Object,
         default: () => null,
     },
+    paging: {
+        type: Object,
+        default: () => null,
+    },
 });
 const upFormUpRef = ref();
 const emit = defineEmits(['next', 'prev', 'formdata']);
-const form = ref({
+const form = ref<any>({
+    printCount: props.opts?.printedCount,
     extraInfo: {
         fileType: '1',
         fileFormat: '1',
         logos: [], // 导出logo
         // 只有禁用的默认有值,
-        fields: ['proName', 'batchSn', 'proSpecn', 'proAdcodeDesc', 'specn', 'cpyName', 'qrcode'], // 导出字段
+        fields: ['proName', 'batchSn', 'proLevel', 'proAdcodeDesc', 'specn', 'cpyName', 'code', 'qrcode'], // 导出字段
         layoutType: '2', // 排版类型
+        email: '',
     },
     printPerson: infoStore.userInfo?.name, // 导出人
 });
-const rules = reactive({});
+const rules = reactive({
+    'extraInfo.fileType': [
+        {
+            required: true,
+            message: '请选择导出类型',
+            trigger: 'change',
+        },
+    ],
+    'extraInfo.logos': [
+        {
+            type: 'array',
+            required: true,
+            message: '请选择导出logo',
+            trigger: 'change',
+        },
+        {
+            type: 'array',
+            max: 2,
+            message: '最多选择2个logo',
+            trigger: 'change',
+        },
+    ],
+    'extraInfo.layoutType': [
+        {
+            required: true,
+            message: '请选择排版类型',
+            trigger: 'change',
+        },
+    ],
+    printCount: [
+        { required: true, message: '请输入导出数量' },
+        // 只能输入大于0的正整数
+        { pattern: /^[1-9]\d*$/, message: '请输入大于0的正整数' },
+        // 打印数量不能大于剩余可打印数量
+        {
+            asyncValidator: (rule: any, value: any) => {
+                if (value === undefined || value === null || value === '') return Promise.resolve();
+                const num = Number(value);
+                if (Number.isNaN(num)) return Promise.reject('导出数量请输入数字');
+                if (num <= 0) return Promise.reject('导出数量需大于0');
+                // 打印数量不能大于剩余可打印数量
+                if (+props?.opts?.printedCount < +num) {
+                    return Promise.reject(`导出数量不能超过待打印数量`);
+                }
+                return Promise.resolve();
+            },
+        },
+    ],
+    'extraInfo.email': [
+        {
+            required: true,
+            message: '请输入邮箱',
+            trigger: 'blur',
+        },
+        {
+            asyncValidator: (rule: any, value: any) => {
+                // 邮箱校验
+                const reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/;
+                if (reg.test(value)) {
+                    return Promise.resolve();
+                } else {
+                    return Promise.reject('请输入正确的邮箱');
+                }
+            },
+        },
+    ],
+    'extraInfo.fileFormat': [
+        {
+            required: true,
+            message: '请选择导出格式',
+            trigger: 'change',
+        },
+    ],
+});
 const changeExtraFileType = (val: any) => {
-    console.log(val);
     form.value.extraInfo.fileFormat = val;
+    form.value.printCount = props.opts?.printedCount;
 };
 const submitForm = async () => {
     try {
         await upFormUpRef.value?.validate();
     } catch (error: any) {
+        // 滚动到第一个错误字段
+        const firstErrorField = error && error[0].field + 'pppp';
+        props.paging?.scrollIntoViewById(firstErrorField, 30, true);
         return;
     }
-    emit('formdata', {
-        ...form.value,
+    uni.showLoading({
+        title: '正在导出...',
     });
-    emit('next', {
-        info: {
-            ...props.info,
-            status: 'completed',
-        },
-        nextStepValue: props.nextStepValue || 'print',
+    const payload = {
+        ...props.opts,
+        ...form.value,
+    };
+    const res = props.opts?.id ? await useClientRequest.get(`/plt-api/app/printLog/update/${props.opts.id}`, payload?.extraInfo) : await useClientRequest.post('/plt-api/app/printLog/printNext', payload);
+    if (!res || res.code !== 200) return;
+    uni.$emit('refreshPackTaskList');
+    uni.$emit('refreshPackTaskDetail');
+    await useClientRequest.get(`/plt-api/app/printLog/export/${res.data?.id || props.opts?.id}`);
+    uni.hideLoading();
+    uni.showToast({
+        title: '导出成功',
+        icon: 'success',
     });
+    setTimeout(() => {
+        uni.navigateBack({
+            delta: 1,
+        });
+    }, 800);
 };
 const prevSteps = () => {
     emit('prev', {
         prevStepValue: props.prevStepValue || 'confirm',
     });
 };
-onMounted(() => {});
+// getFormInfo
+const getFormInfo = async () => {
+    if (!props.opts.id) return;
+    const res = await useClientRequest.get(`/plt-api/app/printLog/${props.opts.id}`);
+    if (res && res.code === 200) {
+        form.value = {
+            ...form.value,
+            ...res.data,
+        };
+    }
+};
+onMounted(() => {
+    getFormInfo();
+});
 </script>

+ 308 - 0
src/plant/packaging/batch-link/index.vue

@@ -0,0 +1,308 @@
+<template>
+    <z-paging ref="paging" bgColor="#F7F7F7" safe-area-inset-bottom paging-class="paging-btm-shadow" refresher-only @onRefresh="onRefresh" scroll-with-animation>
+        <template #top>
+            <ut-navbar title="批量关联" :fixed="false" border></ut-navbar>
+            <view class="pd-5"></view>
+        </template>
+        <view class="pd-24">
+            <view class="mb-30 p-rtv batch-wapper">
+                <view class="d-flex a-c">
+                    <image class="w-50 h-50 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/pcxx_icon.png" mode="widthFix" />
+                    <view class="f-s-28 c-#333 f-w-5">需关联追溯码的批次信息</view>
+                </view>
+                <view class="pl-50">
+                    <view v-if="item" class="border-#8FC1EC b-radius bg-#fff ov-hd">
+                        <pack-card :item="item" :dict="{ pt_pack_ref_type }"></pack-card>
+                    </view>
+                    <view class="pd-30 d-flex j-c">
+                        <view class="c-primary f-s-28">
+                            <span>待关联数量:</span>
+                            <span class="f-s-46 f-w-600">{{ item?.planCount - item?.actualCount || 0 }}</span>
+                            <span>{{ item?.unit }}</span>
+                        </view>
+                    </view>
+                </view>
+                <view class="d-flex a-c">
+                    <image class="w-50 h-50 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/glm_icon.png" mode="widthFix" />
+                    <view class="f-s-28 c-#333 f-w-5">本批次信息要关联到哪些(提前预制的)追溯码上?</view>
+                </view>
+            </view>
+            <view class="pl-50">
+                <template v-for="(row, index) in relations" :key="index">
+                    <view :id="`unchecked-row-${index}`" class="p-rtv form-codes-item bg-fff border-#9DD3AB mb-20 b-radius">
+                        <view class="d-flex j-sb">
+                            <view class="no-num-tag">NO.{{ index + 1 }}</view>
+                        </view>
+                        <view @click="deleteRow(index)" class="pd-10 close-icon">
+                            <up-icon name="close" color="#F74C30" size="34rpx"></up-icon>
+                        </view>
+                        <view class="pd2-20-30">
+                            <view class="f-s-24 c-#999 pd2-4-0">生成批号:{{ row?.item?.batchSn }}</view>
+                            <view class="d-flex f-s-24 c-#999 pd2-4-0">
+                                <view>码段:</view>
+                                <view>
+                                    <view>{{ row?.item?.traceCodeStart || '-' }} 至 </view>
+                                    <view>{{ row?.item?.traceCodeEnd || '-' }}</view>
+                                </view>
+                            </view>
+                            <view class="d-flex flex-wrap">
+                                <view class="hcol-14 f-s-24 pd2-4-0">
+                                    <span class="c-#999">生成数量:</span>
+                                    <span class="c-#999">{{ row?.item?.sumCount || '-' }}个</span>
+                                </view>
+                                <view class="hcol-16 f-s-24 pd2-4-0">
+                                    <span class="c-#999">剩余数量:</span>
+                                    <span class="c-#999">{{ +row?.item?.sumCount - +row?.item?.useCount - +row?.item?.voidCount || '-' }}</span>
+                                </view>
+                                <view class="hcol-20 f-s-24 pd2-4-0">
+                                    <span class="c-#999">生成时间:</span>
+                                    <span class="c-#999">{{ parseTime(row?.item?.createTime, '{y}-{m}-{d} {h}:{i}') || '-' }}</span>
+                                </view>
+                            </view>
+                        </view>
+                        <view class="h-1 bg-#F7F7F7 mg2-0-10"></view>
+                        <view class="pd2-20-30">
+                            <view class="f-s-28 c-#333 f-w-5 mb-16">请输入要关联的预制码编号:</view>
+                            <view class="d-flex a-c j-c mb-24">
+                                <up-input placeholder="7位起始编号" maxlength="7" v-model="row.form.startSn" @change="markRowUnchecked(row)"></up-input>
+                                <view class="pd2-0-20">至</view>
+                                <up-input placeholder="7位结束编号" maxlength="7" v-model="row.form.endSn" @change="markRowUnchecked(row)"></up-input>
+                            </view>
+                            <view class="d-flex j-c pl-120 pr-120 mb-30">
+                                <up-button @click="checkCodesValidItem(row)" :customStyle="formItemBtnCardStyle" type="primary">校验是否可用</up-button>
+                            </view>
+                            <view v-if="row?.sumnCount">
+                                <view class="d-flex a-c">
+                                    <up-icon class="mr-10" name="checkmark-circle-fill" color="#3FAD5B" size="26rpx"></up-icon>
+                                    <span class="f-s-24 c-#999">此次共关联{{ row?.sumnCount }}个追溯码,关联明细如下: </span>
+                                </view>
+                                <view v-for="(col, i) in row?.validCodes" :key="i" class="f-s-24 c-#999 pl-36">
+                                    <span>{{ i + 1 }}、</span>
+                                    <span>编号区间为{{ col.startSn.toString().padStart(7, '0') }} - {{ col.endSn.toString().padStart(7, '0') }};</span>
+                                    <span>共{{ col.count }}个</span>
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                </template>
+                <up-button @click="selectCodes" type="primary" plain customStyle="background: #F5F7F5;">
+                    <image class="w-36 h-36 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/common/select_push_icon.png" mode="widthFix" />
+                    <span>请选择追溯码</span>
+                </up-button>
+            </view>
+        </view>
+        <template #bottom>
+            <view class="pd3-10-24-20">
+                <view class="f-s-28 c-#333 text-center mb-5">此次共关联{{ totalSumCount }}个追溯码</view>
+                <up-button @click="batchLinkCodes" type="primary">批量关联</up-button>
+            </view>
+        </template>
+    </z-paging>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+import { getUrlParams, parseTime, recursiveDecodeURIComponent } from '@/utils/ruoyi';
+import PackCard from '@/plant/models/pack-card.vue';
+import { formItemBtnCardStyle } from '@/assets/styles/uview-plus';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_pack_ref_type } = toRefs<any>(proxy?.useDict('pt_pack_ref_type'));
+const paging = ref<any>(null);
+const item = ref<any>(null);
+const did = ref('');
+const relations = ref<any[]>([]);
+const callbackName = 'refreshCodesRange';
+// 根据id获取基地详情
+const getDetailById = async (id: string) => {
+    const res = await useClientRequest.get(`/plt-api/app/packTask/${id}`);
+    if (res && res.code === 200) {
+        item.value = res.data || null;
+    }
+};
+const onRefresh = () => {
+    getDetailById(did.value);
+    paging.value?.complete();
+};
+const totalSumCount = computed(() => {
+    return relations.value.reduce((sum, item) => sum + +(item?.sumnCount || 0), 0);
+});
+// 判断节点是否在可视区域内如果在则切换tab createIntersectionObserver
+onLoad((options: any) => {
+    did.value = options?.packId || getUrlParams(recursiveDecodeURIComponent(options?.q))?.packId || '';
+    getDetailById(did.value);
+    uni.$on('refreshBase', () => {
+        onRefresh();
+    });
+    uni.$on(callbackName, onCodeRangeSelected);
+});
+onUnload(() => {
+    uni.$off(callbackName, onCodeRangeSelected);
+});
+const deleteRow = (index: number) => {
+    relations.value.splice(index, 1);
+};
+const markRowUnchecked = (row: any) => {
+    row.hasChecked = false;
+    row.validCodes = [];
+    row.sumnCount = 0;
+};
+// 校验单个码段是否有用
+const checkCodesValidItem = async (row: any) => {
+    if (!row?.form?.startSn || !row?.form?.endSn) {
+        uni.showToast({
+            title: '请输入完整的起始编号和结束编号',
+            icon: 'none',
+        });
+        return;
+    }
+    if (Number(row.form.startSn) > Number(row.form.endSn)) {
+        uni.showToast({
+            title: '起始编号不能大于结束编号',
+            icon: 'none',
+        });
+        return;
+    }
+    if (Number(row.form.startSn) < Number(row.item?.startSn)) {
+        uni.showToast({
+            title: '起始编号不能小于已有编号',
+            icon: 'none',
+        });
+        return;
+    }
+    if (Number(row.form.endSn) > Number(row.item?.endSn)) {
+        uni.showToast({
+            title: '结束编号不能大于已有编号',
+            icon: 'none',
+        });
+        return;
+    }
+    const res = await useClientRequest.get(`/plt-api/app/traceCodeLog/checkCodeRange/${row?.form?.id}`, {
+        ...row?.form,
+    });
+    console.log(res);
+    if (!res || res.code !== 200) {
+        row.hasChecked = false;
+        return;
+    }
+    const validCodes = res.data;
+    row.validCodes = validCodes.map((item:any) => ({ ...item, logId: row?.form?.id }));
+    row.sumnCount = validCodes.reduce((sum: number, item: any) => sum + item.count, 0);
+    row.hasChecked = true;
+};
+// 校验码段是否有用
+const checkCodesValid = async (data: any) => {
+    if (relations.value.some((relation) => relation?.item?.id === data?.id)) {
+        uni.showToast({
+            title: '该追溯码段已选择',
+            icon: 'none',
+        });
+        return;
+    }
+    const res = await useClientRequest.get(`/plt-api/app/traceCodeLog/checkCodeRange/${data?.id}`, {
+        ...data,
+    });
+    if (res && res.code === 200) {
+        // return res.data || [];
+        relations.value.push({
+            item: data,
+            form: {
+                id: data?.id,
+                startSn: res.data[0]?.startSn?.toString().padStart(7, '0')
+            },
+            hasChecked: false,
+            validCodes: [],
+            sumnCount: 0,
+        });
+        console.log(relations.value);
+    }
+    // return [];
+};
+const onCodeRangeSelected = (data: any) => {
+    console.log('选中的码段数据:', data);
+    checkCodesValid(data);
+};
+const selectCodes = () => {
+    const selectedIds = relations.value.map((row) => row?.item?.id).filter((id) => id !== null && id !== undefined);
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/tools/select-code-section/index',
+        params: {
+            // 监听函数字符串
+            callback: callbackName,
+            selectedIds: encodeURIComponent(JSON.stringify(selectedIds)),
+        },
+    });
+};
+const batchLinkCodes = async () => {
+    if (relations.value.length === 0) {
+        uni.showToast({
+            title: '请至少选择一个追溯码段进行关联',
+            icon: 'none',
+        });
+        return;
+    }
+    const uncheckedIndex = relations.value.findIndex((row) => !row?.hasChecked);
+    if (uncheckedIndex !== -1) {
+        paging.value?.scrollIntoViewById(`unchecked-row-${uncheckedIndex}`, 30, true);
+        uni.showToast({
+            title: `请先校验第${uncheckedIndex + 1}项`,
+            icon: 'none',
+        });
+        return;
+    }
+    try {
+        await uni.showLoading({
+            title: '关联中...',
+            mask: true,
+        });
+        const params = {
+            packId: did.value,
+            relations: relations.value.map((row: any) => row?.validCodes || [])?.flat(),
+        };
+        await useClientRequest.post('/plt-api/app/packTask/batchRelaction', params);
+        uni.hideLoading();
+        uni.showToast({
+            title: '关联成功',
+            icon: 'success',
+        });
+        uni.$emit('refreshPackTaskList');
+        uni.$emit('refreshPackTaskDetail');
+    
+    } catch (error) {
+        console.error('批量关联失败:', error);
+        uni.hideLoading();
+        uni.showToast({
+            title: '关联失败,请重试',
+            icon: 'none',
+        });
+    }
+};
+</script>
+<style lang="scss" scoped>
+.batch-wapper {
+    &::before {
+        content: '';
+        position: absolute;
+        left: 25rpx;
+        top: 50rpx;
+        bottom: 50rpx;
+        width: 1px;
+        background: #37a954;
+        z-index: -1;
+    }
+}
+.no-num-tag {
+    padding: 10rpx 14rpx;
+    font-size: 20rpx;
+    line-height: 1;
+    font-weight: 600;
+    color: $u-primary;
+    background-color: #d9efde;
+    border-radius: 16rpx 0 16rpx 0;
+}
+.close-icon {
+    position: absolute;
+    right: 0rpx;
+    top: 0rpx;
+    z-index: 1;
+}
+</style>

+ 1 - 1
src/plant/packaging/create/index.vue

@@ -218,7 +218,7 @@ const submit = async () => {
     try {
         await upFormRef.value?.validate();
     } catch (error: any) {
-        const firstErrorField = error && error[0].prop + 'pppp';
+        const firstErrorField = error && error[0].field + 'pppp';
         paging.value?.scrollIntoViewById(firstErrorField, 30, true);
         return;
     }

+ 8 - 3
src/plant/packaging/detail/index.vue

@@ -3,7 +3,10 @@
         <PackTestInfo v-if="form" :packId="did" :form="form" :dict="{ pt_pack_ref_type }" @changeTebs="changeTebs"></PackTestInfo>
     </template>
     <template v-if="viewMode == 'print'">
-        <PrintInfoPage v-if="form" :packId="did" :form="form" :dict="{ pt_pack_ref_type }" @changeTebs="changeTebs"></PrintInfoPage>
+        <PrintInfoPage v-if="form" :packId="did" :form="form" :dict="{ pt_pack_ref_type, pt_code_export_type }" @changeTebs="changeTebs"></PrintInfoPage>
+    </template>
+    <template v-if="viewMode == 'relate'">
+        <RelateInfoPage v-if="form" :packId="did" :form="form" :dict="{ pt_pack_ref_type }" @changeTebs="changeTebs"></RelateInfoPage>
     </template>
 </template>
 <script setup lang="ts">
@@ -11,11 +14,12 @@ import { useClientRequest } from '@/utils/request';
 import { getUrlParams, recursiveDecodeURIComponent } from '@/utils/ruoyi';
 import PackTestInfo from './models/pack-test-info.vue';
 import PrintInfoPage from './models/print-info-page.vue';
+import RelateInfoPage from './models/relate-info-page.vue';
 const viewMode = ref('print'); // print relate
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { pt_pack_ref_type } = toRefs<any>(proxy?.useDict('pt_pack_ref_type'));
+const { pt_pack_ref_type, pt_code_export_type, pt_code_export_format, pt_code_export_layout_type } = toRefs<any>(proxy?.useDict('pt_pack_ref_type', 'pt_code_export_type', 'pt_code_export_format', 'pt_code_export_layout_type'));
 const form = ref<any>(null);
-const did = ref('');
+const did = ref('relate');
 // 获取详情(GAP获评信息)
 const getDetailById = async (id: string) => {
     const res = await useClientRequest.get(`/plt-api/app/packTask/${id}`);
@@ -36,5 +40,6 @@ onMounted(() => {
         getDetailById(did.value)
     })
 });
+
 </script>
 <style lang="scss" scoped></style>

+ 2 - 0
src/plant/packaging/detail/models/pack-test-info.vue

@@ -65,6 +65,8 @@ const emit = defineEmits(['changeTebs']);
 const changeTebs = () => {
     if (props?.form?.refType == '2') {
         emit('changeTebs', 'print');
+    } else {
+        emit('changeTebs', 'relate');
     }
     
 };

+ 52 - 10
src/plant/packaging/detail/models/print-info-page.vue

@@ -13,15 +13,15 @@
                     <view class="pd-20"></view>
                 </pack-card>
                 <view class="btn-card-wrapper d-flex a-c j-sb">
-                    <view class="btn-bottom-bt ls-style" @click.stop="$u.route({ url: '/plant/print/print-self/index', params: { packId: form?.id, autoRelationId: form?.autoRelationId, unit: form?.unit, printedCount: form?.actualCount - form?.printCount } })">
+                    <view class="btn-bottom-bt ls-style" @click.stop="goPrint({ packId: form?.id, autoRelationId: form?.autoRelationId, unit: form?.unit, printedCount: form?.actualCount - form?.printCount }, '/plant/print/print-self/index')">
                         <image class="w-32 h-32 mr-8" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/btn_zxdy_icon.png" mode="widthFix" />
                         <span>自行打印</span>
                     </view>
-                    <view class="btn-bottom-bt ss-style" @click="$u.route({ url: '/plant/export-print/export/index', params: { packId: form?.id, autoRelationId: form?.autoRelationId, printedCount: form?.actualCount - form?.printCount} })">
+                    <view class="btn-bottom-bt ss-style" @click="goPrint({ packId: form?.id, autoRelationId: form?.autoRelationId, unit: form?.unit, printedCount: form?.actualCount - form?.printCount }, '/plant/export-print/export/index')">
                         <image class="w-32 h-32 mr-8" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/dczsm_icon.png" mode="widthFix" />
                         <span>导出追溯码</span>
                     </view>
-                    <view class="btn-bottom-bt fs-style">
+                    <view class="btn-bottom-bt fs-style" @click="showFeatureUnavailable()">
                         <image class="w-32 h-32 mr-8" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/btn_zrdd_icon.png" mode="widthFix" />
                         <span>找人代打</span>
                     </view>
@@ -62,7 +62,32 @@
                             </view>
                         </view>
                     </template>
-                    <template></template>
+                    <template v-if="item?.printType == '2'">
+                        <view class="mb-20 pd-20 bg-#F7F7F7 b-radius">
+                            <view class="f-s-24 c-#333 f-w-5">{{ selectDictLabel(pt_code_export_type, item?.extraInfo?.fileType) }}</view>
+                            <view class="f-s-28 pd2-4-0">
+                                <span class="c-#666">导出数量:</span>
+                                <span class="c-#333 f-w-5">{{ item?.printCount }}</span>
+                            </view>
+                            <view class="f-s-28 pd2-4-0 d-flex">
+                                <span class="c-#666">导出码值:</span>
+                                <view class="flex1 ov-hd c-#333 f-w-5">
+                                    <view>{{ item?.traceCodeStart }} 至</view>
+                                    <view>{{ item?.traceCodeEnd }}</view>
+                                </view>
+                            </view>
+                            <view class="d-flex f-s-24 c-#666">
+                                <view class="flex1 ov-hd">导出人:{{ item?.createByName || '-' }}</view>
+                                <view class="pr-100">导出时间:{{ item?.createTime || '-' }}</view>
+                            </view>
+                            <view class="pt-20 d-flex">
+                                <view class="flex1"></view>
+                                <view class="d-flex a-c">
+                                    <up-button @click="$u.route({ url: '/plant/export-print/export/index', params: item })" :customStyle="formItemBtnListStyle" color="#18BECA">重新导出</up-button>
+                                </view>
+                            </view>
+                        </view>
+                    </template>
                     <template></template>
                 </template>
             </view>
@@ -73,8 +98,9 @@
 import { useClientRequest } from '@/utils/request';
 import PackCard from '@/plant/models/pack-card.vue';
 import { formItemBtnListStyle } from '@/assets/styles/uview-plus';
+import { showFeatureUnavailable } from '@/utils/common';
 
-const paging = ref(null);
+const paging = ref<any>(null);
 const props = defineProps({
     packId: {
         type: String,
@@ -90,7 +116,7 @@ const props = defineProps({
     },
 });
 const printType = ref('1');
-const { pt_pack_ref_type } = toRefs(props?.dict);
+const { pt_pack_ref_type, pt_code_export_type } = toRefs(props?.dict);
 const emit = defineEmits(['changeTebs']);
 const tabs = reactive([
     { label: '打印记录', value: '1' },
@@ -111,7 +137,7 @@ const query = async (pageNum: number, pageSize: number) => {
     const res = await useClientRequest.get('/plt-api/app/printLog/list', params);
     if (res && res?.rows) {
         const { rows } = res;
-        paging.value.complete(rows);
+        paging.value?.complete(rows);
     }
 };
 const onRefresh = () => {
@@ -121,7 +147,7 @@ const onRefresh = () => {
         console.error('刷新列表失败:', error);
     }
 };
-const clickAllPrint = async (item) => {
+const clickAllPrint = async (item: any) => {
     try {
         const res = await uni.showModal({
             title: '全部打印提示',
@@ -129,10 +155,26 @@ const clickAllPrint = async (item) => {
             confirmColor: '#37A954',
         });
         if (res.confirm) {
-            uni.$u.route({ url: '/plant/print/print-all/index', params: item });
+            uni.$u.route({ type: 'navigateTo', url: '/plant/print/print-all/index', params: item });
         }
     } catch (error) {
-        console.error('', error);
+        console.error('全部打印失败:', error);
+    }
+};
+const goPrint = async (params: any, url: string) => {
+    if (!params?.printedCount) {
+        uni.showModal({
+            title: '提示',
+            content: '没有可打印的追溯码了哦~',
+            showCancel: false,
+            confirmColor: '#37A954',
+        });
+        return;
+    }
+    try {
+        uni.$u.route({ type: 'navigateTo', url: url || '/plant/print/print-self/index', params });
+    } catch (error) {
+        console.error('跳转打印页面失败:', error);
     }
 };
 onMounted(() => {

+ 231 - 0
src/plant/packaging/detail/models/relate-info-page.vue

@@ -0,0 +1,231 @@
+<template>
+    <z-paging ref="paging" bgcolor="#F7F7F7" v-model="list" @query="query" safe-area-inset-bottom scroll-with-animation>
+        <template #top>
+            <ut-navbar title="包装任务详情" :fixed="false" border></ut-navbar>
+        </template>
+        <view class="d-flex a-c pd3-30-24-0 f-s-30 f-w-5">
+            <view class="pd2-20-36 card-item-box mr-10 active">{{ form?.refType == '2' ? '打印详情' : '关联详情' }}</view>
+            <view @click="changeTebs" class="pd2-20-36 card-item-box">包装任务信息</view>
+        </view>
+        <view class="bg-fff pd-24">
+            <view class="detail-info-card p-rtv mb-40">
+                <pack-card :item="form" :dict="dict">
+                    <view class="pd-20"></view>
+                </pack-card>
+                <view class="btn-card-wrapper d-flex a-c j-c">
+                    <view class="btn-bottom-bt pm-style" @click="goPrint({ packId: form?.id, autoRelationId: form?.autoRelationId, unit: form?.unit, printedCount: form?.actualCount - form?.printCount }, '/plant/export-print/export/index')">
+                        <image class="w-32 h-32 mr-8" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/print-codes/btn_plgl_icon.png" mode="widthFix" />
+                        <span>批量关联</span>
+                    </view>
+                </view>
+            </view>
+            <view class="d-flex a-c pd2-10-0 j-ed" @click="$u.route({ url: '/tools/view-html/index', params: { url: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/template/pack_print_type.html', title: '打印方式的区别' } })">
+                <up-icon size="28rpx" name="question-circle" color="#999"></up-icon>
+                <span class="c-#999 f-s-24">三种打印方式的区别?怎么选择?</span>
+            </view>
+            <view class="mb-20">
+                <ut-tabs v-model="printType" :tabs="tabs" @change="onRefresh"></ut-tabs>
+            </view>
+            <view>
+                <template v-for="(item, index) in list" :key="index">
+                    <template v-if="item?.printType == '1'">
+                        <view class="mb-20 pd-20 bg-#F7F7F7 b-radius">
+                            <view class="f-s-28 pd2-4-0">
+                                <span class="c-#666">打印数量:</span>
+                                <span class="c-#333 f-w-5">{{ item?.printCount }}</span>
+                            </view>
+                            <view class="f-s-28 pd2-4-0 d-flex">
+                                <span class="c-#666">打印码值:</span>
+                                <view class="flex1 ov-hd c-#333 f-w-5">
+                                    <view>{{ item?.traceCodeStart }} 至</view>
+                                    <view>{{ item?.traceCodeEnd }}</view>
+                                </view>
+                            </view>
+                            <view class="d-flex f-s-24 c-#666">
+                                <view class="flex1 ov-hd">打印人:{{ item?.createByName || '-' }}</view>
+                                <view class="pr-100">打印时间:{{ item?.createTime || '-' }}</view>
+                            </view>
+                            <view class="pt-20 d-flex">
+                                <view class="flex1"></view>
+                                <view class="d-flex a-c">
+                                    <up-button @click="clickAllPrint(item)" :customStyle="formItemBtnListStyle" class="ml-20" color="#18BECA">全部打印</up-button>
+                                    <up-button @click="$u.route({ url: '/plant/print/print-range/index', params: item })" :customStyle="formItemBtnListStyle" class="ml-20" color="#37A954">区间打印</up-button>
+                                </view>
+                            </view>
+                        </view>
+                    </template>
+                    <template v-if="item?.printType == '2'">
+                        <view class="mb-20 pd-20 bg-#F7F7F7 b-radius">
+                            <view class="f-s-24 c-#333 f-w-5">{{ selectDictLabel(pt_code_export_type, item?.extraInfo?.fileType) }}</view>
+                            <view class="f-s-28 pd2-4-0">
+                                <span class="c-#666">导出数量:</span>
+                                <span class="c-#333 f-w-5">{{ item?.printCount }}</span>
+                            </view>
+                            <view class="f-s-28 pd2-4-0 d-flex">
+                                <span class="c-#666">导出码值:</span>
+                                <view class="flex1 ov-hd c-#333 f-w-5">
+                                    <view>{{ item?.traceCodeStart }} 至</view>
+                                    <view>{{ item?.traceCodeEnd }}</view>
+                                </view>
+                            </view>
+                            <view class="d-flex f-s-24 c-#666">
+                                <view class="flex1 ov-hd">导出人:{{ item?.createByName || '-' }}</view>
+                                <view class="pr-100">导出时间:{{ item?.createTime || '-' }}</view>
+                            </view>
+                            <view class="pt-20 d-flex">
+                                <view class="flex1"></view>
+                                <view class="d-flex a-c">
+                                    <up-button @click="$u.route({ url: '/plant/export-print/export/index', params: item })" :customStyle="formItemBtnListStyle" color="#18BECA">重新导出</up-button>
+                                </view>
+                            </view>
+                        </view>
+                    </template>
+                    <template></template>
+                </template>
+            </view>
+        </view>
+    </z-paging>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+import PackCard from '@/plant/models/pack-card.vue';
+import { formItemBtnListStyle } from '@/assets/styles/uview-plus';
+import { showFeatureUnavailable } from '@/utils/common';
+
+const paging = ref<any>(null);
+const props = defineProps({
+    packId: {
+        type: String,
+        default: '',
+    },
+    form: {
+        type: Object,
+        default: () => null,
+    },
+    dict: {
+        type: Object,
+        default: () => null,
+    },
+});
+const printType = ref('1');
+const { pt_pack_ref_type, pt_code_export_type } = toRefs(props?.dict);
+const emit = defineEmits(['changeTebs']);
+const tabs = reactive([
+    { label: '关联记录', value: '1' },
+]);
+const changeTebs = () => {
+    emit('changeTebs', 'pack');
+};
+const list = ref([]);
+const query = async (pageNum: number, pageSize: number) => {
+    const params = {
+        pageNum,
+        pageSize,
+        packId: props.packId,
+        printType: printType.value,
+    };
+    const res = await useClientRequest.get('/plt-api/app/printLog/list', params);
+    if (res && res?.rows) {
+        const { rows } = res;
+        paging.value?.complete(rows);
+    }
+};
+const onRefresh = () => {
+    try {
+        paging.value?.reload();
+    } catch (error) {
+        console.error('刷新列表失败:', error);
+    }
+};
+const clickAllPrint = async (item: any) => {
+    try {
+        const res = await uni.showModal({
+            title: '全部打印提示',
+            content: '您确认需要再次打印该条记录的全部追溯码吗?',
+            confirmColor: '#37A954',
+        });
+        if (res.confirm) {
+            uni.$u.route({ type: 'navigateTo', url: '/plant/print/print-all/index', params: item });
+        }
+    } catch (error) {
+        console.error('全部打印失败:', error);
+    }
+};
+const goPrint = async (params: any, url: string) => {
+    if (!params?.printedCount) {
+        uni.showModal({
+            title: '提示',
+            content: '没有可打印的追溯码了哦~',
+            showCancel: false,
+            confirmColor: '#37A954',
+        });
+        return;
+    }
+    try {
+        uni.$u.route({ type: 'navigateTo', url: url || '/plant/print/print-self/index', params });
+    } catch (error) {
+        console.error('跳转打印页面失败:', error);
+    }
+};
+onMounted(() => {
+    uni.$on('refreshPackTaskDetail', () => {
+        onRefresh();
+    });
+});
+</script>
+<style lang="scss" scoped>
+.card-item-box {
+    color: #999;
+    border-radius: 10rpx 10rpx 0 0;
+
+    &.active {
+        color: $u-primary;
+        background-color: #fff;
+    }
+}
+.detail-info-card {
+    border-radius: 16rpx;
+    border: 1rpx solid #9dd5ab;
+}
+.btn-bottom-bt {
+    width: 208rpx;
+    height: 74rpx;
+    border-radius: 8rpx;
+    border: 1px solid #000;
+    font-size: 26rpx;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+.btn-card-wrapper {
+    position: absolute;
+    left: 20rpx;
+    bottom: -37rpx;
+    right: 20rpx;
+    z-index: 10;
+}
+.ls-style {
+    background-color: #e3fbea;
+    box-shadow: inset 0 0 10px #d2f3da;
+    border-color: #9bd4a9;
+    color: #37a954;
+}
+.ss-style {
+    background-color: #e5fdff;
+    box-shadow: inset 0 0 10px #c7f5f8;
+    border-color: #93e8ee;
+    color: #18beca;
+}
+.fs-style {
+    background-color: #fffaf3;
+    box-shadow: inset 0 0 10px #ffeed7;
+    border-color: #ffd499;
+    color: #fc8834;
+}
+.pm-style {
+    background-color: #E8FDEE;
+    box-shadow: inset 0 0 10px #D2F3DA;
+    border-color: #9BD4A9;
+    color: #37A954;
+}
+</style>

+ 1 - 1
src/plant/packaging/list/index.vue

@@ -43,7 +43,7 @@
                                         <up-button :customStyle="formItemBtnListStyle" v-if="+item?.printCount" @click="$u.route({ url: '/plant/packaging/detail/index', params: { id: item?.id, viewMode: 'print' } })" class="ml-10" color="#37A954">查看打印记录</up-button>
                                     </template>
                                     <template v-if="item.refType == '1'">
-                                        <up-button :customStyle="formItemBtnListStyle" v-if="+item?.planCount - item?.actualCount" class="ml-10" color="#91C747">批量关联</up-button>
+                                        <up-button :customStyle="formItemBtnListStyle" @click="$u.route({ url: '/plant/packaging/batch-link/index', params: { packId: item?.id } })" v-if="(+item?.planCount > +item?.actualCount)" class="ml-10" color="#91C747">批量关联</up-button>
                                         <up-button :customStyle="formItemBtnListStyle" v-if="+item?.actualCount" class="ml-10" color="#91C747">查看关联记录</up-button>
                                     </template>
                                 </view>

+ 1 - 1
src/plant/processing/processing-depstock/index.vue

@@ -161,7 +161,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 4 - 4
src/plant/storage/agro-product/add/index.vue

@@ -77,7 +77,7 @@
                 <!-- 入库日期 -->
                 <view class="h-1" id="instoreDatepppp"></view>
                 <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                    <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                    <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                         <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none"
                             clearable></up-input>
                         <template #right>
@@ -104,12 +104,12 @@
                     <select-warehouse-input v-model="form.warehouses" title="添加农资存放库房" :params="{ type: '1' }"></select-warehouse-input>
                 </up-form-item>
                 <!-- 入库人 -->
-                <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                <up-form-item borderBottom label="入库人" required prop="instoreMg">
                     <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none"
                         clearable></up-input>
                 </up-form-item>
                 <!-- 入库备注 -->
-                <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                <up-form-item borderBottom label="入库备注" prop="remark">
                     <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                 </up-form-item>
             </view>
@@ -168,7 +168,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/storage/agro-product/info-edit/index.vue

@@ -229,7 +229,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 4 - 4
src/plant/storage/agro-product/info-update/index.vue

@@ -165,7 +165,7 @@
                 <!-- 入库日期 -->
                 <view class="h-1" id="instoreDatepppp"></view>
                 <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                    <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                    <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                         <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none" clearable></up-input>
                         <template #right>
                             <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -195,11 +195,11 @@
                     <select-warehouse-input v-model="form.warehouses" title="添加农资存放库房" :params="{ type: '1' }"></select-warehouse-input>
                 </up-form-item>
                 <!-- 入库人 -->
-                <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                <up-form-item borderBottom label="入库人" required prop="instoreMg">
                     <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                 </up-form-item>
                 <!-- 入库备注 -->
-                <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                <up-form-item borderBottom label="入库备注" prop="remark">
                     <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                 </up-form-item>
             </view>
@@ -305,7 +305,7 @@ const submitForm = async () => {
             try {
                 await upFormRef.value?.validate();
             } catch (error: any) {
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 4 - 4
src/plant/storage/fresh-goods/add/index.vue

@@ -64,7 +64,7 @@
                 <!-- 入库日期 -->
                 <view class="h-1" id="instoreDatepppp"></view>
                 <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                    <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                    <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                         <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none" clearable></up-input>
                         <template #right>
                             <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -87,11 +87,11 @@
                     <select-warehouse-input v-model="form.warehouses" title="添加鲜货存放库房" :params="{ type: '4' }"></select-warehouse-input>
                 </up-form-item>
                 <!-- 入库人 -->
-                <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                <up-form-item borderBottom label="入库人" required prop="instoreMg">
                     <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                 </up-form-item>
                 <!-- 入库备注 -->
-                <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                <up-form-item borderBottom label="入库备注" prop="remark">
                     <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                 </up-form-item>
             </view>
@@ -144,7 +144,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/storage/fresh-goods/info-edit/index.vue

@@ -230,7 +230,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 6 - 6
src/plant/storage/fresh-goods/info-update/index.vue

@@ -148,7 +148,7 @@
                     <!-- 入库日期 -->
                     <view class="h-1" id="instoreDatepppp"></view>
                     <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                        <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                        <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                             <up-input v-model="form.instoreBizInfo.instoreDate" placeholder="请选择入库日期" border="none" clearable></up-input>
                             <template #right>
                                 <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -169,11 +169,11 @@
                         <select-warehouse-input v-model="form.warehouses" title="添加鲜货存放库房" :params="{ type: '4' }"></select-warehouse-input>
                     </up-form-item>
                     <!-- 入库人 -->
-                    <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                    <up-form-item borderBottom label="入库人" required prop="instoreMg">
                         <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 入库备注 -->
-                    <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                    <up-form-item borderBottom label="入库备注" prop="remark">
                         <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                     </up-form-item>
                 </view>
@@ -296,11 +296,11 @@
                         <select-warehouse-input v-model="form.warehouses" title="添加鲜货存放库房" :params="{ type: '4' }"></select-warehouse-input>
                     </up-form-item>
                     <!-- 入库人 -->
-                    <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                    <up-form-item borderBottom label="入库人" required prop="instoreMg">
                         <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 入库备注 -->
-                    <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                    <up-form-item borderBottom label="入库备注" prop="remark">
                         <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                     </up-form-item>
                 </view>
@@ -375,7 +375,7 @@ const submitForm = async () => {
             try {
                 await upFormRef.value?.validate();
             } catch (error: any) {
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/storage/loss-register/index.vue

@@ -204,7 +204,7 @@ const submit = async () => {
     try {
         await upFormRef.value?.validate();
     } catch (error: any) {
-        const firstErrorField = error && error[0].prop + 'pppp';
+        const firstErrorField = error && error[0].field + 'pppp';
         paging.value?.scrollIntoViewById(firstErrorField, 30, true);
         return;
     }

+ 4 - 4
src/plant/storage/seed-source/add/index.vue

@@ -78,7 +78,7 @@
                 <!-- 入库日期 -->
                 <view class="h-1" id="instoreDatepppp"></view>
                 <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                    <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                    <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                         <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none" clearable></up-input>
                         <template #right>
                             <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -101,11 +101,11 @@
                     <select-warehouse-input v-model="form.warehouses" title="添加种源存放库房" :params="{ type: '2' }"></select-warehouse-input>
                 </up-form-item>
                 <!-- 入库人 -->
-                <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                <up-form-item borderBottom label="入库人" required prop="instoreMg">
                     <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                 </up-form-item>
                 <!-- 入库备注 -->
-                <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                <up-form-item borderBottom label="入库备注" prop="remark">
                     <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                 </up-form-item>
             </view>
@@ -160,7 +160,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 8 - 8
src/plant/storage/seed-source/info-edit/index.vue

@@ -61,7 +61,7 @@
                 <view class="h-1" id="motherFatherFlagpppp"></view>
                 <ut-action-sheet :tabs="pt_mother_father_flag" mode="custom" title="父母本情况" v-model="form.instoreBizInfo.motherFatherFlag">
                     <template v-if="['A3', 'A4'].includes(form.seedType as string) || ['3'].includes(form.seedSource as string)">
-                        <up-form-item borderBottom label="父母本情况" prop="instoreBizInfo.motherFatherFlag" required>
+                        <up-form-item borderBottom label="父母本情况" prop="motherFatherFlag" required>
                             <view v-if="form.instoreBizInfo.motherFatherFlag" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_mother_father_flag, form.instoreBizInfo.motherFatherFlag) }}</view>
                             <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择父母本情况</view>
                             <template #right>
@@ -110,7 +110,7 @@
                         </view>
                     </up-form-item>
                     <!-- 母本品种 -->
-                    <up-form-item borderBottom label="母本品种" prop="instoreBizInfo.motherVarietyId">
+                    <up-form-item borderBottom label="母本品种" prop="motherVarietyId">
                         <view class="flex1">
                             <up-button v-if="!form.instoreBizInfo.motherVarietyId" @click="selectMotherVarietyId" type="primary" plain>
                                 <image class="w-36 h-36 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/common/select_push_icon.png" mode="widthFix" />
@@ -145,14 +145,14 @@
                     <up-form-item :label="`${genCountMap[form.seedType as 'A3' | 'A4']}`" required class="form-item-bottom-padding-0">
                         <view class="d-flex flex1">
                             <view class="flex1 ov-hd">
-                                <up-form-item prop="instoreBizInfo.genCount" border-bottom class="form-item-top-padding-0">
+                                <up-form-item prop="genCount" border-bottom class="form-item-top-padding-0">
                                     <up-input v-model="form.instoreBizInfo.genCount" :placeholder="`请输入${genCountMap[form.seedType as 'A3' | 'A4']}`" border="none" clearable></up-input>
                                 </up-form-item>
                             </view>
                             <view class="pd-5"></view>
                             <view class="min-w-200">
                                 <ut-action-sheet v-model="form.instoreBizInfo.genUnit" :tabs="pt_gen_unit" mode="custom" title="选择单位">
-                                    <up-form-item prop="instoreBizInfo.genUnit" border-bottom class="form-item-top-padding-0">
+                                    <up-form-item prop="genUnit" border-bottom class="form-item-top-padding-0">
                                         <view class="flex1" style="line-height: 24px">
                                             <view v-if="form.instoreBizInfo.genUnit" class="f-s-30 c-333 f-w-5 text-center">{{ selectDictLabel(pt_gen_unit, form.instoreBizInfo.genUnit) }}</view>
                                             <view v-else class="f-s-30 c-ccc f-w-4 text-center">单位</view>
@@ -270,7 +270,7 @@
                 </up-form-item>
                 <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                 <view class="h-1" id="instoreBizInfo.idFlagpppp"></view>
-                <up-form-item borderBottom label="是否有个体标识" prop="instoreBizInfo.idFlag" required>
+                <up-form-item borderBottom label="是否有个体标识" prop="idFlag" required>
                     <up-radio-group v-model="form.instoreBizInfo.idFlag">
                         <up-radio :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in yes_no" :key="index" :label="item.label" :name="item.value"></up-radio>
                     </up-radio-group>
@@ -278,12 +278,12 @@
                 <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                 <template v-if="+form?.instoreBizInfo?.idFlag">
                     <view class="h-1" id="instoreBizInfo.animalspppp"></view>
-                    <up-form-item borderBottom label="个体标识号" prop="instoreBizInfo.animals" required>
+                    <up-form-item borderBottom label="个体标识号" prop="animals" required>
                         <AnimalsInput v-model="form.instoreBizInfo.animals"></AnimalsInput>
                     </up-form-item>
                 </template>
                 <!-- 保藏方法 -->
-                <up-form-item borderBottom label="保藏方法" prop="instoreBizInfo.storageMethod">
+                <up-form-item borderBottom label="保藏方法" prop="storageMethod">
                     <up-input v-model="form.instoreBizInfo.storageMethod" placeholder="请输入保藏方法" border="none" clearable></up-input>
                 </up-form-item>
                 <!-- 媒体与附件 -->
@@ -421,7 +421,7 @@ const submitForm = async () => {
                 await upFormRef.value?.validate();
             } catch (error: any) {
                 // 滚动到第一个错误字段
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 17 - 17
src/plant/storage/seed-source/info-update/index.vue

@@ -67,7 +67,7 @@
                     <view class="h-1" id="motherFatherFlagpppp"></view>
                     <ut-action-sheet :tabs="pt_mother_father_flag" mode="custom" title="父母本情况" v-model="form.instoreBizInfo.motherFatherFlag">
                         <template v-if="['A3', 'A4'].includes(form.seedType as string) || ['3'].includes(form.seedSource as string)">
-                            <up-form-item borderBottom label="父母本情况" prop="instoreBizInfo.motherFatherFlag" required>
+                            <up-form-item borderBottom label="父母本情况" prop="motherFatherFlag" required>
                                 <view v-if="form.instoreBizInfo.motherFatherFlag" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_mother_father_flag, form.instoreBizInfo.motherFatherFlag) }}</view>
                                 <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择父母本情况</view>
                                 <template #right>
@@ -116,7 +116,7 @@
                             </view>
                         </up-form-item>
                         <!-- 母本品种 -->
-                        <up-form-item borderBottom label="母本品种" prop="instoreBizInfo.motherVarietyId">
+                        <up-form-item borderBottom label="母本品种" prop="motherVarietyId">
                             <view class="flex1">
                                 <up-button v-if="!form.instoreBizInfo.motherVarietyId" @click="selectMotherVarietyId" type="primary" plain>
                                     <image class="w-36 h-36 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/common/select_push_icon.png" mode="widthFix" />
@@ -151,14 +151,14 @@
                         <up-form-item :label="`${genCountMap[form.seedType as 'A3' | 'A4']}`" required class="form-item-bottom-padding-0">
                             <view class="d-flex flex1">
                                 <view class="flex1 ov-hd">
-                                    <up-form-item prop="instoreBizInfo.genCount" border-bottom class="form-item-top-padding-0">
+                                    <up-form-item prop="genCount" border-bottom class="form-item-top-padding-0">
                                         <up-input v-model="form.instoreBizInfo.genCount" :placeholder="`请输入${genCountMap[form.seedType as 'A3' | 'A4']}`" border="none" clearable></up-input>
                                     </up-form-item>
                                 </view>
                                 <view class="pd-5"></view>
                                 <view class="min-w-200">
                                     <ut-action-sheet v-model="form.instoreBizInfo.genUnit" :tabs="pt_gen_unit" mode="custom" title="选择单位">
-                                        <up-form-item prop="instoreBizInfo.genUnit" border-bottom class="form-item-top-padding-0">
+                                        <up-form-item prop="genUnit" border-bottom class="form-item-top-padding-0">
                                             <view class="flex1" style="line-height: 24px">
                                                 <view v-if="form.instoreBizInfo.genUnit" class="f-s-30 c-333 f-w-5 text-center">{{ selectDictLabel(pt_gen_unit, form.instoreBizInfo.genUnit) }}</view>
                                                 <view v-else class="f-s-30 c-ccc f-w-4 text-center">单位</view>
@@ -254,7 +254,7 @@
                     </up-form-item>
                     <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                     <view class="h-1" id="idFlagpppp"></view>
-                    <up-form-item borderBottom label="是否有个体标识" prop="instoreBizInfo.idFlag" required>
+                    <up-form-item borderBottom label="是否有个体标识" prop="idFlag" required>
                         <up-radio-group v-model="form.instoreBizInfo.idFlag">
                             <up-radio :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in yes_no" :key="index" :label="item.label" :name="item.value"></up-radio>
                         </up-radio-group>
@@ -262,12 +262,12 @@
                     <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                     <view class="h-1" id="animalspppp"></view>
                     <template v-if="+form?.instoreBizInfo?.idFlag">
-                        <up-form-item borderBottom label="个体标识号" prop="instoreBizInfo.animals" required>
+                        <up-form-item borderBottom label="个体标识号" prop="animals" required>
                             <AnimalsInput v-model="form.instoreBizInfo.animals"></AnimalsInput>
                         </up-form-item>
                     </template>
                     <!-- 保藏方法 -->
-                    <up-form-item borderBottom label="保藏方法" prop="instoreBizInfo.storageMethod">
+                    <up-form-item borderBottom label="保藏方法" prop="storageMethod">
                         <up-input v-model="form.instoreBizInfo.storageMethod" placeholder="请输入保藏方法" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 媒体与附件 -->
@@ -336,7 +336,7 @@
                     <!-- 入库日期 -->
                     <view class="h-1" id="instoreDatepppp"></view>
                     <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                        <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                        <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                             <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none" clearable></up-input>
                             <template #right>
                                 <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -357,11 +357,11 @@
                         <select-warehouse-input v-model="form.warehouses" title="添加种源存放库房" :params="{ type: '2' }"></select-warehouse-input>
                     </up-form-item>
                     <!-- 入库人 -->
-                    <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                    <up-form-item borderBottom label="入库人" required prop="instoreMg">
                         <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 入库备注 -->
-                    <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                    <up-form-item borderBottom label="入库备注" prop="remark">
                         <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                     </up-form-item>
                 </view>
@@ -422,7 +422,7 @@
                     </up-form-item>
                     <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                     <view class="h-1" id="instoreBizInfo.idFlagpppp"></view>
-                    <up-form-item borderBottom label="是否有个体标识" prop="instoreBizInfo.idFlag" required>
+                    <up-form-item borderBottom label="是否有个体标识" prop="idFlag" required>
                         <up-radio-group v-model="form.instoreBizInfo.idFlag">
                             <up-radio :customStyle="{ marginRight: '60rpx' }" v-for="(item, index) in yes_no" :key="index" :label="item.label" :name="item.value"></up-radio>
                         </up-radio-group>
@@ -430,12 +430,12 @@
                     <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
                     <view class="h-1" id="instoreBizInfo.animalspppp"></view>
                     <template v-if="+form?.instoreBizInfo?.idFlag">
-                        <up-form-item borderBottom label="个体标识号" prop="instoreBizInfo.animals" required>
+                        <up-form-item borderBottom label="个体标识号" prop="animals" required>
                             <AnimalsInput v-model="form.instoreBizInfo.animals"></AnimalsInput>
                         </up-form-item>
                     </template>
                     <!-- 保藏方法 -->
-                    <up-form-item borderBottom label="保藏方法" prop="instoreBizInfo.storageMethod">
+                    <up-form-item borderBottom label="保藏方法" prop="storageMethod">
                         <up-input v-model="form.instoreBizInfo.storageMethod" placeholder="请输入保藏方法" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 媒体与附件 -->
@@ -499,7 +499,7 @@
                     <!-- 入库日期 -->
                     <view class="h-1" id="instoreDatepppp"></view>
                     <ut-datetime-picker v-model="form.instoreBizInfo.instoreDate" :maxDate="new Date()" mode="date">
-                        <up-form-item borderBottom label="入库日期" required prop="instoreBizInfo.instoreDate">
+                        <up-form-item borderBottom label="入库日期" required prop="instoreDate">
                             <up-input v-model="form.instoreBizInfo.instoreDate" readonly placeholder="请选择入库日期" border="none" clearable></up-input>
                             <template #right>
                                 <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
@@ -520,11 +520,11 @@
                         <select-warehouse-input v-model="form.warehouses" title="添加种源存放库房" :params="{ type: '2' }"></select-warehouse-input>
                     </up-form-item>
                     <!-- 入库人 -->
-                    <up-form-item borderBottom label="入库人" required prop="instoreBizInfo.instoreMg">
+                    <up-form-item borderBottom label="入库人" required prop="instoreMg">
                         <up-input v-model="form.instoreBizInfo.instoreMg" placeholder="请输入入库人" border="none" clearable></up-input>
                     </up-form-item>
                     <!-- 入库备注 -->
-                    <up-form-item borderBottom label="入库备注" prop="instoreBizInfo.remark">
+                    <up-form-item borderBottom label="入库备注" prop="remark">
                         <up-textarea v-model="form.instoreBizInfo.remark" placeholder="请输入入库备注" autoHeight></up-textarea>
                     </up-form-item>
                 </view>
@@ -629,7 +629,7 @@ const submitForm = async () => {
             try {
                 await upFormRef.value?.validate();
             } catch (error: any) {
-                const firstErrorField = error && error[0].prop + 'pppp';
+                const firstErrorField = error && error[0].field + 'pppp';
                 paging.value?.scrollIntoViewById(firstErrorField, 30, true);
                 return;
             }

+ 1 - 1
src/plant/storage/storage-room/edit/index.vue

@@ -177,7 +177,7 @@ const submit = async () => {
         await upFormRef.value?.validate();
     } catch (error: any) {
         // 滚动到第一个错误字段
-        const firstErrorField = error && error[0].prop + 'pppp';
+        const firstErrorField = error && error[0].field + 'pppp';
         paging.value?.scrollIntoViewById(firstErrorField, 30, true);
         return;
     }

+ 152 - 0
src/tools/select-code-section/index.vue

@@ -0,0 +1,152 @@
+<template>
+    <z-paging ref="paging" safe-area-inset-bottom v-model="list" bottom-bg-color="#fff" paging-class="paging-btm-shadow" @query="query">
+        <template #top>
+            <ut-navbar title="请选择追溯码" :fixed="false" :breadcrumb="false"></ut-navbar>
+            <view class="pd-20">
+                <ut-search ref="searchRef" v-model="form.keyword" @search="onRefresh" margin="0" :border="false" placeholder="搜生成批号、操作人" bgColor="#fff" height="86rpx" borderRadius="10rpx"></ut-search>
+            </view>
+        </template>
+        <view class="base-content pd-20">
+            <view :class="{ active: item.id === checkedId, disabled: isDisabled(item) }" v-for="(item, index) in list" :key="item.id" @click="clickItem(item)" class="b-radius bg-#fff pd-20 p-rtv select-item-card mb-20">
+                <image v-if="item.id === checkedId" class="w-40 h-40 checked-icon" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-lm/price/checked1.png" mode="widthFix" />
+                <view v-if="isDisabled(item)" class="disabled-tag">已选择</view>
+                <view class="f-s-28 pd2-5-0">
+                    <span class="c-#666">生成批号:</span>
+                    <span class="c-#333 f-w-500">{{ item?.batchSn || '-' }}</span>
+                </view>
+                <view class="f-s-28 pd2-5-0 d-flex">
+                    <span class="c-#666">码段:</span>
+                    <view class="f-w-500 flex1 c-#333 f-w-500">
+                        <view>{{ item?.traceCodeStart || '-' }}<span class="c-#999"> 至 </span></view>
+                        <view>{{ item?.traceCodeEnd || '-' }}</view>
+                    </view>
+                </view>
+                <view class="d-flex">
+                    <view class="f-s-28 pd2-5-0 hcol-14">
+                        <span class="c-#666">生成数量:</span>
+                        <span class="c-#333 f-w-500">{{ item?.sumCount || '-' }}个</span>
+                    </view>
+                    <view class="f-s-28 pd2-5-0 hcol-16">
+                        <span class="c-#666">剩余数量:</span>
+                        <span class="c-#333 f-w-500">{{ +item?.sumCount - +item?.useCount - +item?.voidCount || '-' }}个</span>
+                    </view>
+                </view>
+                <view class="d-flex">
+                    <view class="f-s-24 pd2-5-0 hcol-14 up-line-1">
+                        <span class="c-#666">操作人:</span>
+                        <span class="c-#666">{{ item?.operatorName || '-' }}</span>
+                    </view>
+                    <view class="f-s-24 pd2-5-0 hcol-16 up-line-1">
+                        <span class="c-#666">生成时间:</span>
+                        <span class="c-#666">{{ parseTime(item?.createTime, '{y}-{m}-{d} {h}:{i}') || '-' }}</span>
+                    </view>
+                </view>
+            </view>
+        </view>
+        <template #bottom>
+            <view class="pd-20 d-flex">
+                <up-button type="primary" @click="confirmSelect">确认选择</up-button>
+            </view>
+        </template>
+    </z-paging>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+import { parseTime } from '@/utils/ruoyi';
+const paging = ref<any>(null);
+const list = ref<any[]>([]);
+const form = ref({
+    keyword: '',
+    restFlag: '1',
+});
+const query = async (pageNum: number, pageSize: number) => {
+    const res = await useClientRequest.get('/plt-api/app/traceCodeLog/list', {
+        ...form.value,
+        pageNum: pageNum,
+        pageSize: pageSize,
+    });
+    if (res.code == 200) {
+        paging.value.complete(res.rows || []);
+    }
+};
+const checkedId = ref(null);
+const selectedIds = ref<number[]>([]);
+const isDisabled = (item: any) => selectedIds.value.includes(item?.id);
+const clickItem = (item: any) => {
+    if (isDisabled(item)) {
+        uni.showToast({
+            title: '该追溯码段已被选择',
+            icon: 'none',
+        });
+        return;
+    }
+    checkedId.value = item.id;
+};
+// 确认选择
+const confirmSelect = () => {
+    const selectedItem = list.value.find((item) => item.id === checkedId.value);
+    if (selectedItem && !isDisabled(selectedItem)) {
+        uni.$emit(opts.value.callback, selectedItem);
+        uni.navigateBack();
+    } else {
+        uni.showToast({
+            title: '请选择一项追溯码段信息',
+            icon: 'none',
+        });
+    }
+};
+const onRefresh = () => {
+    try {
+        paging.value?.reload();
+    } catch (e) {
+        console.error('Error refreshing address list:', e);
+    }
+};
+const opts = ref({
+    // 监听函数字符串
+    callback: 'refreshCodesRange',
+});
+onLoad((options: any) => {
+    console.log(options);
+    
+    opts.value.callback = options?.callback || 'refreshCodesRange';
+    if (!options?.selectedIds) return;
+    try {
+        const ids = JSON.parse(decodeURIComponent(options.selectedIds));
+        selectedIds.value = ids || [];
+    } catch (error) {
+        selectedIds.value = [];
+    }
+});
+</script>
+<style lang="scss" scoped>
+.select-item-card {
+    position: relative;
+    border: 1rpx solid #fff;
+    border-radius: 16rpx;
+    overflow: hidden;
+    .checked-icon {
+        position: absolute;
+        right: 0;
+        bottom: 0;
+    }
+    &.active {
+        border-color: $u-primary;
+        background-color: #ebf6ee;
+    }
+    &.disabled {
+        opacity: 0.55;
+        background-color: #f5f5f5;
+    }
+    .disabled-tag {
+        position: absolute;
+        right: 20rpx;
+        top: 20rpx;
+        padding: 4rpx 12rpx;
+        border-radius: 999rpx;
+        font-size: 22rpx;
+        color: #999;
+        background-color: #ececec;
+    }
+}
+</style>

+ 1 - 1
src/tools/select-gap-info/index.vue

@@ -60,7 +60,7 @@ const query = async (pageNum: number, pageSize: number) => {
     const res = await useClientRequest.get('/plt-api/app/gapCertificationInfo/pageList', {
         ...form.value,
         pageNum: pageNum,
-        pageSize: 1000,
+        pageSize,
     });
     if (res.code == 200) {
         paging.value.complete(res.rows || []);

+ 7 - 0
src/utils/common.ts

@@ -405,4 +405,11 @@ export const getDateRangeFrt = (startDate: string, endDate: string): string => {
     }
     return `${startDate}至${endDate}`;
 };
+// 功能暂未开放提示
+export const showFeatureUnavailable = (): void => {
+    uni.showToast({
+        title: '功能暂未开放,敬请期待',
+        icon: 'none',
+    });
+}
 

+ 26 - 0
src/utils/propTypes.ts

@@ -0,0 +1,26 @@
+import { CSSProperties } from 'vue';
+import VueTypes, { createTypes, toValidableType, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
+
+type PropTypes = VueTypesInterface & {
+    readonly style: VueTypeValidableDef<CSSProperties>;
+    readonly fieldOption: VueTypeValidableDef<Array<FieldOption>>;
+};
+
+const propTypes = createTypes({
+    func: undefined,
+    bool: undefined,
+    string: undefined,
+    number: undefined,
+    object: undefined,
+    integer: undefined
+}) as PropTypes;
+
+export default class ProjectTypes extends VueTypes {
+    static get style() {
+        return toValidableType('style', {
+            type: [String, Object],
+            default: undefined
+        });
+    }
+}
+export { propTypes };