lisy il y a 1 mois
Parent
commit
fd87cd9fd5

+ 4 - 0
src/assets/styles/public.scss

@@ -175,3 +175,7 @@ $colors: (
     box-shadow: 6rpx 0px 27rpx 0px rgba(#2a6d52, 0.3);
     background-color: #fff;
 }
+
+.base-shadow {
+    box-shadow: 3rpx 0px 6rpx 0px #C6D2CB;
+}

+ 74 - 15
src/components/ut-action-sheet/ut-action-sheet.vue

@@ -8,7 +8,7 @@
         <view @click="showModel = true" class="flex1">
             <slot></slot>
         </view>
-        <up-popup v-model:show="showModel" mode="center" round="30rpx" closeable @close="showModel = false">
+        <up-popup v-model:show="showModel" mode="center" round="30rpx" :safeAreaInsetBottom="false" closeable @close="showModel = false">
             <view class="w-700">
                 <view class="pd-24">
                     <view class="f-s-32 c-#333 f-w-500">{{ title }}</view>
@@ -27,6 +27,10 @@
                         </ut-row>
                     </view>
                 </scroll-view>
+                <view v-if="multiple" class="d-flex j-c pd-24">
+                    <up-button class="mr-20" @click="onCancel">取消</up-button>
+                    <up-button type="primary" @click="onConfirm">确定</up-button>
+                </view>
             </view>
         </up-popup>
     </template>
@@ -36,7 +40,8 @@ import { ref, watch, computed } from 'vue';
 
 const props = defineProps({
     modelValue: {
-        type: Array,
+        // 支持数组或字符串:多选时根据现有类型返回对应格式
+        type: [Array, String],
         default: () => [],
     },
 
@@ -64,17 +69,38 @@ const props = defineProps({
 });
 const options = computed(() => {
     return props.tabs.map((item: any) => {
+        // 如果 elTagClass正则表达式匹配的是数字,则作为span使用,否则默认10,如果是个对象字符,取span属性值
+        let span = 10;
+        //     Unexpected end of JSON input
+        // at JSON.parse (<anonymous>)
+        if (item.elTagClass) {
+            const num = Number(item.elTagClass);
+            if (!isNaN(num)) {
+                span = num;
+            } else {
+                try {
+                    const obj = JSON.parse(item.elTagClass);
+                    if (obj && obj.span) {
+                        span = obj.span;
+                    }
+                } catch (e) {
+                    // do nothing
+                }
+            }
+        }
         return {
             name: item.label,
             value: item.value,
-            span: item.elTagClass || 10,
-            remark: item.remark,
+            span,
         };
     });
 });
 const showModel = ref(false);
 const emit = defineEmits(['close', 'confirm', 'open', 'update:show', 'update:modelValue', 'change']);
 const checkeds = ref<any>({});
+// 未选择之前的
+const initialCheckeds = ref<any>({});
+
 const close = () => {
     showModel.value = false;
     // 如果有初始值,恢复初始值
@@ -82,6 +108,12 @@ const close = () => {
     emit('update:show', false);
     emit('close');
 };
+
+// 获取当前已选中的值列表
+const getSelectedValues = () => {
+    return Object.keys(checkeds.value).filter((key) => checkeds.value[key]);
+};
+
 const clickCol = (item: any) => {
     // 判断是单选还是多选
     if (props.multiple) {
@@ -103,8 +135,28 @@ const clickCol = (item: any) => {
         close();
     }
 };
-// 未选择之前的
-const initialCheckeds = ref({});
+
+// 多选确认
+const onConfirm = () => {
+    const values = getSelectedValues();
+    let out: any;
+    if (Array.isArray(props.modelValue)) {
+        out = values;
+    } else {
+        // 字符串场景下,用逗号拼接
+        out = values.join(',');
+    }
+    emit('update:modelValue', out);
+    emit('change', out);
+    // 确认后更新初始选中值
+    initialCheckeds.value = { ...checkeds.value };
+    close();
+};
+
+// 多选取消
+const onCancel = () => {
+    close();
+};
 const selectChange = (item: any) => {
     const selectedValues = options.value[item.detail.value].value;
     emit('update:modelValue', selectedValues);
@@ -116,23 +168,30 @@ watch(
     (newVal: any) => {
         // 初始化已选择项
         let selected: any = {};
-        if (props.multiple && Array.isArray(newVal)) {
-            newVal.forEach((val: any) => {
-                selected[val] = true;
-            });
-        } else if (!props.multiple && newVal != null) {
+        if (props.multiple) {
+            if (Array.isArray(newVal)) {
+                newVal.forEach((val: any) => {
+                    selected[val] = true;
+                });
+            } else if (typeof newVal === 'string' && newVal) {
+                newVal
+                    .split(/[,,]/)
+                    .map((val: string) => val.trim())
+                    .filter((val: string) => !!val)
+                    .forEach((val: string) => {
+                        selected[val] = true;
+                    });
+            }
+        } else if (newVal != null) {
             selected = {
                 [newVal as string]: true,
             };
         }
         checkeds.value = selected;
+        initialCheckeds.value = { ...selected };
     },
     { immediate: true },
 );
-onMounted(() => {
-    // 初始化已选择项
-    console.log(props.tabs);
-});
 </script>
 <style lang="scss" scoped>
 .ut-custom-item-sheet {

+ 4 - 1
src/components/ut-navbar/ut-navbar.vue

@@ -3,13 +3,14 @@
         <up-navbar :fixed="fixed" :border="border">
             <template #left>
                 <slot name="left">
-                    <view class="d-flex a-c">
+                    <view class="d-flex a-c" v-if="isLeftBack">
                         <up-icon v-if="showBack" name="arrow-left" size="40rpx" color="#333" @click="handleBackClick"></up-icon>
                         <up-icon v-else name="home" size="40rpx" color="#333" @click="handleHomeClick"></up-icon>
                         <slot name="leftText">
                             <text class="f-s-38 c-#333 f-w-500 ml-20">{{ leftText }}</text>
                         </slot>
                     </view>
+                    <span v-else></span>
                 </slot>
             </template>
             <template #center>
@@ -38,6 +39,7 @@ const props = withDefaults(
         leftText?: string;
         // 是否有面包屑
         breadcrumb?: boolean;
+        isLeftBack?: boolean;
     }>(),
     {
         title: '',
@@ -46,6 +48,7 @@ const props = withDefaults(
         homeUrl: '/pages/index/index',
         leftText: '',
         breadcrumb: true,
+        isLeftBack: true,
     }
 );
 

+ 12 - 70
src/components/ut-tabar/ut-tabar.vue

@@ -1,92 +1,34 @@
 <template>
-    <up-popup v-model:show="showStorage" title="仓储与放行" bgColor="#F7F7F7" round="0" zIndex="1000" closeable>
-        <view class="min-h-600">
-            <view class="c-#333 f-s-34 f-w-500 pd-24">仓储与放行</view>
-            <view class="pd2-10-24">
-                <up-grid :border="false" :column="3" gap="10rpx">
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c" @click="showStorage = false;$u.route({ url: '/plant/storage/storage-room/list/index' })">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_kfgl_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">库房管理</view>
-                        </view>
-                    </up-grid-item>
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_nzk_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">农资库</view>
-                        </view>
-                    </up-grid-item>
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c" @click="showStorage = false;$u.route({ url: '/plant/storage/seed-source/list/index' })">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_zyk_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">种源库</view>
-                        </view>
-                    </up-grid-item>
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_xhk_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">鲜货库</view>
-                        </view>
-                    </up-grid-item>
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_zjpk_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">中间品库</view>
-                        </view>
-                    </up-grid-item>
-                    <up-grid-item>
-                        <view class="pd2-10-0 d-flex flex-cln a-c j-c">
-                            <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
-                                <image class="w-72 h-72" src="@/static/images/plant/storage/nav_cpk_icon.png" mode="widthFix" />
-                            </view>
-                            <view class="c-#333 f-s-28 text-center">成品库</view>
-                        </view>
-                    </up-grid-item>
-                </up-grid>
-            </view>
-            <view class="h-210"></view>
-        </view>
-    </up-popup>
     <view class="w-100%" style="position: fixed; bottom: 0; left: 0; z-index: 1100">
         <view class="p-rtv" style="height: 210rpx">
             <image class="w-100%" src="/static/images/plant/bottombg.png" mode="widthFix" style="position: absolute; bottom: 0; left: 0; z-index: -1" />
             <view class="d-flex h-140 w-100% j-sa" style="position: absolute; bottom: 0; left: 0">
                 <view class="d-flex a-c flex1 j-sa">
                     <view @click="showStorage = false;$u.route({ type: 'switchTab', url: '/pages/plant/base/index' })" class="c-#999 f-s-24 d-flex flex-cln j-c a-c">
-                        <image v-if="activeTab === 'base' && !showStorage" class="w-80 h-80" src="/static/images/plant/bottomBaseActive.png" mode="widthFix" />
+                        <image v-if="activeTab === 'base'" class="w-80 h-80" src="/static/images/plant/bottomBaseActive.png" mode="widthFix" />
                         <image v-else class="w-80 h-80" src="/static/images/plant/bottomBase.png" mode="widthFix" />
-                        <view class="text-center" :class="activeTab === 'base' && !showStorage ? 'c-primary f-w-5' : ''">基地</view>
+                        <view class="text-center" :class="activeTab === 'base' ? 'c-primary f-w-5' : ''">基地</view>
                     </view>
                     <view @click="showStorage = false;$u.route({ type: 'switchTab', url: '/pages/plant/port/index' })" class="c-#999 f-s-24 d-flex flex-cln j-c a-c">
-                        <image v-if="activeTab === 'planting' && !showStorage" class="w-80 h-80" src="/static/images/plant/bottomPlantingBreedingActive.png" mode="widthFix" />
+                        <image v-if="activeTab === 'planting'" class="w-80 h-80" src="/static/images/plant/bottomPlantingBreedingActive.png" mode="widthFix" />
                         <image v-else class="w-80 h-80" src="/static/images/plant/bottomPlantingBreeding.png" mode="widthFix" />
-                        <view class="text-center" :class="activeTab === 'planting' && !showStorage ? 'c-primary f-w-5' : ''">种养殖</view>
+                        <view class="text-center" :class="activeTab === 'planting' ? 'c-primary f-w-5' : ''">种养殖</view>
                     </view>
                 </view>
-                <view class="w-126 d-flex a-c j-c p-rtv" @click="showStorage = !showStorage">
-                    <image v-if="!showStorage" class="w-80 h-80" src="/static/images/plant/bottomWarehouse.png" mode="widthFix" style="position: absolute; top: -40rpx" />
-                    <image v-else class="w-80 h-80" src="/static/images/plant/bottomWarehouseActive.png" mode="widthFix" style="position: absolute; top: -40rpx" />
+                <view class="w-126 d-flex a-c j-c p-rtv" @click="$u.route({ type: 'switchTab', url: '/pages/plant/storage/index' })">
+                    <image v-if="activeTab === 'storage'" class="w-80 h-80" src="/static/images/plant/bottomWarehouseActive.png" mode="widthFix" style="position: absolute; top: -40rpx" />
+                    <image  v-else class="w-80 h-80" src="/static/images/plant/bottomWarehouse.png" mode="widthFix" style="position: absolute; top: -40rpx" />
                 </view>
                 <view class="d-flex a-c flex1 j-sa">
                     <view class="c-#999 f-s-24 d-flex flex-cln j-c a-c">
-                        <image v-if="activeTab === 'processing' && !showStorage" class="w-80 h-80" src="/static/images/plant/bottomProcessingPackagingActive.png" mode="widthFix" />
+                        <image v-if="activeTab === 'processing'" class="w-80 h-80" src="/static/images/plant/bottomProcessingPackagingActive.png" mode="widthFix" />
                         <image v-else class="w-80 h-80" src="/static/images/plant/bottomProcessingPackaging.png" mode="widthFix" />
-                        <view class="text-center" :class="activeTab === 'processing'  && !showStorage ? 'c-primary f-w-5' : ''">加工包装</view>
+                        <view class="text-center" :class="activeTab === 'processing' ? 'c-primary f-w-5' : ''">加工包装</view>
                     </view>
-                    <view class="c-#999 f-s-24 d-flex flex-cln j-c a-c">
-                        <image v-if="activeTab === 'more' && !showStorage" class="w-80 h-80" src="/static/images/plant/bottomMoreActive.png" mode="widthFix" />
+                    <view @click="$u.route({ type: 'switchTab', url: '/pages/plant/more/index' })" class="c-#999 f-s-24 d-flex flex-cln j-c a-c">
+                        <image v-if="activeTab === 'more'" class="w-80 h-80" src="/static/images/plant/bottomMoreActive.png" mode="widthFix" />
                         <image v-else class="w-80 h-80" src="/static/images/plant/bottomMore.png" mode="widthFix" />
-                        <view class="text-center" :class="activeTab === 'more' && !showStorage ? 'c-primary f-w-5' : ''">更多</view>
+                        <view class="text-center" :class="activeTab === 'more' ? 'c-primary f-w-5' : ''">更多</view>
                     </view>
                 </view>
             </view>

+ 113 - 69
src/components/ut-tabs/ut-tabs.vue

@@ -1,52 +1,79 @@
 <template>
     <template v-if="mode == 'scroll-x'">
-        <scroll-view scroll-x class="ut-tabs-scroll" show-scrollbar="false" :scroll-into-view-offset="SCROLL_OFFSET"
-            :scroll-into-view="scrollIntoView" ref="scrollViewRef" scroll-with-animation>
-            <view class="ut-tabs-row">
-                <view v-for="(tab, idx) in tabs" :key="tab.value" :id="'tab-' + idx" class="ut-tab-item p-rtv"
-                    :class="{ active: idx === activeIndex }" @click="selectTab(idx)" ref="tabRefs">
-                    <view class="tab-label" :style="{
-                        fontSize: fontSize,
-                        color: idx === activeIndex ? themeColor : '#999',
-                        fontWeight: idx === activeIndex ? 'bold' : '500'
-                    }">
+        <scroll-view scroll-x class="ut-tabs-scroll" show-scrollbar="false" :scroll-into-view-offset="SCROLL_OFFSET" :scroll-into-view="scrollIntoView" ref="scrollViewRef" scroll-with-animation>
+            <view class="ut-tabs-row gap-30">
+                <view v-for="(tab, idx) in tabs" :key="tab.value" :id="'tab-' + idx" class="ut-tab-item p-rtv" :class="{ active: idx === activeIndex }" @click="selectTab(idx)" ref="tabRefs">
+                    <view
+                        class="tab-label"
+                        :style="{
+                            fontSize: fontSize,
+                            color: idx === activeIndex ? themeColor : '#999',
+                            fontWeight: idx === activeIndex ? 'bold' : '500',
+                        }"
+                    >
+                        <span>{{ tab.label }}</span>
+                        <view v-if="tab.badge && (tab.num as number) > 0" class="tab-badge">{{ tab.num }}</view>
+                    </view>
+                    <view
+                        v-if="idx === activeIndex"
+                        class="tab-underline"
+                        :style="{
+                            background: themeColor,
+                            height: lineHeight,
+                        }"
+                    ></view>
+                </view>
+            </view>
+        </scroll-view>
+    </template>
+    <template v-if="mode == 'scroll-x-card'">
+        <scroll-view scroll-x class="ut-tabs-scroll" show-scrollbar="false" :scroll-into-view-offset="SCROLL_OFFSET" :scroll-into-view="scrollIntoView" ref="scrollViewCardRef" scroll-with-animation>
+            <view class="ut-tabs-row gap-20">
+                <view v-for="(tab, idx) in tabs" :key="tab.value" :id="'tab-' + idx" class="ut-tab-item-card gap-20 p-rtv" :class="{ active: idx === activeIndex }" @click="selectTab(idx)" ref="tabCardRefs">
+                    <view
+                        class="tab-label-card d-flex j-c a-c pd2-0-24 min-w-150"
+                        :style="{
+                            fontSize: fontSize,
+                            color: idx === activeIndex ? '#fff' : '#333',
+                            background: idx === activeIndex ? themeColor : '#fff',
+                        }"
+                    >
                         <span>{{ tab.label }}</span>
-                        <view v-if="tab.badge && tab.num as number > 0" class="tab-badge">{{ tab.num }}</view>
                     </view>
-                    <view v-if="idx === activeIndex" class="tab-underline" :style="{
-                        background: themeColor,
-                        height: lineHeight
-                    }"></view>
                 </view>
             </view>
         </scroll-view>
     </template>
     <template v-if="mode == 'btw'">
-        <view class="ut-tabs-row" :style="{ justifyContent: 'space-between' }">
-            <view v-for="(tab, idx) in tabs" :key="tab.value" class="ut-tab-item p-rtv"
-                :class="{ active: idx === activeIndex }" @click="selectTab(idx)" ref="tabRefs">
-                <view class="tab-label" :style="{
-                    fontSize: fontSize,
-                    color: idx === activeIndex ? themeColor : '#999',
-                    fontWeight: idx === activeIndex ? 'bold' : '500'
-                }">
+        <view class="ut-tabs-row gap-20" :style="{ justifyContent: 'space-between' }">
+            <view v-for="(tab, idx) in tabs" :key="tab.value" class="ut-tab-item p-rtv" :class="{ active: idx === activeIndex }" @click="selectTab(idx)" ref="tabRefs">
+                <view
+                    class="tab-label"
+                    :style="{
+                        fontSize: fontSize,
+                        color: idx === activeIndex ? themeColor : '#999',
+                        fontWeight: idx === activeIndex ? 'bold' : '500',
+                    }"
+                >
                     <span>{{ tab.label }}</span>
-                    <view v-if="tab.badge && tab.num as number > 0" class="tab-badge">{{ tab.num }}</view>
+                    <view v-if="tab.badge && (tab.num as number) > 0" class="tab-badge">{{ tab.num }}</view>
                 </view>
-                <view v-if="idx === activeIndex" class="tab-underline" :style="{
-                    background: themeColor,
-                    height: lineHeight
-                }"></view>
+                <view
+                    v-if="idx === activeIndex"
+                    class="tab-underline"
+                    :style="{
+                        background: themeColor,
+                        height: lineHeight,
+                    }"
+                ></view>
             </view>
         </view>
     </template>
     <template v-if="mode == 'subsection'">
         <view class="tabs-subsection-wrap d-flex">
             <template v-for="(item, idx) in tabs" :key="idx">
