董国庆
2025-06-19 7781b565db049b6c4150113abbddf46e798c900d
修改bug,加权限
14个文件已修改
406 ■■■■■ 已修改文件
culture/src/components/Table/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/detail.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/layouts/components/ElMenu/MenuItem.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/layouts/components/ElMenu/index.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/router/index.js 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/store/index.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/service.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/addDispatch.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/originalRecordTest/detail.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/sampleManage/addSample.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/testResultReport/detail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/login/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/system/role/detail.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/components/Table/index.vue
@@ -1,6 +1,6 @@
<template>
    <div class="table-container" style="width: 100%;">
        <el-table ref="elTable"  border v-bind="$attrs" v-on="$listeners" :height="height">
        <el-table ref="elTable" border v-bind="$attrs" v-on="$listeners" :height="height">
            <slot></slot>
        </el-table>
        <div v-if="total > 0">
@@ -98,6 +98,12 @@
}
::v-deep .el-checkbox__input.is-disabled .el-checkbox__inner {
    background-color: #049C9A !important;
    border-color: #049C9A !important;
}
::v-deep .el-table__expanded-cell {
    padding: 0;
}
culture/src/views/system/role/detail.vue
@@ -339,8 +339,8 @@
/* 当复选框禁用时覆盖默认样式 */
::v-deep .el-checkbox__input.is-disabled.is-checked .el-checkbox__inner {
  background-color: #409eff;
  border-color: #409eff;
  background-color: #049C9A !important;
  border-color: #049C9A !important;
}
::v-deep .el-checkbox.is-disabled .el-checkbox__inner::after {
laboratory/src/layouts/components/ElMenu/MenuItem.vue
@@ -3,7 +3,7 @@
  <!-- <div v-if="!item.meta.hide && menus.includes(item.meta.privilege)"> -->
  <div v-if="item.meta && item.meta.title && !item.meta.hide">
    <!-- 根菜单 -->
    <MenuLink :to="resolvePath()" v-if="!item.children">
    <MenuLink :to="resolvePath()" v-if="!filteredChildren || filteredChildren.length === 0">
      <el-menu-item :index="resolvePath()">
        <i :class="(item.meta && item.meta.icon) || ''"></i>
        <span slot="title">{{ (item.meta && item.meta.title) || '' }}</span>
@@ -16,8 +16,8 @@
        <i :class="(item.meta && item.meta.icon) || ''"></i>
        <span slot="title">{{ (item.meta && item.meta.title) || '' }}</span>
      </template>
      <!-- 这里递归去展示多级菜单 -->
      <menu-item v-for="(route, index) in item.children" :key="index" :item="route"
      <!-- 递归展示多级菜单,已过滤无权限的children -->
      <menu-item v-for="(route, index) in filteredChildren" :key="index" :item="route"
        :fatherPath="resolvePath(route.path)">
      </menu-item>
    </el-submenu>
@@ -29,6 +29,32 @@
import { mapState } from "vuex";
import path from "path";
import MenuLink from "./MenuLink.vue";
function filterMenusByPrivilege(menus, flatMenus) {
  if (!menus) return [];
  return menus
    .filter(menu => {
      if (menu.meta && menu.meta.privilege) {
        return flatMenus.includes(menu.meta.privilege);
      }
      return true;
    })
    .map(menu => {
      if (menu.children && menu.children.length > 0) {
        return {
          ...menu,
          children: filterMenusByPrivilege(menu.children, flatMenus)
        };
      }
      return menu;
    })
    .filter(menu => {
      if (menu.children && menu.children.length === 0) {
        return false;
      }
      return true;
    });
}
export default {
  // 做组件递归时必须定义一个name。然后递归时的组件名就是这里的name值
@@ -50,7 +76,11 @@
  },
  computed: {
    ...mapState(["menus"]),
    ...mapState(["flatMenus"]),
    filteredChildren() {
      // 只对children做权限过滤
      return filterMenusByPrivilege(this.item.children, this.flatMenus);
    }
  },
  data() {
    return {};
laboratory/src/layouts/components/ElMenu/index.vue
@@ -18,9 +18,43 @@
<script>
import routers from "../../../router";
import MenuItem from "./MenuItem.vue";
import { mapState } from "vuex";
// 递归过滤菜单
function filterMenusByPrivilege(menus, flatMenus) {
  return menus
    .filter(menu => {
      // 没有 privilege 字段的菜单默认显示,有 privilege 字段的要判断权限
      if (menu.meta && menu.meta.privilege) {
        return flatMenus.includes(menu.meta.privilege);
      }
      return true;
    })
    .map(menu => {
      // 递归处理 children
      if (menu.children && menu.children.length > 0) {
        return {
          ...menu,
          children: filterMenusByPrivilege(menu.children, flatMenus)
        };
      }
      return menu;
    })
    .filter(menu => {
      // 过滤掉 children 为空的父级菜单
      if (menu.children && menu.children.length === 0) {
        return false;
      }
      return true;
    });
}
export default {
  components: {
    MenuItem,
  },
  computed: {
    ...mapState(["flatMenus"]),
  },
  data() {
    return {
@@ -30,11 +64,13 @@
  mounted() {
    // 获取所有定义的一级菜单和多级菜单
    // 过滤掉登录路由和重定向路由,只获取主布局下的路由
    this.routersList = routers.options.routes.filter(route =>
    const allMenus = routers.options.routes.filter(route =>
      route.path !== '/login' && 
      route.path !== '/' && 
      !route.meta?.hide
    );
    // 权限过滤
    this.routersList = filterMenusByPrivilege(allMenus, this.flatMenus);
  },
};
</script>
laboratory/src/router/index.js
@@ -41,6 +41,7 @@
        meta: {
            title: "中台",
            middleground: true,
            privilege:'middleground'
            // hide: true,
        },
        component: () => import("../views/middleground"),
@@ -49,6 +50,8 @@
        path: "/system",
        meta: {
            title: "系统管理",
             privilege:'system'
        },
        component: Layouts,
        children: [{
@@ -56,6 +59,7 @@
                name: "User",
                meta: {
                    title: "人员管理",
                     privilege:'system_user'
                },
                component: () => import("../views/system/user"),
            },
@@ -64,6 +68,7 @@
                name: "Role",
                meta: {
                    title: "角色管理",
                     privilege:'system_role'
                },
                component: () => import("../views/system/role"),
            },
@@ -98,6 +103,7 @@
                path: "operation-log",
                meta: {
                    title: "操作日志",
                     privilege:'system_operation-log'
                },
                component: () => import("../views/system/operation-log"),
            },
@@ -107,6 +113,7 @@
        path: "/projectList",
        meta: {
            title: "项目组管理",
             privilege:'projectList'
        },
        component: Layouts,
        children: [{
@@ -114,6 +121,7 @@
                name: "ProjectList",
                meta: {
                    title: "项目组管理",
                     privilege:'projectList_list'
                },
                component: () => import("../views/projectList"),
            },
@@ -152,12 +160,14 @@
        component: Layouts,
        meta: {
            title: "实验室数据管理",
              privilege:'dataManagement'
        },
        children: [{
                path: "approvalPlan",
                meta: {
                    title: "项目课题方案审批",
                    keepAlive: true,
                      privilege:'dataManagement_approvalPlan'
                },
                component: () => import("../views/dataManagement/approvalPlan/list.vue"),
            },
@@ -176,6 +186,7 @@
                meta: {
                    title: "实验调度管理",
                    keepAlive: true,
                      privilege:'dataManagement_dispatching'
                },
                component: () => import("../views/dataManagement/dispatching/list.vue"),
            },
@@ -193,6 +204,7 @@
                name: "ConfirmationSheet",
                meta: {
                    title: "检验方法确认单",
                      privilege:'dataManagement_confirmation-sheet'
                },
                component: () => import("../views/dataManagement/confirmation-sheet"),
            },
@@ -210,6 +222,7 @@
                name: "schemeManagement",
                meta: {
                    title: "实验方案管理",
                      privilege:'dataManagement_scheme-management'
                },
                component: () => import("../views/dataManagement/schemeManagement/list.vue"),
            },
@@ -234,6 +247,7 @@
                path: "/sampleManage",
                meta: {
                    title: "样品管理",
                      privilege:'sampleManage'
                    // keepAlive: true,
                },
                component: Parent,
@@ -242,6 +256,7 @@
                        meta: {
                            title: "样品管理",
                            keepAlive: true,
                              privilege:'sampleManage_manage'
                        },
                        component: () => import("../views/dataManagement/sampleManage/list.vue"),
                    },
@@ -259,6 +274,7 @@
                        meta: {
                            title: "取样操作记录列表",
                            keepAlive: true,
                              privilege:'sampleManage_record'
                        },
                        component: () => import("../views/dataManagement/sampleRecordList/list.vue"),
                    },
@@ -276,6 +292,7 @@
                        meta: {
                            title: "送样单列表",
                            keepAlive: true,
                              privilege:'sampleManage_submissionList'
                        },
                        component: () => import("../views/dataManagement/sampleSubmissionList/list.vue"),
                    },
