Selaa lähdekoodia

新增单位系统查看设置功能

lichunyang 1 kuukausi sitten
vanhempi
säilyke
23b433ee9f

BIN
src/assets/img/treeCollapse.png


BIN
src/assets/img/treeExpand.png


BIN
src/assets/img/treeSystemIcon.png


+ 395 - 0
src/components/PersonUnitDialog.vue

@@ -0,0 +1,395 @@
+<template>
+  <el-dialog
+    :model-value="visible"
+    width="45%"
+    @update:model-value="$emit('update:visible', $event)"
+    class="dialog_class"
+    draggable
+  >
+    <template #header="{ titleId, titleClass }">
+      <div class="my-header">
+        <h4 :id="titleId" :class="titleClass">
+          {{ $t("treeData.personUnitView") }}
+        </h4>
+      </div>
+    </template>
+    <div>
+      <p class="description">{{ $t("treeData.createNewUnitSystem") }}</p>
+
+      <el-form
+        :model="formData"
+        label-position="left"
+        :label-width="labelWidth"
+        :rules="formRules"
+        ref="formRef"
+      >
+        <el-row :gutter="20" class="input-row">
+          <el-col :span="10">
+            <el-form-item :label="$t('treeData.chineseName')" prop="chineseName">
+              <el-input v-model="formData.chineseName" placeholder="" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('treeData.englishName')" prop="englishName">
+              <el-input v-model="formData.englishName" placeholder="" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="4" class="lastbtn">
+            <el-button type="primary" @click="submitForm">{{
+              $t("dialog.ok")
+            }}</el-button>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <div class="table-container">
+        <el-table
+          :data="tableData"
+          style="width: 100%"
+          :border="false"
+          max-height="200px"
+        >
+          <el-table-column
+            prop="number"
+            :label="$t('treeData.number')"
+            width="60"
+          />
+          <el-table-column
+            prop="chineseName"
+            :label="$t('treeData.chineseName')"
+          />
+          <el-table-column
+            prop="englishName"
+            :label="$t('treeData.englishName')"
+          />
+          <el-table-column :label="$t('treeData.unit')">
+            <template #default="{ row }">
+              <el-select v-model="row.value" placeholder="" style="width: 100%">
+                <el-option
+                  v-for="unit in unitOptions"
+                  :key="unit"
+                  :label="unit"
+                  :value="unit"
+                />
+              </el-select>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <template #footer>
+      <el-row :gutter="20" class="footer-row">
+        <el-col :span="12">
+          <el-form
+            :model="{ selectedGroupId }"
+            label-position="left"
+            label-width="100px"
+          >
+            <el-form-item :label="$t('treeData.unitSystem')">
+              <el-select
+                v-model="selectedGroupId"
+                placeholder=""
+                style="width: 100%"
+                :key="unitGroups.length"
+              >
+                <el-option
+                  v-for="group in unitGroups"
+                  :key="group.sutId"
+                  :label="group.nameEn"
+                  :value="group.sutId"
+                />
+              </el-select>
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="12" class="lastbtn">
+          <el-button @click="$emit('update:visible', false)">{{
+            $t("dialog.cancel")
+          }}</el-button>
+          <el-button type="primary" @click="handleConfirm">{{
+            $t("dialog.ok")
+          }}</el-button>
+        </el-col>
+      </el-row>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, onMounted, watch } from "vue"
+import { useI18n } from "vue-i18n"
+import { request } from "@/utils/request"
+const { t, locale } = useI18n()
+import { ElMessage } from 'element-plus'
+
+const labelWidth = computed(() => {
+  return locale.value === "zh-CN" ? "80px" : "100px"
+})
+
+// 表单引用
+const formRef = ref(null)
+// 表单校验规则
+const formRules = {
+  chineseName: [
+    {
+      required: true,
+      message: t("treeData.chineseNameRequired"),
+      trigger: "blur"
+    }
+  ],
+  englishName: [
+    {
+      required: true,
+      message: t("treeData.englishNameRequired"),
+      trigger: "blur"
+    }
+  ]
+}
+
+// 单位系统下拉框数据
+const fetchUnitGroups = async () => {
+  const params = {
+    transCode: 'ES0024',
+  };
+  try {
+    const res = await request(params);
+    return res.rows || [];
+  } catch (err) {
+    console.error('Fetch unit groups error:', err);
+    ElMessage.error(err.returnMsg || t('error.fetchFailed'));
+    return [];
+  }
+}
+
+// 单位下拉框数据
+const updateUnit = async (row) => {
+  const group = unitGroups.value.find((g) => g.sutId === selectedGroupId.value);
+  const params = {
+    transCode: 'ES0022',
+    value: row.value,
+    gutId: row.number,
+    sutId: group.sutId
+  };
+  try {
+    const res = await request(params);
+    console.log('Update unit responseffffffdxxxxx:', res);
+    
+    return res.rows || [];
+  } catch (err) {
+    console.error('Fetch unit options error:', err);
+    ElMessage.error(err.returnMsg || t('error.fetchFailed'));
+    return [];
+  }
+};
+
+// 初始化表格数据时调用接口
+const initializeUnits = async () => {
+  if (tableData.value.length === 0 || !selectedGroupId.value) return;
+  for (const row of tableData.value) {
+    if (row.value && row.number) { // 确保 unit 和 number 存在
+      const success = await updateUnit(row);
+      if (!success) {
+        row.unit = ''; 
+      }
+    }
+  }
+};
+
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  },
+  systemUnitData: {
+    type: Array,
+    default: () => [],
+  }
+})
+
+const emit = defineEmits(["update:visible", "confirm"])
+
+// 下拉框数据
+const unitGroups = ref([])
+const selectedGroupId = ref(null);
+const selectedGroup = ref("")
+const unitOptions = ref([])
+
+// 表格数据
+const tableData = ref([])
+
+// 输入框数据
+const formData = ref({
+  chineseName: "",
+  englishName: ""
+})
+
+// 加载下拉框数据并设置默认值
+onMounted(async () => {
+  const groups = await fetchUnitGroups()
+  unitGroups.value = groups
+  if (groups.length > 0) {
+    selectedGroupId.value = groups[0].sutId;
+  }
+})
+
+// 监听 systemUnitData 更新表格
+watch(
+  () => props.systemUnitData,
+  async (newData) => {
+    if (newData.length > 0) {
+      console.log("System Unit Data updated:", newData);
+      
+      tableData.value = newData.map((item) => ({
+        number: item.gutId || 'N/A',
+        chineseName: item.nameZh || '',
+        englishName: item.nameEn || '',
+        value: item.value || '',
+        factor: item.factor || '',
+        utOffset: item.utOffset || '',
+        unit: item.unit || '', // 默认单位
+      }));
+      await initializeUnits();
+    }
+  },
+  { immediate: true }
+);
+
+// 根据下拉框值加载表格数据
+watch(
+  selectedGroupId,
+  async (newId) => {
+    const group = unitGroups.value.find((g) => g.sutId === newId);
+    if (group) {
+      console.log("Selected group:", group);
+      const units = await fetchUnits(group);
+    } else {
+      tableData.value = []
+    }
+  },
+  { immediate: true }
+)
+
+// 保存中英文名称接口
+const submitForm = async () => {
+  try {
+    await formRef.value.validate()
+    await handleSaveName()
+  } catch (error) {
+    console.log("表单校验失败", error)
+    return false
+  }
+}
+const handleSaveName = async () => {
+  try {
+    const params = {
+      transCode: "ES0020",
+      nameZh: formData.value.chineseName,
+      nameEn: formData.value.englishName
+    }
+    const res = await request(params)
+    // tableData.value = [...tableData.value, newUser] // 添加新用户到表格
+    formData.value = { userId: "", userName: "" } // 清空输入框
+    ElMessage.success(t("message.saveSuccess"))
+  } catch (err) {
+    ElMessage.error(t("message.saveFailed"))
+  }
+}
+
+const fetchUnits = async (group) => {
+  const params = {
+    transCode: 'ES0023',
+    gutId: group.sutId,
+  };
+  try {
+    const res = await request(params);
+    return res.rows || [];
+  } catch (err) {
+    console.error('Fetch units error:', err);
+    ElMessage.error(err.returnMsg || t('error.fetchFailed'));
+    return [];
+  }
+};
+
+// footer 确认按钮
+const handleConfirm = () => {
+  emit("confirm", {
+    selectedGroup: selectedGroup.value,
+    formData: formData.value
+  })
+  emit("update:visible", false)
+}
+</script>
+
+<style scoped>
+.my-header {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.dialog_class :deep(.el-dialog__body) {
+  padding: 15px;
+}
+
+.table-container {
+  border: 1px solid var(--el-border-color);
+  padding: 10px;
+  border-radius: 4px;
+}
+
+.el-table {
+  margin-top: 5px;
+}
+
+.lastbtn {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.el-form-item {
+  margin-bottom: 5px;
+}
+
+/* 仅保留数据行水平线 */
+:deep(.el-table__row:not(:last-child) td) {
+  border-bottom: 1px solid var(--el-table-border-color);
+}
+
+:deep(.el-table th, .el-table td) {
+  border-top: none !important;
+  border-right: none !important;
+  border-left: none !important;
+}
+
+:deep(.el-table__inner-wrapper::before) {
+  display: none; /* 移除表格底部边框 */
+}
+
+/* 第二行输入框和按钮样式 */
+.input-row {
+  align-items: center;
+  margin-left: -5px !important;
+}
+
+.lastbtn {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  align-items: center;
+}
+
+/* footer 样式 */
+.footer-row {
+  align-items: center;
+  margin-left: 0px !important;
+}
+
+.description {
+  margin-bottom: 10px;
+  font-size: 14px;
+  color: var(--el-text-color-primary);
+  text-align: left;
+}
+</style>

+ 21 - 0
src/components/ProjectTree/composables/useTree.js

@@ -0,0 +1,21 @@
+import { computed } from 'vue';
+
+export function useTree(emit, props) {
+  // 处理节点点击事件,仅叶子节点触发
+  const handleNodeClick = (node, data, event) => {
+    const isLeaf = data.isLeaf !== undefined ? data.isLeaf : node.isLeaf;
+    if (isLeaf) {
+      emit('node-click', { node, data, event });
+    }
+  };
+
+  // 获取展开/收起图标
+  const getExpandIcon = (node) => {
+    return node.expanded ? props.collapseIcon : props.expandIcon;
+  };
+
+  return {
+    handleNodeClick,
+    getExpandIcon,
+  };
+}

+ 3 - 0
src/components/ProjectTree/index.js

@@ -0,0 +1,3 @@
+import ProjectTree from './index.vue';
+
+export { ProjectTree };

+ 68 - 0
src/components/ProjectTree/index.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="project-tree" :class="{ 'custom-expand': useCustomExpandIcon }">
+    <ElTree
+      :data="data"
+      :props="treeProps"
+      @node-click="handleNodeClick"
+    >
+      <template #default="{ node, data }">
+        <div class="tree-node">
+          <img
+            v-if="useCustomExpandIcon && node.isLeaf === false"
+            :src="getExpandIcon(node)"
+            class="expand-icon"
+            alt="Expand Icon"
+          />
+          <span
+            v-if="useCustomExpandIcon && node.isLeaf"
+            class="expand-icon-placeholder"
+          ></span>
+          <img v-if="nodeIcon" :src="nodeIcon" class="node-icon" alt="Node Icon" />
+          <span>{{ node.label }}</span>
+        </div>
+      </template>
+    </ElTree>
+  </div>
+</template>
+
+<script setup>
+import { ElTree } from 'element-plus';
+import { useTree } from './composables/useTree';
+
+defineOptions({ name: 'ProjectTree' });
+
+const props = defineProps({
+  data: {
+    type: Array,
+    default: () => [],
+  },
+  useCustomExpandIcon: {
+    type: Boolean,
+    default: false,
+  },
+  nodeIcon: {
+    type: String,
+    default: '',
+  },
+  expandIcon: {
+    type: String,
+    default: '',
+  },
+  collapseIcon: {
+    type: String,
+    default: '',
+  },
+    treeProps: {
+    type: Object,
+    default: () => ({ label: 'label', children: 'children', isLeaf: 'isLeaf' }),
+  },
+});
+
+const emit = defineEmits(['node-click']);
+
+const { handleNodeClick, getExpandIcon } = useTree(emit, props);
+</script>
+
+<style scoped lang="scss">
+@import './styles/index.scss';
+</style>

+ 91 - 0
src/components/ProjectTree/styles/index.scss

@@ -0,0 +1,91 @@
+.project-tree {
+  padding: 10px;
+  .el-tree {
+    --el-tree-node-content-height: 32px;
+    --el-tree-text-color: #333;
+    --el-tree-node-hover-bg-color: #f5f7fa;
+    --el-tree-node-indent: 16px; // 子节点缩进,仅为 expandIcon 宽度
+  }
+
+  .tree-node {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    position: relative;
+  }
+
+  .expand-icon {
+    width: 16px;
+    height: 16px;
+    margin-right: 4px;
+    cursor: pointer;
+  }
+
+  .expand-icon-placeholder {
+    width: 16px;
+    height: 16px;
+    margin-right: 4px;
+  }
+
+  .node-icon {
+    width: 16px;
+    height: 16px;
+    margin-right: 4px;
+  }
+
+  // 当使用自定义展开图标时,隐藏默认三角箭头并调整布局
+  &.custom-expand {
+    :deep(.el-tree-node__expand-icon) {
+      display: none !important;
+    }
+
+    // // 为子节点添加水平虚线,连接到父节点的垂直虚线
+    // :deep(.el-tree-node__content) {
+    //   position: relative;
+    //   &::before {
+    //     content: '';
+    //     position: absolute;
+    //     top: 50%;
+    //     left: 8px; // 从父节点的垂直虚线 (left: 8px) 开始
+    //     width: 16px; // 默认连接到 expand-icon 或 placeholder
+    //     height: 1px;
+    //     border-top: 1px dashed #c0c4cc;
+    //   }
+    // }
+
+    // // 叶子节点的水平虚线更长,覆盖 expand-icon 和 node-icon
+    // :deep(.el-tree-node.is-leaf > .el-tree-node__content::before) {
+    //   width: 32px; // 覆盖 expand-icon/placeholder (16px) + node-icon (16px)
+    // }
+
+    // // 为展开的节点(有子节点)添加垂直虚线
+    // :deep(.el-tree-node.is-expanded > .el-tree-node__children) {
+    //   position: relative;
+    //   &::before {
+    //     content: '';
+    //     position: absolute;
+    //     top: 0; // 从父节点的 expand-icon 底部开始
+    //     left: 8px; // 与 expand-icon 或 placeholder 中心对齐
+    //     width: 1px;
+    //     height: 100%; // 覆盖所有子节点
+    //     border-left: 1px dashed #c0c4cc;
+    //   }
+    // }
+
+    // // 最后一个子节点不显示垂直虚线底部
+    // :deep(.el-tree-node__children > .el-tree-node:last-child > .el-tree-node__content::after) {
+    //   content: '';
+    //   position: absolute;
+    //   top: var(--el-tree-node-content-height);
+    //   left: 8px;
+    //   width: 1px;
+    //   height: calc(100% - var(--el-tree-node-content-height));
+    //   background: #fff;
+    // }
+
+    // // 根节点不需要水平虚线
+    // :deep(.el-tree > .el-tree-node > .el-tree-node__content::before) {
+    //   display: none;
+    // }
+  }
+}

+ 0 - 0
src/components/ProjectTree/utils/treeUtils.js


+ 187 - 0
src/components/SystemUnitDialog.vue

@@ -0,0 +1,187 @@
+<template>
+  <el-dialog
+    :model-value="visible"
+    width="40%"
+    @update:model-value="$emit('update:visible', $event)"
+    class="dialog_class"
+    draggable
+  >
+    <template #header="{ titleId, titleClass }">
+      <div class="my-header">
+        <h4 :id="titleId" :class="titleClass">
+          {{ $t("treeData.systemUnitView") }}
+        </h4>
+      </div>
+    </template>
+    <el-form :model="{ selectedGroupId }" label-position="right">
+      <el-row :gutter="20">
+        <el-col :span="16">
+          <el-form-item :label="$t('treeData.selectUnitGroup')">
+            <el-select
+              v-model="selectedGroupId"
+              :placeholder="$t('treeData.selectUnitGroup')"
+              :key="unitGroups.length"
+            >
+              <el-option
+                v-for="group in unitGroups"
+                :key="group.gutId"
+                :label="group.nameEn"
+                :value="group.gutId"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <el-divider />
+    <el-row :gutter="20">
+      <el-col :span="24">
+        <el-table
+          :data="tableData"
+          style="width: 100%"
+          :border="false"
+          max-height="200px"
+        >
+          <el-table-column
+            prop="gutId"
+            :label="$t('treeData.number')"
+            width="80"
+          />
+          <el-table-column
+            prop="nameZh"
+            :label="$t('treeData.chineseName')"
+          />
+          <el-table-column
+            prop="nameEn"
+            :label="$t('treeData.englishName')"
+          />
+          <el-table-column prop="value" :label="$t('treeData.value')" />
+          <el-table-column prop="factor" :label="$t('treeData.factor')" />
+          <el-table-column prop="utOffset" :label="$t('treeData.offset')" />
+        </el-table>
+      </el-col>
+    </el-row>
+    <template #footer>
+      <span class="lastbtn">
+        <el-button @click="$emit('update:visible', false)">
+          {{ $t("dialog.cancel") }}
+        </el-button>
+        <el-button type="primary" @click="handleConfirm">
+          {{ $t("dialog.ok") }}
+        </el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, watch, onMounted } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { ElMessage } from 'element-plus';
+import { request } from '@/utils/request';
+
+const { t } = useI18n();
+
+defineProps({
+  visible: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+const emit = defineEmits(['update:visible', 'confirm']);
+
+const unitGroups = ref([]);
+const selectedGroupId = ref(null); // 绑定 gutId
+const tableData = ref([]);
+
+onMounted(async () => {
+  const groups = await fetchUnitGroups();
+  unitGroups.value = groups;
+  if (groups.length > 0) {
+    selectedGroupId.value = groups[0].gutId;
+  }
+});
+
+watch(
+  selectedGroupId,
+  async (newId) => {
+    const group = unitGroups.value.find((g) => g.gutId === newId);
+    if (group) {
+      const units = await fetchUnits(group);
+      tableData.value = units;
+    } else {
+      tableData.value = [];
+    }
+  },
+  { immediate: true }
+);
+
+const fetchUnitGroups = async () => {
+  const params = {
+    transCode: 'ES0021',
+  };
+  try {
+    const res = await request(params);
+    return res.rows || [];
+  } catch (err) {
+    console.error('Fetch unit groups error:', err);
+    ElMessage.error(err.returnMsg || t('error.fetchFailed'));
+    return [];
+  }
+};
+
+const fetchUnits = async (group) => {
+  const params = {
+    transCode: 'ES0019',
+    gutId: group.gutId,
+  };
+  try {
+    const res = await request(params);
+    return res.rows || [];
+  } catch (err) {
+    console.error('Fetch units error:', err);
+    ElMessage.error(err.returnMsg || t('error.fetchFailed'));
+    return [];
+  }
+};
+
+const handleConfirm = () => {
+  emit('confirm', { tableData: tableData.value });
+  emit('update:visible', false);
+};
+</script>
+
+<style scoped>
+.my-header {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.dialog_class :deep(.el-dialog__body) {
+  padding: 20px;
+}
+
+.el-table {
+  margin-top: 10px;
+}
+
+.lastbtn {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.el-form-item {
+  margin-bottom: 10px;
+}
+
+:deep(.el-form-item__label) {
+  padding-right: 10px;
+}
+
+.el-divider--horizontal {
+  margin: 10px 0 !important;
+}
+</style>

+ 21 - 1
src/locales/en.json

@@ -7,7 +7,9 @@
     "deleteFailed": "Delete failed",
     "deleteCancelled": "Deletion cancelled",
     "logoutSuccess": "Logout successful",
-    "oneSelection": "Please select one item"
+    "oneSelection": "Please select one item",
+    "saveSuccess": "Save successful",
+    "saveFailed": "Save failed"
   },
   "common": {
     "tip": "Tip",
@@ -98,5 +100,23 @@
     "email": "Email",
     "regTime": "Registration Time",
     "mobileNo": "Mobile Number"
+  },
+  "treeData": {
+    "system": "System",
+    "systemSetup": "System Setup",
+    "systemUnitView": "System Unit View",
+    "personUnitView": "Person Unit View",
+    "selectUnitGroup": "Select Unit Group",
+    "number": "Number",
+    "chineseName": "Chinese Name",
+    "englishName": "English Name",
+    "value": "Value",
+    "factor": "Factor",
+    "offset": "Offset",
+    "unit": "Unit",
+    "unitSystem": "Unit System",
+    "createNewUnitSystem": "This operation will create a new unit system:",
+    "chineseNameRequired": "Chinese name is required",
+    "englishNameRequired": "English name is required"
   }
 }

+ 22 - 1
src/locales/zh-CN.json

@@ -7,7 +7,9 @@
     "deleteFailed": "删除失败",
     "deleteCancelled": "已取消删除",
     "logoutSuccess": "退出登录成功",
-    "oneSelection": "请选择一个项目"
+    "oneSelection": "请选择一个项目",
+    "saveSuccess": "保存成功",
+    "saveFailed": "保存失败"
   },
   "common": {
     "tip": "提示",
@@ -98,6 +100,25 @@
     "email": "邮箱",
     "regTime": "注册时间",
     "mobileNo": "手机号码"
+  },
+  "treeData":{
+    "system": "系统",
+    "systemSetup": "系统设置",
+    "systemUnitView": "单位系统查看",
+    "personUnitView": "个人单位查看",
+    "selectUnitGroup": "选择单位组",
+    "number": "Number",
+    "chineseName": "中文名称",
+    "englishName": "英文名称",
+    "value": "值",
+    "factor": "计算因子",
+    "offset": "偏移量",
+    "unit": "单位",
+    "unitSystem": "单位系统",
+    "createNewUnitSystem": "该操作将创建一个新的单位系统:",
+    "chineseNameRequired": "中文名称不能为空",
+    "englishNameRequired": "英文名称不能为空"
+
   }
 
 }

+ 76 - 1
src/views/model/index.vue

@@ -53,7 +53,20 @@
             </el-collapse>
           </el-tab-pane>
 
-          <el-tab-pane label="Project" name="Project"></el-tab-pane>
+          <el-tab-pane label="Project" name="Project">
+            <!-- 使用自定义图标和垂直虚线 -->
+            <ProjectTree
+              :data="treeData"
+              :useCustomExpandIcon="true"
+              :nodeIcon="systemIcon"
+              :expandIcon="expandIcon"
+              :collapseIcon="collapseIcon"
+              :treeProps="{ label: 'label', children: 'children', isLeaf: 'isLeaf' }"
+              @node-click="handleNodeClick"
+            />
+            <!-- 使用 Element Plus 默认箭头(无前置图标和虚线) -->
+            <!-- <ProjectTree :data="treeData" :useCustomExpandIcon="false" @node-click="handleNodeClick" /> -->
+          </el-tab-pane>
           <el-tab-pane label="Result" name="Result">
             <el-empty v-if="activities.length === 0" description="暂无数据" />
             <el-timeline v-else>
@@ -196,6 +209,20 @@
     <!-- 运行弹窗 -->
     <RunDialog ref="RunDialogRef" :runData="arrobj"/>
 
+    <!-- 单元系统弹窗 -->
+    <SystemUnitDialog
+      :visible="showSystemUnitDialog"
+      @update:visible="showSystemUnitDialog = $event"
+      @confirm="handleSystemUnitConfirm"
+    />
+    <!-- 个人单元弹窗 -->
+    <PersonUnitDialog
+      :visible="showPersonUnitDialog"
+      @update:visible="showPersonUnitDialog = $event"
+      :systemUnitData="systemUnitData"
+      @confirm="handlePersonUnitConfirm"
+    />
+
   </el-container>
 </template>
 
@@ -208,6 +235,7 @@ import { useProjectStore } from "@/store/project"
 import { useI18n } from "vue-i18n"
 import vueflow from "./vueflow/index.vue"
 import useDragAndDrop from "./vueflow/useDnD"
+import { ProjectTree } from '@/components/ProjectTree';
 import {
   ZoomIn,
   ZoomOut,
@@ -226,6 +254,11 @@ import changebak from "./vueflow/changebak.vue"
 import SLDataDialog from "./dialog/SLDataDialog.vue"
 import RunDialog from "./dialog/RunDialog.vue"
 import { useVueFlow } from "@vue-flow/core"
+import SystemUnitDialog from '@/components/SystemUnitDialog.vue';
+import PersonUnitDialog from '@/components/PersonUnitDialog.vue';
+import systemIcon from '@/assets/img/treeSystemIcon.png';
+import expandIcon from '@/assets/img/treeExpand.png';
+import collapseIcon from '@/assets/img/treeCollapse.png';
 
 const { zoomIn, zoomOut, fitView } = useVueFlow()
 
@@ -235,6 +268,48 @@ const projectStore = useProjectStore()
 
 const { onDragStart, onDragLeave, treeobj, onDrop } = useDragAndDrop()
 
+// 树中单元系统的弹窗显示控制
+const showSystemUnitDialog = ref(false);
+const showPersonUnitDialog = ref(false);
+// 存储 SystemUnitDialog 的 tableData
+const systemUnitData = ref([]);
+
+// 项目树数据
+const treeData = ref([
+  {
+    id: "root",
+    label: t('treeData.system'),
+    children: [
+      { id: "systemSetup", label: t('treeData.systemSetup'),children: [{ id: "systemUnit", label: t('treeData.systemUnitView'), children: [] }, { id: "personUnit", label: t('treeData.personUnitView'), children: [] }]}
+    ],
+  },
+]);
+
+// 项目树节点点击事件
+const handleNodeClick = ({ node, data, event }) => {
+  console.log("Node clicked:", node, data, event);
+  if (node.id === 'systemUnit') {
+    console.log("System Unit clicked");
+    showSystemUnitDialog.value = true;
+  } else if (node.id === 'personUnit') {
+    showPersonUnitDialog.value = true;
+  }
+};
+
+
+// 单元系统弹窗确认事件
+const handleSystemUnitConfirm = (data) => {
+  console.log('System Unit Dialog confirmed:', data);
+  systemUnitData.value = data.tableData || [];
+  showSystemUnitDialog.value = false;
+};
+
+// 个人单元弹窗确认事件
+const handlePersonUnitConfirm = (data) => {
+  console.log('Person Unit Dialog confirmed:', data);
+  showPersonUnitDialog.value = false;
+};
+
 const getImgPath = (url) => {
   return new URL(`../../assets/img/${url}`, import.meta.url).href
 }