-                <view class="flex1 subsection-item d-flex p-rtv j-c a-c f-s-32 c-999"  @click="selectTab(idx)" :class="{ active: idx === activeIndex }">
-                    <slot :name="item.value" :active="idx === activeIndex">
-                        {{ item.label }}
-                    </slot>
+                <view class="flex1 subsection-item d-flex p-rtv j-c a-c f-s-32 c-999" @click="selectTab(idx)" :class="{ active: idx === activeIndex }">
+                    <slot :name="item.value" :active="idx === activeIndex">{{ item.label }}</slot>
                 </view>
             </template>
         </view>
@@ -54,60 +81,68 @@
 </template>
 
 <script setup lang="ts">
-
 const props = defineProps({
     tabs: {
-        type: Array as () => Array<{ label: string; value: string; badge?: boolean; num?: number }>,
-        default: () => []
+        type: Array as () => Array<{
+            label: string;
+            value: string;
+            badge?: boolean;
+            num?: number;
+        }>,
+        default: () => [],
     },
     modelValue: {
         type: [String, Number],
-        default: ''
+        default: '',
     },
     themeColor: {
         type: String,
-        default: '#37A954'
+        default: '#37A954',
     },
     fontSize: {
         type: String,
-        default: '30rpx'
+        default: '30rpx',
     },
     lineHeight: {
         type: String,
-        default: '6rpx'
+        default: '6rpx',
     },
     mode: {
         type: String,
-        default: 'scroll-x' // btw subsection
-    }
-})
+        default: 'scroll-x', // btw subsection scroll-x-card
+    },
+});
 const SCROLL_OFFSET = ref(-(uni as any).$u?.getPx('200rpx'));
-const emit = defineEmits(['update:modelValue', 'change'])
-
-const activeIndex = ref(0)
-const scrollIntoView = ref('')
-const scrollViewRef = ref(null)
-const tabRefs = ref([])
-
-watch(() => props.modelValue, (val: any) => {
-    const idx = props.tabs.findIndex(tab => tab.value === val)
-    if (idx !== -1) {
-        activeIndex.value = idx
-        scrollToTab(idx)
-    }
-})
+const emit = defineEmits(['update:modelValue', 'change']);
+
+const activeIndex = ref(0);
+const scrollIntoView = ref('');
+const scrollViewRef = ref(null);
+const scrollViewCardRef = ref(null);
+const tabRefs = ref([]);
+
+watch(
+    () => props.modelValue,
+    (val: any) => {
+        const idx = props.tabs.findIndex((tab) => tab.value === val);
+        if (idx !== -1) {
+            activeIndex.value = idx;
+            scrollToTab(idx);
+        }
+    },
+);
 
 const selectTab = (idx: number) => {
-    activeIndex.value = idx
-    emit('update:modelValue', props.tabs[idx].value)
-    emit('change', props.tabs[idx])
-    scrollToTab(idx)
-}
+    activeIndex.value = idx;
+    emit('update:modelValue', props.tabs[idx].value);
+    emit('change', props.tabs[idx]);
+    scrollToTab(idx);
+};
 
 // 主动滚动到选中tab
 const scrollToTab = (idx: number) => {
-    scrollIntoView.value = 'tab-' + idx
-}
+    scrollIntoView.value = 'tab-' + idx;
+};
 </script>
 
 <style lang="scss" scoped>
@@ -132,7 +167,6 @@ const scrollToTab = (idx: number) => {
     font-weight: 500;
     color: #666;
     cursor: pointer;
-    padding: 0 24rpx;
 
     .tab-label {
         position: relative;
@@ -160,20 +194,30 @@ const scrollToTab = (idx: number) => {
             box-sizing: border-box;
             z-index: 2;
         }
-
-
     }
 
     .tab-underline {
         position: absolute;
-        left: 24rpx;
-        right: 24rpx;
+        left: 0rpx;
+        right: 0rpx;
         bottom: 0;
         border-radius: 3rpx;
         transition: width 0.2s;
         z-index: 1;
     }
 }
+
+.ut-tab-item-card {
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    .tab-label-card {
+        box-sizing: border-box;
+        border-radius: 28rpx;
+        height: 54rpx;
+    }
+}
+
 .tabs-subsection-wrap {
     height: 88rpx;
     border-radius: 10rpx;
@@ -181,7 +225,7 @@ const scrollToTab = (idx: number) => {
     overflow: hidden;
 
     .active.subsection-item {
-        background-color: #37A954;
+        background-color: #37a954;
         color: #fff;
     }
 }

+ 74 - 0
src/components/ut-tag-dict/ut-tag-dict.vue

@@ -0,0 +1,74 @@
+<template>
+    <view class="ut-tag-dict-wrap">
+        <template v-for="(item, index) in list" :key="item.value">
+            <view class="dict-item-tab" :style="itemStyle(item?.elTagClass as string)">{{ item?.label }}</view>
+        </template>
+    </view>
+</template>
+<script setup lang="ts">
+const props = defineProps({
+    value: {
+        type: [String, Array],
+        default: '',
+    },
+    options: {
+        type: Array as () => Array<DictDataOption>,
+        default: () => [],
+    },
+});
+const list = computed(() => {
+    const val = props.value;
+    let arr: Array<DictDataOption> = [];
+    if (Array.isArray(val)) {
+        val.forEach((v) => {
+            const item = props.options.find((item) => item.value === v);
+            if (item) {
+                arr.push(item);
+            }
+        });
+        return arr;
+    } else {
+        // 值是string也可能是多个‘,’分隔
+        const vals = String(val).split(',');
+        vals.forEach((v) => {
+            const item = props.options.find((item) => item.value === v);
+            if (item) {
+                arr.push(item);
+            }
+        });
+        return arr;
+    }
+});
+const itemStyle = (elTagClass: string) => {
+    if (elTagClass) {
+        const num = Number(elTagClass);
+        if (!isNaN(num)) {
+            return {};
+        } else {
+            try {
+                const obj = JSON.parse(elTagClass);
+                return obj;
+            } catch (e) {
+                // do nothing
+            }
+        }
+    }
+    return {};
+};
+</script>
+<style lang="scss" scoped>
+.ut-tag-dict-wrap {
+    display: inline-flex;
+    flex-wrap: wrap;
+    gap: 24rpx;
+
+    .dict-item-tab {
+        padding: 6rpx 16rpx;
+        font-size: 20rpx;
+        color: #333;
+        background-color: #f7f7f7;
+        border-radius: 18rpx;
+        font-weight: 500;
+    }
+}
+</style>

+ 65 - 0
src/models/contact-unit-input/contact-unit-input.vue

@@ -0,0 +1,65 @@
+<template>
+    <up-button v-if="!modelValue" type="primary" @click="selectContactUnitShow = true" plain>
+        <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png" mode="widthFix" />
+        <span>{{ placeholder }}</span>
+    </up-button>
+    <view v-else class="bg-#FBFDFB card-info-block pd-24 p-rtv mt-16">
+        <view>
+            <view class="f-s-34 c-#333 f-w-500">{{ info?.cusName }}</view>
+            <view class="f-s-24 c-#666">{{ info?.cusCode }}</view>
+        </view>
+        <view
+            class="close-icon pd-16"
+            @click="emit('update:modelValue', '');emit('update:info', null)"
+        >
+            <up-icon color="#F81242" name="close" size="32rpx"></up-icon>
+        </view>
+    </view>
+    <SelectContactUnit v-if="selectContactUnitShow" :title="title" v-model:show="selectContactUnitShow" :params="params" @confirm="confirmSelection"></SelectContactUnit>
+</template>
+<script setup lang="ts">
+import SelectContactUnit from '../select-contact-unit/select-contact-unit.vue';
+
+const props = defineProps({
+    modelValue: {
+        type: String,
+        default: () => '',
+    },
+    title: {
+        type: String,
+        default: '选择往来单位',
+    },
+    placeholder: {
+        type: String,
+        default: '请选择往来单位信息',
+    },
+    info: {
+        type: Object,
+        default: () => ({}),
+    },
+    params: {
+        type: Object,
+        default: () => ({}),
+    },
+});
+const selectContactUnitShow = ref(false);
+
+const emit = defineEmits(['update:modelValue', 'update:info', 'change']);
+const confirmSelection = (info: any) => {
+    emit('update:modelValue', info.id);
+    emit('update:info', info);
+    emit('change', info);
+};
+</script>
+<style scoped lang="scss">
+.close-icon {
+    position: absolute;
+    top: 0;
+    right: 0;
+    z-index: 10;
+}
+.card-info-block {
+    border: 1rpx solid #afddbb;
+    border-radius: 10rpx;
+}
+</style>

+ 142 - 0
src/models/select-contact-unit/select-contact-unit.vue

@@ -0,0 +1,142 @@
+<template>
+    <up-popup :show="show" mode="right" @close="close">
+        <view class="w-680 p-rtv" style="height: 100vh">
+            <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" :fixed="false" @query="query" safe-area-inset-bottom>
+                <template #top>
+                    <up-navbar :fixed="false" border>
+                        <template #left>
+                            <view class="f-s-34 c-#333 f-w-500">{{ title }}</view>
+                        </template>
+                    </up-navbar>
+                    <view class="pd3-10-24-10">
+                        <ut-tabs :tabs="[{ label: '全部', value: '' }, ...pt_cus_type]" v-model="form.cusType" @change="onRefresh"></ut-tabs>
+                        <view class="pd-10"></view>
+                        <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>
+                <template>
+                    <view class="pd-24">
+                        <up-swipe-action>
+                            <template v-for="item in list" :key="item?.id">
+                                <view @click="clickRow(item)" class="b-radius bg-#fff pd-24 p-rtv select-item mb-20" :class="{ 'active': item?.id === checkedId }">
+                                    <view class="d-flex j-sb a-c li-item-head mb-16">
+                                        <view class="li-left-tag">{{ selectDictLabel(pt_cus_type, item?.cusType) }}</view>
+                                        <view class="f-s-22 c-#666">{{ item?.updateTime || item?.createTime }}</view>
+                                    </view>
+                                    <view class="f-s-34 c-#333 f-w-500">{{ item?.cusName }}</view>
+                                    <view class="f-s-24 c-#666">{{ item?.cusCode }}</view>
+                                    <view class="pd-5"></view>
+                                    <view class="f-s-28 pd2-5-0">
+                                        <span class="c-#666">联系电话:</span>
+                                        <span class="c-#333 f-w-600">{{ item?.contactTel }}</span>
+                                    </view>
+                                    <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>
+                            </template>
+                        </up-swipe-action>
+                    </view>
+                </template>
+                <!-- 空数据处理 -->
+
+                <template #empty>
+                    <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx">暂无往来单位信息,点击+号新增吧</ut-empty>
+                </template>
+                <template #bottom>
+                    <view class="pd-24 bg-#fff d-flex">
+                        <up-button @click="close" class="mr-30" color="#F2F2F2" style="color: #333;">取消</up-button>
+                        <up-button @click="confirmSelection" type="primary">确认选择</up-button>
+                    </view>
+                </template>
+            </z-paging>
+        </view>
+    </up-popup>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const {  pt_cus_type, pt_cpy_type } = toRefs<any>(proxy?.useDict('pt_cus_type', 'pt_cpy_type'));
+const paging = ref();
+const props = defineProps({
+    params: {
+        type: Object,
+        default: () => ({}),
+    },
+    show: {
+        type: Boolean,
+        default: false,
+    },
+    title: {
+        type: String,
+        default: '选择往来单位',
+    },
+});
+
+const form = ref({
+    keyword: '',
+    cusType: '',
+});
+const checkedId = ref(null);
+const checkedInfo = ref<any>(null);
+const emit = defineEmits(['update:show', 'confirm']);
+const list = ref<any[]>([]);
+const query = async (pageNum: number, pageSize: number) => {
+    const params = {
+        pageNum,
+        pageSize,
+        ...props.params,
+        ...form.value,
+    };
+    const res = await useClientRequest.get<any>('/plt-api/app/customer/list', params);
+    if (!res || res.code !== 200) return;
+    const { rows } = res;
+    paging.value?.complete(rows);
+};
+const confirmSelection = () => {
+    if (checkedInfo.value) {
+        emit('confirm', checkedInfo.value);
+        close();
+    } else {
+        uni.showToast({
+            title: '请' + props.title,
+            icon: 'none',
+        });
+    }
+};
+const clickRow = (item: any) => {
+    checkedId.value = item.id;
+    checkedInfo.value = item;
+};
+const close = () => {
+    emit('update:show', false);
+};
+const onRefresh = () => {
+    paging.value?.reload();
+};
+</script>
+<style scoped lang="scss">
+.li-item-head {
+    margin-left: -24rpx;
+    margin-top: -24rpx;
+}
+.li-left-tag {
+    padding: 4rpx 12rpx;
+    background-color: #ebf6ee;
+    color: #37a954;
+    border-radius: 16rpx 0 16rpx 0;
+    font-size: 20rpx;
+    font-weight: 500;
+}
+.select-item {
+    border: 1rpx solid #fff;
+
+    &.active {
+        border-color: $u-primary;
+        background-color: rgba($u-primary, 0.1);
+    }
+    .checked-icon {
+        position: absolute;
+        right: 0;
+        bottom: 0;
+    }
+}
+</style>

+ 44 - 0
src/pages.json

@@ -17,6 +17,20 @@
                 "navigationBarTitleText": "种植端基地"
             }
         },