@@ -297,6 +314,7 @@
                meta: {
                    title: "取样送样记录",
                    keepAlive: true,
                     privilege:'dataManagement_deliveryRecord'
                },
                component: () => import("../views/dataManagement/SampleDeliveryRecord/list.vue"),
            },
@@ -315,6 +333,7 @@
                meta: {
                    title: "原始检验记录",
                    keepAlive: true,
                     privilege:'dataManagement_originalRecordTest'
                },
                component: () => import("../views/dataManagement/originalRecordTest/list.vue"),
            },
@@ -333,6 +352,7 @@
                meta: {
                    title: "检验报告管理",
                    keepAlive: true,
                     privilege:'dataManagement_inspectionReport'
                },
                component: () => import("../views/dataManagement/inspectionReport/list.vue"),
            },
@@ -351,6 +371,7 @@
                meta: {
                    title: "实验结果汇报",
                    keepAlive: true,
                     privilege:'dataManagement_testResultReport'
                },
                component: () => import("../views/dataManagement/testResultReport/list.vue"),
            },
@@ -369,6 +390,7 @@
                meta: {
                    title: "实验中止审批",
                    keepAlive: true,
                     privilege:'dataManagement_suspendExperiment'
                },
                component: () => import("../views/dataManagement/suspendExperiment/list.vue"),
            },
