Ver Fonte

加工完成

lisy há 1 semana atrás
pai
commit
637694055d

+ 1 - 6
src/App.vue

@@ -6,6 +6,7 @@ import { useInfoStore } from '@/store';
 const infoStore = useInfoStore();
 onLaunch(async () => {
     console.log('App Launch');
+    infoStore?.setNavConfig('default'); // 或 'custom',根据需要设置默认导航配置
     // 应用启动时检查登录状态
     try {
         // await autoLogin();
@@ -13,12 +14,6 @@ onLaunch(async () => {
         console.error('Auto login check failed:', error);
     }
 });
-// 设置token并指定过期时间(例如24小时)
-console.log('设定token');
-// infoStore.setToken('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJhcHBfdXNlcjoxOTQwMjQ1NzU5Mjk2ODY0MjU3Iiwicm5TdHIiOiJxRTE5RXhnZHVwa2hpdWo4eUo2M1pSZ0M1ZGxrNmt4YyIsImNsaWVudGlkIjoiMjAyNTAyMTQiLCJvcGVuaWQiOiJva0NHMjRrU29nT2VWTGFkc1JVYm8tS2JqR2Y4IiwidXNlcklkIjoxOTQwMjQ1NzU5Mjk2ODY0MjU3fQ.g8ZPjLyKcQQ2WOOsyoopjQMHepnutGJ5a1MGvAbgwzs');
-console.log('获取用户信息,app');
-// infoStore.getUserInfo();
-// infoStore.getCompanyInfo();
 onShow(() => {
     console.log('App Show');
 });

+ 44 - 14
src/components/ut-tabar/ut-tabar.vue

@@ -1,16 +1,8 @@
 <template>
     <view class="d-flex a-c j-sb bg-fff pd-10">
-        <view
-            v-for="item in navs"
-            :key="item.id"
-            @click="navigate(item)"
-            class="c-#999 f-s-24 d-flex flex-cln j-c a-c flex1"
-        >
-            <image
-                :class="'w-64 h-64'"
-                :src="activeTab === item.id ? item.activeIcon : item.icon"
-                mode="widthFix"
-            />
+        <view v-for="item in navs" :key="item.id" @click="navigate(item)"
+            class="c-#999 f-s-24 d-flex flex-cln j-c a-c flex1">
+            <image :class="'w-64 h-64'" :src="activeTab === item.id ? item.activeIcon : item.icon" mode="widthFix" />
             <view class="text-center" :class="activeTab === item.id ? 'c-primary f-w-5' : ''">
                 {{ item.label }}
             </view>
@@ -20,17 +12,21 @@
 </template>
 
 <script setup lang="ts">
+import { useInfoStore } from '@/store';
+import { computed } from 'vue';
+
 const showStorage = ref(false);
+const infoStore = useInfoStore();
 
 defineProps<{
-    activeTab?: string; // 当前活跃的tab标识符:'base' | 'planting' | 'warehouse' | 'processing' | 'more'
+    activeTab?: string; // 当前活跃的 tab 标识符:'base' | 'planting' | 'warehouse' | 'processing' | 'more'
 }>();
 
 const windowInfo = uni.getWindowInfo();
 const safeAreaBottom = windowInfo.safeAreaInsets.bottom;
 
-// data-driven nav items
-const navs = [
+// 默认导航项
+const defaultNavs = [
     {
         id: 'base',
         label: '基地',
@@ -68,6 +64,40 @@ const navs = [
     },
 ];
 
+// 自定义导航项(仅显示 processing, storage, more)
+const customNavs = [
+    {
+        id: 'processing',
+        label: '加工包装',
+        icon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomProcessingPackaging.png',
+        activeIcon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomProcessingPackagingActive.png',
+        url: '/pages/plant/processing/index',
+    },
+    {
+        id: 'storage',
+        label: '仓储',
+        icon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomWarehouse.png',
+        activeIcon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomWarehouseActive.png',
+        url: '/pages/plant/storage/index',
+    },
+    {
+        id: 'more',
+        label: '更多',
+        icon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomMore.png',
+        activeIcon: 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/bottomMoreActive.png',
+        url: '/pages/plant/more/index',
+    },
+];
+
+// 根据 navConfig 动态计算导航项
+const navs = computed(() => {
+    if (infoStore.navConfig !== 'default') {
+        return customNavs;
+    }
+    // 默认显示全部导航项
+    return defaultNavs;
+});
+
 function navigate(item: { id: string; url: string }) {
     // certain tabs should clear showStorage flag
     if (item.id === 'base' || item.id === 'planting') {

+ 153 - 0
src/components/ut-tree/ut-tree-node.vue

@@ -0,0 +1,153 @@
+<template>
+    <view class="u-tree-node" :style="{ paddingLeft: depth * 20 + 'px' }">
+        <view class="u-tree-node-content" @click="toggle">
+            <!-- 只有第一级(有子节点)才显示展开/折叠图标 -->
+            <up-icon v-if="hasChildren" class="u-tree-node-toggle" :name="node.expanded ? 'arrow-down-fill' : 'play-right-fill'" size="12" />
+            <!-- 第二级没有子节点,显示一个占位空格保持对齐 -->
+            <view v-else class="u-tree-node-indent" style="width: 16px; margin-right: 5px"></view>
+            <up-checkbox v-if="showCheckbox" usedAlone :size="12" :checked="node.checked" @change="toggleCheck" style="margin-right: 10px" />
+            <!-- 自定义插槽内容 -->
+            <slot :nodeData="node" :level="depth + 1">
+                {{ node[props.props.label] }}
+            </slot>
+        </view>
+
+        <!-- 子节点渲染:只渲染一级,不递归 -->
+        <view v-if="hasChildren && (node.expanded === undefined ? false : node.expanded)" class="u-tree-node-children" :style="{ paddingLeft: (depth + 1) * 20 + 'px' }">
+            {{ node.expanded }}
+            <view v-for="child in node.children" :key="child?.id" class="u-tree-node-child">
+                <view class="u-tree-node-content" @click.stop="toggleChildCheck(child)">
+                    <!-- 第二级不显示展开图标,用占位符 -->
+                    <view class="u-tree-node-indent" style="width: 16px; margin-right: 5px"></view>
+                    <up-checkbox usedAlone :size="12" :checked="child.checked" @change="toggleChildCheck($event, child)" style="margin-right: 10px" />
+                    <!-- 第二级显示内容:直接使用 label,不使用插槽避免重复插槽警告 -->
+                    <text>{{ child?.label }}</text>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue';
+
+defineOptions({
+    name: 'TreeNode',
+});
+
+const props = defineProps({
+    node: {
+        type: Object,
+        required: true,
+    },
+    props: {
+        type: Object,
+        required: true,
+    },
+    showCheckbox: {
+        type: Boolean,
+        default: false,
+    },
+    checkStrictly: {
+        type: Boolean,
+        default: false,
+    },
+    expandOnClickNode: {
+        type: Boolean,
+        default: true,
+    },
+    depth: {
+        type: Number,
+        default: 0,
+    },
+});
+
+const emit = defineEmits(['node-click', 'check-change']);
+
+const hasChildren = computed(() => {
+    return props.node.children && props.node.children.length > 0;
+});
+
+// 切换当前节点的展开/折叠状态
+const toggle = () => {
+    if (props.expandOnClickNode && hasChildren.value) {
+        props.node.expanded = !props.node.expanded;
+    }
+    emit('node-click', props.node);
+};
+
+// 切换当前节点的复选框状态
+const toggleCheck = (checked: boolean) => {
+    props.node.checked = checked;
+    if (!props.checkStrictly) {
+        updateChildCheckStatus(props.node, checked);
+    }
+    emit('check-change', props.node);
+};
+
+// 切换子节点的复选框状态
+const toggleChildCheck = (event: boolean | Event, child?: any) => {
+    // 如果是直接传入的 checked 值和子节点
+    if (child) {
+        child.checked = event as boolean;
+        emit('check-change', child);
+        return;
+    }
+    // 如果是点击事件,需要处理
+    const checked = event as boolean;
+    if (props.node.children) {
+        props.node.children.forEach((c: any) => {
+            c.checked = checked;
+        });
+        emit('check-change', props.node);
+    }
+};
+
+// 更新子节点的复选框状态
+const updateChildCheckStatus = (node: any, checked: boolean) => {
+    if (node[props.props.children]) {
+        node[props.props.children].forEach((child: any) => {
+            child.checked = checked;
+        });
+    }
+};
+</script>
+
+<style scoped>
+.u-tree-node {
+    position: relative;
+}
+
+.u-tree-node-content {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    padding-left: 20px;
+    padding-right: 10px;
+    padding-top: 8px;
+    padding-bottom: 8px;
+    cursor: pointer;
+}
+
+.u-tree-node-content:hover {
+    background-color: #f5f7fa;
+}
+
+.u-tree-node-toggle {
+    margin-right: 5px;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    width: 16px;
+    height: 16px;
+}
+
+.u-tree-node-children {
+    overflow: hidden;
+}
+
+.u-tree-node-child {
+    padding-top: 4px;
+    padding-bottom: 4px;
+}
+</style>

+ 112 - 0
src/components/ut-tree/ut-tree.vue

@@ -0,0 +1,112 @@
+<template>
+    <scroll-view class="u-tree" scroll-y enable-flex>
+        <TreeNode v-for="node in treeData" :key="node[props.nodeKey]" :node="node" :props="props" :show-checkbox="showCheckbox" :check-strictly="checkStrictly" :expand-on-click-node="expandOnClickNode" :depth="0" @node-click="handleNodeClick" @check-change="$emit('check-change', $event)">
+            <template #default="{ nodeData, level }">
+                <slot :node="nodeData" :level="level"></slot>
+            </template>
+        </TreeNode>
+    </scroll-view>
+</template>
+
+<script setup>
+import TreeNode from './ut-tree-node.vue';
+import { ref, watch, onMounted } from 'vue';
+
+const props = defineProps({
+    data: {
+        type: Array,
+        required: true,
+    },
+    props: {
+        type: Object,
+        default: () => ({
+            label: 'label',
+            children: 'children',
+            nodeKey: 'id',
+        }),
+    },
+    showCheckbox: {
+        type: Boolean,
+        default: false,
+    },
+    defaultExpandAll: {
+        type: Boolean,
+        default: false,
+    },
+    expandOnClickNode: {
+        type: Boolean,
+        default: true,
+    },
+    checkStrictly: {
+        type: Boolean,
+        default: false,
+    },
+});
+
+const emit = defineEmits(['node-click', 'check-change']);
+
+const treeData = ref([]);
+
+// 暴露方法给父组件
+const getCheckedNodes = () => {
+    const traverse = (nodes) => {
+        let result = [];
+        nodes.forEach((node) => {
+            if (node.checked) {
+                result.push(node);
+            }
+            if (node[props.props.children] && node[props.props.children].length > 0) {
+                result = result.concat(traverse(node[props.props.children]));
+            }
+        });
+        return result;
+    };
+    return traverse(treeData.value);
+};
+
+// 定义 expose
+defineExpose({
+    getCheckedNodes,
+});
+
+// 初始化树数据 - 所有节点都设置为相同的 expanded 值
+const initTree = () => {
+    treeData.value = JSON.parse(JSON.stringify(props.data));
+    initExpandedState(treeData.value, false);
+};
+
+// 初始化展开状态 - 所有节点都设置为相同的 expanded 值
+const initExpandedState = (nodes, expanded) => {
+    nodes.forEach((node) => {
+        // 设置当前节点的 expanded 状态
+        node.expanded = expanded;
+        // 递归处理子节点
+        if (node[props.props.children]) {
+            initExpandedState(node[props.props.children], expanded);
+        }
+    });
+};
+
+watch(
+    () => props.data,
+    (newVal) => {
+        treeData.value = JSON.parse(JSON.stringify(newVal));
+        initExpandedState(treeData.value, props.defaultExpandAll);
+    },
+    { deep: true, immediate: true },
+);
+
+const handleNodeClick = (node) => {
+    emit('node-click', node);
+};
+
+onMounted(() => {
+    initTree();
+});
+</script>
+
+<style scoped>
+.u-tree {
+    font-size: 28rpx;
+}
+</style>

+ 107 - 40
src/pages/plant/base/index.vue

@@ -4,14 +4,18 @@
             <up-navbar :fixed="true" :bgColor="navBarBgColor">
                 <template #left>
                     <view class="d-flex a-c pb-5" id="topup-navbar" :style="{ width: `${bubble.left - 30}px` }">
-                        <image class="home_icon mr-20" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/home.png" mode="widthFix" />
+                        <image class="home_icon mr-20"
+                            src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/home.png"
+                            mode="widthFix" />
                         <text class="f-s-40 c-333 f-w-5 w-s-no">中药材种植全链条追溯</text>
                         <view class="flex1"></view>
                     </view>
                 </template>
             </up-navbar>
         </template>
-        <view class="h-500 w-100%" style="background: linear-gradient(to left, #d2f7d5, #eafad8); position: absolute; top: 0; left: 0; z-index: -1"> </view>
+        <view class="h-500 w-100%"
+            style="background: linear-gradient(to left, #d2f7d5, #eafad8); position: absolute; top: 0; left: 0; z-index: -1">
+        </view>
         <template>
             <up-navbar :fixed="false" bgColor="transparent">
                 <template #left>
@@ -20,7 +24,8 @@
             </up-navbar>
             <view class="user-page-header pd-10 d-flex a-c mg-14 p-rtv">
                 <view class="user-page-header-avatar mr-20 p-rtv">
-                    <up-avatar size="116rpx" :src="avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'"></up-avatar>
+                    <up-avatar size="116rpx"
+                        :src="avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'"></up-avatar>
                 </view>
                 <view class="flex1 ov-hd mr-40">
                     <view class="p-rtv d-flex a-c mb-6">
@@ -29,7 +34,8 @@
                             <text class="c-999 f-s-24">{{ setCipByNum(phone ?? null, 3, 4) || '-' }}</text>
                         </view>
                     </view>
-                    <view class="f-s-22 mr-10 radius-30 pt-4 pb-4 pl-10 pr-10 c-primary bg-#b7e8bc" style="width: max-content">
+                    <view class="f-s-22 mr-10 radius-30 pt-4 pb-4 pl-10 pr-10 c-primary bg-#b7e8bc"
+                        style="width: max-content">
                         {{ currentCpyName }}
                     </view>
                 </view>
@@ -38,46 +44,63 @@
         <template>
             <view class="p-rtv">
                 <view class="pd-10 mg-14">
-                    <view class="b-radius pd-6" style="border: 1rpx solid #fff; background: linear-gradient(90deg, #c1f3c5 0%, rgba(193, 243, 197, 0.5) 20%, rgba(255, 255, 255, 0.5) 35%, rgba(255, 255, 255, 0.5) 50%, rgba(232, 255, 234, 0.5) 100%, #e8ffea 100%), linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.3) 30%, rgba(255, 255, 255, 0.3) 80%, transparent 100%)">
+                    <view class="b-radius pd-6"
+                        style="border: 1rpx solid #fff; background: linear-gradient(90deg, #c1f3c5 0%, rgba(193, 243, 197, 0.5) 20%, rgba(255, 255, 255, 0.5) 35%, rgba(255, 255, 255, 0.5) 50%, rgba(232, 255, 234, 0.5) 100%, #e8ffea 100%), linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.3) 30%, rgba(255, 255, 255, 0.3) 80%, transparent 100%)">
                         <view class="b-radius pd-10 p-rtv" style="border: 1rpx solid #baedbf">
-                            <image class="w-200" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/typeofBusiness.png" mode="widthFix" style="position: absolute; top: 10rpx; left: 10rpx" />
+                            <image class="w-200"
+                                src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/typeofBusiness.png"
+                                mode="widthFix" style="position: absolute; top: 10rpx; left: 10rpx" />
                             <view v-if="!speciesArray.length" class="pd-20"></view>
                             <view v-if="speciesArray.length" class="d-flex pr-15">
                                 <view class="flex1"></view>
-                                <view class="f-s-22 c-primary" @click="$u.route({ url: '/plant/species/config/index' })">去修改{{ '>' }}</view>
+                                <view class="f-s-22 c-primary"
+                                    @click="$u.route({ url: '/plant/species/config/index' })">去修改{{ '>' }}</view>
                             </view>
                             <view v-if="speciesArray.length" class="c-#333 f-s-24 d-flex pl-40 pr-15 pb-15 pt-15">
                                 <view class="ov-hd tx-ov w-s-no">{{ speciesArray.join('、') }}</view>
-                                <view v-if="speciesArray.length > 4" class="flex1 w-s-no">等{{ speciesArray.length }}个品种 </view>
+                                <view v-if="speciesArray.length > 4" class="flex1 w-s-no">等{{ speciesArray.length }}个品种
+                                </view>
                             </view>
-                            <view v-if="!speciesArray.length" @click="$u.route({ url: '/plant/species/config/index' })" class="c-primary bg-#E3F6E7 f-s-22 mg-at radius-10 w-250 h-50 d-flex a-c j-c"> 暂未配置品种,去配置{{ '>' }}</view>
+                            <view v-if="!speciesArray.length" @click="$u.route({ url: '/plant/species/config/index' })"
+                                class="c-primary bg-#E3F6E7 f-s-22 mg-at radius-10 w-250 h-50 d-flex a-c j-c">
+                                暂未配置品种,去配置{{ '>' }}</view>
                             <view v-if="!speciesArray.length" class="pd-7"></view>
                         </view>
                     </view>
                 </view>
-                <view class="b-radius pt-0 bg-#f7f7f7" style="border: 1rpx solid #fff; border-bottom-color: transparent; margin-top: -40rpx">
+                <view class="b-radius pt-0 bg-#f7f7f7"
+                    style="border: 1rpx solid #fff; border-bottom-color: transparent; margin-top: -40rpx">
                     <up-sticky :offset-top="stickyTop" zIndex="10">
                         <view class="pd-24 p-rtv bg-#f7f7f7">
-                            <image src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/basePlotBG.png" class="w-100%" mode="widthFix" style="position: absolute; top: 0; left: 0"></image>
+                            <image src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/basePlotBG.png"
+                                class="w-100%" mode="widthFix" style="position: absolute; top: 0; left: 0"></image>
                             <view class="d-flex a-c mb-26 p-rtv">
                                 <view class="p-rtv d-flex flex-cln">
                                     <view class="c-333 f-s-32 f-w-5 z-index-1">基地与地块管理</view>
-                                    <image class="w-230 h-11" style="margin-top: -10rpx" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/BasePlotManagement.png" mode="widthFix" />
+                                    <image class="w-230 h-11" style="margin-top: -10rpx"
+                                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/BasePlotManagement.png"
+                                        mode="widthFix" />
                                 </view>
                                 <view class="flex1"></view>
-                                <view @click="$u.route({ url: '/plant/base/gap-base-info/index' })" class="c-primary f-s-22 z-index-1">GAP基地获评信息管理{{ '>' }}</view>
+                                <view @click="$u.route({ url: '/plant/base/gap-base-info/index' })"
+                                    class="c-primary f-s-22 z-index-1">GAP基地获评信息管理{{ '>' }}</view>
                             </view>
                             <view class="d-flex a-c p-rtv">
                                 <view class="w-220">
-                                    <ut-action-sheet v-model="form.queryType" :tabs="typeNums" @change="onRefresh" title="选择原料类型">
+                                    <ut-action-sheet v-model="form.queryType" :tabs="typeNums" @change="onRefresh"
+                                        title="选择原料类型">
                                         <view class="d-flex search-select-item a-c">
-                                            <view class="flex1 ov-hd f-s-26 c-333 text-center f-w-5 w-s-no up-line-1">{{ selectDictLabel(typeNums, form?.queryType) || '全部' }} </view>
-                                            <up-icon size="24rpx" color="#333" name="arrow-down-fill" class="ml-5"></up-icon>
+                                            <view class="flex1 ov-hd f-s-26 c-333 text-center f-w-5 w-s-no up-line-1">{{
+                                                selectDictLabel(typeNums, form?.queryType) || '全部' }} </view>
+                                            <up-icon size="24rpx" color="#333" name="arrow-down-fill"
+                                                class="ml-5"></up-icon>
                                         </view>
                                     </ut-action-sheet>
                                 </view>
                                 <view class="pl-16 flex1 ov-hd">
-                                    <ut-search ref="searchRef" v-model="form.keyword" @search="changeSeach" margin="0" :border="false" placeholder="搜基地名称、编号、地址、负责人" bgColor="#fff" height="86rpx" borderRadius="10rpx"></ut-search>
+                                    <ut-search ref="searchRef" v-model="form.keyword" @search="changeSeach" margin="0"
+                                        :border="false" placeholder="搜基地名称、编号、地址、负责人" bgColor="#fff" height="86rpx"
+                                        borderRadius="10rpx"></ut-search>
                                 </view>
                             </view>
                         </view>
@@ -85,8 +108,10 @@
                     <view class="pd4-10-24-24-24">
                         <template>
                             <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/base/base-detail/index', params: { id: item.id } })">
+                                <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/base/base-detail/index', params: { id: item.id } })">
                                         <view class="c-333 f-s-34 pd-5 f-w-5">{{ item?.baseName }}</view>
                                         <view class="c-ccc f-s-24 pd-5 pt-0">{{ item?.baseCode }}</view>
                                         <view class="d-flex a-c">
@@ -102,27 +127,45 @@
                                         </view>
                                         <view class="c-333 f-s-28 pd-5">
                                             <text class="c-#666">基地地址:</text>
-                                            <text class="f-w-5">{{ (item?.gapInfo?.adcodeName || '') + (item?.gapInfo?.address || '') || '-' }}</text>
+                                            <text class="f-w-5">{{ (item?.gapInfo?.adcodeName || '') +
+                                                (item?.gapInfo?.address || '') || '-' }}</text>
                                         </view>
                                         <view v-if="item?.plantingVarieties?.length" class="c-333 f-s-28 pd-5 d-flex">
                                             <text class="c-#666 w-s-no">当前在地品种:</text>
-                                            <text class="ov-hd tx-ov w-s-no f-w-5">{{ item.plantingVarieties?.map((items) => items.variety).join('、') || '-' }}</text>
-                                            <text v-if="item?.plantingVarieties?.length" class="flex1 w-s-no f-w-5">等{{ item.plantingVarieties?.length }}个品种</text>
+                                            <text class="ov-hd tx-ov w-s-no f-w-5">{{
+                                                item.plantingVarieties?.map((items) => items.variety).join('、') || '-'
+                                            }}</text>
+                                            <text v-if="item?.plantingVarieties?.length" class="flex1 w-s-no f-w-5">等{{
+                                                item.plantingVarieties?.length }}个品种</text>
                                         </view>
                                         <template v-if="item.gapInfo?.basePic">
                                             <view class="pd-10"></view>
                                             <view class="p-rtv">
-                                                <image class="w-full h-310" :src="item.gapInfo?.basePic" mode="aspectFill"></image>
-                                                <view class="d-flex flex-cln a-ed" style="position: absolute; bottom: 20rpx; right: 0">
-                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20 mb-10" style="border-radius: 10rpx 0 0 10rpx; width: max-content">{{ item?.contactName }}负责</view>
-                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20 mb-10" style="border-radius: 10rpx 0 0 10rpx; width: max-content">{{ selectDictLabel(pt_org_type, item?.orgType) }}</view>
-                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20" style="border-radius: 10rpx 0 0 10rpx; width: max-content">经度:E{{ item?.gapInfo?.lng }} 纬度:N{{ item?.gapInfo?.lat }}</view>
+                                                <image class="w-full h-310" :src="item.gapInfo?.basePic"
+                                                    mode="aspectFill"></image>
+                                                <view class="d-flex flex-cln a-ed"
+                                                    style="position: absolute; bottom: 20rpx; right: 0">
+                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20 mb-10"
+                                                        style="border-radius: 10rpx 0 0 10rpx; width: max-content">{{
+                                                            item?.contactName }}负责</view>
+                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20 mb-10"
+                                                        style="border-radius: 10rpx 0 0 10rpx; width: max-content">{{
+                                                            selectDictLabel(pt_org_type, item?.orgType) }}</view>
+                                                    <view class="pd2-10-20 bg-black-op-0.5 c-#ccc f-s-20"
+                                                        style="border-radius: 10rpx 0 0 10rpx; width: max-content">
+                                                        经度:E{{ item?.gapInfo?.lng }} 纬度:N{{ item?.gapInfo?.lat }}</view>
                                                 </view>
                                                 <view style="position: absolute; top: 20rpx; left: 0">
                                                     <template v-for="(resq, index) in item?.resInfo" :key="index">
-                                                        <view class="base-status-gap-1" v-if="resq?.res == '1'">获评{{ resq?.medicineName }}{{ selectDictLabel(pt_base_form, resq?.type) }}基地</view>
-                                                        <view class="base-status-gap-2" v-if="resq?.res == '2'">标记{{ resq?.medicineName }}{{ selectDictLabel(pt_base_form, resq?.type) }}基地未通过审核</view>
-                                                        <view class="base-status-gap-0" v-if="resq?.res == '0'">标记{{ resq?.medicineName }}{{ selectDictLabel(pt_base_form, resq?.type) }}基地待审核</view>
+                                                        <view class="base-status-gap-1" v-if="resq?.res == '1'">获评{{
+                                                            resq?.medicineName }}{{ selectDictLabel(pt_base_form,
+                                                                resq?.type) }}基地</view>
+                                                        <view class="base-status-gap-2" v-if="resq?.res == '2'">标记{{
+                                                            resq?.medicineName }}{{ selectDictLabel(pt_base_form,
+                                                                resq?.type) }}基地未通过审核</view>
+                                                        <view class="base-status-gap-0" v-if="resq?.res == '0'">标记{{
+                                                            resq?.medicineName }}{{ selectDictLabel(pt_base_form,
+                                                                resq?.type) }}基地待审核</view>
                                                     </template>
                                                 </view>
                                             </view>
@@ -134,11 +177,13 @@
                                             </view>
                                             <view v-if="item?.orgType" class="c-333 f-s-28 pd-5">
                                                 <text class="c-#666">组织方式:</text>
-                                                <text class="f-w-5">{{ selectDictLabel(pt_org_type, item?.orgType) }}</text>
+                                                <text class="f-w-5">{{ selectDictLabel(pt_org_type, item?.orgType)
+                                                }}</text>
                                             </view>
                                             <view v-if="item?.orgType" class="c-333 f-s-28 pd-5">
                                                 <text class="c-#666">经纬度:</text>
-                                                <text class="f-w-5">E{{ item?.gapInfo?.lng }},N{{ item?.gapInfo?.lat }}</text>
+                                                <text class="f-w-5">E{{ item?.gapInfo?.lng }},N{{ item?.gapInfo?.lat
+                                                }}</text>
                                             </view>
                                         </template>
                                         <view v-if="+(item?.tempFlag ?? 0)" class="temp_flag">暂存</view>
@@ -152,9 +197,13 @@
         </template>
         <template #empty>
             <view class="" style="margin-top: -200rpx">
-                <ut-empty class="mg-at" color="#ccc" size="28rpx" image="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/noEmptyBase.png">尚未添加绘制种养殖基地信息~</ut-empty>
-                <view class="b-radius c-#fff f-s-36 bg-#37A954 h-78 w-382 d-flex a-c j-c mg-at" @click="showDeleteDialog = true">
-                    <img class="w-38 h-36 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/chooseGAP.png" alt="" mode="widthFix" />
+                <ut-empty class="mg-at" color="#ccc" size="28rpx"
+                    image="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/noEmptyBase.png">尚未添加绘制种养殖基地信息~</ut-empty>
+                <view class="b-radius c-#fff f-s-36 bg-#37A954 h-78 w-382 d-flex a-c j-c mg-at"
+                    @click="showDeleteDialog = true">
+                    <img class="w-38 h-36 mr-10"
+                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/chooseGAP.png" alt=""
+                        mode="widthFix" />
                     <text>去添加基地</text>
                 </view>
             </view>
@@ -164,24 +213,38 @@
         </template>
     </z-paging>
 
-    <ut-confirm-dialog v-model:show="showDeleteDialog" width="80vw" title="请选择要添加到基地类型" :confirmText="'确认选择'" :cancelText="'取消'" @confirm="handlechoseConfirm" @cancel="handleDeleteCancel">
+    <ut-confirm-dialog v-model:show="showDeleteDialog" width="80vw" title="请选择要添加到基地类型" :confirmText="'确认选择'"
+        :cancelText="'取消'" @confirm="handlechoseConfirm" @cancel="handleDeleteCancel">
         <view class="" v-for="item in pt_base_type" :key="item?.value">
-            <view style="border: 1rpx solid" :style="{ backgroundColor: item?.value == basetype ? '#EBF6EE' : '#f7f7f7', borderColor: item?.value == basetype ? '#37A954' : 'transparent' }" class="pr-30 d-flex a-c mb-20 radius-100" @click="handlechose(item.value)">
+            <view style="border: 1rpx solid"
+                :style="{ backgroundColor: item?.value == basetype ? '#EBF6EE' : '#f7f7f7', borderColor: item?.value == basetype ? '#37A954' : 'transparent' }"
+                class="pr-30 d-flex a-c mb-20 radius-100" @click="handlechose(item.value)">
                 <view class="radius-50% mg-8">
-                    <up-avatar size="90rpx" :src="item?.avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'" class="mr-20"></up-avatar>
+                    <up-avatar v-if="+item?.value == 1" size="90rpx"
+                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/Herbal_Cultivation.png"
+                        class="mr-20" />
+                    <up-avatar v-if="+item?.value == 2" size="90rpx"
+                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/TCM_Animal_Farming.png"
+                        class="mr-20" />
+                    <up-avatar v-if="+item?.value == 3" size="90rpx"
+                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/Tissue_Culture_Lab.png"
+                        class="mr-20" />
                 </view>
                 <view class="c-#333 f-s-34">
                     {{ item?.label }}
                 </view>
                 <view class="flex1"></view>
                 <view class="d-flex">
-                    <img v-if="basetype === item.value" class="w-30 h-30" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/chooseSuccessfully.png" mode="widthFix" alt="" />
+                    <img v-if="basetype === item.value" class="w-30 h-30"
+                        src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/chooseSuccessfully.png"
+                        mode="widthFix" alt="" />
                 </view>
             </view>
         </view>
     </ut-confirm-dialog>
     <ut-suspension @click="showDeleteDialog = true">
-        <image src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/addBase.png" mode="widthFix" class="w-120 h-120"></image>
+        <image src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/addBase.png" mode="widthFix"
+            class="w-120 h-120"></image>
     </ut-suspension>
 </template>
 <script setup lang="ts">
@@ -422,6 +485,7 @@ onShow(() => {
     box-sizing: border-box;
     padding: 12rpx;
 }
+
 .temp_flag {
     position: absolute;
     right: 0;
@@ -432,6 +496,7 @@ onShow(() => {
     padding: 4rpx 16rpx;
     border-radius: 0 16rpx 0 16rpx;
 }
+
 .base-status-gap-1 {
     font-size: 24rpx;
     color: #fff;
@@ -440,6 +505,7 @@ onShow(() => {
     padding: 6rpx 24rpx 6rpx 16rpx;
     border-radius: 0 20rpx 20rpx 0;
 }
+
 .base-status-gap-2 {
     font-size: 24rpx;
     color: #fff;
@@ -448,6 +514,7 @@ onShow(() => {
     padding: 6rpx 24rpx 6rpx 16rpx;
     border-radius: 0 20rpx 20rpx 0;
 }
+
 .base-status-gap-0 {
     font-size: 24rpx;
     color: #fff;

+ 123 - 8
src/pages/plant/processing/index.vue

@@ -1,16 +1,87 @@
 <template>
     <z-paging ref="paging" bgColor="#F7F7F7">
-        <template #top>
+        <template #top v-if="!showHeader">
             <ut-navbar title="产地加工及包装赋码任务" :fixed="false" :breadcrumb="false">
-                <template #left><view class=""></view></template>
+                <template #left>
+                    <view class=""></view>
+                </template>
             </ut-navbar>
+            <view class="h-36"></view>
         </template>
-        <view class="h-40"></view>
-        <view class="base-content pd-20 b-radius">
+        <template v-if="showHeader">
+            <template #top>
+                <up-navbar :fixed="true" :bgColor="navBarBgColor">
+                    <template #left>
+                        <view class="d-flex a-c pb-5" id="topup-navbar" :style="{ width: `${bubble.left - 30}px` }">
+                            <text class="f-s-40 c-333 f-w-5 w-s-no">产地加工及包装赋码任务</text>
+                            <view class="flex1"></view>
+                        </view>
+                    </template>
+                </up-navbar>
+            </template>
+            <view class="h-500 w-100%"
+                style="background: linear-gradient(to left, #d2f7d5, #eafad8); position: absolute; top: 0; left: 0; z-index: -1">
+            </view>
+            <template>
+                <up-navbar :fixed="false" bgColor="transparent">
+                    <template #left>
+                        <view class="pd-10"></view>
+                    </template>
+                </up-navbar>
+                <view class="user-page-header pd-10 d-flex a-c mg-14 p-rtv">
+                    <view class="user-page-header-avatar mr-20 p-rtv">
+                        <up-avatar size="116rpx"
+                            :src="avatar || 'https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/common/avatar.png'"></up-avatar>
+                    </view>
+                    <view class="flex1 ov-hd mr-40">
+                        <view class="p-rtv d-flex a-c mb-6">
+                            <view class="flex1 ov-hd f-s-32 c-333 d-flex a-ed">
+                                <text class="mr-12 up-line-1 f-w-5">{{ name }}</text>
+                                <text class="c-999 f-s-24">{{ setCipByNum(phone ?? null, 3, 4) || '-' }}</text>
+                            </view>
+                        </view>
+                        <view class="f-s-22 mr-10 radius-30 pt-4 pb-4 pl-10 pr-10 c-primary bg-#b7e8bc"
+                            style="width: max-content">
+                            {{ currentCpyName }}
+                        </view>
+                    </view>
+                </view>
+            </template>
+            <view class="pd-10 mg-14 mb-0 pb-0">
+                <view class="b-radius pd-6"
+                    style="border: 1rpx solid #fff; background: linear-gradient(90deg, #c1f3c5 0%, rgba(193, 243, 197, 0.5) 20%, rgba(255, 255, 255, 0.5) 35%, rgba(255, 255, 255, 0.5) 50%, rgba(232, 255, 234, 0.5) 100%, #e8ffea 100%), linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.3) 30%, rgba(255, 255, 255, 0.3) 80%, transparent 100%)">
+                    <view class="b-radius pd-10 p-rtv" style="border: 1rpx solid #baedbf">
+                        <image class="w-200"
+                            src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/typeofBusiness.png"
+                            mode="widthFix" style="position: absolute; top: 10rpx; left: 10rpx" />
+                        <view v-if="!speciesArray.length" class="pd-20"></view>
+                        <view v-if="speciesArray.length" class="d-flex pr-15">
+                            <view class="flex1"></view>
+                            <view class="f-s-22 c-primary" @click="$u.route({ url: '/plant/species/config/index' })">
+                                去修改{{ '>' }}
+                            </view>
+                        </view>
+                        <view v-if="speciesArray.length" class="c-#333 f-s-24 d-flex pl-40 pr-15 pb-15 pt-15">
+                            <view class="ov-hd tx-ov w-s-no">{{ speciesArray.join('、') }}</view>
+                            <view v-if="speciesArray.length > 4" class="flex1 w-s-no">等{{ speciesArray.length }}个品种
+                            </view>
+                        </view>
+                        <view v-if="!speciesArray.length" @click="$u.route({ url: '/plant/species/config/index' })"
+                            class="c-primary bg-#E3F6E7 f-s-22 mg-at radius-10 w-250 h-50 d-flex a-c j-c"> 暂未配置品种,去配置{{
+                                '>' }}
+                        </view>
+                        <view v-if="!speciesArray.length" class="pd-7"></view>
+                    </view>
+                </view>
+            </view>
+        </template>
+
+        <view class="base-content pd-24 b-radius p-rtv">
             <!-- 产地加工卡片 -->
             <view class="process-card" @click="$u.route({ url: '/plant/processing/processing-index/index' })">
                 <view class="w-200 h-200 d-flex a-c j-c" style="flex-shrink: 0">
-                    <image class="w-100% h-100%" src="/static/images/plant/processing/initial_processing.png" mode="aspectFit" />
+                    <image class="w-100% h-100%" src="/static/images/plant/processing/initial_processing.png"
+                        mode="aspectFit" />
                 </view>
                 <view class="card-content">
                     <view class="f-s-46 c-#333 f-w-6 mb-12">产地加工</view>
@@ -20,7 +91,8 @@
             <!-- 包装赋码卡片 -->
             <view class="process-card" @click="$u.route({ url: '/plant/packaging/list/index' })">
                 <view class="w-200 h-200 d-flex a-c j-c" style="flex-shrink: 0">
-                    <image class="w-100% h-100%" src="/static/images/plant/processing/packaging_coding.png" mode="aspectFit" />
+                    <image class="w-100% h-100%" src="/static/images/plant/processing/packaging_coding.png"
+                        mode="aspectFit" />
                 </view>
                 <view class="card-content">
                     <view class="f-s-46 c-#333 f-w-6 mb-12">包装赋码</view>
@@ -34,11 +106,54 @@
     </z-paging>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { useInfoStore } from '@/store';
+import { setCipByNum } from '@/utils/public';
+import { useClientRequest } from '@/utils/request';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const infoStore = useInfoStore();
+const instance = getCurrentInstance();
+const navBarBgColor = ref('transparent');
+const name = computed(() => infoStore.userInfo?.name || '');
+const phone = computed(() => infoStore.userInfo?.phone || '');
+const currentCpyName = computed(() => infoStore.userInfo?.currentCpyName || '');
+const avatar = computed(() => infoStore.userInfo?.avatar || '');
+const bubble = ref(uni.getMenuButtonBoundingClientRect());
+const speciesArray = ref([]);
+const stickyTop = ref(0);
+// 根据 navConfig 判断是否显示头部:default 显示,custom 隐藏
+const showHeader = computed(() => infoStore.navConfig !== 'default');
+
+
+const getSpecies = async () => {
+    const res = await useClientRequest.get('/plt-api/app/cpyVariety/list');
+    if (res?.code === 200) {
+        speciesArray.value = res.data?.map((item: any) => item.medicineName);
+    }
+};
+onMounted(() => {
+    if (showHeader.value) {
+        const querys = uni.createSelectorQuery().in(instance?.proxy);
+        querys
+            .select('#topup-navbar')
+            .boundingClientRect((data: any) => {
+                console.log(data);
+                stickyTop.value = data.top + data.height;
+            })
+            .exec();
+        getSpecies();
+    }
+});
+onShow(() => {
+    if (showHeader.value) {
+        getSpecies();
+    }
+});
+</script>
 
 <style lang="scss" scoped>
 .base-content {
-    padding-top: 10px;
+    padding-top: 20px;
     background: linear-gradient(to bottom, #dcf8d9, #f7f7f7 70rpx);
     border: 1rpx solid #fff;
 }

+ 99 - 38
src/plant/port/port-create/models/drawer_laboratory.vue

@@ -18,25 +18,14 @@
                         </view>
                     </view>
                 </scroll-view>
-                <up-virtual-list v-if="mixData.length > 0" :listData="mixData" :itemHeight="60" :height="600" :buffer="8" class="mt-10">
-                    <template #default="{ item }">
-                        <view class="custom-checkbox" :class="{ 'custom-checkbox--checked': item.selected }" @click="handleCustomCheckboxClick(item.id)">
-                            <view class="custom-checkbox__inner">
-                                <text v-if="item.selected" class="custom-checkbox__icon">✓</text>
-                                <text class="custom-checkbox__label">{{ item.landName }}</text>
-                            </view>
+                <ut-tree v-if="treeData.length > 0" ref="treeRef" :data="treeData" :props="defaultProps" show-checkbox default-expand-all @check-change="handleCheckChange" class="mt-10">
+                    <template #default="{ node, level }">
+                        <view class="custom-tree-node">
+                            <text v-if="level === 1" class="layer-label">{{ node.label }}</text>
+                            <text v-else class="item-label">{{ node.label }}</text>
                         </view>
                     </template>
-                </up-virtual-list>
-                <!-- <scroll-view class="w-50% pd-16" :style="`height: calc(100vh - 70px - ${top}px)`" scroll-y="true">
-                    <view v-if="mixData.length > 0" class="custom-checkbox custom-checkbox--all" @click="handleAllCheckboxChange(!aloneChecked)">
-                        <view class="custom-checkbox__inner">
-                            <text v-if="aloneChecked" class="custom-checkbox__icon">✓</text>
-                            <text class="custom-checkbox__label">全选</text>
-                        </view>
-                    </view>
-                    <view v-if="mixData.length == 0 && showtitle" class="">请先在左侧添加选择组培架,选择后此处将会展示具体信息。</view>
-                </scroll-view> -->
+                </ut-tree>
             </view>
             <view class="w-700 bg-#fff h-100 d-flex a-c gap-20 pt-20 pb-20" style="position: fixed; bottom: 0; right: 0">
                 <up-button @click="handleClose" style="margin-left: 20rpx">取消</up-button>
@@ -48,6 +37,7 @@
 <script setup lang="ts">
 import { useClientRequest } from '@/utils/request';
 import { ref, reactive, watch, computed } from 'vue';
+import UtTree from '@/components/ut-tree/ut-tree.vue';
 const instance = getCurrentInstance();
 const props = defineProps<{
     modelValue: boolean;
@@ -65,6 +55,16 @@ const form = ref({
 const list = ref<any[]>([]);
 // 右侧架子数据
 const mixData = ref<any[]>([]);
+// 树形数据
+const treeData = ref<any[]>([]);
+// 树形组件引用
+const treeRef = ref<any>(null);
+// 树形节点配置
+const defaultProps = {
+    children: 'children',
+    label: 'label',
+    nodeKey: 'id',
+};
 const showtitle = ref(true);
 // 当前选择地块
 const landId = ref(-1);
@@ -91,6 +91,7 @@ const changeBase = (index: number, item: any) => {
     activeBase.value = index;
     //创建右侧的架数据
     mixData.value = [];
+    treeData.value = [];
     const layersCount = Number(item.layers);
     // 解析 capacityAmount 为数字
     const capacityCount = Number(item.capacityAmount);
@@ -98,29 +99,47 @@ const changeBase = (index: number, item: any) => {
     // 创建两个序列数组
     const layersArray = Array.from(
         { length: layersCount || 0 },
-        (_, index) => index + 1 // 生成 1-10
+        (_, index) => index + 1, // 生成 1-10
     );
 
     const capacityArray = Array.from(
         { length: capacityCount || 0 },
-        (_, index) => index + 1 // 生成 1-capacityCount
+        (_, index) => index + 1, // 生成 1-capacityCount
     );
-    // 双重循环使用 flatMap
+
+    // 生成树形数据:第一级为层,第二级为每层的容量
+    // 注意:不要设置 expanded 字段,让 ut-tree 组件自动处理
+    const newTreeData = layersArray.map((layer) => ({
+        id: `layer-${layer}`,
+        label: `第${layer}层`,
+        children: capacityArray.map((capacity) => ({
+            id: `layer-${layer}-item-${capacity}`,
+            label: `${capacity}`,
+        })),
+    }));
+    treeData.value = newTreeData;
+
+    console.log('树形数据:', treeData.value);
+    console.log('layers:', layersCount, 'capacity:', capacityCount);
+
+    // 同时生成扁平数据用于兼容
     const newData = layersArray.flatMap((layer) =>
         capacityArray.map((capacity) => ({
             id: `${layer}-${capacity}`,
             landName: `${layer}-${capacity}`,
             selected: false, // 添加 selected 字段,初始为 false
-        }))
+        })),
     );
     mixData.value = newData;
-    setTimeout(() => {
-        console.log(mixData.value);
-    }, 2000);
 
     landId.value = item.id;
     aloneChecked.value = false;
 };
+
+// 树形复选框变化处理
+const handleCheckChange = (node: any) => {
+    console.log('节点勾选状态变化:', node);
+};
 // 选择checkbox>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 const aloneChecked = ref(false);
 
@@ -170,24 +189,40 @@ const confirm = () => {
             icon: 'none',
         });
         return;
-    } else {
-        // 检查是否有选中的项
-        const selectedItems = mixData.value.filter((item) => item.selected);
-        if (selectedItems.length == 0) {
-            uni.showToast({
-                title: '请选择地块',
-                icon: 'none',
-            });
-            return;
-        }
+    }
+
+    // 使用 treeRef 获取选中的叶子节点
+    const checkedNodes = treeRef.value?.getCheckedNodes() || [];
+
+    // 过滤出叶子节点(第二级节点)
+    const leafNodes = checkedNodes.filter((node: any) => node.children === undefined || node.children.length === 0);
+
+    if (leafNodes.length == 0) {
+        uni.showToast({
+            title: '请选择地块',
+            icon: 'none',
+        });
+        return;
     }
 
     // 通过 landId 查找选中的地块
     const selectedBase = list.value.find((item) => item.id === landId.value);
-    // 获取选中的数据项
-    const selectedData = mixData.value.filter((item) => item.selected);
-    // 获取选中的ID数组
-    const selectedIds = selectedData.map((item) => item.id);
+
+    // 获取选中的数据项(转换为原有格式)
+    const selectedData = leafNodes.map((node: any) => {
+        // 从节点 id 中提取层和容量信息 (格式:layer-X-item-Y)
+        const parts = node.id.split('-');
+        const layer = parts[1];
+        const capacity = parts[3];
+        return {
+            id: `${layer}-${capacity}`,
+            landName: `${layer}-${capacity}`,
+            selected: true,
+        };
+    });
+
+    // 获取选中的 ID 数组
+    const selectedIds = selectedData.map((item: any) => item.id);
 
     if (selectedBase) {
         // 抛出对象给父组件
@@ -353,4 +388,30 @@ onMounted(() => {
     color: #37a954;
     font-weight: 600;
 }
+
+/* 树形组件自定义样式 */
+.custom-tree-node {
+    display: flex;
+    align-items: center;
+    width: 100%;
+}
+
+.layer-label {
+    font-size: 28rpx;
+    color: #333;
+    font-weight: 500;
+}
+
+.item-label {
+    font-size: 26rpx;
+    color: #666;
+}
+
+:deep(.u-tree-node__content) {
+    padding: 12rpx 20rpx;
+}
+
+:deep(.u-tree-node__label) {
+    flex: 1;
+}
 </style>

+ 20 - 23
src/plant/processing/processing-detail-list/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <z-paging ref="paging" v-model="list" bgColor="#f7f7f7" @query="query" hide-no-more-inside hide-empty-view>
+    <z-paging ref="paging" bgColor="#f7f7f7" hide-no-more-inside hide-empty-view>
         <template #top>
             <ut-navbar title="加工任务详情" :fixed="false"> </ut-navbar>
         </template>
@@ -63,7 +63,7 @@
             </view>
             <!-- 原料信息列表 -->
             <view v-if="+activeTab == 0">
-                <view v-if="list.length === 0 && +activeTab == 0 && !loading" class="d-flex flex-cln a-c pd-40">
+                <view v-if="inputList.length === 0 && +activeTab == 0" class="d-flex flex-cln a-c pd-40">
                     <ut-empty color="#ccc" size="28rpx" image=" https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-plt/plant/noEmpty.png">暂无加工原料信息</ut-empty>
                     <up-button type="primary" @click="goAssociate">去关联原料信息</up-button>
                 </view>
@@ -72,7 +72,7 @@
                     <view class="flex1"></view>
                     <up-button type="error" style="width: 160rpx; height: 60rpx" @click="withdraw">撤回用料</up-button>
                 </view>
-                <view v-for="(item, index) in list" :key="index" class="bg-#fff b-radius pd-24">
+                <view v-for="(item, index) in inputList" :key="index" class="bg-#fff b-radius pd-24">
                     <!-- 类型标签 -->
                     <view class="d-flex j-sb a-c li-item-head mb-16">
                         <view class="li-left-tag" :class="{ [`bg-instore-${item?.storageInfo?.instoreType}`]: true }">{{ selectDictLabel(pt_fresh_instore_type, item?.storageInfo?.instoreType) }}</view>
@@ -173,11 +173,10 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { pt_stock_type, pt_standard_type, pt_fresh_instore_type, pt_final_form_type } = toRefs<any>(proxy?.useDict('pt_stock_type', 'pt_standard_type', 'pt_fresh_instore_type', 'pt_final_form_type'));
 
 const paging = ref();
-const list = ref<any[]>([]);
+const inputList = ref<any[]>([]);
 const taskId = ref('');
 const taskDetail = ref<any>({});
 const outputList = ref<any[]>([]);
-const loading = ref(false);
 
 const activeTab = ref(0);
 const tabs = [
@@ -202,30 +201,25 @@ const loadTaskDetail = async () => {
     }
 };
 
-// z-paging 查询原料列表
-const query = async (pageNum: number, pageSize: number) => {
-    loading.value = true;
+// 获取原料信息列表
+const getInputList = async () => {
     try {
-        const res = await useClientRequest.get('/plt-api/app/processInputMaterial/pageList', {
-            pageNum,
-            pageSize,
+        const res: any = await useClientRequest.get('/plt-api/app/processInputMaterial/pageList', {
             processId: taskId.value,
         });
-        if (res) {
-            const { rows } = res;
-            paging.value.complete(rows);
+        if (res && res.rows) {
+            inputList.value = res.rows;
         }
-        getOutputList();
+        return res;
     } catch (error) {
         console.error('加载原料列表失败:', error);
-        paging.value.complete([]);
-    } finally {
-        loading.value = false;
+        inputList.value = [];
     }
 };
+
 const goAssociate = () => {
     uni.$once(`updatesupervise-${taskDetail?.value?.id}`, function (data) {
-        paging.value?.reload();
+        getInputList();
     });
 
     uni.$u.route({
@@ -242,7 +236,7 @@ const onTabChange = (tabItem: any) => {
         getOutputList();
     } else {
         // 切换回原料信息,重新加载
-        paging.value?.reload();
+        getInputList();
     }
 };
 
@@ -284,7 +278,7 @@ const gotoDetail = () => {
 const handleUpdateTaskDetail = () => {
     loadTaskDetail(); // 重新加载任务详情
     if (+activeTab.value === 0) {
-        paging.value?.reload(); // 刷新原料列表
+        getInputList(); // 刷新原料列表
     } else {
         getOutputList(); // 刷新产出列表
     }
@@ -296,10 +290,13 @@ onLoad((options: any) => {
     uni.$on('updateprocesstasklist', handleUpdateTaskDetail);
     if (taskId.value) {
         loadTaskDetail();
+        getInputList();
+        getOutputList();
     }
     if (options?.output) {
         activeTab.value = 1;
         getOutputList();
+        getInputList(); /*  */
     }
 });
 
@@ -316,11 +313,11 @@ const withdraw = async () => {
     });
     console.log(res);
     if (res.confirm) {
-        const delRes = await useClientRequest.get(`/plt-api/app/processInputMaterial/callbackInput/${list.value?.[0]?.id}`);
+        const delRes = await useClientRequest.get(`/plt-api/app/processInputMaterial/callbackInput/${inputList.value?.[0]?.id}`);
         if (delRes && delRes.code === 200) {
             uni.showToast({ title: '删除成功', icon: 'none' });
             uni.$emit(`updatesupervise-${taskId.value}`, []);
-            paging.value?.reload();
+            getInputList();
         }
     }
 };

+ 0 - 0
src/static/images/audit/plant/GAP三无一全获评信息审核应用.png → src/static/images/audit/plant/GAP_Certification_Audit.png


+ 0 - 0
src/static/images/audit/plant/中药材种植全链条追溯应用.png → src/static/images/audit/plant/TCM_Traceability_System.png


+ 0 - 0
src/static/images/plant/药材种植.png → src/static/images/plant/Herbal_Cultivation.png


+ 0 - 0
src/static/images/plant/药材养殖.png → src/static/images/plant/TCM_Animal_Farming.png


+ 0 - 0
src/static/images/plant/组培实验室.png → src/static/images/plant/Tissue_Culture_Lab.png


+ 12 - 3
src/store/modules/info.ts

@@ -148,12 +148,19 @@ export const useInfoStore = defineStore(
             }
         };
         // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-        // 微信小程序登录获取的code
+        // 微信小程序登录获取的 code
 
         const wxLogin = async (data: unknown) => {
             const res = await useClientRequest.post(`/plt-api/auth/login`, data, false);
             setToken(res.data?.access_token);
         };
+        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+        // 导航配置
+        const navConfig = ref<string>('default');
+        // 设置导航配置
+        const setNavConfig = (value: string) => {
+            navConfig.value = value;
+        };
         return {
             token,
             setToken,
@@ -166,6 +173,8 @@ export const useInfoStore = defineStore(
             companyInfo,
             getCompanyInfo,
             wxLogin,
+            navConfig,
+            setNavConfig,
         };
     },
     {
@@ -173,7 +182,7 @@ export const useInfoStore = defineStore(
         persist: {
             key: INFOSTORE_KEY,
             storage: uniStorage,
-            pick: ['userInfo', 'companyInfo'],
+            pick: ['userInfo', 'companyInfo', 'navConfig'],
         },
-    }
+    },
 );