+        // 种植端仓储与放行
+        {
+            "path": "pages/plant/storage/index",
+            "style": {
+                "navigationBarTitleText": "种植端仓储与放行"
+            }
+        },
+        // 种植端更多
+        {
+            "path": "pages/plant/more/index",
+            "style": {
+                "navigationBarTitleText": "种植端更多"
+            }
+        },
         //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
         {
             "path": "pages/index/index",
@@ -213,6 +227,30 @@
                 }
             ]
         },
+        // 往来单位管理
+        {
+            "root": "plant/contact-unit",
+            "pages": [
+                {
+                    "path": "unit-list/index",
+                    "style": {
+                        "navigationBarTitleText": "往来单位管理"
+                    }
+                },
+                {
+                    "path": "unit-edit/index",
+                    "style": {
+                        "navigationBarTitleText": "新增往来单位信息"
+                    }
+                },
+                {
+                    "path": "unit-detail/index",
+                    "style": {
+                        "navigationBarTitleText": "往来单位详情"
+                    }
+                }
+            ]
+        },
         {
             "root": "tools",
             "pages": [
@@ -297,6 +335,12 @@
             },
             {
                 "pagePath": "pages/plant/port/index"
+            },
+            {
+                "pagePath": "pages/plant/storage/index"
+            },
+            {
+                "pagePath": "pages/plant/more/index"
             }
         ]
     },

+ 22 - 0
src/pages/plant/more/index.vue

@@ -0,0 +1,22 @@
+<template>
+    <z-paging ref="paging" bgColor="#fff">
+        <template #top>
+            <ut-navbar title="更多" :fixed="false" :isLeftBack="false" :breadcrumb="false"></ut-navbar>
+        </template>
+        <view class="base-content pd-20">
+            <up-grid :border="false" :column="3" gap="10rpx">
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c" @click="$u.route({ url: '/plant/contact-unit/unit-list/index' })">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_kfgl_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">往来单位管理</view>
+                    </view>
+                </up-grid-item>
+            </up-grid>
+        </view>
+    </z-paging>
+    <ut-tabar activeTab="more"></ut-tabar>
+</template>
+<script setup lang="ts"></script>
+<style lang="scss" scoped></style>

+ 62 - 0
src/pages/plant/storage/index.vue

@@ -0,0 +1,62 @@
+<template>
+    <z-paging ref="paging" bgColor="#fff">
+        <template #top>
+            <ut-navbar title="仓储与放行" :fixed="false" :isLeftBack="false" :breadcrumb="false"></ut-navbar>
+        </template>
+        <view class="base-content pd-20">
+            <up-grid :border="false" :column="3" gap="10rpx">
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c" @click="$u.route({ url: '/plant/storage/storage-room/list/index' })">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_kfgl_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">库房管理</view>
+                    </view>
+                </up-grid-item>
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_nzk_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">农资库</view>
+                    </view>
+                </up-grid-item>
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c" @click="$u.route({ url: '/plant/storage/seed-source/list/index' })">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_zyk_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">种源库</view>
+                    </view>
+                </up-grid-item>
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_xhk_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">鲜货库</view>
+                    </view>
+                </up-grid-item>
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_zjpk_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">中间品库</view>
+                    </view>
+                </up-grid-item>
+                <up-grid-item>
+                    <view class="pd2-10-0 d-flex flex-cln a-c j-c">
+                        <view class="w-109 h-109 bg-#fff radius-50% d-flex a-c j-c mb-10">
+                            <image class="w-72 h-72" src="@/static/images/plant/storage/nav_cpk_icon.png" mode="widthFix" />
+                        </view>
+                        <view class="c-#333 f-s-28 text-center">成品库</view>
+                    </view>
+                </up-grid-item>
+            </up-grid>
+        </view>
+    </z-paging>
+    <ut-tabar activeTab="storage"></ut-tabar>
+</template>
+<script setup lang="ts"></script>
+<style lang="scss" scoped></style>

+ 289 - 292
src/plant/base/base-detail/index.vue

@@ -1,329 +1,326 @@
 <template>
-    <view class="ksqulc">
-        <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="bg-fff mb-20">
-                    <view class="pd-5"></view>
-                    <ut-tabs v-model="activeTab" :tabs="tabs" mode="btw" @change="changeActiveTab"></ut-tabs>
+    <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="bg-fff mb-20 pd2-0-24">
+                <view class="pd-5"></view>
+                <ut-tabs v-model="activeTab" :tabs="tabs" mode="btw" @change="changeActiveTab"></ut-tabs>
+            </view>
+        </template>
+        <view class="p-rtv">
+            <!-- 基本信息 -->
+            <view ref="baseRef" class="pd-24" id="base12345">
+                <view class="startline-title">基本信息</view>
+            </view>
+            <view class="pd-24 bg-#fff mb-10">
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地类型:</span>
+                    <span class="c-#333">{{ selectDictLabel(pt_base_type, form?.baseInfo?.baseType) || '-' }}</span>
                 </view>
-            </template>
-            <view class="p-rtv">
-                <!-- 基本信息 -->
-                <view ref="baseRef" class="pd-24" id="base12345">
-                    <view class="startline-title">基本信息</view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地名称:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.baseName || '-' }}</span>
                 </view>
-                <view class="pd-24 bg-#fff mb-10">
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地编号:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.baseCode || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">建设时间:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.buildDate || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地组织方式:</span>
+                    <span class="c-#333">{{ selectDictLabel(pt_org_type, form?.baseInfo?.orgType) || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地负责人:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.contactName || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">联系电话:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.contactTel || '-' }}</span>
+                </view>
+                <template v-if="['1', '2'].includes(form?.baseInfo?.baseType)">
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地类型:</span>
-                        <span class="c-#333">{{ selectDictLabel(pt_base_type, form?.baseInfo?.baseType) || '-' }}</span>
+                        <span class="c-#666">是否为GAP基地:</span>
+                        <span class="c-#333">{{ selectDictLabel(yes_no, form?.baseInfo?.gapFlag) || '-' }}</span>
                     </view>
-                    <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地名称:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.baseName || '-' }}</span>
+                    <view v-if="form?.baseInfo?.gapId" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">关联GAP信息:</view>
+                        <view class="bg-#FBFDFB pd-24 p-rtv flex1 radius-10 gap-info-card">
+                            <view class="f-s-32 f-w-500 c-#333">{{ form?.baseInfo?.gapInfo?.gapBaseName || '-' }}</view>
+                            <view class="f-s-24 c-#ccc mb-10">{{ form?.baseInfo?.gapInfo?.ratedDate }}获评</view>
+                            <view class="d-flex gap-10 flex-wrap">
+                                <view class="w-330 f-s-28">
+                                    <span class="c-#666">申报品种:</span>
+                                    <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.medicineName }}</span>
+                                </view>
+                                <view class="w-290 f-s-28">
+                                    <span class="c-#666">基地面积:</span>
+                                    <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.area }}{{ form?.baseInfo?.gapInfo?.areaUnit }}</span>
+                                </view>
+                                <view class="f-s-28">
+                                    <span class="c-#666">基地地址:</span>
+                                    <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.adcodeName }} {{ form?.baseInfo?.gapInfo?.address || '-' }}</span>
+                                </view>
+                            </view>
+                        </view>
                     </view>
-                    <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地编号:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.baseCode || '-' }}</span>
+                </template>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地所在地区:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.gapInfo?.adcodeName || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">详细地址:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.gapInfo?.address || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <view class="f-s-30 c-#666 mb-10">基地范围:</view>
+                    <view class="bg-#f7f7f7 d-flex ov-hd p-rtv">
+                        <image @click="previewImage([form?.baseInfo?.gapInfo?.basePic])" class="w-full" v-if="form?.baseInfo?.gapInfo?.basePic" preview :src="form?.baseInfo?.gapInfo?.basePic" mode="'widthFix'"></image>
+                        <view v-else class="w-full h-120 d-flex a-c j-c c-999">暂无基地范围</view>
                     </view>
-                    <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">建设时间:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.buildDate || '-' }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地面积:</span>
+                    <span class="c-#333">{{ form?.baseInfo?.gapInfo?.area || '-' }}{{ form?.baseInfo?.gapInfo?.areaUnit || mapUnitByBaseType[form?.baseInfo?.baseType || '1'] }}</span>
+                </view>
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">基地经纬度:</span>
+                    <span class="c-#333">E{{ form?.baseInfo?.gapInfo?.lng || '-' }}, N{{ form?.baseInfo?.gapInfo?.lat || '-' }}</span>
+                </view>
+            </view>
+            <view class="h-1" id="plot12345"></view>
+            <!-- 地块/圈舍/培养架信息 -->
+            <view ref="plotRef" class="pd-24">
+                <view class="startline-title" v-if="form?.baseInfo?.baseType == '1'">地块信息</view>
+                <view class="startline-title" v-else-if="form?.baseInfo?.baseType == '2'">圈舍信息</view>
+                <view class="startline-title" v-else-if="form?.baseInfo?.baseType == '3'">培养架信息</view>
+            </view>
+            <view class="pd-24 bg-#fff mb-10">
+                <template v-if="Array.isArray(form?.landInfoList) && form.landInfoList.length">
+                    <view v-for="(item, index) in form.landInfoList" :key="index" class="plot-item pd-24 mb-20">
+                        <view class="d-flex mb-16">
+                            <view class="f-s-32 f-w-5 c-#333 flex1 mr-10">{{ item?.landName || '-' }}</view>
+                            <view v-if="item?.contactName" class="f-s-24 c-#333">负责人:{{ item?.contactName }}</view>
+                        </view>
+                        <template v-if="form?.baseInfo?.baseType == '3'">
+                            <view class="d-flex flex-wrap gap-10">
+                                <view class="f-s-28 c-#666 w-310">
+                                    <span>层数:</span>
+                                    <span class="c-#333 f-w-5">{{ item?.layers || '-' }}</span>
+                                </view>
+                                <view class="f-s-28 c-#666 w-310">
+                                    <span>每层容量:</span>
+                                    <span class="c-#333 f-w-5">{{ item?.capacityAmount || '-' }}{{ item?.capacityUnit || '-' }}</span>
+                                </view>
+                                <view class="f-s-28 c-#666 w-310">
+                                    <span>总容量:</span>
+                                    <span class="c-#333 f-w-5">{{ (item?.capacityAmount || 0) * (item?.layers || 0) || '-' }}{{ item?.capacityUnit || '-' }}</span>
+                                </view>
+                                <view class="f-s-28 c-#666 w-310">
+                                    <span v-if="item?.lightType" class="mr-10">{{ selectDictLabel(pt_light_type, item?.lightType) }}</span>
+                                    <span v-if="item?.tempeStatus">{{ +item?.tempeStatus ? '有独立温控' : '无独立温控' }}</span>
+                                </view>
+                            </view>
+                        </template>
+                        <template v-else>
+                            <view class="f-s-28 c-#666">
+                                <span>面积:</span>
+                                <span class="c-#333 f-w-5">{{ item?.area || '-' }}{{ item?.areaUnit || '-' }}</span>
+                            </view>
+                        </template>
                     </view>
+                </template>
+                <view v-else class="c-999 f-s-28">暂无信息</view>
+            </view>
+            <!-- 选址依据及环境信息 -->
+            <view class="pd-24">
+                <view class="startline-title">选址依据及环境信息</view>
+            </view>
+            <view class="h-1" id="environment12345"></view>
+            <!-- 基地类型 1:种植基地 -->
+            <template v-if="form?.baseInfo?.baseType == '1'">
+                <view class="pd-24 bg-#fff mb-10">
+                    <view class="f-s-32 c-#333 f-w-600">选址依据</view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地组织方式:</span>
-                        <span class="c-#333">{{ selectDictLabel(pt_org_type, form?.baseInfo?.orgType) || '-' }}</span>
+                        <span class="c-#666">是否道地产区:</span>
+                        <span class="c-#333">{{ selectDictLabel(yes_no, form?.environmentInfo?.daoStatus) || '-' }}</span>
                     </view>
-                    <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地负责人:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.contactName || '-' }}</span>
+                    <view v-if="form?.environmentInfo?.adaptFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地选址依据/标准:</view>
+                        <ut-album :urls="form?.environmentInfo?.adaptFile"></ut-album>
+                    </view>
+                    <view v-if="form?.environmentInfo?.accordFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">适应性证明材料:</view>
+                        <ut-album :urls="form?.environmentInfo?.accordFile"></ut-album>
                     </view>
+                </view>
+                <view class="pd-24 bg-#fff mb-10">
+                    <view class="f-s-32 c-#333 f-w-600">环境信息</view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">联系电话:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.contactTel || '-' }}</span>
+                        <span class="c-#666">土壤类型:</span>
+                        <span class="c-#333">{{ selectDictLabel(pt_soil_type, form?.environmentInfo?.soilType) || '-' }}</span>
                     </view>