@@ -379,12 +401,14 @@
        component: Layouts,
        meta: {
            title: "专业报告库审批",
              privilege:'reportLibrary'
        },
        children: [{
                path: "feasibilityStudy",
                meta: {
                    title: "可研报告库",
                    keepAlive: true,
                      privilege:'reportLibrary_feasibilityStudy'
                },
                component: () => import("../views/reportLibrary/feasibilityStudy/index.vue"),
            },
@@ -406,12 +430,12 @@
                },
                component: () => import("../views/reportLibrary/feasibilityStudy/add.vue"),
            },
            {
                path: "feasibilityReport",
                meta: {
                    title: "可行报告库",
                    keepAlive: true,
                      privilege:'reportLibrary_feasibilityReport'
                },
                component: () => import("../views/reportLibrary/feasibilityReport/index.vue"),
            },
@@ -440,6 +464,7 @@
                meta: {
                    title: "工艺开发工具",
                    keepAlive: true,
                      privilege:'reportLibrary_processDevelopment'
                },
                component: () => import("../views/reportLibrary/processDevelopment/index.vue"),
            },
@@ -462,14 +487,12 @@
                },
                component: () => import("../views/reportLibrary/processDevelopment/add.vue"),
            },
            {
                path: "verificationRelease",
                meta: {
                    title: "验证与发布",
                    keepAlive: true,
                      privilege:'reportLibrary_verificationRelease'
                },
                component: () => import("../views/reportLibrary/verificationRelease/index.vue"),
            },
@@ -496,6 +519,7 @@
                meta: {
                    title: "立项报告库",
                    keepAlive: true,
                      privilege:'reportLibrary_projectProposalLibrary'
                },
                component: () => import("../views/reportLibrary/projectProposalLibrary/index.vue"),
            },
@@ -524,12 +548,14 @@
        component: Layouts,
        meta: {
            title: "化验师QA专题报告",
             privilege:'chemistQa'
        },
        children: [{
                path: "projectTesting",
                meta: {
                    title: "项目检测项、检验包列表",
                    keepAlive: true,
                     privilege:'chemistQa_projectTesting'
                },
                component: () => import("../views/chemistQa/projectTesting/index.vue"),
            },
@@ -556,6 +582,7 @@
                meta: {
                    title: "中试、生产验证试验检验分析报告",
                    keepAlive: true,
                     privilege:'chemistQa_pilotAndProduction'
                },
                component: () => import("../views/chemistQa/pilotAndProduction/index.vue"),
            },
@@ -573,6 +600,7 @@
                meta: {
                    title: "原辅料、包材、竞品检验分析报告",
                    keepAlive: true,
                     privilege:'chemistQa_rawMaterials'
                },
                component: () => import("../views/chemistQa/rawMaterials/index.vue"),
            },
@@ -590,6 +618,7 @@
                meta: {
                    title: "产品报批及项目工作总计报告",
                    keepAlive: true,
                     privilege:'chemistQa_productApproval'
                },
                component: () => import("../views/chemistQa/productApproval/index.vue"),
            },
@@ -609,11 +638,13 @@
        component: Layouts,
        meta: {
            title: "工作交付评定",
             privilege:'deliveryAssessment'
        },
        children: [{
                path: "projectTeamIntegral",
                meta: {
                    title: "项目组总积分",
                     privilege:'deliveryAssessment_projectTeamIntegral'
                },
                component: () => import("../views/deliveryAssessment/projectTeamIntegral"),
            },
@@ -630,6 +661,7 @@
                path: "taskList",
                meta: {
                    title: "课题列表",
                     privilege:'deliveryAssessment_taskList'
                },
                component: () => import("../views/deliveryAssessment/taskList"),
            },
@@ -638,6 +670,7 @@
                path: "restsTask",
                meta: {
                    title: "实验员其他任务",
                     privilege:'deliveryAssessment_restsTask'
                },
                component: () => import("../views/deliveryAssessment/restsTask"),
            },
@@ -646,6 +679,7 @@
                path: "clinicalTrial",
                meta: {
                    title: "临床试验积分列表",
                     privilege:'deliveryAssessment_clinicalTrial'
                },
                component: () => import("../views/deliveryAssessment/clinicalTrial"),
            },
@@ -654,6 +688,7 @@
                path: "testingAndEvaluation",
                meta: {
                    title: "检测项评定列表",
                     privilege:'deliveryAssessment_testingAndEvaluation'
                },
                component: () => import("../views/deliveryAssessment/testingAndEvaluation"),
            },
@@ -662,6 +697,7 @@
                path: "experimentResults",
                meta: {
                    title: "实验结果评定",
                     privilege:'deliveryAssessment_experimentResults'
                },
                component: () => import("../views/deliveryAssessment/experimentResults"),
            },
@@ -670,6 +706,7 @@
                path: "assayTaskList",
                meta: {
                    title: "课题评定列表",
                     privilege:'deliveryAssessment_assayTaskList'
                },
                component: () => import("../views/deliveryAssessment/assayTaskList"),
            },
@@ -678,6 +715,7 @@
                path: "processEngineerEvaluate",
                meta: {
                    title: "工艺工程师工作评定详情",
                     privilege:'deliveryAssessment_processEngineerEvaluate'
                },
                component: () => import("../views/deliveryAssessment/processEngineerEvaluate"),
            },
@@ -686,6 +724,7 @@
                path: "testerWorkerEvaluate",
                meta: {
                    title: "实验员工作评定",
                     privilege:'deliveryAssessment_testerWorkerEvaluate'
                },
                component: () => import("../views/deliveryAssessment/testerWorkerEvaluate"),
            },
@@ -705,6 +744,7 @@
                path: "chemistEvaluate",
                meta: {
                    title: "化验师工作评定",
                     privilege:'deliveryAssessment_chemistEvaluate'
                },
                component: () => import("../views/deliveryAssessment/chemistEvaluate"),
            },
@@ -725,6 +765,7 @@
                name: 'QAList',
                meta: {
                    title: "化验师QA专题报告评定",
                     privilege:'deliveryAssessment_QAList',
                    keepAlive: true,
                },
                component: () => import("../views/deliveryAssessment/QA"),
@@ -735,6 +776,7 @@
                name: 'ExperimenterJobEvaluation',
                meta: {
                    title: "实验员工作评定详情",
                     privilege:'deliveryAssessment_experimenterJobEvaluation',
                    keepAlive: true,
                },
                component: () => import("../views/deliveryAssessment/experimenterJobEvaluation"),
@@ -746,6 +788,7 @@
                meta: {
                    title: "化验师工作评定详情",
                    keepAlive: true,
                     privilege:'deliveryAssessment_technicianJobEvaluation'
                },
                component: () => import("../views/deliveryAssessment/technicianJobEvaluation"),
            },
@@ -756,6 +799,7 @@
                meta: {
                    title: "专业报告库评定",
                    keepAlive: true,
                     privilege:'deliveryAssessment_reportEvaluation'
                },
                component: () => import("../views/deliveryAssessment/reportEvaluation"),
            },
@@ -792,10 +836,21 @@
        return;
    }
    // 判断是否拥有要跳转菜单权限
    let menus = store.state.menus
    if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) {
        return
    // 权限判断(使用flatMenus)
    let flatMenus = store.state.flatMenus
    if (!flatMenus || flatMenus.length === 0) {
        // 刷新后从sessionStorage恢复
        const menus = JSON.parse(sessionStorage.getItem('menus') || '[]')
        const flat = JSON.parse(sessionStorage.getItem('flatMenus') || '[]')
        store.commit('SET_MENUS', menus)
        store.commit('SET_FLAT_MENUS', flat)
        flatMenus = flat
    }
    if (to.meta && to.meta.privilege) {
        if (!flatMenus.includes(to.meta.privilege)) {
            next('/403') // 无权限跳转403
            return
        }
    }
    // 设置标签列表
laboratory/src/store/index.js
@@ -5,6 +5,7 @@
const store = new Vuex.Store({
  state: {
    menus: sessionStorage.getItem('menuList') ? JSON.parse(sessionStorage.getItem('menuList')) : [],
    flatMenus: sessionStorage.getItem('flatMenus') ? JSON.parse(sessionStorage.getItem('flatMenus')) : [], // 新增,拍平后的path数组
    keepAliveList: sessionStorage.getItem('keepAliveList') ? JSON.parse(sessionStorage.getItem('keepAliveList')) : [],//缓存页面
    tagList: sessionStorage.getItem('tagList') ? JSON.parse(sessionStorage.getItem('tagList')) : [],//标签列表
    isFold: false,//是否折叠
@@ -37,6 +38,9 @@
    SET_MENUS(state, data) {
      state.menus = data;
    },
    SET_FLAT_MENUS(state, data) {
      state.flatMenus = data;
    },
    SET_KEEPALIVELIST(state, data) {
      state.keepAliveList = data;
      sessionStorage.setItem('keepAliveList', JSON.stringify(data));
@@ -53,6 +57,9 @@
    setMenus({ commit }, data) {
      commit('SET_MENUS', data);
    },
    setFlatMenus({ commit }, data) {
      commit('SET_FLAT_MENUS', data);
    },
    setKeepAliveList({ commit }, data) {
      commit('SET_KEEPALIVELIST', data);
    },
laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue
@@ -94,7 +94,6 @@
        planName: '', // 项目课题方案名称
        testCode: '', // 实验编号
        testName: '', // 实验名称
        sampleCode: '' // 取样单编号
      },
      selectedScheduling: null, // 添加选中的实验调度数据
      currentTestItem: null, // 当前编辑的检测项
@@ -147,7 +146,6 @@
        planName: selectedData.projectName || '',
        testCode: selectedData.experimentCode || '',
        testName: selectedData.experimentName || '',
        sampleCode: selectedData.experimentCode || '' // 使用实验编号作为取样单编号
      };
    },
@@ -349,7 +347,6 @@
        planName: this.selectedScheduling.projectName || '', // 所属项目课题方案
        testCode: this.selectedScheduling.experimentCode || '', // 实验编号
        testName: this.selectedScheduling.experimentName || '', // 实验名称
        sampleCode: this.selectedScheduling.experimentCode || '' // 取样单编号
      }
      this.confirmDialogVisible = true
    },