-                    <template v-if="['1', '2'].includes(form?.baseInfo?.baseType)">
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">是否为GAP基地:</span>
-                            <span class="c-#333">{{ selectDictLabel(yes_no, form?.baseInfo?.gapFlag) || '-' }}</span>
-                        </view>
-                        <view v-if="form?.baseInfo?.gapId" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">关联GAP信息:</view>
-                            <view class="bg-#FBFDFB pd-24 p-rtv flex1 radius-10 gap-info-card">
-                                <view class="f-s-32 f-w-500 c-#333">{{ form?.baseInfo?.gapInfo?.gapBaseName || '-' }}</view>
-                                <view class="f-s-24 c-#ccc mb-10">{{ form?.baseInfo?.gapInfo?.ratedDate }}获评</view>
-                                <view class="d-flex gap-10 flex-wrap">
-                                    <view class="w-330 f-s-28">
-                                        <span class="c-#666">申报品种:</span>
-                                        <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.medicineName }}</span>
-                                    </view>
-                                    <view class="w-290 f-s-28">
-                                        <span class="c-#666">基地面积:</span>
-                                        <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.area }}{{ form?.baseInfo?.gapInfo?.areaUnit }}</span>
-                                    </view>
-                                    <view class="f-s-28">
-                                        <span class="c-#666">基地地址:</span>
-                                        <span class="c-#333 f-w-500">{{ form?.baseInfo?.gapInfo?.adcodeName }} {{ form?.baseInfo?.gapInfo?.address || '-' }}</span>
-                                    </view>
-                                </view>
-                            </view>
-                        </view>
-                    </template>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地所在地区:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.gapInfo?.adcodeName || '-' }}</span>
+                        <span class="c-#666">土壤质地:</span>
+                        <span class="c-#333">{{ selectDictLabel(pt_soil_texture, form?.environmentInfo?.soilTexture) || '-' }}</span>
                     </view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">详细地址:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.gapInfo?.address || '-' }}</span>
+                        <span class="c-#666">有机质含量:</span>
+                        <span class="c-#333">{{ form?.environmentInfo?.organic || '-' }}</span>
                     </view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <view class="f-s-30 c-#666 mb-10">基地范围:</view>
-                        <view class="bg-#f7f7f7 d-flex ov-hd p-rtv">
-                            <image @click="previewImage([form?.baseInfo?.gapInfo?.basePic])" class="w-full" v-if="form?.baseInfo?.gapInfo?.basePic" preview :src="form?.baseInfo?.gapInfo?.basePic" mode="'widthFix'"></image>
-                            <view v-else class="w-full h-120 d-flex a-c j-c c-999">暂无基地范围</view>
-                        </view>
+                        <span class="c-#666">土壤PH值:</span>
+                        <span class="c-#333">{{ form?.environmentInfo?.soilPh || '-' }}</span>
                     </view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地面积:</span>
-                        <span class="c-#333">{{ form?.baseInfo?.gapInfo?.area || '-' }}{{ form?.baseInfo?.gapInfo?.areaUnit || mapUnitByBaseType[form?.baseInfo?.baseType || '1'] }}</span>
+                        <span class="c-#666">水源类型:</span>
+                        <span class="c-#333">{{ selectDictLabel(pt_water_type, form?.environmentInfo?.waterType) || '-' }}</span>
                     </view>
                     <view class="f-s-30 pd2-16-0 info-border-bottom">
-                        <span class="c-#666">基地经纬度:</span>
-                        <span class="c-#333">E{{ form?.baseInfo?.gapInfo?.lng || '-' }}, N{{ form?.baseInfo?.gapInfo?.lat || '-' }}</span>
+                        <span class="c-#666">无霜期:</span><span class="c-#333">{{ form?.environmentInfo?.notFrost || '-' }}<text v-if="form?.environmentInfo?.notFrost">天</text></span>
+                    </view>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年降水量:</span><span class="c-#333">{{ form?.environmentInfo?.precipitation || '-' }}<text v-if="form?.environmentInfo?.precipitation">mm</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年平均气温:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年绝对最高气温:</span><span class="c-#333">{{ form?.environmentInfo?.maxTem || '-' }}<text v-if="form?.environmentInfo?.maxTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年绝对最低气温:</span><span class="c-#333">{{ form?.environmentInfo?.minTem || '-' }}<text v-if="form?.environmentInfo?.minTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年日照时数:</span><span class="c-#333">{{ form?.environmentInfo?.sunshineHours || '-' }}<text v-if="form?.environmentInfo?.sunshineHours">小时</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">海拔:</span><span class="c-#333">{{ form?.environmentInfo?.altitude || '-' }}<text v-if="form?.environmentInfo?.altitude">米</text></span></view
+                    >
+                    <view v-if="form?.environmentInfo?.report?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">水、土壤、大气等环评报告:</view>
+                        <ut-album :urls="form?.environmentInfo?.report"></ut-album>
+                    </view>
+                    <view v-if="form?.environmentInfo?.basePic" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地图片:</view>
+                        <ut-album :urls="form?.environmentInfo?.basePic"></ut-album>
+                    </view>
+                    <view v-if="form?.environmentInfo?.baseVoice?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地视频:</view>
+                        <ut-album :urls="form?.environmentInfo?.baseVoice"></ut-album>
                     </view>
                 </view>
-                <view class="h-1" id="plot12345"></view>
-                <!-- 地块/圈舍/培养架信息 -->
-                <view ref="plotRef" class="pd-24">
-                    <view class="startline-title" v-if="form?.baseInfo?.baseType == '1'">地块信息</view>
-                    <view class="startline-title" v-else-if="form?.baseInfo?.baseType == '2'">圈舍信息</view>
-                    <view class="startline-title" v-else-if="form?.baseInfo?.baseType == '3'">培养架信息</view>
-                </view>
+            </template>
+
+            <!-- 基地类型 2:养殖基地 -->
+            <template v-else-if="form?.baseInfo?.baseType == '2'">
                 <view class="pd-24 bg-#fff mb-10">
-                    <template v-if="Array.isArray(form?.landInfoList) && form.landInfoList.length">
-                        <view v-for="(item, index) in form.landInfoList" :key="index" class="plot-item pd-24 mb-20">
-                            <view class="d-flex mb-16">
-                                <view class="f-s-32 f-w-5 c-#333 flex1 mr-10">{{ item?.landName || '-' }}</view>
-                                <view v-if="item?.contactName" class="f-s-24 c-#333">负责人:{{ item?.contactName }}</view>
-                            </view>
-                            <template v-if="form?.baseInfo?.baseType == '3'">
-                                <view class="d-flex flex-wrap gap-10">
-                                    <view class="f-s-28 c-#666 w-310">
-                                        <span>层数:</span>
-                                        <span class="c-#333 f-w-5">{{ item?.layers || '-' }}</span>
-                                    </view>
-                                    <view class="f-s-28 c-#666 w-310">
-                                        <span>每层容量:</span>
-                                        <span class="c-#333 f-w-5">{{ item?.capacityAmount || '-' }}{{ item?.capacityUnit || '-' }}</span>
-                                    </view>
-                                    <view class="f-s-28 c-#666 w-310">
-                                        <span>总容量:</span>
-                                        <span class="c-#333 f-w-5">{{ (item?.capacityAmount || 0) * (item?.layers || 0) || '-' }}{{ item?.capacityUnit || '-' }}</span>
-                                    </view>
-                                    <view class="f-s-28 c-#666 w-310">
-                                        <span v-if="item?.lightType" class="mr-10">{{ selectDictLabel(pt_light_type, item?.lightType) }}</span>
-                                        <span v-if="item?.tempeStatus">{{ +item?.tempeStatus ? '有独立温控' : '无独立温控' }}</span>
-                                    </view>
-                                </view>
-                            </template>
-                            <template v-else>
-                                <view class="f-s-28 c-#666">
-                                    <span>面积:</span>
-                                    <span class="c-#333 f-w-5">{{ item?.area || '-' }}{{ item?.areaUnit || '-' }}</span>
-                                </view>
-                            </template>
-                        </view>
-                    </template>
-                    <view v-else class="c-999 f-s-28">暂无信息</view>
-                </view>
-                <!-- 选址依据及环境信息 -->
-                <view  class="pd-24">
-                    <view class="startline-title">选址依据及环境信息</view>
+                    <view class="f-s-32 c-#333 f-w-600">选址依据</view>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom">
+                        <span class="c-#666">是否道地产区:</span>
+                        <span class="c-#333">{{ selectDictLabel(yes_no, form?.environmentInfo?.daoStatus) || '-' }}</span>
+                    </view>
+                    <view v-if="form?.environmentInfo?.adaptFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地选址依据/标准:</view>
+                        <ut-album :urls="form?.environmentInfo?.adaptFile"></ut-album>
+                    </view>
+                    <view v-if="form?.environmentInfo?.accordFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">适应性证明材料:</view>
+                        <ut-album :urls="form?.environmentInfo?.accordFile"></ut-album>
+                    </view>
                 </view>
-                <view class="h-1" id="environment12345"></view>
-                <!-- 基地类型 1:种植基地 -->
-                <template v-if="form?.baseInfo?.baseType == '1'">
-                    <view class="pd-24 bg-#fff mb-10">
-                        <view class="f-s-32 c-#333 f-w-600">选址依据</view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">是否道地产区:</span>
-                            <span class="c-#333">{{ selectDictLabel(yes_no, form?.environmentInfo?.daoStatus) || '-' }}</span>
-                        </view>
-                        <view v-if="form?.environmentInfo?.adaptFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地选址依据/标准:</view>
-                            <ut-album :urls="form?.environmentInfo?.adaptFile"></ut-album>
-                        </view>
-                        <view v-if="form?.environmentInfo?.accordFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">适应性证明材料:</view>
-                            <ut-album :urls="form?.environmentInfo?.accordFile"></ut-album>
-                        </view>
+                <view class="pd-24 bg-#fff mb-10">
+                    <view class="f-s-32 c-#333 f-w-600">环境信息</view>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">水源类型:</span><span class="c-#333">{{ selectDictLabel(pt_water_type, form?.environmentInfo?.waterType) || '-' }}</span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">无霜期:</span><span class="c-#333">{{ form?.environmentInfo?.notFrost || '-' }}<text v-if="form?.environmentInfo?.notFrost">天</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年降水量:</span><span class="c-#333">{{ form?.environmentInfo?.precipitation || '-' }}<text v-if="form?.environmentInfo?.precipitation">mm</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年平均气温:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年绝对最高气温:</span><span class="c-#333">{{ form?.environmentInfo?.maxTem || '-' }}<text v-if="form?.environmentInfo?.maxTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年绝对最低气温:</span><span class="c-#333">{{ form?.environmentInfo?.minTem || '-' }}<text v-if="form?.environmentInfo?.minTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">年日照时数:</span><span class="c-#333">{{ form?.environmentInfo?.sunshineHours || '-' }}<text v-if="form?.environmentInfo?.sunshineHours">小时</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">海拔:</span><span class="c-#333">{{ form?.environmentInfo?.altitude || '-' }}<text v-if="form?.environmentInfo?.altitude">米</text></span></view
+                    >
+                    <view v-if="form?.environmentInfo?.report?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">水、大气等环评报告:</view>
+                        <ut-album :urls="form?.environmentInfo?.report"></ut-album>
                     </view>
-                    <view class="pd-24 bg-#fff mb-10">
-                        <view class="f-s-32 c-#333 f-w-600">环境信息</view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">土壤类型:</span>
-                            <span class="c-#333">{{ selectDictLabel(pt_soil_type, form?.environmentInfo?.soilType) || '-' }}</span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">土壤质地:</span>
-                            <span class="c-#333">{{ selectDictLabel(pt_soil_texture, form?.environmentInfo?.soilTexture) || '-' }}</span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">有机质含量:</span>
-                            <span class="c-#333">{{ form?.environmentInfo?.organic || '-' }}</span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">土壤PH值:</span>
-                            <span class="c-#333">{{ form?.environmentInfo?.soilPh || '-' }}</span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">水源类型:</span>
-                            <span class="c-#333">{{ selectDictLabel(pt_water_type, form?.environmentInfo?.waterType) || '-' }}</span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">无霜期:</span><span class="c-#333">{{ form?.environmentInfo?.notFrost || '-' }}<text v-if="form?.environmentInfo?.notFrost">天</text></span>
-                        </view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年降水量:</span><span class="c-#333">{{ form?.environmentInfo?.precipitation || '-' }}<text v-if="form?.environmentInfo?.precipitation">mm</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年平均气温:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年绝对最高气温:</span><span class="c-#333">{{ form?.environmentInfo?.maxTem || '-' }}<text v-if="form?.environmentInfo?.maxTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年绝对最低气温:</span><span class="c-#333">{{ form?.environmentInfo?.minTem || '-' }}<text v-if="form?.environmentInfo?.minTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年日照时数:</span><span class="c-#333">{{ form?.environmentInfo?.sunshineHours || '-' }}<text v-if="form?.environmentInfo?.sunshineHours">小时</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">海拔:</span><span class="c-#333">{{ form?.environmentInfo?.altitude || '-' }}<text v-if="form?.environmentInfo?.altitude">米</text></span></view
-                        >
-                        <view v-if="form?.environmentInfo?.report?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">水、土壤、大气等环评报告:</view>
-                            <ut-album :urls="form?.environmentInfo?.report"></ut-album>
-                        </view>
-                        <view v-if="form?.environmentInfo?.basePic" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地图片:</view>
-                            <ut-album :urls="form?.environmentInfo?.basePic"></ut-album>
-                        </view>
-                        <view v-if="form?.environmentInfo?.baseVoice?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地视频:</view>
-                            <ut-album :urls="form?.environmentInfo?.baseVoice"></ut-album>
-                        </view>
+                    <view v-if="form?.environmentInfo?.basePic" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地图片:</view>
+                        <ut-album :urls="form?.environmentInfo?.basePic"></ut-album>
                     </view>
-                </template>
-
-                <!-- 基地类型 2:养殖基地 -->
-                <template v-else-if="form?.baseInfo?.baseType == '2'">
-                    <view class="pd-24 bg-#fff mb-10">
-                        <view class="f-s-32 c-#333 f-w-600">选址依据</view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom">
-                            <span class="c-#666">是否道地产区:</span>
-                            <span class="c-#333">{{ selectDictLabel(yes_no, form?.environmentInfo?.daoStatus) || '-' }}</span>
-                        </view>
-                        <view v-if="form?.environmentInfo?.adaptFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地选址依据/标准:</view>
-                            <ut-album :urls="form?.environmentInfo?.adaptFile"></ut-album>
-                        </view>
-                        <view v-if="form?.environmentInfo?.accordFile?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">适应性证明材料:</view>
-                            <ut-album :urls="form?.environmentInfo?.accordFile"></ut-album>
-                        </view>
+                    <view v-if="form?.environmentInfo?.baseVoice?.length" class="f-s-30 pd2-16-0 info-border-bottom">
+                        <view class="c-#666 mb-10">基地视频:</view>
+                        <ut-album :urls="form?.environmentInfo?.baseVoice"></ut-album>
                     </view>
-                    <view class="pd-24 bg-#fff mb-10">
-                        <view class="f-s-32 c-#333 f-w-600">环境信息</view>
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">水源类型:</span><span class="c-#333">{{ selectDictLabel(pt_water_type, form?.environmentInfo?.waterType) || '-' }}</span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">无霜期:</span><span class="c-#333">{{ form?.environmentInfo?.notFrost || '-' }}<text v-if="form?.environmentInfo?.notFrost">天</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年降水量:</span><span class="c-#333">{{ form?.environmentInfo?.precipitation || '-' }}<text v-if="form?.environmentInfo?.precipitation">mm</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年平均气温:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年绝对最高气温:</span><span class="c-#333">{{ form?.environmentInfo?.maxTem || '-' }}<text v-if="form?.environmentInfo?.maxTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年绝对最低气温:</span><span class="c-#333">{{ form?.environmentInfo?.minTem || '-' }}<text v-if="form?.environmentInfo?.minTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">年日照时数:</span><span class="c-#333">{{ form?.environmentInfo?.sunshineHours || '-' }}<text v-if="form?.environmentInfo?.sunshineHours">小时</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">海拔:</span><span class="c-#333">{{ form?.environmentInfo?.altitude || '-' }}<text v-if="form?.environmentInfo?.altitude">米</text></span></view
-                        >
-                        <view v-if="form?.environmentInfo?.report?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">水、大气等环评报告:</view>
-                            <ut-album :urls="form?.environmentInfo?.report"></ut-album>
+                </view>
+            </template>
+            <!-- 基地类型 3:组培基地 -->
+            <template v-else-if="form?.baseInfo?.baseType == '3'">
+                <view class="pd-24 bg-#fff mb-10">
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">温度:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">湿度:</span><span class="c-#333">{{ form?.environmentInfo?.humidity || '-' }}<text v-if="form?.environmentInfo?.humidity">%</text></span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">洁净度:</span><span class="c-#333">{{ form?.environmentInfo?.clean || '-' }}</span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">光照:</span><span class="c-#333">{{ form?.environmentInfo?.light || '-' }}</span></view
+                    >
+                    <view class="f-s-30 pd2-16-0 info-border-bottom"
+                        ><span class="c-#666">光照周期:</span><span class="c-#333">{{ form?.environmentInfo?.lightCycle || '-' }}</span></view
+                    >
+                </view>
+            </template>
+        </view>
+        <template #bottom>
+            <view class="pd-20 d-flex">
+                <template v-if="!+form.baseInfo?.tempFlag">
+                    <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base/index', params: { id: did } })" v-if="!form?.baseInfo?.swyqRes" class="mr-20" color="#18BECA">去标记为三无一全基地{{ '>' }}</up-button>
+                    <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['2'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#FC333F">
+                        <view>
+                            <view>标记为三无一全基地</view>
+                            <view>未通过{{ '>' }}</view>
                         </view>
-                        <view v-if="form?.environmentInfo?.basePic" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地图片:</view>
-                            <ut-album :urls="form?.environmentInfo?.basePic"></ut-album>
+                    </up-button>
+                    <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['0'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#F4A91A">
+                        <view>
+                            <view>标记为三无一全基地</view>
+                            <view>待审核{{ '>' }}</view>
                         </view>
-                        <view v-if="form?.environmentInfo?.baseVoice?.length" class="f-s-30 pd2-16-0 info-border-bottom">
-                            <view class="c-#666 mb-10">基地视频:</view>
-                            <ut-album :urls="form?.environmentInfo?.baseVoice"></ut-album>
+                    </up-button>
+                    <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['1'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#AECEBF">
+                        <view>
+                            <view>标记为三无一全基地</view>
+                            <view>已通过{{ '>' }}</view>
                         </view>
-                    </view>
-                </template>
-                <!-- 基地类型 3:组培基地 -->
-                <template v-else-if="form?.baseInfo?.baseType == '3'">
-                    <view class="pd-24 bg-#fff mb-10">
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">温度:</span><span class="c-#333">{{ form?.environmentInfo?.avgTem || '-' }}<text v-if="form?.environmentInfo?.avgTem">℃</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">湿度:</span><span class="c-#333">{{ form?.environmentInfo?.humidity || '-' }}<text v-if="form?.environmentInfo?.humidity">%</text></span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">洁净度:</span><span class="c-#333">{{ form?.environmentInfo?.clean || '-' }}</span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">光照:</span><span class="c-#333">{{ form?.environmentInfo?.light || '-' }}</span></view
-                        >
-                        <view class="f-s-30 pd2-16-0 info-border-bottom"
-                            ><span class="c-#666">光照周期:</span><span class="c-#333">{{ form?.environmentInfo?.lightCycle || '-' }}</span></view
-                        >
-                    </view>
+                    </up-button>
                 </template>
-           
+                <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/base-edit/index', params: { id: did } })" type="primary">去修改</up-button>
             </view>
-            <template #bottom>
-                <view class="pd-20 d-flex">
-                    <template v-if="!+form.baseInfo?.tempFlag">
-                        <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base/index', params: { id: did } })" v-if="!form?.baseInfo?.swyqRes" class="mr-20" color="#18BECA">去标记为三无一全基地{{ '>' }}</up-button>
-                        <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['2'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#FC333F">
-                            <view>
-                                <view>标记为三无一全基地</view>
-                                <view>未通过{{ '>' }}</view>
-                            </view>
-                        </up-button>
-                        <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['0'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#F4A91A">
-                            <view>
-                                <view>标记为三无一全基地</view>
-                                <view>待审核{{ '>' }}</view>
-                            </view>
-                        </up-button>
-                        <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/mark-swyq-base-detail/index', params: { id: did } })" v-if="['1'].includes(form?.baseInfo?.swyqRes)" class="mr-20" color="#AECEBF">
-                            <view>
-                                <view>标记为三无一全基地</view>
-                                <view>已通过{{ '>' }}</view>
-                            </view>
-                        </up-button>
-                    </template>
-                    <up-button @click="$u.route({ type: 'navigateTo', url: '/plant/base/base-edit/index', params: { id: did } })" type="primary">去修改</up-button>
-                </view>
-            </template>
-        </z-paging>
-    </view>
+        </template>
+    </z-paging>
 </template>
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';

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

@@ -2,7 +2,7 @@
     <z-paging ref="paging" bgColor="#F7F7F7" safe-area-inset-bottom paging-class="paging-btm-shadow" scroll-with-animation>
         <template #top>
             <ut-navbar :title="(did && !+form?.baseInfo?.tempFlag ? '编辑基地' : '添加基地')" :fixed="false" border></ut-navbar>
-            <view class="bg-fff mb-20">
+            <view class="bg-fff mb-20 pd2-0-24">
                 <view class="pd-5"></view>
                 <ut-tabs v-model="activeTab" :tabs="tabs" mode="btw" @change="changeActiveTab"></ut-tabs>
             </view>

+ 54 - 0
src/plant/contact-unit/models/type.ts

@@ -0,0 +1,54 @@
+/**
+ * CustomerAddDTO,往来单位添加对象 pt_customer
+ */
+export interface CustomerAddDTO {
+    /**
+     * 往来单位简称
+     */
+    abbravName?: string;
+    /**
+     * 行政区代码
+     */
+    adcdCode?: string;
+    /**
+     * 地址
+     */
+    address?: string;
+    /**
+     * 联系人
+     */
+    contact?: string;
+    /**
+     * 联系电话
+     */
+    contactTel?: string;
+    /**
+     * 往来单位类型
+     */
+    cpyType?: string[];
+    /**
+     * 往来单位编码-统一信用代码
+     */
+    cusCode?: string;
+    /**
+     * 往来单位名称
+     */
+    cusName?: string;
+    /**
+     * 客户类型
+     */
+    cusType: string;
+    /**
+     * 邮编
+     */
+    postcode?: string;
+    /**
+     * 备注
+     */
+    remark?: string;
+    /**
+     * 往来单位细分类型
+     */
+    subdivisionType?: string;
+    [property: string]: any;
+}

+ 169 - 0
src/plant/contact-unit/unit-detail/index.vue

@@ -0,0 +1,169 @@
+<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>
+        </template>
+
+        <template>
+            <view class="pd-24 bg-#fff mb-10">
+                <!-- 往来单位类型 -->
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">往来单位类型:</span>
+                    <span class="c-#333 f-w-600">
+                        {{ (form?.cpyType && form.cpyType.length) ? selectDictLabels(pt_cpy_type, form.cpyType, ',') : '-' }}
+                    </span>
+                </view>
+                <!-- 往来单位性质 -->
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">往来单位性质:</span>
+                    <span class="c-#333 f-w-600">{{ selectDictLabel(pt_cus_type, form?.cusType) || '-' }}</span>
+                </view>
+
+                <!-- 个人 / 单位 信息 -->
+                <template v-if="form?.cusType == '1'">
+                    <view class="f-s-30 pd2-16-0 info-border-bottom">
+                        <span class="c-#666">姓名:</span>
+                        <span class="c-#333 f-w-600">{{ form?.cusName || '-' }}</span>
+                    </view>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom">
+                        <span class="c-#666">身份证号:</span>
+                        <span class="c-#333 f-w-600">{{ form?.cusCode || '-' }}</span>
+                    </view>
+                </template>
+                <template v-else>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom">
+                        <span class="c-#666">往来单位名称:</span>
+                        <span class="c-#333 f-w-600">{{ form?.cusName || '-' }}</span>
+                    </view>
+                    <view class="f-s-30 pd2-16-0 info-border-bottom">
+                        <span class="c-#666">统一社会信用代码/组织机构代码:</span>
+                        <span class="c-#333 f-w-600">{{ form?.cusCode || '-' }}</span>
+                    </view>
+                </template>
+
+                <!-- 细分类型 -->
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">细分类型:</span>
+                    <span class="c-#333 f-w-600">{{ selectDictLabel(pt_subdivision_type, form?.subdivisionType) || '-' }}</span>
+                </view>
+
+                <!-- 联系人 -->
+                <view v-if="form?.contact" class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">联系人:</span>
+                    <span class="c-#333 f-w-600">{{ form?.contact }}</span>
+                </view>
+
+                <!-- 联系电话 -->
+                <view v-if="form?.contactTel" class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">联系电话:</span>
+                    <span class="c-#333 f-w-600">{{ form?.contactTel }}</span>
+                </view>
+
+                <!-- 所在地区 -->
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">往来单位所在地区:</span>
+                    <span class="c-#333 f-w-600">{{ form?.adcdCodeName || '-' }}</span>
+                </view>
+
+                <!-- 详细地址 -->
+                <view class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">往来单位具体地址:</span>
+                    <span class="c-#333 f-w-600">{{ form?.address || '-' }}</span>
+                </view>
+
+                <!-- 邮编,仅在特定往来单位类型下展示 -->
+                <view v-if="form?.cpyType && form.cpyType.includes('3') && form.postcode" class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">邮编:</span>
+                    <span class="c-#333 f-w-600">{{ form?.postcode }}</span>
+                </view>
+
+                <!-- 备注 -->
+                <view v-if="form?.remark" class="f-s-30 pd2-16-0 info-border-bottom">
+                    <span class="c-#666">备注:</span>
+                    <span class="c-#333 f-w-600">{{ form?.remark }}</span>
+                </view>
+            </view>
+        </template>
+
+        <template #empty>
+            <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx">暂无往来单位详情</ut-empty>
+        </template>
+        <template #bottom>
+            <view class="pd3-10-24-24">
+                <view class="f-s-24 c-#ccc pd-12">
+                    <span class="mr-30">最新修改人: {{ form?.operatorName || '-' }}</span>
+                    <span>最新修改时间: {{ form?.operateTime || '-' }}</span>
+                </view>
+                <up-button type="primary" @click="clickEdit">修改</up-button>
+            </view>
+        </template>
+    </z-paging>
+</template>
+
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_cus_type, pt_cpy_type, pt_subdivision_type } = toRefs<any>(
+    proxy?.useDict('pt_cus_type', 'pt_cpy_type', 'pt_subdivision_type')
+);
+
+const paging = ref<any>(null);
+const form = ref<any>({});
+const did = ref('');
+
+// 获取详情(往来单位信息)
+const getDetailById = async (id: string) => {
+    if (!id) return;
+    const res = await useClientRequest.get(`/plt-api/app/customer/getInfo/${id}`);
+    if (res && res.code === 200) {
+        form.value = res.data || {};
+    }
+};
+
+const onRefresh = () => {
+    getDetailById(did.value);
+    paging.value?.complete();
+};
+
+const clickEdit = () => {
+    uni.$on('contact-unit-detail-refresh', () => {
+        getDetailById(did.value);
+        uni.$off('contact-unit-detail-refresh');
+    });
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/plant/contact-unit/unit-edit/index',
+        params: {
+            id: did.value,
+        },
+    });
+};
+
+// 页面入参解析并加载
+onLoad((options: any) => {
+    did.value = options?.id || '';
+    getDetailById(did.value);
+
+});
+onMounted(() => {
+    uni.$on('refreshContactUnitDetail', () => {
+        getDetailById(did.value);
+    });
+});
+</script>
+
+<style lang="scss" scoped>
+.z-paging-wrap {
+    position: absolute;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    left: 0;
+}
+.startline-title {
+    font-size: 32rpx;
+    font-weight: 600;
+    color: #333;
+}
+</style>

+ 246 - 0
src/plant/contact-unit/unit-edit/index.vue

@@ -0,0 +1,246 @@
+<template>
+    <z-paging ref="paging" bgColor="#fff" safe-area-inset-bottom paging-class="paging-btm-shadow" scroll-with-animation>
+        <template #top>
+            <ut-navbar :title="did ? '编辑往来单位信息' : '新增往来单位信息'" :fixed="false" border></ut-navbar>
+        </template>
+        <up-form class="p-rtv" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
+            <view class="pd-24 bg-#fff mb-10">
+                <!-- 往来单位类型(多个可用逗号分隔) -->
+                <view class="h-1" id="cpyTypepppp"></view>
+                <ut-action-sheet v-model="form.cpyType" :tabs="pt_cpy_type" mode="custom" title="选择往来单位类型" multiple>
+                    <up-form-item borderBottom label="往来单位类型" required prop="cpyType">
+                        <view v-if="form.cpyType?.length" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabels(pt_cpy_type, form.cpyType, ',') }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择往来单位类型</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+                </ut-action-sheet>
+                <!-- 往来单位性质 -->
+                <view class="h-1" id="cusTypepppp"></view>
+                <ut-action-sheet v-model="form.cusType" :tabs="pt_cus_type" mode="custom" title="选择往来单位性质">
+                    <up-form-item borderBottom label="往来单位性质" required prop="cusType">
+                        <view v-if="form.cusType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_cus_type, form.cusType) }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择往来单位性质</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+                </ut-action-sheet>
+                <!-- 往来单位名称 -->
+                <template v-if="form.cusType == '1'">
+                    <view class="h-1" id="cusNamepppp"></view>
+                    <up-form-item borderBottom label="姓名" required prop="cusName">
+                        <up-input v-model="form.cusName" placeholder="请输入姓名" border="none" clearable></up-input>
+                    </up-form-item>
+                    <!-- 统一社会信用代码 -->
+                    <view class="h-1" id="cusCodepppp"></view>
+                    <up-form-item borderBottom label="身份证号" prop="cusCode" required>
+                        <up-input v-model="form.cusCode" placeholder="请输入身份证号" maxlength="18" border="none" clearable></up-input>
+                    </up-form-item>
+                </template>
+                <!-- 往来单位名称 -->
+                <template v-else>
+                    <view class="h-1" id="cusNamepppp"></view>
+                    <up-form-item borderBottom label="往来单位名称" required prop="cusName">
+                        <up-input v-model="form.cusName" placeholder="请输入往来单位名称" border="none" clearable></up-input>
+                    </up-form-item>
+                    <!-- 统一社会信用代码 -->
+                    <view class="h-1" id="cusCodepppp"></view>
+                    <up-form-item borderBottom label="统一社会信用代码/组织机构代码" prop="cusCode" required>
+                        <up-input v-model="form.cusCode" placeholder="请输入统一社会信用代码/组织机构代码" maxlength="30" border="none" clearable></up-input>
+                    </up-form-item>
+                </template>
+
+                <ut-action-sheet v-model="form.subdivisionType" :tabs="pt_subdivision_type" mode="custom" title="选择细分类型">
+                    <up-form-item borderBottom label="细分类型" prop="subdivisionType">
+                        <view v-if="form.subdivisionType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_subdivision_type, form.subdivisionType) }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择细分类型</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+                </ut-action-sheet>
+
+                <!-- 联系人 -->
+                <up-form-item borderBottom label="联系人" prop="contact">
+                    <up-input v-model="form.contact" placeholder="请输入联系人" border="none" clearable></up-input>
+                </up-form-item>
+
+                <!-- 联系电话 -->
+                <view class="h-1" id="contactTelpppp"></view>
+                <up-form-item borderBottom label="联系电话" prop="contactTel">
+                    <up-input v-model="form.contactTel" placeholder="请输入联系电话" border="none" clearable></up-input>
+                </up-form-item>
+                <!-- 所在地区 -->
+                <view class="h-1" id="adcdCodepppp"></view>
+                <up-form-item @click="showArea = true" borderBottom label="往来单位所在地区" required prop="adcdCode">
+                    <view v-if="form.adcdCode" class="f-s-30 c-333 f-w-5 flex1">{{ form.adcdCodeName }}</view>
+                    <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择往来单位所在地区</view>
+                    <template #right>
+                        <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                    </template>
+                </up-form-item>
+
+                <!-- 详细地址 -->
+                <up-form-item borderBottom label="往来单位具体地址" prop="address">
+                    <up-input v-model="form.address" placeholder="请输入往来单位具体地址" border="none" clearable></up-input>
+                </up-form-item>
+                <!-- 邮编 -->
+                <up-form-item v-if="form.cpyType?.includes('3')" borderBottom label="邮编" prop="postcode">
+                    <up-input v-model="form.postcode" placeholder="请输入邮编" border="none" clearable></up-input>
+                </up-form-item>
+                <!-- 备注 -->
+                <up-form-item label="备注" prop="remark">
+                    <up-textarea v-model="form.remark" placeholder="请输入备注" maxlength="300" autoHeight clearable></up-textarea>
+                </up-form-item>
+            </view>
+        </up-form>
+        <template #bottom>
+            <view class="pd-20">
+                <up-button type="primary" @click="submit">
+                    <text>{{ did ? '保存' : '提交' }}</text>
+                </up-button>
+            </view>
+        </template>
+    </z-paging>
+    <ut-picker-area v-model:show="showArea" v-model="form.adcdCode" @confirm="confirmArea"></ut-picker-area>
+</template>
+<script setup lang="ts">
+import type { CustomerAddDTO } from '../models/type';
+import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_cus_type, pt_cpy_type, pt_subdivision_type } = toRefs<any>(proxy?.useDict('pt_cus_type', 'pt_cpy_type', 'pt_subdivision_type'));
+const upFormRef = ref();
+const paging = ref();
+const did = ref<string>('');
+const showArea = ref(false);
+
+const form = ref<CustomerAddDTO & { adcdCodeName?: string }>({
+    cusType: '',
+    cusName: '',
+    abbravName: '',
+    adcdCode: '',
+    adcdCodeName: '',
+    address: '',
+    contact: '',
+    contactTel: '',
+    cpyType: [],
+    cusCode: '',
+    postcode: '',
+    remark: '',
+    subdivisionType: '',
+} as CustomerAddDTO & { adcdCodeName?: string });
+
+// 用于输入展示,提交时再转换为数组
+const cpyTypeText = ref('');
+
+const rules = reactive({
+    cpyType: [{ required: true, type: 'array', message: '请选择往来单位类型', trigger: 'blur' }],
+    cusType: [{ required: true, message: '请选择往来单位性质', trigger: 'blur' }],
+    // cusName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+    // cusCode: [{ required: true, message: '请输入身份证号', trigger: 'blur' }],
+    // 如果是选择个人是姓名和身份证号必填,否则单位名称和统一社会信用代码必填
+    cusName: [
+        {
+            asyncValidator: (rule: any, value: string, callback: (error?: Error) => void) => {
+                if (form.value.cusType == '1') {
+                    if (!value || !value.trim()) {
+                        return callback(new Error('请输入姓名'));
+                    }
+                } else {
+                    if (!value || !value.trim()) {
+                        return callback(new Error('请输入往来单位名称'));
+                    }
+                }
+                callback();
+            },
+        }
+    ],
+    cusCode: [
+        {
+            asyncValidator: (rule: any, value: string, callback: (error?: Error) => void) => {
+                if (form.value.cusType == '1') {
+                    if (!value || !value.trim()) {
+                        return callback(new Error('请输入身份证号'));
+                    }
+                } else {
+                    if (!value || !value.trim()) {
+                        return callback(new Error('请输入统一社会信用代码/组织机构代码'));
+                    }
+                }
+                callback();
+            },
+        }
+    ],
+    adcdCode: [{ required: true, message: '请选择往来单位所在地区', trigger: 'blur' }],
+    contactTel: [
+        {
+            pattern: /^(\+?\d{1,4}[-\s]?)?((\d{3,4}[-\s]?)?\d{7,8}|1[1-9]\d{9})$/,
+            message: '请输入正确的联系电话',
+            trigger: 'blur',
+        },
+    ],
+});
+
+const loadDetail = async (id: string) => {
+    if (!id) return;
+    const res = await useClientRequest.get(`/plt-api/app/customer/getInfo/${id}`);
+    if (res && res.code === 200) {
+        const data = res.data || {};
+        form.value = {
+            ...data,
+        } as CustomerAddDTO & { adcdCodeName?: string };
+    }
+};
+
+const submit = async () => {
+    try {
+        await upFormRef.value?.validate();
+    } catch (error: any) {
+        const firstErrorField = error && error[0].prop + 'pppp';
+        paging.value?.scrollIntoViewById(firstErrorField, 30, true);
+        return;
+    }
+
+    try {
+        await uni.showLoading({ title: did.value ? '保存中...' : '提交中...', mask: true });
+        const url = did.value ? '/plt-api/app/customer/edit' : '/plt-api/app/customer/add';
+        const payload: any = { ...(form.value as any) };
+        if (did.value) payload.id = did.value;
+        const res = await useClientRequest.post(url, payload);
+        uni.hideLoading();
+        if (res && res.code === 200) {
+            uni.showToast({ title: did.value ? '保存成功' : '新增成功', icon: 'success' });
+            uni.$emit('refreshContactUnitDetail');
+            uni.$emit('refreshContactUnitList');
+            setTimeout(() => uni.navigateBack(), 300);
+        }
+    } catch (e) {
+        uni.hideLoading();
+        console.error('保存往来单位失败:', e);
+    }
+};
+
+const confirmArea = (area: any) => {
+    form.value.adcdCodeName = area.fullName;
+};
+
+onLoad((options: any) => {
+    did.value = options?.id || '';
+    if (did.value) {
+        loadDetail(did.value);
+    }
+    paging.value?.complete();
+});
+</script>
+<style lang="scss" scoped>
+.startline-title {
+    font-size: 32rpx;
+    font-weight: 600;
+    color: #333;
+}
+.base-bottom-wrap {
+    background-color: #fff;
+}
+</style>