@@ -446,6 +443,7 @@
          // 设置实验调度数据
          this.selectedScheduling = {
            id: res.dispatchId,
            ...res
          }
          this.tableData = [{
            // planCode: res.projectName,
@@ -463,6 +461,12 @@
            status: this.getStatusText(res.status) // 状态
          }]
          // this.confirmFormData = {
          //   planName: res.projectName || '',
          //   testCode: res.experimentCode || '',
          //   testName: res.experimentName || '',
          // };
          console.log('confirmFormData confirmFormData ',this.confirmFormData)
          // 设置检测项数据
          this.testItems = res.testMethodConfirmSheetTerms.map(item => ({
@@ -478,6 +482,7 @@
            confirmSign: res.confirmSign,
            signTime: res.signTime
          }
        }
      } catch (error) {
        this.$message.error('获取详情失败:' + (error.message || '未知错误'))
laboratory/src/views/dataManagement/confirmation-sheet/service.js
@@ -30,9 +30,9 @@
}
// 获取实验调度列表
export const getDispatchList = (data) => {
  return axios.get('/open/t-experiment-dispatch/chemistSignList', { ...data })
  return axios.get('/open/t-experiment-dispatch/chemistSignList', { params:data })
}
// 撤销
export const revokedSheet = (data) => {
  return axios.get('/open/t-test-method-confirm-sheet/revokedSheet', { params:data })
  return axios.put(`/open/t-test-method-confirm-sheet/revokedSheet?id=${data.id}`, {params:data })
}
laboratory/src/views/dataManagement/dispatching/addDispatch.vue
@@ -527,6 +527,11 @@
        const index = this.allTaskTableData.findIndex(item => item === row)
        if (index > -1) {
          this.allTaskTableData.splice(index, 1)
          // 删除后判断是否需要跳页
          const maxPage = Math.ceil(this.allTaskTableData.length / this.taskPageSize) || 1;
          if (this.taskPageNum > maxPage) {
            this.taskPageNum = maxPage;
          }
          this.updateTaskTableData();
          this.$message.success('删除成功')
        }
@@ -546,6 +551,7 @@
        this.allTaskTableData.splice(index, 1, taskData);
      } else {
        this.allTaskTableData.push(taskData);
        this.taskPageNum = 1; // 新增后回到第一页
      }
      this.updateTaskTableData();
      // 更新表单数据
laboratory/src/views/dataManagement/originalRecordTest/detail.vue
@@ -1,17 +1,11 @@
<template>
  <Card>
    <el-form
      ref="form"
      :model="form"
      :rules="rules"
      inline
      label-position="top"
    >
    <el-form ref="form" :model="form" :rules="rules" inline label-position="top">
      <div style="padding-left: 25px">
        <el-form-item prop="originalCode" label="原始检验记录编号">
          <el-input v-model="form.originalCode" placeholder="请输入" disabled />
        </el-form-item>
      </div>
      <div class="header-title" style="margin-bottom: 38px">
@@ -41,14 +35,8 @@
          <div>一 、检测标准</div>
        </div>
      </div>
      <AiEditor
        ref="standardEditor"
        :value="editorContents.termStandard"
        height="200px"
        style="margin: 20px 0;"
        placeholder="请输入检测标准..."
        :readOnly="isDetail"
      />
      <AiEditor ref="standardEditor" :value="editorContents.termStandard" height="200px" style="margin: 20px 0;"
        placeholder="请输入检测标准..." :readOnly="isDetail" />
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
@@ -56,14 +44,8 @@
          <div>二 、检测仪器</div>
        </div>
      </div>
      <AiEditor
        ref="instrumentEditor"
        :value="editorContents.termInstrument"
        height="200px"
        style="margin: 20px 0;"
        placeholder="请输入检测仪器..."
        :readOnly="isDetail"
      />
      <AiEditor ref="instrumentEditor" :value="editorContents.termInstrument" height="200px" style="margin: 20px 0;"
        placeholder="请输入检测仪器..." :readOnly="isDetail" />
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
@@ -71,14 +53,8 @@
          <div>三 、检测试剂</div>
        </div>
      </div>
      <AiEditor
        ref="reagentEditor"
        :value="editorContents.termReagent"
        height="200px"
        style="margin: 20px 0;"
        placeholder="请输入检测试剂..."
        :readOnly="isDetail"
      />
      <AiEditor ref="reagentEditor" :value="editorContents.termReagent" height="200px" style="margin: 20px 0;"
        placeholder="请输入检测试剂..." :readOnly="isDetail" />
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
@@ -86,14 +62,8 @@
          <div>四 、检测步骤</div>
        </div>
      </div>
      <AiEditor
        ref="stepsEditor"
        :value="editorContents.termStep"
        height="200px"
        style="margin: 20px 0;"
        placeholder="请输入检测步骤..."
        :readOnly="isDetail"
      />
      <AiEditor ref="stepsEditor" :value="editorContents.termStep" height="200px" style="margin: 20px 0;"
        placeholder="请输入检测步骤..." :readOnly="isDetail" />
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
@@ -103,7 +73,9 @@
        <el-button v-if="!isDetail" type="primary" class="el-icon-plus" @click="handleAddTask">添加检测数据</el-button>
      </div>
      <Table :data="taskTableData" :total="0" :height="null" class="rwuTable">
      <Table :data="taskTableData" :total="allTaskTableData.length" :height="null"
        :queryForm="{ pageNum: currentPage, pageSize: pageSize }" :disAblePagination="true"
        @handleCurrentChange="handleCurrentChange" class="rwuTable">
        <el-table-column type="index" label="序号" width="80"></el-table-column>
        <el-table-column prop="sampleCode" label="检测样编号"></el-table-column>
        <el-table-column prop="testData" label="检测数据"></el-table-column>