+ 150 - 0
src/plant/contact-unit/unit-list/index.vue

@@ -0,0 +1,150 @@
+<template>
+    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" safe-area-inset-bottom>
+        <template #top>
+            <ut-navbar title="往来单位管理" :fixed="false" border :breadcrumb="false"></ut-navbar>
+            <view class="d-flex a-c pd-24">
+                <view class="min-w-220 flex1">
+                    <ut-action-sheet v-model="form.cusType" :tabs="[{ label: '全部', value: '' }, ...pt_cus_type]" mode="custom" @change="onRefresh" title="选择往来单位性质">
+                        <view class="d-flex search-select-item a-c">
+                            <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ selectDictLabel(pt_cus_type, form.cusType) || '全部' }}</view>
+                            <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="mr-5"></up-icon>
+                        </view>
+                    </ut-action-sheet>
+                </view>
+                <view class="h-86 pl-20 w-100%">
+                    <ut-search ref="searchRef" v-model="form.keyword" @search="onRefresh" margin="0" :border="false" :placeholder="placeholder" bgColor="#fff" height="86rpx" borderRadius="10rpx"></ut-search>
+                </view>
+            </view>
+            <view class="pd2-0-24">
+                <ut-tabs v-model="form.cpyType" mode="scroll-x-card" fontSize="26rpx" :tabs="pt_cpy_type" @change="onRefresh"></ut-tabs>
+            </view>
+        </template>
+
+        <template>
+            <view class="pd-24">
+                <up-swipe-action>
+                    <up-swipe-action-item v-for="item in list" :name="item?.id" :key="item?.id" :disabled="item?.storeCount" :options="optionsAction" @click="clickSwipe" class="mb-20 b-radius">
+                        <view @click.stop="clickItem(item)" class="b-radius bg-#fff pd-24 p-rtv base-shadow">
+                            <view class="d-flex j-sb a-c li-item-head mb-16">
+                                <view class="li-left-tag">{{ selectDictLabel(pt_cus_type, item?.cusType) }}</view>
+                                <view class="f-s-22 c-#666">{{ item?.updateTime || item?.createTime }}</view>
+                            </view>
+                            <view class="f-s-34 c-#333 f-w-500">{{ item?.cusName }}</view>
+                            <view class="f-s-24 c-#666">{{ item?.cusCode }}</view>
+                            <view class="pd-5"></view>
+                            <view class="f-s-28 pd2-5-0">
+                                <span class="c-#666">联系电话:</span>
+                                <span class="c-#333 f-w-600">{{ item?.contactTel }}</span>
+                            </view>
+                            <ut-tag-dict :options="pt_cpy_type" :value="item?.cpyType"></ut-tag-dict>
+                        </view>
+                    </up-swipe-action-item>
+                </up-swipe-action>
+            </view>
+        </template>
+        <!-- 空数据处理 -->
+
+        <template #empty>
+            <ut-empty class="mg-at" size="28rpx" color="#999" padding="10rpx"> 暂无往来单位信息,点击+号新增吧</ut-empty>
+        </template>
+    </z-paging>
+    <ut-suspension @click="$u.route({ url: '/plant/contact-unit/unit-edit/index' })">
+        <image src="@/static/images/common/btn_add_logo.png" mode="widthFix" class="w-120 h-120"></image>
+    </ut-suspension>
+</template>
+<script setup lang="ts">
+import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { pt_cus_type, pt_cpy_type } = toRefs<any>(proxy?.useDict('pt_cus_type', 'pt_cpy_type'));
+const paging = ref();
+const list = ref<any[]>([]);
+const placeholder = ref('搜往来单位名称、代码');
+
+const form = ref({
+    keyword: '',
+    cusType: '',
+    cpyType: '',
+});
+
+const query = async (pageNum: number, pageSize: number) => {
+    const params = {
+        pageNum,
+        pageSize,
+        ...form.value,
+    };
+    const res = await useClientRequest.get<any>('/plt-api/app/customer/list', params);
+    if (!res || res.code !== 200) return;
+    const { rows } = res;
+    paging.value.complete(rows);
+};
+const onRefresh = () => {
+    paging.value?.reload();
+};
+const optionsAction = reactive([
+    {
+        text: '删除',
+        style: {
+            backgroundColor: '#f56c6c',
+        },
+    },
+]);
+const clickSwipe = async (event: object) => {
+    const { name, index } = event as any;
+    if (index === 0) {
+        // 删除
+        const res = await uni.showModal({
+            title: '删除提示',
+            content: '删除后不可撤回,请谨慎操作!',
+            confirmColor: '#f56c6c',
+        });
+        console.log(res);
+        if (res.confirm) {
+            const delRes = await useClientRequest.get(`/plt-api/app/customer/remove/${name}`);
+            if (delRes && delRes.code === 200) {
+                uni.showToast({ title: '删除成功', icon: 'none' });
+                onRefresh();
+            }
+        }
+    }
+};
+const clickItem = (item: any) => {
+    uni.$u.route({
+        type: 'navigateTo',
+        url: '/plant/contact-unit/unit-detail/index',
+        params: {
+            id: item?.id,
+        },
+    });
+};
+
+onMounted(() => {
+    uni.$on('refreshContactUnitList', () => {
+        onRefresh();
+    });
+});
+</script>
+<style lang="scss" scoped>
+// @import '@/assets/styles/theme.scss';
+.search-select-item {
+    height: 86rpx;
+    background-color: #fff;
+    border-radius: 10rpx;
+    box-sizing: border-box;
+    padding-left: 16rpx;
+    padding-right: 16rpx;
+    padding-top: 14rpx;
+    padding-bottom: 14rpx;
+}
+.li-item-head {
+    margin-left: -24rpx;
+    margin-top: -24rpx;
+}
+.li-left-tag {
+    padding: 4rpx 12rpx;
+    background-color: #ebf6ee;
+    color: #37a954;
+    border-radius: 16rpx 0 16rpx 0;
+    font-size: 20rpx;
+    font-weight: 500;
+}
+</style>

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