@@ -111,14 +83,8 @@
        <el-table-column label="检测图片" width="200">
          <template slot-scope="scope">
            <div class="image-preview" v-if="scope.row.photos && scope.row.photos.length">
              <el-image
                v-for="(photo, index) in scope.row.photos"
                :key="index"
                :src="photo.url"
                :preview-src-list="getPhotoUrls(scope.row.photos)"
                fit="cover"
                class="preview-image"
              >
              <el-image v-for="(photo, index) in scope.row.photos" :key="index" :src="photo.url"
                :preview-src-list="getPhotoUrls(scope.row.photos)" fit="cover" class="preview-image">
                <div slot="error" class="image-slot">
                  <i class="el-icon-picture-outline"></i>
                </div>
@@ -130,21 +96,15 @@
        <el-table-column label="检测图谱" width="200">
          <template slot-scope="scope">
            <div v-if="scope.row.spectrums && scope.row.spectrums.length">
              <el-link
                v-for="(spectrum, index) in scope.row.spectrums"
                :key="index"
                type="primary"
                :href="spectrum.url"
                target="_blank"
                class="spectrum-link"
              >
              <el-link v-for="(spectrum, index) in scope.row.spectrums" :key="index" type="primary" :href="spectrum.url"
                target="_blank" class="spectrum-link">
                {{ spectrum.name }}
              </el-link>
            </div>
            <span v-else>无图谱</span>
          </template>
        </el-table-column>
        <el-table-column v-if="!isDetail" label="操作" width="150">
          <template slot-scope="scope">
            <el-button type="text" @click="handleEditTask(scope.row)">编辑</el-button>
@@ -159,19 +119,13 @@
          <div>六 、检测结果运算</div>
        </div>
      </div>
      <AiEditor
        ref="resultCalculationEditor"
        :value="editorContents.termResult"
        height="200px"
        style="margin: 20px 0;"
        placeholder="请输入检测结果运算..."
        :readOnly="isDetail"
      />
      <AiEditor ref="resultCalculationEditor" :value="editorContents.termResult" height="200px" style="margin: 20px 0;"
        placeholder="请输入检测结果运算..." :readOnly="isDetail" />
      <Table :data="taskTableData" :total="0" :height="null" class="rwuTable">
        <el-table-column type="index" label="序号" width="80"></el-table-column>
        <el-table-column prop="sampleCode" label="检测样编号"></el-table-column>
        <el-table-column prop="testData" label="检测数据"></el-table-column>
        <el-table-column label="检测结果" >
        <el-table-column label="检测结果">
          <template slot-scope="scope">
            <el-input v-model="scope.row.resultText" placeholder="请输入检测结果" :disabled="isDetail"></el-input>
          </template>
@@ -180,19 +134,14 @@
      <div class="add-project-footer" v-if="!isDetail">
        <el-button type="primary" class="save-btn" @click="handleSubmit(false)">填写完毕</el-button>
        <el-button @click="handleSaveDraft">存草稿</el-button>
        <!-- <el-button @click="handleSaveDraft">存草稿</el-button> -->
      </div>
    </el-form>
    <!-- 添加检测数据弹窗 -->
    <add-dialog
      ref="addDialog"
      :visible.sync="dialogVisible"
      :is-edit="isEdit"
      @success="handleTaskSubmit"
    />
    <add-dialog ref="addDialog" :visible.sync="dialogVisible" :is-edit="isEdit" @success="handleTaskSubmit" />
  </Card>