@@ -91,7 +91,10 @@ const form = ref<SeedSourceAddTypeEnum>({
     storeType: '2',
     seedInfoList: [],
     warehouses: [],
-    instoreBizInfo: {},
+    instoreBizInfo: {
+        motherFatherFlag: '',
+        idFlag: '0',
+    },
 });
 const rules = reactive({});
 

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

@@ -1,6 +1,5 @@
 <template>
-    <z-paging class="" ref="paging" bgColor="#fff" paging-class="paging-btm-shadow" safe-area-inset-bottom
-        scroll-with-animation>
+    <z-paging class="" ref="paging" bgColor="#fff" paging-class="paging-btm-shadow" safe-area-inset-bottom scroll-with-animation>
         <template #top>
             <ut-navbar :title="did ? '编辑种源入库信息' : '添加种源入库信息'" :fixed="false" border></ut-navbar>
         </template>
@@ -9,8 +8,7 @@
                 <!-- 基本信息 -->
                 <ut-action-sheet :tabs="pt_seed_type" mode="custom" title="种源类型" v-model="form.seedType">
                     <up-form-item borderBottom label="种源类型" required prop="seedType">
-                        <view v-if="form.seedType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_seed_type,
-                            form.seedType) }}</view>
+                        <view v-if="form.seedType" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_seed_type, form.seedType) }}</view>
                         <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择基地类型</view>
                         <template #right>
                             <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
@@ -20,8 +18,7 @@
                 <up-form-item borderBottom label="物种基原" required prop="varietyId">
                     <view class="flex1">
                         <up-button v-if="!form.varietyId" @click="selectVarietyId" type="primary" plain>
-                            <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png"
-                                mode="widthFix" />
+                            <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png" mode="widthFix" />
                             <span>请选择物种基原</span>
                         </up-button>
                         <view v-else class="bg-#FBFDFB card-info-block pd-24 p-rtv">
@@ -34,7 +31,13 @@
                                 <span class="f-s-24 c-#666">{{ form?.varietyInfo?.genusLatinName }}</span>
                             </view>
                             <view class="f-s-24 c-#666">产出:{{ form?.varietyInfo?.medicineName }}</view>
-                            <view class="close-icon pd-16" @click="form.varietyId = ''; form.varietyInfo = null;">
+                            <view
+                                class="close-icon pd-16"
+                                @click="
+                                    form.varietyId = '';
+                                    form.varietyInfo = null;
+                                "
+                            >
                                 <up-icon color="#F81242" name="close" size="32rpx"></up-icon>
                             </view>
                         </view>
@@ -45,19 +48,16 @@
                 </up-form-item>
                 <ut-action-sheet :tabs="pt_seed_source" mode="custom" title="种源来源" v-model="form.seedSource">
                     <up-form-item borderBottom label="种源来源" required prop="seedSource">
-                        <view v-if="form.seedSource" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_seed_source,
-                            form.seedSource) }}</view>
+                        <view v-if="form.seedSource" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(pt_seed_source, form.seedSource) }}</view>
                         <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择种源来源</view>
                         <template #right>
                             <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
                         </template>
                     </up-form-item>
                 </ut-action-sheet>
-                <ut-action-sheet :tabs="pt_mother_father_flag" mode="custom" title="父母本情况"
-                    v-model="form.motherFatherFlag">
-                    <up-form-item borderBottom label="父母本情况" required prop="motherFatherFlag">
-                        <view v-if="form.motherFatherFlag" class="f-s-30 c-333 f-w-5 flex1">{{
-                            selectDictLabel(pt_mother_father_flag, form.motherFatherFlag) }}</view>
+                <ut-action-sheet :tabs="pt_mother_father_flag" mode="custom" title="父母本情况" v-model="form.instoreBizInfo.motherFatherFlag">
+                    <up-form-item borderBottom label="父母本情况" prop="motherFatherFlag">
+                        <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>
                             <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
@@ -66,71 +66,90 @@
                 </ut-action-sheet>
                 <template>
                     <!-- 父本品种 -->
-                    <up-form-item borderBottom label="父本品种" prop="fatherVarietyId">
+                    <up-form-item v-if="form?.instoreBizInfo?.motherFatherFlag == '2'" borderBottom label="父本品种" prop="fatherVarietyId">
                         <view class="flex1">
-                            <up-button v-if="!form.fatherVarietyId" @click="selectFatherVarietyId" type="primary" plain>
-                                <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png"
-                                    mode="widthFix" />
+                            <up-button v-if="!form.instoreBizInfo.fatherVarietyId" @click="selectFatherVarietyId" type="primary" plain>
+                                <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png" mode="widthFix" />
                                 <span>请选择父本品种</span>
                             </up-button>
                             <view v-else class="bg-#FBFDFB card-info-block pd-24 p-rtv">
                                 <view class="mb-16">
-                                    <span class="f-s-34 c-#333 f-w-5 mr-16">{{ form?.fatherVarietyInfo?.varietyName
-                                        }}</span>
-                                    <span class="f-s-24 c-#666">{{ form?.fatherVarietyInfo?.latinName }}</span>
+                                    <span class="f-s-34 c-#333 f-w-5 mr-16">{{ form?.instoreBizInfo?.fatherVarietyInfo?.varietyName }}</span>
+                                    <span class="f-s-24 c-#666">{{ form?.instoreBizInfo?.fatherVarietyInfo?.latinName }}</span>
                                 </view>
                                 <view class="mb-16">
-                                    <span class="f-s-28 c-#333 f-w-5 mr-16">{{ form?.fatherVarietyInfo?.genusName
-                                        }}</span>
-                                    <span class="f-s-24 c-#666">{{ form?.fatherVarietyInfo?.genusLatinName }}</span>
+                                    <span class="f-s-28 c-#333 f-w-5 mr-16">{{ form?.instoreBizInfo?.fatherVarietyInfo?.genusName }}</span>
+                                    <span class="f-s-24 c-#666">{{ form?.instoreBizInfo?.fatherVarietyInfo?.genusLatinName }}</span>
                                 </view>
-                                <view class="f-s-24 c-#666">产出:{{ form?.fatherVarietyInfo?.medicineName }}</view>
-                                <view class="close-icon pd-16"
-                                    @click="form.fatherVarietyId = ''; form.fatherVarietyInfo = null;">
+                                <view class="f-s-24 c-#666">产出:{{ form?.instoreBizInfo?.fatherVarietyInfo?.medicineName }}</view>
+                                <view
+                                    class="close-icon pd-16"
+                                    @click="
+                                        form.instoreBizInfo.fatherVarietyId = '';
+                                        form.instoreBizInfo.fatherVarietyInfo = null;
+                                    "
+                                >
                                     <up-icon color="#F81242" name="close" size="32rpx"></up-icon>
                                 </view>
                             </view>
                         </view>
                     </up-form-item>
                     <!-- 母本品种 -->
-                    <up-form-item borderBottom label="母本品种" prop="motherVarietyId">
+                    <up-form-item borderBottom label="母本品种" prop="instoreBizInfo.motherVarietyId">
                         <view class="flex1">
-                            <up-button v-if="!form.motherVarietyId" @click="selectMotherVarietyId" type="primary" plain>
-                                <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png"
-                                    mode="widthFix" />
+                            <up-button v-if="!form.instoreBizInfo.motherVarietyId" @click="selectMotherVarietyId" type="primary" plain>
+                                <image class="w-36 h-36 mr-10" src="@/static/images/common/select_push_icon.png" mode="widthFix" />
                                 <span>请选择母本品种</span>
                             </up-button>
                             <view v-else class="bg-#FBFDFB card-info-block pd-24 p-rtv mt-16">
                                 <view class="mb-16">
-                                    <span class="f-s-34 c-#333 f-w-5 mr-16">{{ form?.motherVarietyInfo?.varietyName
-                                        }}</span>
-                                    <span class="f-s-24 c-#666">{{ form?.motherVarietyInfo?.latinName }}</span>
+                                    <span class="f-s-34 c-#333 f-w-5 mr-16">{{ form?.instoreBizInfo?.motherVarietyInfo?.varietyName }}</span>
+                                    <span class="f-s-24 c-#666">{{ form?.instoreBizInfo?.motherVarietyInfo?.latinName }}</span>
                                 </view>
                                 <view class="mb-16">
-                                    <span class="f-s-28 c-#333 f-w-5 mr-16">{{ form?.motherVarietyInfo?.genusName
-                                        }}</span>
-                                    <span class="f-s-24 c-#666">{{ form?.motherVarietyInfo?.genusLatinName }}</span>
+                                    <span class="f-s-28 c-#333 f-w-5 mr-16">{{ form?.instoreBizInfo?.motherVarietyInfo?.genusName }}</span>
+                                    <span class="f-s-24 c-#666">{{ form?.instoreBizInfo?.motherVarietyInfo?.genusLatinName }}</span>
                                 </view>
-                                <view class="f-s-24 c-#666">产出:{{ form?.motherVarietyInfo?.medicineName }}</view>
-                                <view class="close-icon pd-16"
-                                    @click="form.motherVarietyId = ''; form.motherVarietyInfo = null;">
+                                <view class="f-s-24 c-#666">产出:{{ form?.instoreBizInfo?.motherVarietyInfo?.medicineName }}</view>
+                                <view
+                                    class="close-icon pd-16"
+                                    @click="
+                                        form.instoreBizInfo.motherVarietyId = '';
+                                        form.instoreBizInfo.motherVarietyInfo = null;
+                                    "
+                                >
                                     <up-icon color="#F81242" name="close" size="32rpx"></up-icon>
                                 </view>
                             </view>
                         </view>
                     </up-form-item>
                 </template>
-                <up-form-item borderBottom label="受托单位" prop="entrustId">
-                    <up-input v-model="form.entrustId" placeholder="请输入受托单位" border="none" clearable></up-input>
+                <up-form-item label="繁衍世代" prop="instoreBizInfo.genCount" border-bottom>
+                    <up-input v-model="form.instoreBizInfo.genCount" border="none" placeholder="请输入繁衍世代" clearable />
+                    <template #right>
+                        <view @click.stop>
+                            <ut-action-sheet v-model="form.genUnit" :tabs="pt_gen_unit" mode="custom" title="选择单位">
+                                <!-- 可点击选择单位 -->
+                                <view class="d-flex pd-10" style="">
+                                    <span>{{ form.genUnit || '代' }}</span>
+                                    <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                                </view>
+                            </ut-action-sheet>
+                        </view>
+                    </template>
+                </up-form-item>
+                <up-form-item borderBottom label="受托单位" prop="entrustId" required>
+                    <view class="flex1">
+                        <ContactUnitInput v-model="form.entrustId" v-model:info="form.entrustInfo" :params="{ cpyType: '2' }" title="选择受托单位" placeholder="请选择受托单位信息"></ContactUnitInput>
+                    </view>
                 </up-form-item>
 
                 <!-- 入库数量与单位 -->
-
                 <up-form-item label="入库量" prop="capacity" required borderBottom>
                     <up-input v-model="form.capacity" placeholder="请输入入库量" border="none" clearable />
                     <template #right>
                         <view @click.stop>
-                            <ut-action-sheet v-model="form.unit" :tabs="pt_materail_unit" mode="custom" title="选择单位">
+                            <ut-action-sheet v-model="form.unit" :tabs="pt_seed_unit" mode="custom" title="选择单位">
                                 <!-- 可点击选择单位 -->
                                 <view class="d-flex pd-10" style="">
                                     <span>{{ form.unit || '株' }}</span>
@@ -140,34 +159,44 @@
                         </view>
                     </template>
                 </up-form-item>
-
                 <!-- 检验报告与供应商信息 -->
                 <up-form-item borderBottom label="检验报告" prop="examinReport">
                     <up-input v-model="form.examinReport" placeholder="请输入检验报告编号或说明" border="none" clearable></up-input>
                 </up-form-item>
                 <up-form-item borderBottom label="供应商" prop="supplierId">
-                    <up-input v-model="form.supplierId" placeholder="请输入供应商" border="none" clearable></up-input>
-                </up-form-item>
-                <up-form-item borderBottom label="供应商名称" prop="supplier">
-                    <up-input v-model="form.supplier" placeholder="请输入供应商名称" border="none" clearable></up-input>
-                </up-form-item>
-                <up-form-item borderBottom label="生产商" prop="producer">
-                    <up-input v-model="form.producer" placeholder="请输入生产商名称" border="none" clearable></up-input>
+                     <view class="flex1">
+                        <ContactUnitInput v-model="form.supplierId" v-model:info="form.supplierInfo" :params="{ cpyType: '4' }" title="选择供应商" placeholder="请选择供应商信息"></ContactUnitInput>
+                    </view>
                 </up-form-item>
-
                 <!-- 菌种编码信息 -->
                 <up-form-item borderBottom label="菌种/菌株编号" prop="fungusCode">
                     <up-input v-model="form.fungusCode" placeholder="请输入菌种/菌株编号" border="none" clearable></up-input>
                 </up-form-item>
-                <up-form-item borderBottom label="菌种编码类型" prop="fungusCodeType">
-                    <up-input v-model="form.fungusCodeType" placeholder="请输入菌种编码类型" border="none" clearable></up-input>
+                <up-form-item borderBottom label="供应商是否是生产商" prop="supplierProducerFlag">
+                     <up-radio-group v-model="form.supplierProducerFlag">
+                        <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>
+                </up-form-item>
+                <up-form-item borderBottom label="生产商" prop="producer">
+                    <up-input v-model="form.producer" placeholder="请输入生产商名称" border="none" clearable></up-input>
                 </up-form-item>
 
                 <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
-                <up-form-item borderBottom label="是否有个体标识" prop="animalIds">
-                    
+                <up-form-item borderBottom label="是否有个体标识" prop="instoreBizInfo.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>
+                </up-form-item>
+                <!-- 个体标识:此处仅占位,后续可改为多选列表 -->
+                <template v-if="+form?.instoreBizInfo?.idFlag">
+                    <up-form-item borderBottom label="个体标识号" prop="instoreBizInfo.animals" required>
+                        <AnimalsInput v-model="form.instoreBizInfo.animals"></AnimalsInput>
+                    </up-form-item>
+                </template>
+                <!-- 保藏方法 -->
+                <up-form-item borderBottom label="保藏方法" prop="instoreBizInfo.storageMethod">
+                    <up-input v-model="form.instoreBizInfo.storageMethod" placeholder="请输入保藏方法" border="none" clearable></up-input>
                 </up-form-item>
-
                 <!-- 媒体与附件 -->
                 <up-form-item borderBottom label="种源图片" prop="imgs">
                     <ut-upload v-model="form.imgs" :max-count="9"></ut-upload>
@@ -180,13 +209,17 @@
                 <up-form-item borderBottom label="种源产地" prop="adcode">
                     <up-input v-model="form.adcode" placeholder="请输入种源产地行政编码" border="none" clearable></up-input>
                 </up-form-item>
-                <up-form-item borderBottom label="繁殖材料" prop="generationMaterial">
-                    <up-input v-model="form.generationMaterial" placeholder="请输入繁殖材料" border="none"
-                        clearable></up-input>
-                </up-form-item>
+                <ut-action-sheet :tabs="pt_breeding_materials" mode="custom" title="繁殖材料" multiple v-model="form.generationMaterial">
+                    <up-form-item borderBottom label="繁殖材料" prop="generationMaterial">
+                        <view v-if="form.generationMaterial" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabels(pt_breeding_materials, form.generationMaterial, ',') }}</view>
+                        <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择繁殖材料</view>
+                        <template #right>
+                            <up-icon size="22rpx" color="#2A6D52" name="arrow-down-fill"></up-icon>
+                        </template>
+                    </up-form-item>
+                </ut-action-sheet>
                 <up-form-item borderBottom label="繁殖地点/采集地点" prop="generationAdcode">
-                    <up-input v-model="form.generationAdcode" placeholder="请输入繁殖/采集地点编码或名称" border="none"
-                        clearable></up-input>
+                    <up-input v-model="form.generationAdcode" placeholder="请输入繁殖/采集地点编码或名称" border="none" clearable></up-input>
                 </up-form-item>
 
                 <!-- 资质证明附件(暂按上传控件处理,可后续细化) -->
@@ -215,22 +248,32 @@
             </view>
         </template>
     </z-paging>
+    
 </template>
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';
 import { seedInfoListType } from '../models/type';
+import AnimalsInput from '../models/animals-input.vue';
+import SelectContactUnit from '@/models/select-contact-unit/select-contact-unit.vue';
+import ContactUnitInput from '@/models/contact-unit-input/contact-unit-input.vue';
+
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { pt_seed_type, pt_seed_source, pt_materail_unit, pt_mother_father_flag } = toRefs<any>(proxy?.useDict('pt_seed_type', 'pt_seed_source', 'pt_materail_unit', 'pt_mother_father_flag'));
+const { pt_seed_type, pt_seed_source, pt_materail_unit, pt_mother_father_flag, pt_seed_unit, pt_fungus_code_type, pt_breeding_materials, yes_no, pt_cus_type, pt_cpy_type, pt_gen_unit } = toRefs<any>(proxy?.useDict('pt_seed_type', 'pt_seed_source', 'pt_materail_unit', 'pt_mother_father_flag', 'pt_op_method', 'pt_seed_unit', 'pt_fungus_code_type', 'pt_breeding_materials', 'yes_no', 'pt_cus_type', 'pt_cpy_type', 'pt_gen_unit'));
 const paging = ref<any>(null);
+const selectContactUnitShow = ref(false);
 const upFormRef = ref<any>(null);
 const form = ref<seedInfoListType>({
     imgs: [],
-    vedios: [],
     spCert: [],
     newSpCert: [],
     importCert: [],
     seedCheckCert: [],
     unit: '株',
+    instoreBizInfo: {
+        motherFatherFlag: '',
+        idFlag: '1',
+        genUnit: '代',
+    },
 });
 const rules = reactive({});
 
@@ -276,8 +319,8 @@ const selectVarietyId = () => {
 };
 const selectFatherVarietyId = () => {
     uni.$once('updateBiologicalname', function (data) {
-        form.value.fatherVarietyId = data.msg.id;
-        form.value.fatherVarietyInfo = data.msg;
+        form.value.instoreBizInfo.fatherVarietyId = data.msg.id;
+        form.value.instoreBizInfo.fatherVarietyInfo = data.msg;
     });
     uni.$u.route({
         type: 'navigateTo',
@@ -289,8 +332,8 @@ const selectFatherVarietyId = () => {
 };
 const selectMotherVarietyId = () => {
     uni.$once('updateBiologicalname', function (data) {
-        form.value.motherVarietyId = data.msg.id;
-        form.value.motherVarietyInfo = data.msg;
+        form.value.instoreBizInfo.motherVarietyId = data.msg.id;
+        form.value.instoreBizInfo.motherVarietyInfo = data.msg;
     });
     uni.$u.route({
         type: 'navigateTo',
@@ -303,7 +346,7 @@ const selectMotherVarietyId = () => {
 const did = ref('');
 onLoad((optins: any) => {
     if (optins.id) {
-        // 编辑加载详
+        // 编辑加载详
         did.value = optins.id;
     } else {
     }

+ 50 - 7
src/plant/storage/seed-source/list/index.vue

@@ -6,11 +6,11 @@
 
         <view class="pd3-24-24-0">
             <view class="mb-20">
-                <ut-tabs mode="subsection" :tabs="tabs" v-model="form.queryType"></ut-tabs>
+                <ut-tabs mode="subsection" :tabs="tabs"></ut-tabs>
             </view>
             <view class="d-flex a-c">
                 <view class="min-w-170 flex1">
-                    <ut-action-sheet v-model="form.queryType" :tabs="[{ label: '全部', value: '' }]" @change="onRefresh" title="选择原料类型">
+                    <ut-action-sheet :tabs="[{ label: '全部', value: '' }]" @change="onRefresh" title="选择原料类型">
                         <view class="d-flex search-select-item a-c">
                             <view class="flex1 ov-hd f-s-28 c-333 text-center f-w-5 w-s-no">{{ '全部' }} </view>
                             <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="mr-5"></up-icon>
@@ -23,7 +23,15 @@
             </view>
             <view></view>
         </view>
-        <view class="pd-24 bg-#f7f7f7"> </view>
+        <view class="pd-24 bg-#f7f7f7">
+            <up-swipe-action>
+                <up-swipe-action-item v-for="(item, index) in list" :key="index" :name="item?.id" :options="optionsActionTemp" @click="clickTempSwipe" class="mb-20 b-radius">
+                    <view class="b-radius bg-#fff pd-20 p-rtv" @click.stop="$u.route({ url: '/plant/storage/seed-source/detail/index', params: { id: item.id } })">
+                        <view>{{ item?.variety }}</view>
+                    </view>
+                </up-swipe-action-item>
+            </up-swipe-action>
+        </view>
 
         <template #empty>
             <view class="d-flex flex-cln a-c" style="margin-top: -200rpx">
@@ -40,8 +48,8 @@ import { useClientRequest } from '@/utils/request';
 import SourceBottom from './model/source-bottom.vue';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { pt_task_type } = toRefs<any>(proxy?.useDict('pt_task_type'));
-const list = ref<unknown[]>();
-const form = ref({ queryType: 'seed', keyword: '' });
+const list = ref<any[]>();
+const form = ref({ keyword: '' });
 const paging = ref();
 const tabs = ref([
     { label: '有库存', value: 'seed' },
@@ -57,13 +65,48 @@ const query = async (pageNum: number, pageSize: number) => {
         pageSize,
         ...form.value,
     };
-    const res = await useClientRequest.get('/plt-api/app/plantationTask/list', params);
+    const res = await useClientRequest.get('/plt-api/app/storageSeed/page', params);
     if (res) {
         const { rows } = res;
         paging.value.complete(rows);
     }
 };
-
+// 暂存项左滑删除配置
+const optionsActionTemp = reactive([
+    {
+        text: '删除',
+        style: {
+            backgroundColor: '#f56c6c',
+        },
+    },
+]);
+// 暂存项删除点击(本地移除)
+const clickTempSwipe = async (event: object) => {
+    const { name, index } = event as any;
+    if (index === 0) {
+        try {
+            const res = await uni.showModal({
+                title: '删除提示',
+                content: '确定删除该基地吗?',
+                confirmColor: '#f56c6c',
+            });
+            if (!res.confirm) return;
+            await uni.showLoading({
+                title: '删除中...',
+                mask: true,
+            });
+            await useClientRequest.get(`/plt-api/app/base/delById/${name}`);
+            uni.hideLoading();
+            uni.showToast({
+                title: '删除成功',
+                icon: 'success',
+            });
+            paging.value?.reload();
+        } catch (error) {
+            console.error('删除暂存基地失败:', error);
+        }
+    }
+};
 const onRefresh = () => {
     paging.value.reload();
 };

+ 162 - 0
src/plant/storage/seed-source/models/animals-input.vue

@@ -0,0 +1,162 @@
+<template>
+    <view class="flex1">
+        <view>
+            <up-swipe-action>
+                <template v-for="(item, index) in list" :key="index">
+                    <up-swipe-action-item class="mb-20" :options="options" @click="clickPlotSwipe($event, item, index)">
+                        <view class="ul-block-item pd-24">
+                            {{ item.animalId }}
+                        </view>
+                    </up-swipe-action-item>
+                </template>
+            </up-swipe-action>
+        </view>
+        <view class="d-flex">
+            <up-button class="flex1 mr-20" color="#18BECA" plain @click="onScan">
+                <image class="w-36 h-36 mr-10" src="@/static/images/common/scan_icon_o.png" mode="widthFix" />
+                <span>扫一扫添加</span>
+            </up-button>
+            <up-button @click="onAddClick" class="flex1" color="#37A954" plain>
+                <image class="w-36 h-36 mr-10" src="@/static/images/common/edit_icon.png" mode="widthFix" />
+                <span>手动输入添加</span>
+            </up-button>
+        </view>
+    </view>
+    <ut-confirm-dialog title="添加个体标识" v-model:show="showPop" width="680rpx">
+        <view>
+            <up-form ref="upFormRef" :model="form" :rules="rules" labelWidth="auto" class="p-rtv" labelPosition="top">
+                <up-form-item label="个体标识号" border-bottom prop="animalId" required>
+                    <up-input v-model="form.animalId" border="none" :maxlength="200" clearable placeholder="请输入个体标识号"></up-input>
+                </up-form-item>
+            </up-form>
+        </view>
+        <template #footer>
+            <view class="d-flex j-c pd-30">
+                <up-button @click="showPop = false" class="mr-30" style="color: #333" color="#F2F2F2">取消</up-button>
+                <up-button @click="onConfirm" type="primary">确认</up-button>
+            </view>
+        </template>
+    </ut-confirm-dialog>
+</template>
+<script setup lang="ts">
+const props = defineProps({
+    modelValue: {
+        type: Array,
+        default: () => [],
+    },
+});
+const upFormRef = ref();
+const rules = reactive({
+    animalId: [{ required: true, message: '请输入个体标识号', trigger: 'blur' }],
+});
+const showPop = ref(false);
+const form = ref({
+    animalId: '',
+});
+// -1 表示新增,其它为编辑的下标
+const editIndex = ref<number>(-1);
+const emit = defineEmits(['update:modelValue']);
+const list = ref<any[]>(props.modelValue);
+const options = ref([
+    {
+        text: '编辑',
+        name: 'edit',
+        style: {
+            backgroundColor: '#37a954',
+            color: '#fff',
+        },
+    },
+    {
+        text: '删除',
+        name: 'delete',
+        style: {
+            backgroundColor: '#FF3B30',
+            color: '#fff',
+        },
+    },
+]);
+const clickPlotSwipe = (e: any, item: any, index: number) => {
+    console.log(e);
+    
+    if (e.index == 0) {
+        // 编辑个体标识
+        console.log('编辑个体标识', item, index);
+        editIndex.value = index;
+        form.value.animalId = item?.animalId || '';
+        showPop.value = true;
+    } else if (e.index == 1) {
+        // 删除个体标识
+        list.value.splice(index, 1);
+        emit('update:modelValue', [...list.value]);
+        
+    }
+};
+const onConfirm = async () => {
+    try {
+        // uview-plus 的 up-form 暴露 validate 方法
+        await upFormRef.value?.validate();
+        if (editIndex.value > -1) {
+            // 编辑模式:更新当前项
+            list.value[editIndex.value] = { ...list.value[editIndex.value], ...form.value };
+        } else {
+            // 新增模式:追加一项
+            list.value.push({ ...form.value });
+        }
+        emit('update:modelValue', [...list.value]);
+        showPop.value = false;
+        form.value.animalId = '';
+        editIndex.value = -1;
+    } catch (e) {
+        // 校验不通过
+    }
+};
+// 手动新增按钮点击
+const onAddClick = () => {
+    editIndex.value = -1;
+    form.value.animalId = '';
+    showPop.value = true;
+};
+
+// 扫一扫添加
+const onScan = () => {
+    // #ifdef MP-WEIXIN
+    uni.scanCode({
+        onlyFromCamera: true,
+        success: (res) => {
+            const code = (res.result || '').trim();
+            if (!code) return;
+            // 直接追加到列表
+            list.value.push({ animalId: code });
+            emit('update:modelValue', [...list.value]);
+        },
+        fail: () => {},
+    });
+    // #endif
+    // 其他端如 H5/App 可按需再做兼容
+};
+watch(
+    () => props.modelValue,
+    (newVal) => {
+        list.value = newVal;
+    },
+);
+</script>
+<script lang="ts">
+export default {
+    options: {
+        // 微信小程序中 options 选项
+        multipleSlots: true, //  在组件定义时的选项中启动多slot支持,默认启用
+        styleIsolation: 'shared', //  启动样式隔离。当使用页面自定义组件,希望父组件影响子组件样式时可能需要配置。具体配置选项参见:微信小程序自定义组件的样式
+        addGlobalClass: true, //  表示页面样式将影响到自定义组件,但自定义组件中指定的样式不会影响页面。这个选项等价于设置 styleIsolation: apply-shared
+        virtualHost: true, //  将自定义节点设置成虚拟的,更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
+    },
+};
+</script>
+<style lang="scss" scoped>
+.ul-block-item {
+    border-radius: 16rpx;
+    border: 1px solid #AFDDBB;
+    // 字体数字可换行
+    word-break: break-all;
+}
+</style>

+ 14 - 0
src/plant/storage/seed-source/models/type.ts

@@ -74,6 +74,7 @@ export interface seedInfoListType {
     seedCheckCert?: AccesseryDTO[];
 
     [property: string]: any;
+    instoreBizInfo: instoreBizInfoType;
 }
 export interface AccesseryDTO {
     /**
@@ -107,4 +108,17 @@ export interface instoreBizInfoType {
     instoreMg?: string;
     /** 备注 */
     remark?: string;
+    /** 父母本情况 */
+    motherFatherFlag: string;
+    /** 父本品种ID */
+    fatherVarietyId?: string;
+        /** 母本品种ID */
+    motherVarietyId?: string;
+    fatherVarietyInfo?: any;
+    motherVarietyInfo?: any;
+    idFlag: string;
+    animals?: any[];
+    storageMethod?: string;
+    genUnit?: string;
+    [property: string]: any;
 }

BIN
src/static/images/common/edit_icon.png


BIN
src/static/images/common/scan_icon_o.png