</template>
<script>
import AddDialog from './components/addDialog.vue'
import AiEditor from '@/components/AiEditor'
@@ -238,7 +187,10 @@
        experimentName: [{ required: true, message: "请输入检测方法名字", trigger: "blur" }],
        experimentCode: [{ required: true, message: "请输入检测方法编号", trigger: "blur" }]
      },
      taskTableData: []
      currentPage: 1,
      pageSize: 15,
      allTaskTableData: [],
      taskTableData: [],
    };
  },
  methods: {
@@ -256,7 +208,6 @@
              termName: data.testMethodConfirmSheetTerm.termName || '',
              termMethod: data.testMethodConfirmSheetTerm.termMethod || '',
              termMethodCode: data.testMethodConfirmSheetTerm.termMethodCode || '',
              termStandard: data.termStandard || '',
              termInstrument: data.termInstrument || '',
              termReagent: data.termReagent || '',
@@ -273,7 +224,7 @@
            };
            // 设置检测数据表格
            if (data.testMethodConfirmSheetOriginalDataList && data.testMethodConfirmSheetOriginalDataList.length > 0) {
              this.taskTableData = data.testMethodConfirmSheetOriginalDataList.map(item => ({
              this.allTaskTableData = data.testMethodConfirmSheetOriginalDataList.map(item => ({
                sampleCode: item.dataCode || '',
                testData: item.dataTitle || '',
                resultText: item.resultText || '',
@@ -281,7 +232,11 @@
                spectrums: item.dataFiles ? JSON.parse(item.dataFiles) : [],
                createTime: item.createTime || moment().format('YYYY-MM-DD HH:mm:ss')
              }));
            } else {
              this.allTaskTableData = [];
            }
            this.currentPage = 1;
            this.updateTableData();
          }
        }).catch(err => {
          console.error('获取详情失败:', err);
@@ -297,7 +252,7 @@
    handleEditTask(row) {
      this.isEdit = true;
      this.currentEditIndex = this.taskTableData.findIndex(item => item === row);
      const editData = {
        dataCode: row.sampleCode,
        dataTitle: row.testData,
@@ -329,9 +284,9 @@
        type: "warning",
      })
        .then(() => {
          const index = this.taskTableData.findIndex((item) => item === row);
          const index = this.allTaskTableData.findIndex((item) => item === row);
          if (index > -1) {
            const item = this.taskTableData[index];
            const item = this.allTaskTableData[index];
            if (item.photos) {
              item.photos.forEach(photo => {
                if (photo.url.startsWith('blob:')) {
@@ -346,12 +301,17 @@
                }
              });
            }
            this.taskTableData.splice(index, 1);
            this.allTaskTableData.splice(index, 1);
            // 删除后判断是否需要跳页
            const maxPage = Math.ceil(this.allTaskTableData.length / this.pageSize) || 1;
            if (this.currentPage > maxPage) {
              this.currentPage = maxPage;
            }
            this.updateTableData();
            this.$message.success("删除成功");
          }
        })
        .catch(() => {});
        .catch(() => { });
    },
    handleTaskSubmit(formData) {
      const newData = {
@@ -362,18 +322,17 @@
        spectrums: formData.dataFiles ? JSON.parse(formData.dataFiles) : [],
        createTime: this.isEdit ? this.taskTableData[this.currentEditIndex].createTime : moment().format('YYYY-MM-DD HH:mm:ss')
      };
      if (this.isEdit && this.currentEditIndex > -1) {
        this.taskTableData.splice(this.currentEditIndex, 1, newData);
        this.$message.success('更新成功');
        this.allTaskTableData.splice(this.currentEditIndex, 1, newData);
      } else {
        this.taskTableData.push(newData);
        this.$message.success('添加成功');
        this.allTaskTableData.push(newData);
        this.currentPage = 1; // 新增后回到第一页
      }
      this.updateTableData();
      this.dialogVisible = false;
      this.isEdit = false;
      this.currentEditIndex = -1;
      this.$message.success(this.isEdit ? '更新成功' : '添加成功');
    },
    getPhotoUrls(photos) {
      return photos.map(photo => photo.url);
@@ -471,9 +430,9 @@
          testMethodConfirmSheetOriginalDataList: this.taskTableData.map(item => ({
            dataCode: item.sampleCode,
            dataTitle: item.testData,
            dataType: item.photos && item.spectrums ? '1,2' :
                     item.photos ? '1' :
                     item.spectrums ? '2' : '',
            dataType: item.photos && item.spectrums ? '1,2' :
              item.photos ? '1' :
                item.spectrums ? '2' : '',
            dataFiles: JSON.stringify(item.spectrums || []),
            dataPictures: (item.photos || []).map(photo => photo.url).join(','),
            originalId: this.form.id,
@@ -482,7 +441,7 @@
        };
        console.log('提交数据:', submitData);
        // 调用更新接口
        const res = await update(submitData);
        if (res.code === 200) {
@@ -506,6 +465,15 @@
    // 存草稿
    handleSaveDraft() {
      this.handleSubmit(true);
    },
    updateTableData() {
      const start = (this.currentPage - 1) * this.pageSize;
      const end = this.currentPage * this.pageSize;
      this.taskTableData = this.allTaskTableData.slice(start, end);
    },
    handleCurrentChange(page) {
      this.currentPage = page;
      this.updateTableData();
    }
  },
  created() {
@@ -513,12 +481,13 @@
  }
};
</script>
<style scoped lang="less">
.ai-editor-container{
.ai-editor-container {
  margin-left: 40px;
  width: 85%;
}
.el-form--inline .el-form-item {
  margin-right: 83px;
}
@@ -530,7 +499,7 @@
  gap: 13px;
  margin-top: 38px;
  margin-bottom: 38px;
  .header-title-left {
    display: flex;
    align-items: center;
@@ -549,6 +518,7 @@
      line-height: 27px;
      font-family: "Source Han Sans CN Bold Bold";
    }
    div {
      flex-shrink: 0;
      font-weight: bold;
@@ -556,6 +526,7 @@
      color: #222222;
      line-height: 27px;
      font-family: "Source Han Sans CN Bold Bold";
      &:before {
        content: "*";
        color: #f56c6c;
@@ -608,7 +579,7 @@
.spectrum-link {
  display: block;
  margin-bottom: 5px;
  &:last-child {
    margin-bottom: 0;
  }
laboratory/src/views/dataManagement/sampleManage/addSample.vue
@@ -82,7 +82,7 @@
              <el-table-column prop="addAuxiliaryTen" label="加辅10" width="150"></el-table-column>
            </template>
            <el-table-column prop="sampleAmount" label="取样量" width="150"></el-table-column>
            <el-table-column prop="pictures" label="拍照" width="150">
            <!-- <el-table-column prop="pictures" label="拍照" width="150">
              <template slot-scope="scope">
                <template v-if="scope.row.pictures">
                  <el-image
@@ -95,8 +95,9 @@
                </template>
                <span v-else>-</span>
              </template>
            </el-table-column>
            <el-table-column prop="handlePersonName" label="操作人员" width="150"></el-table-column>
            </el-table-column> -->
            <el-table-column prop="sendTime" label="送样时间" width="150"></el-table-column>
            <el-table-column prop="sendPersonName" label="送样人" width="150"></el-table-column>
            <el-table-column label="状态" prop="status" width="100" fixed="right">
              <template slot-scope="scope">
                <span>{{ scope.row.status == '2' ? '待接收' : '已接收' }}</span>
@@ -148,9 +149,10 @@
                <span v-else>-</span>
              </template>
            </el-table-column>
            <el-table-column prop="handlePersonName" label="操作人员" width="150"></el-table-column>
            <el-table-column prop="receiveTime" label="收样时间" width="150"></el-table-column>
            <el-table-column prop="receiver" label="收样人" width="150"></el-table-column>
            <el-table-column prop="sendTime" label="送样时间" width="150"></el-table-column>
            <el-table-column prop="sendPersonName" label="送样人" width="150"></el-table-column>
            <el-table-column prop="receiptsTime" label="收样时间" width="150"></el-table-column>
            <el-table-column prop="receiptsPersonName" label="收样人" width="150"></el-table-column>
            <el-table-column label="状态" prop="status" width="100" fixed="right">
              <template slot-scope="scope">
                <span>{{ scope.row.status == '3' ? '已接收' : '待接收' }}</span>
@@ -234,7 +236,7 @@
      />
      <div class="add-project-footer" v-if="isEngineer && pageType !== 'detail'">
        <el-button type="primary" class="save-btn" @click="handleSave">保存</el-button>
        <el-button type="primary" class="save-btn" @click="handleSave">{{'发送'}}</el-button>
        <el-button @click="handleSaveDraft">存草稿</el-button>
      </div>
    </div>
laboratory/src/views/dataManagement/testResultReport/detail.vue
@@ -469,7 +469,7 @@
    },
    // 去评价
    handleEvaluate(type) {
      if(this.$route.query.type == 'view' && type !='processEngineer'){
      if(this.$route.query.type == 'view' || type !='processEngineer'){
        this.$message.warning('当前为查看模式,无法进行评价');
        return;
      }
laboratory/src/views/login/index.vue
@@ -95,10 +95,28 @@
        this.$message.warning('请输入密码')
        return
      }
      // 工具函数:拍平menus,获取所有path
      function flattenMenus(menus) {
        let result = []
        menus.forEach(menu => {
          if (menu.path) result.push(menu.path)
          if (menu.children && menu.children.length) {
            result = result.concat(flattenMenus(menu.children))
          }
        })
        return result
      }
      loginReq(this.loginForm).then(res => {
        sessionStorage.setItem('token', res.token)
        sessionStorage.setItem('userInfo', JSON.stringify(res.userInfo.user))
        this.$router.push('/system')
        sessionStorage.setItem('menus', JSON.stringify(res.menus))
        // 拍平path数组
        const flatMenus = flattenMenus(res.menus)
        sessionStorage.setItem('flatMenus', JSON.stringify(flatMenus))
        // 存到vuex
        this.$store.commit('SET_MENUS', res.menus)
        this.$store.commit('SET_FLAT_MENUS', flatMenus)
        this.$router.push('/middleground')
      })
    }
  }
laboratory/src/views/system/role/detail.vue
@@ -22,7 +22,7 @@
            </div>
            <div class="sconed">
              <div class="subpage"
                v-if="(item.children.length > 0 && item.children[0].children.length > 0) || item.children[0].children.menuType != 'F'">
                v-if="item.children && item.children.length > 0 && ((item.children[0].children && item.children[0].children.length > 0) || item.children[0].menuType != 'F')">
                <div v-for="item1 in item.children" :key="item1.menuId" class="two">
                  <div class="left">
                    <el-checkbox disabled :checked="item1.selected">
@@ -260,7 +260,7 @@
        border-right: none;
        .left {
          width: 200px;
          width: 300px;
          padding: 13px 20px;
          border-right: 1px solid #e8e8e8;
        }
@@ -299,7 +299,7 @@
  }
  .title {
    width: 200px;
    width: 300px;
    padding: 8px 20px;
  }
}
@@ -318,6 +318,10 @@
  div:nth-child(2) {
    margin-right: 8px;
  }
}
::v-deep .checkbox__inner{
  background-color: #009688 !important;
  border-color: #009688 !important;
}
.no-data {
@@ -338,8 +342,8 @@
/* 当复选框禁用时覆盖默认样式 */
::v-deep .el-checkbox__input.is-disabled.is-checked .el-checkbox__inner {
  background-color: #409eff;
  border-color: #409eff;
  background-color: #049C9A !important;
  border-color: #049C9A !important;
}
::v-deep .el-checkbox.is-disabled .el-checkbox__inner::after {