pyt
2025-06-23 7ef2454c7df85c9a8fd493552398d4ac07c460d4
Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory
49个文件已修改
2103 ■■■■ 已修改文件
culture/src/main.js 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/utils/request.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/middleground/index.vue 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/projectList/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/breeding-record/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/validation/primitive-cell/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/detail.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/user/components/inherit.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/user/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/App.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/AiEditor/index.vue 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/addTableData.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/index.vue 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SelectMember/index.vue 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/chooseProject/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/main.js 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/router/index.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/utils/baseurl.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/utils/request.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/utils/utils.js 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/chemistQa/projectTesting/add.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/chemistQa/projectTesting/components/approval/index.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/chemistQa/projectTesting/index.vue 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/chemistQa/projectTesting/service.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/inspectionReport/detail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/suspendExperiment/list.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/testResultReport/list.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/middleground/index.vue 332 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/projectList/addProject.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/projectList/editProject.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityReport/add.vue 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityReport/components/approval/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityReport/index.vue 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/add.vue 115 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/components/approval/index.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/index.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/processDevelopment/add.vue 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/processDevelopment/components/approval/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/processDevelopment/index.vue 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/projectProposalLibrary/add.vue 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/projectProposalLibrary/components/approval/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/projectProposalLibrary/index.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/verificationRelease/add.vue 117 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/verificationRelease/components/approval/index.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/verificationRelease/index.vue 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/main.js
@@ -1,9 +1,12 @@
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
// import Antd from 'ant-design-vue';
// import 'ant-design-vue/dist/antd.css';
// import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';
import {Calendar,ConfigProvider } from 'ant-design-vue';
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';
import 'ant-design-vue/dist/antd.css';
import '@/assets/font/font.css'
import App from "./App.vue";
import router from "./router";
@@ -21,7 +24,9 @@
Vue.config.productionTip = false;
Vue.use(ElementUI, { size: 'small' })
Vue.use(Antd)
// Vue.use(Antd)
Vue.use('Calendar',Calendar)
Vue.use(ConfigProvider)
Vue.component('Table', Table)
Vue.component('TableCustom', TableCustom)
Vue.component('Card', Card)
culture/src/utils/request.js
@@ -1,7 +1,12 @@
import axios from 'axios'
import apiConfig from './baseurl'
import { Message } from 'element-ui'
import { encryptBySM4, decryptBySM4 } from './sm4'  // 添加decryptBySM4
import {
  Message
} from 'element-ui'
import {
  encryptBySM4,
  decryptBySM4
} from './sm4' // 添加decryptBySM4
const service = axios.create({
  // baseURL: apiConfig.baseURL,
@@ -26,7 +31,9 @@
    if (config.method == 'post') {
      if (!config.data) config.data = {};
      if (needEncrypt) {
        config.data = { param: encryptBySM4(config.data) };
        config.data = {
          param: encryptBySM4(config.data)
        };
      }
    }
    return config
@@ -55,33 +62,35 @@
        console.error('数据解密失败:', e);
      }
    }
    if (res.data.code == 200) {
      if (!res.data) {
        return Promise.resolve({})
      }
      return Promise.resolve(res.data.data || res.data)
    } else {
      if (res.data.data.code == 103 || res.data.data.code == 401) {
      if (res.data.data.code == 200) {
        return Promise.resolve(res.data.data || res.data)
      } else if (res.data.data.code == 103 || res.data.data.code == 401) {
        Message({
          message: res.data.data.msg || '登录已过期,请重新登录',
          type: 'warning',
          duration: 2000
        })
        sessionStorage.clear();
        window.location.replace('/');
      } else if (res.data.data.code == 500) {
        Message({
          message: res.data.data.msg || '服务器错误',
          type: 'error',
          duration: 2000
        })
        return Promise.reject(res.data.data)
      } else {
        return Promise.resolve(res.data.data || res.data)
      }
      Message({
        message: res.data.data.msg || '服务器错误',
        type: 'error',
        duration: 2000
      })
      return Promise.reject(res.data.data)
    }
  },
  error => {
    return Promise.reject(error.message)
  }
)
export default service
export default service
culture/src/views/middleground/index.vue
@@ -65,11 +65,13 @@
</template>
<script>
import { loginReq } from './service'
import { Calendar } from "ant-design-vue";
import HeaderNav from '../../layouts/components/HeaderNav.vue'
export default {
  name: 'Login',
  components: {
    HeaderNav,
    ACalendar: Calendar,
    // ElCalendar // 注册 ElCalendar 组件
  },
@@ -286,6 +288,7 @@
        .module-item {
          width: 100%;
          height: 307px;
          border-radius: 20px;
        }
      }
@@ -353,6 +356,8 @@
      cursor: pointer;
      transition: all 0.3s ease;
      overflow: hidden;
      border-radius: 20px;
      padding-bottom: 40px;
    }
    .module-bg {
@@ -439,11 +444,12 @@
        content: '';
        position: absolute;
        left: 50%;
        bottom: -5px;
        bottom: -15px;
        transform: translateX(-50%);
        width: 50%;
        height: 2px;
        background-color: #007bff;
        width: 66px;
        height: 3px;
        background: #24595b;
        border-radius: 1px;
      }
    }
@@ -780,7 +786,7 @@
              height: 55px;
              background: #FFFFFF;
              border-radius: 8px;
              border: 1px solid #EDEDED;
              border: 1px solid #ededed;
              display: flex;
              justify-content: center;
              align-items: center;
@@ -807,13 +813,32 @@
            &.ant-fullcalendar-today .ant-fullcalendar-date {
              // border-color: #009688;
            }
            &.ant-fullcalendar-last-month-cell {
              .ant-fullcalendar-value {
                color: #ffffff !important;
              }
            }
            &.ant-fullcalendar-next-month-btn-day {
              .ant-fullcalendar-date {}
              .ant-fullcalendar-value {
                color: #ffffff !important;
                &:hover {
                  // background: #FFFFFF;
                  color: rgba(4, 156, 154, 0.1) !important;
                }
              }
            }
          }
        }
        .ant-fullcalendar-month-panel-selected-cell {
          .ant-fullcalendar-month {
            border-top-color: #009688 !important;
            background: rgba(4, 156, 154, .2);
            // background: rgba(4, 156, 154, .2);
            background: rgba(4, 156, 154, 0.2);
            .ant-fullcalendar-value {
              color: #FFFFFF;
culture/src/views/projectList/index.vue
@@ -62,22 +62,24 @@
            <el-button
              v-if="row.status == 1"
              type="text"
              style="margin-right: 10px;"
              @click="handleChangeStatus(row, 2)"
              >封存</el-button
            >
            <el-button
              v-if="row.status == 2"
              type="text"
              style="margin-right: 10px;"
              @click="handleChangeStatus(row, 1)"
              >解封</el-button
            >
            <el-button type="text" @click="handleProject('edit', row.id)"
            <el-button type="text" style="margin-right: 10px;" @click="handleProject('edit', row.id)"
              >编辑</el-button
            >
            <el-button type="text" @click="handleProject('detail', row.id)"
            <el-button type="text" style="margin-right: 10px;" @click="handleProject('detail', row.id)"
              >详情</el-button
            >
            <el-button type="text" @click="handleDel(row)">删除</el-button>
            <el-button type="text"  @click="handleDel(row)">删除</el-button>
          </template>
        </el-table-column>
      </template>
@@ -99,6 +101,7 @@
<script>
import { getProjectList, changeStatus, deleteProject } from "./service";
import moment from "moment";
export default {
  name: "ProjectList",
  data() {
culture/src/views/strain-library/breeding-record/index.vue
@@ -118,7 +118,7 @@
      tableData: [],
      delData: null,
      total: 0,
      roleType: JSON.parse(sessionStorage.getItem('userInfo')).roleType,
      roleType: Number(JSON.parse(sessionStorage.getItem('userInfo')).roleType),
    };
  },
  created() {
culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue
@@ -72,7 +72,7 @@
          </el-table-column>
          <el-table-column prop="boundTime" label="操作时间" />
          <el-table-column prop="handleName" label="操作人姓名" />
          <el-table-column prop="preserveName" label="签核确认人姓名" />
          <el-table-column prop="preserveName" label="菌种保藏人签字" />
          <el-table-column label="状态">
            <template #default="{ row }">
              <el-tag :type="row.confirmTime ? 'success' : 'warning'">
culture/src/views/strain-library/validation/primitive-cell/index.vue
@@ -58,8 +58,8 @@
              @click="$router.push('/strain/validation/confirm-detail?id=' + row.id)">确认</el-button>
            <el-button type="text" v-if="roleType == 4" @click="handleDetail(row)">详情</el-button>
            <el-button type="text" v-if="roleType != 4" @click="handleDetail2(row)">详情</el-button>
            <el-button type="text" v-if="roleType == 4 && currentType == 'draft'" @click="handleEdit(row)">编辑</el-button>
            <el-button type="text" v-if="roleType == 4 && currentType == 'draft'" @click="handleDelete(row)">删除</el-button>
            <el-button type="text" v-if="(roleType == 1)||(roleType == 4 && currentType == 'draft')" @click="handleEdit(row)">编辑</el-button>
            <el-button type="text" v-if="(roleType == 1)||(roleType == 4 && currentType == 'draft')" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </template>
@@ -95,7 +95,7 @@
      showDelConfirm: false,
      editDialogValue: {},
      currentDetail: {},
      roleType: JSON.parse(sessionStorage.getItem("userInfo")).roleType,
      roleType:Number(JSON.parse(sessionStorage.getItem("userInfo")).roleType),
      form: {
        identifyingStrainCode: "",
        identifyingStrainName: "",
culture/src/views/system/role/detail.vue
@@ -87,8 +87,8 @@
          </div>
        </el-form>
        <Table :data="data" :total="pagination.total" :queryForm="pagination" @currentChange="handleCurrentChange"
          @sizeChange="handleSizeChange">
        <Table :data="data" :total="pagination.total" :queryForm="pagination" @handleCurrentChange="handleCurrentChange"
          @handleSizeChange="handleSizeChange">
          <el-table-column label="序号" type="index" width="50">
          </el-table-column>
          <el-table-column prop="nickName" label="姓名"></el-table-column>
@@ -104,7 +104,7 @@
            <template slot-scope="{row}">
              <div class="status_class">
                <div :class="row.status == 0 ? 'green' : 'red'"></div>
                <div>{{ row.status == 0 ? '正常' : '停用' }}</div>
                <div>{{ row.status == 0 ? '正常' : '禁用' }}</div>
                <div v-if="row.status == 1" style="cursor: pointer;" @click="dialogVisibleView = true, rowView = row">
                  <i class="el-icon-warning"></i>
                </div>
culture/src/views/system/user/components/inherit.vue
@@ -1,12 +1,12 @@
<template>
    <div>
        <el-dialog :visible.sync="dialogVisible" @close="$emit('close')" title="账号继承" :show-close="false">
        <el-dialog :visible.sync="dialogVisible" :z-index="1000" @close="$emit('close')" title="账号继承" :show-close="false">
            <div class="inherit-title">当前账号</div>
            <div class="inherit-content">
                <div>姓名:张三</div>
                <div>电话:102929292929</div>
                <div>角色:工艺工程师</div>
                <div>登录账号:328746378</div>
                <div>姓名:{{row.nickName}}</div>
                <div>电话:{{row.phonenumber}}</div>
                <div>角色:{{row.roleName}}</div>
                <div>登录账号:{{row.userName}}</div>
            </div>
            <div class="inherit-table-title">
                <div class="inherit-title">继承账号</div>
culture/src/views/system/user/index.vue
@@ -167,7 +167,8 @@
          this.getListData()
        })
      } else {
        add(form).then(() => {
        add(form).then((res) => {
          console.log('qeqweqweqweq',res);
          this.row = {}
          this.dialogVisible = false
          this.$message.success('添加成功')
laboratory/package.json
@@ -17,6 +17,7 @@
    "core-js": "^3.41.0",
    "element-ui": "^2.15.6",
    "moment": "^2.30.1",
    "dayjs": "^1.11.0",
    "sm-crypto": "^0.3.13",
    "vue": "^2.7.16",
    "vue-router": "^3.6.5",
laboratory/src/App.vue
@@ -113,6 +113,16 @@
  border-color: #009688 !important;
  background: #e6ffff !important;
}
.el-form {
  .el-date-editor--daterange{
    .el-range-separator{
      width: 30px;
    }
    .el-input__inner {
    width: 220px !important;
  }
  }
}
.card-custom {
  .el-form {
@@ -122,31 +132,35 @@
      line-height: 14px;
    }
    .el-input__inner {
      width: 290px;
      width: 290px !important;
      padding: 0 12px;
      border-radius: 6px;
      border: 1px solid rgba(0, 0, 0, 0.15);
    }
    .el-date-editor {
      .el-range-separator{
      .el-range-editor--small .el-range-separator {
        width: 22px;
      }
      .el-input__inner {
        width: 260px;
        width: 240px !important;
        padding: 0 12px 0 30px;
        border-radius: 6px;
        border: 1px solid rgba(0, 0, 0, 0.15);
      }
    }
    .el-pagination__sizes {
      .el-input__inner {
        width: 100px;
      }
    }
    .el-pagination__jump {
      .el-input__inner {
        width: 50px;
@@ -162,7 +176,7 @@
    .el-input__inner {
      width: 200px;
    }
    .el-pagination__sizes {
      .el-input__inner {
@@ -178,6 +192,10 @@
  }
}
.el-dialog {
  border-radius: 16px 16px 6px 6px;
laboratory/src/components/AiEditor/index.vue
@@ -7,6 +7,8 @@
<script>
import { AiEditor } from "aieditor";
import 'aieditor/dist/style.css'
// import { customUploadRequest, getFullUrl } from '@/utils/utils'
import apiConfig from '@/utils/baseurl'
export default {
  name: 'AiEditor',
@@ -101,7 +103,110 @@
        // 禁用调整大小功能
        resize: false,
        // 添加唯一标识
        id: `editor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
        id: `editor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
        // 自定义图片上传功能
        image: {
          uploadUrl: apiConfig.imgUrl,
          uploadHeaders: {
            Authorization: sessionStorage.getItem('token') || '',
            // ...headers
          },
          uploader: (file, uploadUrl, headers, formName = 'file') => {
            const formData = new FormData();
            formData.append('file', file);
            return new Promise((resolve, reject) => {
              fetch(apiConfig.imgUrl, {
                method: "post",
                headers: { 'Accept': 'application/json', ...headers },
                body: formData,
              }).then((resp) => resp.json())
                .then(json => {
                  let data = {
                    "errorCode": 0,
                    "data": {
                      "src": apiConfig.showImgUrl + json.msg,
                      "alt": "图片 alt"
                    }
                  }
                  resolve(data);
                }).catch((error) => {
                  console.log('error error', error)
                  // reject(error);
                })
            });
          },
        },
        video: {
          uploadUrl: apiConfig.imgUrl,
          uploadFormName: "video", //上传时的文件表单名称
          uploadHeaders: {
            Authorization: sessionStorage.getItem('token') || '',
          },
          uploader: (file, uploadUrl, headers, formName = 'file') => {
            const formData = new FormData();
            formData.append('file', file);
            return new Promise((resolve, reject) => {
              fetch(apiConfig.imgUrl, {
                method: "post",
                headers: { 'Accept': 'application/json', ...headers },
                body: formData,
              }).then((resp) => resp.json())
                .then(json => {
                  let data = {
                    "errorCode": 0,
                    "data": {
                      "src": apiConfig.showImgUrl + json.msg,
                      "poster": "http://your-domain.com/poster.jpg"
                    }
                  }
                  resolve(data);
                }).catch((error) => {
                  console.log('error error', error)
                  // reject(error);
                })
            });
          },
        },
        attachment: {
          uploadUrl: apiConfig.imgUrl,
          uploadFormName: "attachment", //上传时的文件表单名称
          // uploadHeaders: {
          //     "jwt": "xxxxx",
          //     "other": "xxxx",
          // },
          uploadHeaders: () => {
            return {
              Authorization: sessionStorage.getItem('token') || '',
            }
          },
          uploader: (file, uploadUrl, headers, formName = 'file') => {
            const formData = new FormData();
            formData.append('file', file);
            return new Promise((resolve, reject) => {
              fetch(apiConfig.imgUrl, {
                method: "post",
                headers: { 'Accept': 'application/json', ...headers },
                body: formData,
              }).then((resp) => resp.json())
                .then(json => {
                  let data = {
                    "errorCode": 0,
                    "data": {
                      "href": apiConfig.showImgUrl + json.msg,
                      "fileName": file.name
                    }
                  }
                  resolve(data);
                }).catch((error) => {
                  console.log('error error', error)
                  // reject(error);
                })
            });
          },
        },
      }
      try {
laboratory/src/components/DynamicComponent/addTableData.vue
@@ -53,16 +53,18 @@
                >
                  <el-upload
                    class="upload-demo"
                    action="#"
                    :file-list="spectrumList"
                    :auto-upload="false"
                    :action="uploadUrl"
                    :headers="uploadHeaders"
                    :file-list="imageList"
                    :auto-upload="true"
                    list-type="picture-card"
                    :on-change="handleSpectrumChange"
                    :on-remove="handleSpectrumRemove"
                    :on-change="handleImageChange"
                    :on-remove="handleImageRemove"
                    :on-success="handleImageSuccess"
                    :on-preview="handlePreview"
                    :disabled="!checkEditPermission(header)"
                  >
                    <i class="el-icon-plus"></i>
                    <!-- <div slot="tip" class="el-upload__tip">暂未连接服务器,使用默认图片</div> -->
                  </el-upload>
                </el-form-item>
                <el-form-item
@@ -140,11 +142,16 @@
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" @click="handleSubmit">确 定</el-button>
    </div>
    <el-dialog :visible.sync="imagePreviewVisible" append-to-body>
      <img width="100%" :src="imagePreviewUrl" alt="" />
    </el-dialog>
  </el-dialog>
</template>
  
<script>
import { listByRole } from './service';
import { getFullUrl } from '@/utils/utils';
import apiConfig from '@/utils/baseurl';
export default {
  name: "AddDialog",
@@ -173,9 +180,15 @@
      form: {},
      rules: {},
      photoList: [],
      spectrumList: [],
      imageList: [],
      defaultImageUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg', // 默认图片地址
      userOptions: []
      userOptions: [],
      imagePreviewVisible: false,
      imagePreviewUrl: '',
      uploadUrl: apiConfig.imgUrl,
      uploadHeaders: {
        Authorization: sessionStorage.getItem('token') || ''
      }
    };
  },
  computed: {
@@ -318,14 +331,13 @@
      }
      // 设置图谱列表
      if (data.spectrums && data.spectrums.length) {
        this.spectrumList = data.spectrums.map((spectrum) => ({
          name: spectrum.name,
          url: spectrum.url,
          status: "success",
        }));
      } else {
        this.spectrumList = [];
      this.imageList = [];
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader && data[imageHeader.name]) {
        this.imageList = [{
          name: 'image',
          url: getFullUrl(data[imageHeader.name]),
        }];
      }
      // 重置表单校验状态
@@ -346,7 +358,7 @@
      this.dialogVisible = false;
      this.$refs.form?.resetFields();
      this.photoList = [];
      this.spectrumList = [];
      this.imageList = [];
      this.initFormData();
    },
    handleSubmit() {
@@ -356,7 +368,6 @@
          const submitData = {
            ...this.form,
            photos: this.photoList,
            spectrums: this.spectrumList,
          };
          
          // 为用户类型字段添加用户完整信息
@@ -380,32 +391,41 @@
        }
      });
    },
    handlePhotoChange(file, fileList) {
      this.photoList = fileList;
      this.$refs.form.validateField("photos");
    },
    handleSpectrumChange(file, fileList) {
      // 使用默认图片替代实际上传
      this.spectrumList = [{
        name: '默认图片.jpg',
        url: this.defaultImageUrl,
        status: 'success'
      }];
      // 同时更新form中对应的字段值以通过表单验证
    handleImageChange(file, fileList) {
      this.imageList = fileList;
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader && imageHeader.name) {
        // 保存图片URL,这样在表格中可以直接使用
        this.$set(this.form, imageHeader.name, this.defaultImageUrl);
        console.log('设置图片字段:', imageHeader.name, this.defaultImageUrl);
      if (imageHeader) {
        this.$refs.form.validateField(imageHeader.name);
      }
      this.$refs.form.validateField("spectrums");
    },
    handleSpectrumRemove(file) {
      this.spectrumList = [];
    handleImageSuccess(res, file, fileList) {
      console.log('res, file, fileList',res, file, fileList)
      const url = res.msg;
      file.url = getFullUrl(url);
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader) {
        this.$set(this.form, imageHeader.name, url);
        this.$refs.form.validateField(imageHeader.name);
      }
      this.imageList = fileList.map(f => {
        if (f.uid === file.uid) {
          return file;
        }
        return f;
      });
    },
    handleImageRemove(file, fileList) {
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader) {
        this.$set(this.form, imageHeader.name, '');
      }
      this.imageList = fileList;
    },
    handlePreview(file) {
      this.imagePreviewUrl = file.url;
      this.imagePreviewVisible = true;
    },
    getFullUrl,
  },
  mounted() {
    // 获取用户列表数据
laboratory/src/components/DynamicComponent/index.vue
@@ -16,16 +16,17 @@
      <div v-for="(item, idx) in components" :key="item.id" class="dynamic-component">
        <!-- 富文本 -->
        <div v-if="item.type == 'richText'">
          <AiEditor :ref="`editor_${item.id}`" :value="item.data.content" height="200px" :readOnly="!editable" placeholder="请输入内容..."
            :disabled="!editable" />
          <AiEditor :ref="`editor_${item.id}`" :value="item.data.content" height="200px" :readOnly="!editable"
            placeholder="请输入内容..." :disabled="!editable" />
        </div>
        <!-- 自定义表格 -->
        <div v-else-if="item.type == 'customTable'" style="flex: 1">
          <div v-if="editable" class="table-actions">
            <el-button size="mini"  @click="showTableHeaderDialog(idx)">添加表头</el-button>
            <el-button size="mini" @click="showTableHeaderDialog(idx)">添加表头</el-button>
            <el-button size="mini" type="primary" @click="showAddRowDialog(idx, item.data.headers)">添加数据</el-button>
          </div>
          <Table :data="item.data.rows" :total="null" :height="null" class="groupTable" :key="item.id + '_' + JSON.stringify(item.data.rows).length">
          <Table :data="item.data.rows" :total="null" :height="null" class="groupTable"
            :key="item.id + '_' + JSON.stringify(item.data.rows).length">
            <el-table-column v-for="(header, hidx) in item.data.headers" :key="hidx" :label="header.name"
              :prop="header.name">
              <template slot-scope="scope">
@@ -35,10 +36,8 @@
                </template>
                <!-- 图片类型显示 -->
                <template v-else-if="header.type === 'image'">
                  <img v-if="scope.row[header.name]"
                       :src="scope.row[header.name]"
                       alt="头像"
                       class="table-image" />
                  <img v-if="scope.row[header.name]" :src="getFullUrl(scope.row[header.name])" alt="头像"
                    class="table-image" />
                </template>
                <!-- 其他类型 -->
                <template v-else>
@@ -47,9 +46,9 @@
              </template>
            </el-table-column>
            <el-table-column label="更新时间" prop="updateTime" min-width="180"></el-table-column>
            <el-table-column  label="操作" min-width="200" v-if="dialogCanEdit">
            <el-table-column label="操作" min-width="200" v-if="dialogCanEdit">
              <template slot-scope="scope">
                <el-button type="text" @click="handleEditRow(idx, scope.$index)" >编辑</el-button>
                <el-button type="text" @click="handleEditRow(idx, scope.$index)">编辑</el-button>
                <el-button type="text" v-if="editable" @click="handleDeleteRow(idx, scope.$index)">删除</el-button>
              </template>
            </el-table-column>
@@ -57,8 +56,10 @@
        </div>
        <!-- 文件上传 -->
        <div v-else-if="item.type == 'fileUpload'">
          <el-upload v-if="editable" action="#" :file-list="item.data.fileList"
            :on-change="(file, fileList) => handleFileChange(idx, fileList)" list-type="text">
          <el-upload v-if="editable" :action="uploadUrl" :headers="uploadHeaders" :file-list="item.data.fileList"
            :on-change="(file, fileList) => handleFileChange(idx, fileList)"
            :on-success="(res, file, fileList) => handleFileSuccess(res, file, fileList, idx)"
            list-type="text">
            <el-button size="small" icon="el-icon-upload2">点击上传</el-button>
          </el-upload>
          <div v-else>
@@ -70,24 +71,21 @@
        <!-- 图片上传 -->
        <div v-else-if="item.type == 'imageUpload'">
          <div class="image-upload-container">
            <el-upload v-if="editable" action="#" :file-list="item.data.imageList"
            <el-upload v-if="editable"
            :action="uploadUrl"
            :headers="uploadHeaders"
             :file-list="item.data.imageList"
              :on-change="(file, fileList) => handleImageChange(idx, fileList)"
              :on-success="(res, file, fileList) => handleImageSuccess(res, file, fileList, idx)"
              :auto-upload="true"
              :http-request="() => { }"
              :before-upload="beforeImageUpload"
              :on-success="(res, file, fileList) => handleImageSuccess(res, file, fileList, idx)" :auto-upload="true"
              :before-upload="beforeImageUpload"
              list-type="picture-card"
              :on-preview="(file) => handlePreview(file, idx)"
              class="image-uploader">
              :on-preview="(file) => handlePreview(file, idx)" class="image-uploader">
              <i class="el-icon-plus"></i>
              <div class="upload-text">上传图片</div>
            </el-upload>
            <div v-else class="image-preview">
              <el-image v-for="image in item.data.imageList"
                :key="image.uid"
                :src="image.url"
                :preview-src-list="item.data.imageList.map(img => img.url)"
                class="preview-image" />
              <el-image v-for="image in item.data.imageList" :key="image.uid" :src="getFullUrl(image.url)"
                :preview-src-list="item.data.imageList.map(img => getFullUrl(img.url))" class="preview-image" />
            </div>
            <div class="uploaf-notice">支持.jpg .png格式</div>
          </div>
@@ -98,10 +96,10 @@
    </div>
    <addTableHeader  :visible.sync="tableHeaderDialog.visible" :participants="participants"
      @confirm="confirmAddHeader"></addTableHeader>
    <addTableData  :visible.sync="rowDialog.visible" :headerList="rowDialog.headers"
      :editData="rowDialog.form" :isEdit="rowDialog.isEdit" @success="confirmAddRow">
    <addTableHeader :visible.sync="tableHeaderDialog.visible" :participants="participants" @confirm="confirmAddHeader">
    </addTableHeader>
    <addTableData :visible.sync="rowDialog.visible" :headerList="rowDialog.headers" :editData="rowDialog.form"
      :isEdit="rowDialog.isEdit" @success="confirmAddRow">
    </addTableData>
    <el-dialog :visible.sync="imagePreviewVisible" width="auto" top="10vh" :show-close="true" v-if="imagePreviewUrl">
@@ -116,6 +114,8 @@
import Table from "../Table/index.vue";
import addTableHeader from "./addTableHeader.vue";
import addTableData from "./addTableData.vue";
import apiConfig from '../../utils/baseurl'
import { getFullUrl } from '@/utils/utils'
export default {
  name: "DynamicComponent",
@@ -150,6 +150,11 @@
  },
  data() {
    return {
      apiConfig: apiConfig,
      uploadUrl: apiConfig.imgUrl,
      uploadHeaders: {
        Authorization: sessionStorage.getItem('token') || ''
      },
      showAddDialog: false,
      components: [],
      tableHeaderDialog: {
@@ -212,17 +217,17 @@
    getUserDisplayText(fieldName, rowData) {
      // 检查是否有对应的userInfo数据
      const userInfoKey = `${fieldName}_userInfo`;
      // 如果没有rowData或fieldName,直接返回空字符串
      if (!rowData || !fieldName) {
        return '';
      }
      // 情况1: 有_userInfo数据
      if (rowData[userInfoKey] && Array.isArray(rowData[userInfoKey])) {
        return rowData[userInfoKey].map(user => user.label || '').join(', ');
      }
      // 情况2: 只有用户ID数组
      if (Array.isArray(rowData[fieldName])) {
        // 使用participants查找用户信息
@@ -231,12 +236,12 @@
          return user ? (user.nickName || user.userName || userId) : userId;
        }).join(', ');
      }
      // 情况3: 已经是字符串(可能是之前格式化过的)
      if (typeof rowData[fieldName] === 'string') {
        return rowData[fieldName];
      }
      // 默认返回空字符串
      return '';
    },
@@ -244,7 +249,7 @@
      if (!userArray || !Array.isArray(userArray) || userArray.length === 0) {
        return '';
      }
      // 查找参与者列表中的用户,获取昵称并用逗号拼接
      const userNames = userArray.map(userId => {
        const user = this.participants.find(p => p.userId === userId);
@@ -277,6 +282,7 @@
    submit() {
      const data = this.components.map(component => {
        let componentData = null;
        const prefix = apiConfig.showImgUrl;
        switch (component.type) {
          case 'richText':
@@ -292,10 +298,20 @@
            };
            break;
          case 'fileUpload':
            componentData = component.data.fileList;
            componentData = component.data.fileList.map(file => {
              if (file.url && file.url.startsWith(prefix)) {
                return { ...file, url: file.url.substring(prefix.length) };
              }
              return file;
            });
            break;
          case 'imageUpload':
            componentData = component.data.imageList;
            componentData = component.data.imageList.map(image => {
              if (image.url && image.url.startsWith(prefix)) {
                return { ...image, url: image.url.substring(prefix.length) };
              }
              return image;
            });
            break;
        }
@@ -311,18 +327,18 @@
      // if (!this.editable) return;
      const { idx, rowIndex, isEdit } = this.rowDialog;
      // 处理formData中的数据,保证用户信息的完整性
      const processedData = { ...formData };
      // 调试输出
      console.log('添加/编辑行数据:', processedData,'isEdit',isEdit);
      console.log('添加/编辑行数据:', processedData, 'isEdit', isEdit);
      if (isEdit) {
        // Vue无法检测到对象或数组深层属性的变化,使用Vue.set来确保响应式
        this.$set(
          this.components[idx].data.rows,
          rowIndex,
          this.components[idx].data.rows,
          rowIndex,
          {
            ...processedData,
            updateTime: new Date().toLocaleString()
@@ -335,15 +351,15 @@
          updateTime: new Date().toLocaleString()
        });
      }
      console.log('this.components',this.components);
      console.log('this.components', this.components);
      // 手动触发组件更新
      this.$forceUpdate();
      // 延迟发送事件,确保数据已更新
      this.$nextTick(() => {
        this.emitUpdate();
      });
      this.rowDialog.visible = false;
      this.rowDialog.form = {};
    },
@@ -439,34 +455,27 @@
    },
    handleFileChange(idx, fileList) {
      if (!this.editable) return;
      fileList = fileList.map(file => {
        if (!file.url) {
          file.url = 'https://picsum.photos/200/200';
        }
        if (!file.name) {
          file.name = '默认文件.txt';
        }
        return file;
      });
      // 只做 fileList 同步
      this.components[idx].data.fileList = fileList;
      this.emitUpdate();
    },
    handleFileSuccess(res, file, fileList, idx) {
      // 上传成功后设置真实 url
      file.url = this.getFullUrl(res.msg);
      this.components[idx].data.fileList = fileList;
      this.emitUpdate();
    },
    handleImageChange(idx, fileList) {
      if (!this.editable) return;
      fileList = fileList.map(file => {
        if (!file.url) {
          file.url = 'https://picsum.photos/200/200';
        }
        return file;
      });
      // 只做 imageList 同步
      this.components[idx].data.imageList = fileList;
      this.emitUpdate();
    },
    handleImageSuccess(res, file, fileList, idx) {
      file.url = 'https://picsum.photos/200/200';
      // 上传成功后设置真实 url
      file.url = this.getFullUrl(res.msg);
      this.components[idx].data.imageList = fileList;
      this.emitUpdate();
    },
    beforeImageUpload(file) {
      const isJPG = file.type === 'image/jpeg';
@@ -481,13 +490,14 @@
        this.$message.error('上传图片大小不能超过 2MB!');
        return false;
      }
      this.imagePreviewVisible = true;
      return true;
    },
    handlePreview(file, idx) {
      // 使用el-image的preview-src-list实现预览
      // 这里直接用Element的图片预览能力,实际上el-upload会自动处理
      // 但如果你想自定义弹窗,可以用如下代码:
      this.imagePreviewUrl = file.url;
      this.imagePreviewUrl = this.getFullUrl(file.url);
      this.imagePreviewVisible = true;
    },
    emitUpdate() {
@@ -495,6 +505,9 @@
      const updatedComponents = JSON.parse(JSON.stringify(this.components));
      this.$emit('update:dataSource', updatedComponents);
    },
    getFullUrl,
  },
  computed: {
  },
};
</script>
laboratory/src/components/SelectMember/index.vue
@@ -13,16 +13,16 @@
                                <img src="@/assets/public/search-outline@2x.png" />
                                <el-input v-model="search" placeholder="请输入" />
                                <div class="select-member-content-left-search-input-close">
                                    <img @click.stop="searchRole" v-if="search"
                                    <img @click.stop="searchRoleRest" v-if="search"
                                        src="@/assets/public/close-circle-fill@2x.png" />
                                </div>
                            </div>
                            <el-button type="primary">搜索</el-button>
                            <el-button type="primary" @click="searchRole()">搜索</el-button>
                        </div>
                        <div class="select-member-content-left-list">
                            <div class="select-member-content-left-list-title">角色列表</div>
                            <div class="select-member-content-left-list-itemBox">
                                <div @click="searchUserList(item.roleId)" v-for="item in roleList" :key="item.roleId"
                                <div @click="handleRoleClick(item.roleId)" v-for="item in roleList" :key="item.roleId"
                                    class="select-member-content-left-list-itemBox-item"
                                    :class="roleId == item.roleId && 'active'">
                                    {{ item.roleName }}
@@ -36,20 +36,20 @@
                        <div class="select-member-content-right-header">
                            <div class="select-member-content-right-header-text">人员列表</div>
                            <div class="select-member-content-right-header-search">
                                <el-input clearable v-model="nickNameOrPhone" placeholder="请输入姓名" />
                                <el-button type="primary">搜索</el-button>
                                <el-input clearable v-model="nickNameOrPhone" placeholder="请输入姓名"  />
                                <el-button type="primary" @click="searchUserList(null)">搜索</el-button>
                            </div>
                        </div>
                        <Table ref="memberTable" :height="null" :row-key="row => row.userId" :data="tableData"
                        <Table ref="memberTable" :height="500" :row-key="row => row.userId" :data="tableData"
                            :total="0" @selection-change="handleSelectionChange" :row-class-name="tableRowClassName">
                            <el-table-column type="selection" width="55" />
                            <el-table-column label="角色" prop="roleType" >
                            <el-table-column label="角色" prop="roleId" >
                                <template #default="scope">
                                    <span v-if="scope.row.roleType == 1">超级管理员</span>
                                    <span v-if="scope.row.roleType == 2">审批人</span>
                                    <span v-if="scope.row.roleType == 3">工艺工程师</span>
                                    <span v-if="scope.row.roleType == 4">化验师</span>
                                    <span v-if="scope.row.roleType == 5">实验员</span>
                                    <span v-if="scope.row.roleId == 1">超级管理员</span>
                                    <span v-if="scope.row.roleId == 2">审批人</span>
                                    <span v-if="scope.row.roleId == 3">工艺工程师</span>
                                    <span v-if="scope.row.roleId == 4">化验师</span>
                                    <span v-if="scope.row.roleId == 5">实验员</span>
                                </template>
                            </el-table-column>
                            <el-table-column label="姓名" prop="nickName" />
@@ -92,6 +92,21 @@
        }
    },
    methods: {
        searchRole(){
            if(this.search){
                this.roleList=this.roleList.filter(item=> item.roleName.includes(this.search))
            }else{
                getRoleList().then(res => {
                if (this.projectId) {
                    // 过滤出实验员和化验师角色
                    this.roleList = res.filter(item => item.roleId == 4 || item.roleId == 5);
                } else {
                    this.roleList = res;
                }
            });
            }
        },
        setSelection(selected) {
            this.selectData = selected;
            // 确保 tableData 和 memberTable 都存在
@@ -118,44 +133,74 @@
            this.searchUserList(null);
        },
        handleSelectionChange(val) {
            this.selectData = val
            // 获取当前表格所有 userId
            const currentIds = this.tableData.map(i => i.userId);
            // 1. 保留不在当前表格的已选
            const remain = this.selectData.filter(i => !currentIds.includes(i.userId));
            // 2. 合并当前表格新选中的
            const merged = [...remain, ...val];
            // 3. 去重(以 userId 为唯一标识)
            const unique = [];
            const map = {};
            for (const item of merged) {
                if (!map[item.userId]) {
                    unique.push(item);
                    map[item.userId] = true;
                }
            }
            this.selectData = unique;
        },
        handleRoleClick(clickedRoleId) {
            if (this.roleId === clickedRoleId) {
                // 再次点击,取消筛选
                this.roleId = null;
                this.searchUserList(null);
            } else {
                // 切换到新角色
                this.roleId = clickedRoleId;
                this.searchUserList(clickedRoleId);
            }
        },
        async searchUserList(roleId) {
            this.roleId = roleId
            // this.roleId = roleId // 不再赋值 roleId,由 handleRoleClick 控制
            // 根据是否有项目组ID来决定调用不同的接口
            let params = {
                roleIds: roleId ? [roleId] : [],
                nickNameOrPhone: this.searchName,
                nickNameOrPhone: this.nickNameOrPhone,
                pageSize: 9999,
                pageNum: 1
            };
            if (this.projectId) {
                params={
                    ...params,
                    roleId: roleId?roleId:'',
                    projectId: this.projectId
                    projectId: this.projectId,
                    nickName: this.nickNameOrPhone,
                }
                delete params.roleIds;
                // TODO: 这里需要替换为新的接口调用
                const res = await listByRole(params);
                this.tableData = res.filter(item => item.roleId == 4 || item.roleId == 5);
                this.tableData = res.filter(item => item.status==0 && (item.roleId == 4 || item.roleId == 5));
            } else {
                const res = await getUserList(params);
                this.tableData = res.records;
                this.tableData = res.records.filter(item=> item.status==0);
            }
            // 数据加载完成后重新应用选中状态
            this.setSelection(this.selectData)
        },
        searchRole() {
        searchRoleRest() {
            this.search = ''
        },
        open() {
            this.visible = true
        },
        close() {
            this.visible = false
            this.visible = false;
            this.selectData = [];
            this.roleId = null;
            this.search = '';
            this.nickNameOrPhone = '';
            this.tableData = [];
        },
        submit() {
            this.$emit('submit', this.selectData)
laboratory/src/components/chooseProject/index.vue
@@ -73,6 +73,10 @@
    },
    methods: {
        open() {
            if(this.form.date && this.form.date.length === 2){
                this.form.startTime=this.form.date[0]
                this.form.endTime=this.form.date[1]
            }
            getDataList({ ...this.form }).then(res => {
                console.log('/////////////', res);
                this.tableData = res.data.records || []
laboratory/src/main.js
@@ -1,8 +1,12 @@
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import {Calendar} from 'ant-design-vue';
import {Calendar,ConfigProvider } from 'ant-design-vue';
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';
import 'ant-design-vue/dist/antd.css';
// import Antd from 'ant-design-vue';
// import 'ant-design-vue/dist/antd.css';
// import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';
import '@/assets/font/font.css'
import App from "./App.vue";
import router from "./router";
@@ -17,11 +21,18 @@
import './assets/tailwind.css'
import './styles/element-variables.less'
import dayjs from "../node_modules/dayjs/dayjs.min.js";
import "dayjs/locale/zh-cn";
dayjs.locale("zh-cn");
Vue.config.productionTip = false;
Vue.use(ElementUI, { size: 'small' })
Vue.use('Calendar',Calendar)
Vue.use(ConfigProvider)
// Vue.use(Antd)
Vue.component('Table', Table)
Vue.component('TableCustom', TableCustom)
Vue.component('Card', Card)
@@ -71,5 +82,9 @@
new Vue({
  router,
  store,
  render: (h) => h(App),
  render: (h) => (
    <a-config-provider locale={zhCN}>
      <App />
    </a-config-provider>
  ),
}).$mount("#app");
laboratory/src/router/index.js
@@ -22,6 +22,7 @@
      keepAlive: true,  ------是否缓存
    }
 */
console.log('222222222222222222222',JSON.parse(sessionStorage.getItem('userInfo')).roleType=='5')
const routes = [{
        path: "/",
@@ -256,7 +257,9 @@
                        meta: {
                            title: "样品管理",
                            keepAlive: true,
                              privilege:'sampleManage_manage'
                            privilege:'sampleManage',
                            hide:JSON.parse(sessionStorage.getItem('userInfo')).roleType=='5'?true:false,
                            //   privilege:'sampleManage_manage'
                        },
                        component: () => import("../views/dataManagement/sampleManage/list.vue"),
                    },
@@ -274,6 +277,7 @@
                        meta: {
                            title: "取样操作记录列表",
                            keepAlive: true,
                            // privilege:'sampleManage'
                              privilege:'sampleManage_record'
                        },
                        component: () => import("../views/dataManagement/sampleRecordList/list.vue"),
@@ -292,6 +296,7 @@
                        meta: {
                            title: "送样单列表",
                            keepAlive: true,
                            // privilege:'sampleManage'
                              privilege:'sampleManage_submissionList'
                        },
                        component: () => import("../views/dataManagement/sampleSubmissionList/list.vue"),
@@ -508,7 +513,7 @@
            {
                path: "editVerificationRelease",
                meta: {
                    title: "新增验证与发布",
                    title: "编辑验证与发布",
                    hide: true,
                    keepAlive: true,
                },
laboratory/src/utils/baseurl.js
@@ -2,7 +2,8 @@
    // 开发环境
    development: {
        baseURL: "http://192.168.110.34:8081",
        imgUrl: "",
        imgUrl: "http://192.168.110.34:8081/open/file/upload",
        showImgUrl:'http://192.168.110.34:11222/'
    },
    // 生产环境
    production: {
laboratory/src/utils/request.js
@@ -19,12 +19,14 @@
    if (config.method == 'get') {
      if (!config.params) config.params = {};
      console.log('请求数据',config.params)
      config.params = {
        ...config.params,
      }
    }
    if (config.method == 'post') {
      if (!config.data) config.data = {};
      console.log('请求数据',config.data)
      if (needEncrypt) {
        config.data = { param: encryptBySM4(config.data) };
      }
@@ -56,13 +58,37 @@
      }
    }
    if (res.data.code == 200) {
      console.log('res.data',res.data)
      if (res.config.url.startsWith('/api')) { //有
        if(res.data.data.code == 200){
          return Promise.resolve(res.data.data || res.data)
        }
        if (res.data.data.code == 103 || res.data.data.code == 401) {
          Message({
            message: res.data.data.msg || '登录已过期,请重新登录',
            type: 'warning',
            duration: 2000
          })
          sessionStorage.clear();
          window.location.replace('/');
          return Promise.reject(res.data.data.data)
        }
        Message({
          message: res.data.data.msg || '服务器错误',
          type: 'error',
          duration: 2000
        })
        return Promise.reject(res.data.data.data)
      }
      if (!res.data) {
        return Promise.resolve({})
      }
      console.log('res', res.data.data || res.data)
      return Promise.resolve(res.data.data || res.data)
    } else {
      if (res.data.code == 103 || res.data.code == 401) {
        Message({
          message: res.data.msg || '登录已过期,请重新登录',
laboratory/src/utils/utils.js
@@ -1,3 +1,6 @@
import axios from 'axios';
import apiConfig from './baseurl';
export const customRequest = (params) => {
  const { file, onSuccess, onError } = params;
  uploadObs(file)
@@ -7,4 +10,30 @@
    .catch((ret) => {
      onError();
    });
};
};
export const customUploadRequest = ({ file, onSuccess, onError, action, headers }) => {
  // 默认 action 为 apiConfig.imgUrl
  const uploadUrl = action || apiConfig.imgUrl;
  // 默认 headers 带上 Authorization
  const uploadHeaders = {
    Authorization: sessionStorage.getItem('token') || '',
    ...headers
  };
  const formData = new FormData();
  formData.append('file', file);
  axios.post(uploadUrl, formData, { headers: uploadHeaders })
    .then(res => {
      onSuccess(res.data);
    })
    .catch(err => {
      onError(err);
    });
};
export function getFullUrl(url) {
  if (!url) return '';
  if (/^https?:\/\//.test(url)) return url;
  return apiConfig.showImgUrl + url;
}
laboratory/src/views/chemistQa/projectTesting/add.vue
@@ -17,7 +17,7 @@
                    <el-table-column prop="personCharge" label="项目负责人" />
                    <el-table-column prop="staffName" label="项目组成员">
                                    <template #default="{ row }">
                                        <span>{{row.staffs.map(item => item.nickName).join(',')}}</span>
                                        <span>{{row.staffName?row.staffName:row.staffs.map(item => item.nickName).join(',')}}</span>
                                    </template>
                                </el-table-column>
                    <el-table-column prop="createTime" label="创建时间" />
laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue
@@ -40,7 +40,8 @@
                    </el-col>
                    <el-col :span="24">
                        <el-form-item prop="developPersonName" label="制定人">
                            <el-input v-model="form.developPersonName" style="width: 100%;" placeholder="请输入制定人" disabled />
                            <el-input v-model="form.developPersonName" style="width: 100%;" placeholder="请输入制定人"
                                disabled />
                        </el-form-item>
                        <el-form-item prop="developDate" label="制定日期" style="margin-left: 100px;">
                            <el-date-picker :prefix-icon="null" v-model="form.developDate" type="date" disabled
@@ -66,12 +67,17 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 18px">
                    <el-upload
                    <!-- <el-upload
                        action="#" 
                        :file-list="fileList"
                        :http-request="handleUpload"
                        :before-upload="beforeUpload"
                        :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload> -->
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
@@ -91,7 +97,8 @@
import { Card } from 'element-ui';
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addDetail, getDetailInfo,updateDetail,getDetail  } from './service'
import { addDetail, getDetailInfo, updateDetail, getDetail } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
@@ -111,7 +118,7 @@
                itemId: "",
                status: 1,
                itemId: "",
                qaReportFiles: [],
                qaReportFileList: [],
                commitPersonId: null,
            },
            tableData: [],
@@ -135,26 +142,26 @@
        this.form.commitPersonId = JSON.parse(sessionStorage.getItem('userInfo')).userId
        this.form.developDate = new Date().toISOString().split('T')[0];
        this.form.itemId=this.$route.query.itemId
        if(this.form.itemId){
            getDetail(this.form.itemId).then(res=>{
                if(res){
                    let item={
                        teamName:res.projectTeamVO.teamName,
                        teamId:res.teamId,
                        remark:res.remark,
        this.form.itemId = this.$route.query.itemId
        if (this.form.itemId) {
            getDetail(this.form.itemId).then(res => {
                if (res) {
                    let item = {
                        teamName: res.projectTeamVO.teamName,
                        teamId: res.teamId,
                        remark: res.remark,
                        itemName:res.itemName,
                        itemCode:res.itemCode,
                        createBy:res.createBy,
                        createTime:res.createTime
                        itemName: res.itemName,
                        itemCode: res.itemCode,
                        createBy: res.createBy,
                        createTime: res.createTime
                    }
                   this.tableData = [{ ...item }]
                    this.tableData = [{ ...item }]
                }
            })
        }
        console.log('this.$route.query.itemId',this.$route.query)
        console.log('this.$route.query.itemId', this.$route.query)
        if (this.$route.query.id) {
            this.getDetail()
        }
@@ -162,14 +169,25 @@
    methods: {
        getDetail() {
            getDetailInfo({id:this.$route.query.id}).then(res => {
            getDetailInfo({ id: this.$route.query.id }).then(res => {
                if (res) {
                    this.form = {
                        ...res,
                        reportContent: Number(res.reportContent)
                    }
                    // this.tableData = [{ ...res.data.projectTeam, staffName: res.data.staffNames }]
                    this.fileList = res.qaReportFiles || []
                    // this.fileList = res.qaReportFileList || []
                    if (res.qaReportFileList && res.qaReportFileList.length > 0) {
                        this.fileList = res.qaReportFileList.map(file => ({
                            name: file.fileName,
                            url: getFullUrl(file.fileUrl),
                            uid: file.id
                        }))
                        this.form.qaReportFileList = res.fileList
                    } else {
                        this.fileList = []
                        this.form.qaReportFileList = []
                    }
                } else {
                    this.$message.error(res.message || '获取详情失败')
                }
@@ -183,12 +201,12 @@
        submit() {
            this.$refs.form.validate((valid) => {
                if (!valid) return
                if (this.$refs.materialEditor.getContent() == '<p></p>') {
                    this.$message.error('请输入报告正文')
                    return
                }
                let data = {
                    ...this.form,
                    reportText: this.$refs.materialEditor.getContent(),
@@ -197,8 +215,9 @@
                this.loading = true
                if (this.$route.query.id) {
                    console.log('data updateDetail',data)
                    console.log('data updateDetail', data)
                    updateDetail({ ...data, id: this.$route.query.id }).then(res => {
                        console.log('res',res)
                        if (res.code === 200) {
                            this.$message.success('修改成功')
                            this.$router.back()
@@ -209,8 +228,9 @@
                        this.loading = false
                    })
                } else {
                    console.log('data addDetail',data)
                    console.log('data addDetail', data)
                    addDetail(data).then(res => {
                        console.log('res',res)
                        if (res.code === 200) {
                            this.$message.success('发布成功')
                            this.$router.back()
@@ -226,7 +246,7 @@
        save() {
            this.$refs.form.validate((valid) => {
                if (!valid) return
                let data = {
                    ...this.form,
                    reportText: this.$refs.materialEditor.getContent(),
@@ -261,36 +281,56 @@
                }
            })
        },
        beforeUpload(file) {
                 // 上传前校验
                 beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const file = options.file;
            const fileObj = {
                fileName: file.name,
                fileSize: file.size,
                createTime: new Date().toISOString(),
                createBy: JSON.parse(sessionStorage.getItem('userInfo')).userId,
                reportType: 1,
                status: 1,
                id: Date.now().toString(),
                fileUrl: 'https://example.com/default-file-url'
            };
            this.fileList.push({
                name: file.name,
                url: fileObj.fileUrl
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.qaReportFileList.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
            this.form.qaReportFiles.push(fileObj);
            this.$message.success('文件上传成功');
        },
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.qaReportFiles.splice(index, 1);
                this.form.qaReportFileList.splice(index, 1);
            }
        },
    },
laboratory/src/views/chemistQa/projectTesting/components/approval/index.vue
@@ -72,7 +72,7 @@
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve" v-if="type === 'approve'">
        <div class="approval-dialog-approve" v-if="type === 'approve'">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
@@ -107,7 +107,7 @@
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
import { getDetailInfo, getDetail,detailAuditReport } from '../../service'
import { getDetailInfo, getDetail, detailAuditReport } from '../../service'
export default {
    name: "ApprovalDialog",
@@ -142,7 +142,7 @@
                processData: [],
            },
            tableData: [],
            fileList:[],
            fileList: [],
            radio1: 1,
            rules: {},
            status: "1",
@@ -172,7 +172,17 @@
            getDetailInfo({ id: this.data.id }).then(res => {
                if (res) {
                    this.form = { ...res, reportContent: Number(res.reportContent), processData: [] }
                    this.fileList = res.qaReportFileList
                    if (res.qaReportFileList && res.qaReportFileList.length > 0) {
                        this.fileList = res.qaReportFileList.map(file => ({
                            name: file.fileName,
                            url: getFullUrl(file.fileUrl),
                            uid: file.id
                        }))
                        this.form.qaReportFileList = res.fileList
                    } else {
                        this.fileList = []
                        this.form.qaReportFileList = []
                    }
                    // 组装流程数据
                    let processData = [];
                    // 提交节点
@@ -228,13 +238,13 @@
        getDetail() {
            getDetail(this.data.itemId).then(res => {
                if (res) {
                    this.tableData = [{...res,teamName:res.projectTeamVO.teamName}]
                    this.tableData = [{ ...res, teamName: res.projectTeamVO.teamName }]
                }
            })
        },
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
laboratory/src/views/chemistQa/projectTesting/index.vue
@@ -75,8 +75,8 @@
                                        </template>
                                    </el-table-column>
                                    <el-table-column prop="developPerson" label="制订人" />
                                    <el-table-column prop="developDate" label="制订日期" />
                                    <el-table-column prop="auditPersonId" label="审批人" />
                                    <el-table-column prop="createTime" label="制订日期" />
                                    <el-table-column prop="auditPersonName" label="审批人" />
                                    <el-table-column prop="auditTime" label="审批时间" />
                                    <el-table-column prop="status" label="状态">
                                        <template #default="{ row }">
@@ -119,16 +119,16 @@
                    <el-table-column prop="createBy" label="创建人" />
                    <el-table-column prop="createTime" label="创建时间" />
                    <el-table-column prop="auditTime" label="审批时间" v-if="!isChemist" />
                    <el-table-column prop="age" label="状态">
                    <el-table-column prop="age" label="状态" v-if="isApprovaler">
                        <template #default="{ row }">
                            <!-- 化验师的状态显示 -->
                            <template v-if="isChemist">
                                <el-tag v-if="row.status == -1" type="info" color="#fff">草稿箱</el-tag>
                                <el-tag v-else-if="row.status == 1" type="warning">已提交</el-tag>
                                <el-tag v-else-if="row.status == 2" type="primary">待评定</el-tag>
                                <el-tag v-else-if="row.status == 3" type="success">已评定</el-tag>
                            </template>
                            <!-- 其他角色的状态显示 -->
                            <template v-else>
                                <el-tag v-if="row.status == -1" type="info" color="#fff">草稿箱</el-tag>
                                <el-tag v-else-if="row.status == 1" type="warning">待审核</el-tag>
@@ -244,6 +244,10 @@
        isProcessEngineer() {
            const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
            return userInfo.roleType == 3; // 3是工艺工程师
        },
        isApprovaler() {
            const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
            return userInfo.roleType == 2; // 2是审批人
        }
    },
    methods: {
@@ -354,18 +358,24 @@
                if (this.currentAction === 'delete') {
                    if (this.confirmType === 'deleteReport') {
                        const res = await deleteDetail({ id: this.currentRow.id });
                        if (res.code === 200) {
                        if (res) {
                            this.loading = false;
                            this.$message.success('删除成功');
                            const parentItemId = this._getParentItemId(this.currentRow.id);
                            await this._refreshReportList(parentItemId);
                            this.closeConfirm();
                            await this.getList();
                        } else {
                            this.$message.error(res.msg || '删除失败');
                        }
                    } else if (this.confirmType === 'deleteItem') {
                        const res = await deleteData({ id: this.currentRow.id });
                        if (res.code === 200) {
                        if (res) {
                            this.loading = false;
                            this.$message.success('删除成功');
                            this.closeConfirm();
                            await this.getList();
                        } else {
                            this.$message.error(res.msg || '删除失败');
@@ -374,9 +384,13 @@
                } else if (this.currentAction === 'revoke') {
                    const res = await revokedReport({ id: this.currentRow.id });
                    if (res.code === 200) {
                        this.loading = false;
                        this.$message.success('撤销审批成功');
                        const parentItemId = this._getParentItemId(this.currentRow.id);
                        await this._refreshReportList(parentItemId);
                         this.loading = false;
                        this.closeConfirm();
                        await this.getList();
                    } else {
                        this.$message.error(res.msg || '撤销审批失败');
                    }
@@ -386,6 +400,23 @@
                this.$message.error('操作失败,请重试');
            } finally {
                this.loading = false;
            }
        },
        _getParentItemId(reportId) {
            return Object.keys(this.reportList).find(key =>
                this.reportList[key].some(report => report.id === reportId)
            );
        },
        async _refreshReportList(itemId) {
            if (!itemId) return;
            try {
                const res = await getListByItemId({ id: itemId });
                if (res) {
                    this.$set(this.reportList, itemId, res || []);
                }
            } catch (error) {
                console.error('刷新报告列表失败:', error);
                this.$message.error('刷新报告列表失败');
            }
        },
        handleCurrentChange(page) {
@@ -471,7 +502,7 @@
        async handleSubmitConfirm() {
            if (!this.rowId) return;
            try {
                this.loading = true;
                // this.loading = true;
                const res = await commitEvaluate({ id: this.rowId });
                if (res.code === 200) {
                    this.$message.success('提交评定成功');
@@ -490,14 +521,14 @@
        },
        async handleSearch() {
            try {
                this.loading = true;
                console.log('111111111')
                // this.loading = true;
                await this.$refs.searchForm.validate();
                this.queryForm.pageNum = 1;
                await this.getList();
            } catch (error) {
                if (error === false) {
                    this.$message.warning('请检查表单填写是否正确');
                } else {
                // 如果是校验失败,error会是false,此时不做任何处理,因为el-form会展示错误信息
                if (error !== false) {
                    this.$message.error('查询失败,请重试');
                }
            } finally {
@@ -506,8 +537,9 @@
        },
        async handleReset() {
            try {
                this.loading = true;
                // this.loading = true;
                this.$refs.searchForm.resetFields();
                // resetFields会把status也置为初始值'',需要根据当前tab重新设置
                this.form = {
                    itemCode: '',
                    itemName: '',
@@ -517,6 +549,7 @@
                    pageNum: 1,
                    pageSize: 10
                };
                this.form.status = this.currentType === 'draft' ? '-1' : '';
                this.queryForm.pageNum = 1;
                await this.getList();
            } catch (error) {
laboratory/src/views/chemistQa/projectTesting/service.js
@@ -63,5 +63,5 @@
}
// 撤销QA检测项报告管理状态
export function revokedReport(data) {
  return axios.get(`/open/t-qa-test-item-report/revokedReport?id=${data.id}`)
  return axios.put(`/open/t-qa-test-item-report/revokedReport?id=${data.id}`)
}
laboratory/src/views/dataManagement/inspectionReport/detail.vue
@@ -61,7 +61,7 @@
      />
      <div class="add-project-footer" v-if="pageType !== 'view'">
        <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>
    </el-form>
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
@@ -241,6 +241,7 @@
          { required: true, message: "请添加实验设备", trigger: "change" },
        ],
      },
      userRole:'',
      groupTableData: [],
      groupData: [],
      taskTableData: [],
@@ -266,6 +267,8 @@
    };
  },
  async created() {
    const userInfo=JSON.parse(sessionStorage.getItem('userInfo') || '{}');
    this.userRole=userInfo.roleType || '';
    // 检查是否为编辑模式
    if (this.$route.query.type === 'edit' && this.$route.query.id) {
      this.isEdit = true;
laboratory/src/views/dataManagement/suspendExperiment/list.vue
@@ -57,8 +57,8 @@
        <el-table-column prop="experimentName" label="实验名称"></el-table-column>
        <el-table-column prop="experimentDate" label="实验日期"></el-table-column>
        <el-table-column prop="schemePersonName" label="实验员"></el-table-column>
        <el-table-column prop="createTime" label="创建日期"></el-table-column>
        <el-table-column prop="createBy" label="创建人"></el-table-column>
        <el-table-column prop="createTime" label="提交日期"></el-table-column>
        <el-table-column prop="createBy" label="提交人"></el-table-column>
        <el-table-column prop="status" label="当前状态">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.status)">
laboratory/src/views/dataManagement/testResultReport/list.vue
@@ -205,6 +205,7 @@
        pageSize: 10
      };
      this.dateRange = [];
      this.getTableData();
    },
    handleSearch() {
      this.getTableData();
laboratory/src/views/middleground/index.vue
@@ -5,13 +5,16 @@
    </div>
    <div class="middleground" :class="{
      'column': windowWidth < 1240,
      'mobile': windowWidth < 800
      column: windowWidth < 1240,
      mobile: windowWidth < 800,
    }">
      <!-- 左侧模块区域 -->
      <div class="left-modules" :class="[currentModuleLayout, {
        'mobile-layout': windowWidth < 800
      }]">
      <div class="left-modules" :class="[
        currentModuleLayout,
        {
          'mobile-layout': windowWidth < 800,
        },
      ]">
        <div class="module-item" v-for="(item, index) in filteredModuleList" :key="index"
          @click="handleModuleClick(item)">
          <div class="module-bg"></div>
@@ -29,7 +32,7 @@
        <!-- 日历 -->
        <div class="calendar-section">
          <div class="title-canlender">日历</div>
          <a-calendar @panelChange="onPanelChange" />
          <a-calendar @panelChange="onPanelChange" :locale="local" />
        </div>
        <!-- 待办事项 -->
@@ -40,11 +43,9 @@
            <div class="todo-item" v-for="i in 6" :key="i">
              <div class="todo-details">
                <div class="notice-card">
                  <div class="todo-icon">
                  </div>
                  <div class="todo-icon"></div>
                  <div class="red-notice"></div>
                </div>
                <span class="todo-title">您有 [1] 条 【项目课题方案】 等待审批</span>
              </div>
@@ -59,18 +60,17 @@
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { Calendar } from 'ant-design-vue';
import { loginReq } from './service'
import HeaderNav from '../../layouts/components/HeaderNav.vue'
import { Calendar } from "ant-design-vue";
import { loginReq } from "./service";
import HeaderNav from "../../layouts/components/HeaderNav.vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
// 引入 Element UI 的日历组件
// import { ElCalendar } from 'element-ui';
export default {
  name: 'Login',
  name: "Login",
  components: {
    HeaderNav,
    ACalendar: Calendar,
@@ -80,146 +80,146 @@
  data() {
    return {
      windowWidth: window.innerWidth,
      local: zhCN,
      loginForm: {
        username: '',
        password: ''
        username: "",
        password: "",
      },
      date: new Date(),
      viewWidth: '',
      viewWidth: "",
      scale: 1,
      // 审批人
      moduleList2: [
      {
          text: '实验室运行模块',
          icon: require('../../assets/login/img1.png'),
          path: '/dataManagement'
        {
          text: "实验室运行模块",
          icon: require("../../assets/login/img1.png"),
          path: "/dataManagement/approvalPlan",
        },
        {
          text: '专业报告库',
          icon: require('../../assets/login/img2.png'),
          path: '/reportLibrary'
          text: "专业报告库",
          icon: require("../../assets/login/img2.png"),
          path: "/reportLibrary/feasibilityStudy",
        },
        {
          text: '化验师提交',
          icon: require('../../assets/login/img7.png'),
          path: '/chemistQa'
          text: "化验师提交",
          icon: require("../../assets/login/img7.png"),
          path: "/chemistQa/projectTesting",
        },
        {
          text: '评定模块',
          icon: require('../../assets/login/img4.png'),
          path: '/deliveryAssessment'
        }
          text: "评定模块",
          icon: require("../../assets/login/img4.png"),
          path: "/deliveryAssessment/projectTeamIntegral",
        },
      ],
      // 工艺工程师
      moduleList3: [
        {
          text: '实验室运行模块',
          icon: require('../../assets/login/img1.png'),
          path: '/dataManagement'
          text: "实验室运行模块",
          icon: require("../../assets/login/img1.png"),
          path: "/dataManagement/approvalPlan",
        },
        {
          text: '评定模块',
          icon: require('../../assets/login/img4.png'),
          path: '/deliveryAssessment'
          text: "评定模块",
          icon: require("../../assets/login/img4.png"),
          path: "/deliveryAssessment/projectTeamIntegral",
        },
        {
          text: '专业报告库',
          icon: require('../../assets/login/img2.png'),
          path: '/reportLibrary'
          text: "专业报告库",
          icon: require("../../assets/login/img2.png"),
          path: "/reportLibrary/feasibilityStudy",
        },
        {
          text: '化验师QA专题报告库',
          icon: require('../../assets/login/img7.png'),
          path: '/chemistQa'
        }
          text: "化验师QA专题报告库",
          icon: require("../../assets/login/img7.png"),
          path: "/chemistQa/projectTesting",
        },
      ],
      // 化验师
      moduleList4: [
        {
          text: '实验室运行模块',
          icon: require('../../assets/login/img1.png'),
          path: '/dataManagement'
          text: "实验室运行模块",
          icon: require("../../assets/login/img1.png"),
          path: "/dataManagement/dispatching",
        },
        {
          text: '评定模块',
          icon: require('../../assets/login/img4.png'),
          path: '/deliveryAssessment'
          text: "评定模块",
          icon: require("../../assets/login/img4.png"),
          path: "/deliveryAssessment/projectTeamIntegral",
        },
        {
          text: '专业报告库',
          icon: require('../../assets/login/img2.png'),
          path: '/reportLibrary'
          text: "专业报告库",
          icon: require("../../assets/login/img2.png"),
          path: "/reportLibrary/feasibilityStudy",
        },
        {
          text: '化验师提交',
          icon: require('../../assets/login/img7.png'),
          path: '/chemistQa'
        }
          text: "化验师提交",
          icon: require("../../assets/login/img7.png"),
          path: "/chemistQa/projectTesting",
        },
      ],
      // 实验员
      moduleList5: [
        {
          text: '实验室运行模块',
          icon: require('../../assets/login/img1.png'),
          path: '/dataManagement'
          text: "实验室运行模块",
          icon: require("../../assets/login/img1.png"),
          path: "/dataManagement/dispatching",
        },
        {
          text: '菌种库',
          icon: require('../../assets/login/img8.png'),
          path: '/projectList'
        },
        {
          text: '专业报告库',
          icon: require('../../assets/login/img2.png'),
          path: '/reportLibrary'
        },
        {
          text: '化验师提交',
          icon: require('../../assets/login/img3.png'),
          path: '/chemistQa'
        },
        // {
        //   text: "菌种库",
        //   icon: require("../../assets/login/img8.png"),
        //   path: "/projectList/list",
        // },
        {
          text: '评定模块',
          icon: require('../../assets/login/img4.png'),
          path: '/deliveryAssessment'
          path: '/deliveryAssessment/projectTeamIntegral'
        },
        {
          text: "专业报告库",
          icon: require("../../assets/login/img2.png"),
          path: "/reportLibrary/feasibilityStudy",
        },
        {
          text: "化验师提交",
          icon: require("../../assets/login/img3.png"),
          path: "/chemistQa/projectTesting",
        },
      ],
      // 超级管理员
      moduleList6: [
        {
          text: '实验室运行模块',
          icon: require('../../assets/login/img1.png'),
          path: '/dataManagement'
          text: "实验室运行模块",
          icon: require("../../assets/login/img1.png"),
          path: "/dataManagement/approvalPlan",
        },
        {
          text: '评定模块',
          icon: require('../../assets/login/img4.png'),
          path: '/deliveryAssessment'
          text: "评定模块",
          icon: require("../../assets/login/img4.png"),
          path: "/deliveryAssessment/projectTeamIntegral",
        },
        {
          text: '项目组管理',
          icon: require('../../assets/login/img5.png'),
          path: '/projectList'
          text: "项目组管理",
          icon: require("../../assets/login/img5.png"),
          path: "/projectList/list",
        },
        {
          text: '专业报告库',
          icon: require('../../assets/login/img2.png'),
          path: '/reportLibrary'
          text: "专业报告库",
          icon: require("../../assets/login/img2.png"),
          path: "/reportLibrary/feasibilityStudy",
        },
        {
          text: '化验师提交',
          icon: require('../../assets/login/img7.png'),
          path: '/chemistQa'
          text: "化验师提交",
          icon: require("../../assets/login/img7.png"),
          path: "/chemistQa/projectTesting",
        },
        {
          text: '系统管理',
          icon: require('../../assets/login/img6.png'),
          path: '/system'
        }
      ]
    }
          text: "系统管理",
          icon: require("../../assets/login/img6.png"),
          path: "/system/user",
        },
      ],
    };
  },
  created() {
@@ -229,7 +229,6 @@
  mounted() {
    // 监听窗口大小变化
    window.addEventListener("resize", this.handleResize);
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听
@@ -237,24 +236,24 @@
  },
  methods: {
    onPanelChange(e) {
      console.log('eeeeeee', e)
      console.log("eeeeeee", e);
    },
    // 添加处理窗口大小变化的方法
    handleResize() {
      this.windowWidth = window.innerWidth;
    },
    handleModuleClick(item) {
     if(item.path){
      this.$router.push({
        path: item.path,
      })
     }
      if (item.path) {
        this.$router.push({
          path: item.path,
        });
      }
    },
  },
  computed: {
    currentModuleList() {
      const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
      const userType = userInfo.userType;
      const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
      const userType = userInfo.roleType;
      switch (userType) {
        case 2: // 审批人
@@ -272,29 +271,29 @@
      }
    },
    filteredModuleList() {
      return this.currentModuleList.filter(item => item);
      return this.currentModuleList.filter((item) => item);
    },
    currentModuleLayout() {
      const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
      const userType = userInfo.userType;
      const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
      const userType = userInfo.roleType;
      switch (userType) {
        case 2: // 审批人
          return 'layout-4';
          return "layout-4";
        case 3: // 工艺工程师
          return 'layout-4';
          return "layout-4";
        case 4: // 化验师
          return 'layout-4';
          return "layout-4";
        case 5: // 实验员
          return 'layout-5';
          return "layout-4";
        case 6: // 超级管理员
          return 'layout-6';
          return "layout-6";
        default:
          return 'layout-6'; // 默认返回化验师的布局
          return "layout-6"; // 默认返回化验师的布局
      }
    }
  }
}
    },
  },
};
</script>
<style scoped lang="less">
.flex {
@@ -313,7 +312,7 @@
  width: 100vw;
  min-height: 100vh;
  /* 确保页面至少和视口一样高,并随内容扩展 */
  background: url('../../assets/login/midBg.png') no-repeat center center;
  background: url("../../assets/login/midBg.png") no-repeat center center;
  background-size: cover;
  display: flex;
  flex-direction: column;
@@ -364,6 +363,7 @@
        .module-item {
          width: 100%;
          height: 307px;
          border-radius: 20px;
        }
      }
@@ -431,6 +431,8 @@
      cursor: pointer;
      transition: all 0.3s ease;
      overflow: hidden;
      border-radius: 20px;
      padding-bottom: 40px;
    }
    .module-bg {
@@ -439,7 +441,7 @@
      left: 0;
      width: 100%;
      height: calc(100% - 75px);
      background: url('../../assets/login/cardBg.png') no-repeat center;
      background: url("../../assets/login/cardBg.png") no-repeat center;
      background-size: cover;
      transition: transform 0.3s ease;
      z-index: 1;
@@ -460,18 +462,20 @@
      display: flex;
      justify-content: center;
      align-items: center;
      background: url('../../assets/login/iconBg.png') no-repeat center;
      background: url("../../assets/login/iconBg.png") no-repeat center;
      background-size: 100% 100%;
      z-index: 2;
      &::before {
        content: '';
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 40px;
        background: linear-gradient(to bottom, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0) 100%);
        background: linear-gradient(to bottom,
            rgba(255, 255, 255, 0.3) 0%,
            rgba(255, 255, 255, 0) 100%);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
        pointer-events: none;
@@ -479,13 +483,15 @@
      }
      &::after {
        content: '';
        content: "";
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 40px;
        background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 100%);
        background: linear-gradient(to bottom,
            rgba(255, 255, 255, 0) 0%,
            rgba(255, 255, 255, 0.8) 100%);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
        pointer-events: none;
@@ -514,14 +520,16 @@
      z-index: 3;
      &::after {
        content: '';
        content: "";
        position: absolute;
        left: 50%;
        bottom: -5px;
        bottom: -15px;
        transform: translateX(-50%);
        width: 50%;
        height: 2px;
        background-color: #007bff;
        width: 66px;
        height: 3px;
        background: #24595b;
        border-radius: 1px;
      }
    }
@@ -774,7 +782,7 @@
        .ant-fullcalendar-header {
          .ant-radio-group {
            .ant-radio-button-wrapper {
              background: #FFFFFF;
              background: #ffffff;
              margin: 0 4px;
              color: #666;
@@ -785,7 +793,7 @@
              &.ant-radio-button-wrapper-checked {
                background-color: #009688 !important;
                border-color: #009688 !important;
                color: #FFFFFF !important;
                color: #ffffff !important;
                box-shadow: none !important;
              }
            }
@@ -793,8 +801,8 @@
          .ant-select {
            .ant-select-selection {
              background: #FFFFFF;
              border: 1px solid #EDEDED;
              background: #ffffff;
              border: 1px solid #ededed;
              border-radius: 8px;
              color: #666;
@@ -815,8 +823,8 @@
          .ant-select-dropdown {
            .ant-select-dropdown-menu {
              background: #FFFFFF;
              border: 1px solid #EDEDED;
              background: #ffffff;
              border: 1px solid #ededed;
              border-radius: 8px;
              box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
@@ -825,11 +833,12 @@
                &:hover {
                  background-color: #f0f0f0;
                  // color: #f0f0f0;
                }
                &.ant-select-dropdown-menu-item-selected {
                  background-color: #009688 !important;
                  color: #FFFFFF !important;
                  color: #ffffff !important;
                }
              }
            }
@@ -856,15 +865,15 @@
              margin: 0;
              padding: 0;
              height: 55px;
              background: #FFFFFF;
              background: #ffffff;
              border-radius: 8px;
              border: 1px solid #EDEDED;
              border: 1px solid #ededed;
              display: flex;
              justify-content: center;
              align-items: center;
              &:hover {
                background-color: rgba(4, 156, 154, .1);
                background-color: rgba(4, 156, 154, 0.1);
              }
              .ant-fullcalendar-value {
@@ -885,21 +894,40 @@
            &.ant-fullcalendar-today .ant-fullcalendar-date {
              // border-color: #009688;
            }
            &.ant-fullcalendar-last-month-cell {
              .ant-fullcalendar-value {
                color: #ffffff !important;
              }
            }
            &.ant-fullcalendar-next-month-btn-day {
              .ant-fullcalendar-date {}
              .ant-fullcalendar-value {
                color: #ffffff !important;
                &:hover {
                  // background: #FFFFFF;
                  color: rgba(4, 156, 154, 0.1) !important;
                }
              }
            }
          }
        }
        .ant-fullcalendar-month-panel-selected-cell {
          .ant-fullcalendar-month {
            border-top-color: #009688 !important;
            background: rgba(4, 156, 154, .2);
            background: rgba(4, 156, 154, 0.2);
            .ant-fullcalendar-value {
              color: #FFFFFF;
              color: #ffffff;
            }
            :hover {
              .ant-fullcalendar-month {
                background: rgba(4, 156, 154, .2);
                background: rgba(4, 156, 154, 0.2);
              }
            }
          }
@@ -911,7 +939,7 @@
            :hover {
              .ant-fullcalendar-month {
                background: rgba(4, 156, 154, .2);
                background: rgba(4, 156, 154, 0.2);
              }
            }
          }
@@ -919,7 +947,7 @@
        .ant-fullcalendar-month-panel-cell {
          .ant-fullcalendar-month:hover {
            background: rgba(4, 156, 154, .2);
            background: rgba(4, 156, 154, 0.2);
          }
        }
      }
@@ -955,7 +983,7 @@
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 20PX;
        margin-bottom: 20px;
        /* 分隔线 */
        &:first-child {
@@ -970,7 +998,6 @@
        .notice-card {
          position: relative;
          margin-right: 12px;
        }
        .todo-icon {
@@ -978,10 +1005,9 @@
          width: 24px;
          height: 24px;
          flex-shrink: 0;
          background: url('../../assets//login/notice.png') no-repeat center;
          background: url("../../assets//login/notice.png") no-repeat center;
          background-position: center;
          background-size: 100% 100%;
        }
        .red-notice {
@@ -1013,7 +1039,7 @@
          margin-right: 6px;
          margin-left: 20px;
          flex-shrink: 0;
          background: url('../../assets//login/time.png') no-repeat center;
          background: url("../../assets//login/time.png") no-repeat center;
          background-position: center;
          background-size: 100% 100%;
        }
@@ -1023,7 +1049,7 @@
          height: 14px;
          margin-right: 6px;
          flex-shrink: 0;
          background: url('../../assets//login/mi.png') no-repeat center;
          background: url("../../assets//login/mi.png") no-repeat center;
          background-position: center;
          background-size: 100% 100%;
        }
laboratory/src/views/projectList/addProject.vue
@@ -23,7 +23,7 @@
                        <div :class="item == 1 || item == 2 ? 'member-name-box' : 'member-name-box-2'">
                            <el-tooltip v-for="i in memberList(item)" :key="i.userId" class="member-name" effect="dark"
                                :content="i.nickName" placement="top">
                                <span>{{ i.nickName }}</span>
                                <span style="overflow: hidden;width: 60px; display: block;padding: 0 7px;">{{ i.nickName }}</span>
                            </el-tooltip>
                        </div>
                        <div class="member-edit" v-if="memberList(item).length != 0" @click="editUserList">修改</div>
@@ -44,7 +44,7 @@
    name: 'AddProject',
    data() {
        return {
            form: {},
            form: this.getDefaultForm(),
            rules: {
                teamName: [{ required: true, message: '请输入项目组名称', trigger: 'blur' }],
                personCharge: [{ required: true, message: '请输入项目组描述', trigger: 'blur' }]
@@ -58,6 +58,19 @@
        }
    },
    methods: {
        getDefaultForm() {
            return {
                teamName: '',
                personCharge: ''
            }
        },
        resetForm() {
            this.form = this.getDefaultForm();
            this.selectMemberData = [];
            if (this.$refs.form) {
                this.$refs.form.resetFields();
            }
        },
        submitForm() {
            this.$refs.form.validate((valid) => {
                if (valid) {
@@ -65,20 +78,16 @@
                        this.$message.error('请选择项目组成员')
                        return
                    }
                    const ROLE_NAME_TO_TYPE = {
                        '审批人': 2,
                        '工艺工程师': 3,
                        '实验员': 4,
                        '化验师': 5
                    };
                    const data = {
                        teamName: this.form.teamName,
                        personCharge: this.form.personCharge,
                        staffs: this.selectMemberData.map(member => ({
                            userId: member.userId,
                            roleType: ROLE_NAME_TO_TYPE[member.roleName]
                            roleType: member.roleType
                        }))
                    }
                    console.log('data data data',data)
                    addProject(data).then(res => {
                        if (res.code == 200) {
                            this.$message.success('添加成功')
@@ -90,6 +99,9 @@
        },
        addMember() {
            this.$refs.selectMember.open()
            this.$nextTick(() => {
                this.$refs.selectMember.setSelection(this.selectMemberData);
            });
        },
        memberList(i) {
            switch (i) {
@@ -113,6 +125,7 @@
                    return
                }
            }
            console.log('data data data',data)
            this.selectMemberData = data;
            this.$refs.selectMember.close();
        },
@@ -122,6 +135,9 @@
                this.$refs.selectMember.setSelection(this.selectMemberData);
            });
        }
    },
    mounted() {
        this.resetForm();
    }
}
</script>
laboratory/src/views/projectList/editProject.vue
@@ -23,7 +23,7 @@
                        <div :class="item == 1 || item == 2 ? 'member-name-box' : 'member-name-box-2'">
                            <el-tooltip v-for="i in memberList(item)" :key="i.userId" class="member-name" effect="dark"
                                :content="i.nickName" placement="top">
                                <span>{{ i.nickName }}</span>
                                <span style="overflow: hidden;width: 60px; display: block;padding: 0 7px;">{{ i.nickName }}</span>
                            </el-tooltip>
                        </div>
                        <div class="member-edit" v-if="memberList(item).length != 0" @click="editUserList">修改</div>
@@ -107,6 +107,9 @@
        },
        addMember() {
            this.$refs.selectMember.open()
            this.$nextTick(() => {
                this.$refs.selectMember.setSelection(this.selectMemberData);
            });
        },
        memberList(i) {
            switch (i) {
@@ -123,10 +126,23 @@
            }
        },
        selectUser(data) {
            // this.selectMemberData = data;
            for (const [roleId, config] of Object.entries(this.ROLE_CONFIG)) {
                const members = data.filter(item => item.roleName === config.label);
                if (members.length > config.limit) {
                    this.$message.error(`${config.label}最多只能选择${config.limit}个`);
                    return
                }
            }
            console.log('data data data',data)
            this.selectMemberData = data;
            this.$refs.selectMember.close();
        },
        editUserList() {
            this.$refs.selectMember.open(this.selectMemberData);
            this.$nextTick(() => {
                this.$refs.selectMember.setSelection(this.selectMemberData);
            });
        }
    }
}
laboratory/src/views/reportLibrary/feasibilityReport/add.vue
@@ -27,7 +27,7 @@
                    </div>
                </div>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                    <el-input v-model="form.reportCode" disabled style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
@@ -57,8 +57,10 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
                </el-form-item>
@@ -77,6 +79,7 @@
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addData, getDetail, editData } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
@@ -89,15 +92,16 @@
            form: {
                reportCode: "",
                reportName: "",
                reportText: ""
                reportText: "",
                feasibilityReportFiles:[]
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            rules: {
                reportCode: [
                    { required: true, message: '请输入报告编号', trigger: 'blur' }
                ],
                // reportCode: [
                //     { required: true, message: '请输入报告编号', trigger: 'blur' }
                // ],
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
                ],
@@ -117,13 +121,77 @@
            getDetail(this.$route.query.id).then(res => {
                this.form = res
                this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }]
                this.fileList = res.fileList
                if (res.feasibilityReportFiles && res.feasibilityReportFiles.length > 0) {
                    this.fileList = res.feasibilityReportFiles.map(file => ({
                        name: file.fileName,
                        url: getFullUrl(file.fileUrl),
                        uid: file.id
                    }))
                    this.form.feasibilityReportFiles = res.fileList
                } else {
                    this.fileList = []
                    this.form.feasibilityReportFiles = []
                }
            })
        },
        getProjectData(data) {
            this.tableData = [data]
            this.$forceUpdate()
            this.showChoose = false
        },
           // 上传前校验
           beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            reportType: 2, // 报告类型
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.feasibilityReportFiles.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
        },
        // 删除文件
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.feasibilityReportFiles.splice(index, 1);
            }
        },
        submit() {
            if (this.tableData.length == 0) {
@@ -183,16 +251,27 @@
                if (valid) {
                    this.loading = true
                    addData({ ...data }).then(res => {
                        if (res.code === 200) {
                            this.$message.success('提交成功')
                            this.$router.back()
                        } else {
                            this.$message.error(res.message)
                        }
                    }).finally(() => {
                        this.loading = false
                    })
                    if (this.$route.query.id) {
                        editData({ ...data, id: this.$route.query.id }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('修改成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        })
                    } else {
                        addData({ ...data }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('发布成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        }).finally(() => {
                            this.loading = false
                        })
                    }
                }
            })
        },
laboratory/src/views/reportLibrary/feasibilityReport/components/approval/index.vue
@@ -78,7 +78,7 @@
                            <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                通过
                            </div>
                            <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3">
                            <div class="reject" :class="status == '4' && 'activeStatus'" @click.stop="status = 4">
                                驳回
                            </div>
                        </div>
@@ -96,7 +96,7 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">确认</el-button>
        </div>
    </el-dialog>
</template>
@@ -192,6 +192,7 @@
                        type: data.status === 2 ? "primary" : "danger",
                        mode: "list",
                        fields: [
                        { label: "审核结果:", value: data.status == 4 ? '驳回' : "通过" || "" },
                            { label: "审批意见:", value: data.auditRemark || "" },
                            { label: "审核人:", value: data.auditPersonName || "" },
                            { label: "审核时间:", value: data.auditTime || "" },
@@ -220,7 +221,7 @@
                        type: "success",
                        mode: "list",
                        fields: [
                            { label: "已评定" },
                            { label: "评定状态:已评定" },
                            { label: "评定人:", value: data.evaluatePersonName || "" },
                            { label: "评定时间:", value: data.evaluateTime || "" }
                        ],
laboratory/src/views/reportLibrary/feasibilityReport/index.vue
@@ -37,8 +37,8 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button type="default" style="margin-right: 10px;" @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
@@ -75,11 +75,11 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleApproval(row)"
                            v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button>
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleDetail(row)" v-if="!isDraft">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)"
                        v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button>
                         v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">编辑</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button>
                             v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">删除</el-button>
                      
                        <el-button type="text" @click="handleRevoke(row)"
                            v-if="row.status == 1 && roleType == 3">撤销审批</el-button>
@@ -217,6 +217,16 @@
            } else {
                data = this.form
            }
            // 处理日期范围
            if (data.date && data.date.length === 2) {
                data.startTime = this.formatDate(data.date[0])
                data.endTime = this.formatDate(data.date[1])
            } else {
                data.startTime = ''
                data.endTime = ''
            }
            getDataList(data).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records || []
@@ -238,6 +248,27 @@
                    this.getList()
                }
            })
        },
        handleReset() {
            this.form.teamName = ''
            this.form.reportName = ''
            this.form.reportCode = ''
            this.form.date = ''
            this.form.status = ''
            this.form.startTime = ''
            this.form.endTime = ''
            this.form.pageNum = 1
            this.getList()
        },
        handleSearch() {
            this.form.pageNum = 1
            this.getList()
        },
        formatDate(date) {
            const year = date.getFullYear()
            const month = String(date.getMonth() + 1).padStart(2, '0')
            const day = String(date.getDate()).padStart(2, '0')
            return `${year}-${month}-${day}`
        }
    }
}
laboratory/src/views/reportLibrary/feasibilityStudy/add.vue
@@ -28,7 +28,7 @@
                    </div>
                </div>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                    <el-input v-model="form.reportCode" disabled style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
@@ -58,8 +58,10 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
                </el-form-item>
@@ -78,6 +80,8 @@
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addData, getDetail, editData } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
        AiEditor,
@@ -89,15 +93,16 @@
            form: {
                reportCode: "",
                reportName: "",
                reportText: ""
                reportText: "",
                feasibilityReportFiles: [] // 添加附件数组
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            rules: {
                reportCode: [
                    { required: true, message: '请输入报告编号', trigger: 'blur' }
                ],
                // reportCode: [
                //     { required: true, message: '请输入报告编号', trigger: 'blur' }
                // ],
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
                ],
@@ -117,7 +122,18 @@
            getDetail(this.$route.query.id).then(res => {
                this.form = res
                this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }]
                this.fileList = res.fileList
                // 处理文件回显
                if (res.feasibilityReportFiles && res.feasibilityReportFiles.length > 0) {
                    this.fileList = res.feasibilityReportFiles.map(file => ({
                        name: file.fileName,
                        url: getFullUrl(file.fileUrl),
                        uid: file.id
                    }))
                    this.form.feasibilityReportFiles = res.fileList
                } else {
                    this.fileList = []
                    this.form.feasibilityReportFiles = []
                }
            })
        },
        //获取选择项目组数据
@@ -125,6 +141,60 @@
            this.tableData = [data]
            this.$forceUpdate()
            this.showChoose = false
        },
        // 上传前校验
        beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            reportType: 1, // 可行性研究报告类型
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.feasibilityReportFiles.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
        },
        // 删除文件
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.feasibilityReportFiles.splice(index, 1);
            }
        },
        submit() {
            console.log(this.$refs.materialEditor.getContent());
@@ -186,16 +256,27 @@
                if (valid) {
                    this.loading = true
                    addData({ ...data }).then(res => {
                        if (res.code === 200) {
                            this.$message.success('提交成功')
                            this.$router.back()
                        } else {
                            this.$message.error(res.message)
                        }
                    }).finally(() => {
                        this.loading = false
                    })
                    if (this.$route.query.id) {
                        editData({ ...data, id: this.$route.query.id }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('修改成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        })
                    } else {
                        addData({ ...data }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('发布成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        }).finally(() => {
                            this.loading = false
                        })
                    }
                }
            })
        },
laboratory/src/views/reportLibrary/feasibilityStudy/components/approval/index.vue
@@ -1,7 +1,7 @@
<template>
    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog" :style="{height: obj.isDetail ? '50vh' : '40vh'}">
        <div class="approval-dialog" :style="{ height: obj.isDetail ? '50vh' : '40vh' }">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
@@ -78,7 +78,7 @@
                            <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                通过
                            </div>
                            <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3">
                            <div class="reject" :class="status == '4' && 'activeStatus'" @click.stop="status = 4">
                                驳回
                            </div>
                        </div>
@@ -95,8 +95,8 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
            <el-button @click="handleClose">{{ obj.isDetail ? '关闭' : '取 消' }}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">确认</el-button>
        </div>
    </el-dialog>
</template>
@@ -187,11 +187,12 @@
                    ]
                });
                if (data.status == 2 || data.status == 3) {
                if (data.status == 2 || data.status == 4) {
                    processData.push({
                        type: data.status === 2 ? "primary" : "danger",
                        type: 'primary',
                        mode: "list",
                        fields: [
                            { label: "审核结果:", value: data.status == 4 ? '驳回' : "通过" || "" },
                            { label: "审批意见:", value: data.auditRemark || "" },
                            { label: "审核人:", value: data.auditPersonName || "" },
                            { label: "审核时间:", value: data.auditTime || "" },
@@ -220,7 +221,7 @@
                        type: "success",
                        mode: "list",
                        fields: [
                            { label: "已评定" },
                            { label: "评定状态:已评定" },
                            { label: "评定人:", value: data.evaluatePersonName || "" },
                            { label: "评定时间:", value: data.evaluateTime || "" }
                        ],
laboratory/src/views/reportLibrary/feasibilityStudy/index.vue
@@ -37,8 +37,8 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button type="default" style="margin-right: 10px;" @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
@@ -75,11 +75,12 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleApproval(row)"
                            v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button>
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button>
                        <el-button type="text" @click="handleDetail(row)" v-if="!isDraft">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button>
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">编辑</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">删除</el-button>
                        <el-button type="text" @click="handleRevoke(row)"
                            v-if="row.status == 1 && roleType == 3">撤销审批</el-button>
                    </template>
@@ -216,6 +217,16 @@
            } else {
                data = this.form
            }
            // 处理日期范围
            if (this.form.date && this.form.date.length === 2) {
                data.startTime = this.form.date[0]
                data.endTime = this.form.date[1]
            } else {
                data.startTime = ''
                data.endTime = ''
            }
            getDataList(data).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records || []
@@ -237,6 +248,18 @@
                    this.getList()
                }
            })
        },
        handleReset() {
            this.form.pageNum = 1
            this.form.teamName = ''
            this.form.reportName = ''
            this.form.reportCode = ''
            this.form.date = ''
            this.form.status = ''
            this.getList()
        },
        handleSearch() {
            this.getList()
        }
    }
}
@@ -295,7 +318,7 @@
    justify-content: center;
    // margin-bottom: 21px;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #606266;
    line-height: 27px;
@@ -316,7 +339,6 @@
    justify-content: center;
    // margin-bottom: 21px;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #049C9A;
    line-height: 27px;
laboratory/src/views/reportLibrary/processDevelopment/add.vue
@@ -28,7 +28,7 @@
                    </div>
                </div>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                    <el-input v-model="form.reportCode" disabled style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
@@ -58,8 +58,10 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
                </el-form-item>
@@ -78,6 +80,7 @@
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addData, getDetail, editData } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
        AiEditor,
@@ -89,15 +92,16 @@
            form: {
                reportCode: "",
                reportName: "",
                reportText: ""
                reportText: "",
                feasibilityReportFiles: [] // 添加附件数组
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            rules: {
                reportCode: [
                    { required: true, message: '请输入报告编号', trigger: 'blur' }
                ],
                // reportCode: [
                //     { required: true, message: '请输入报告编号', trigger: 'blur' }
                // ],
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
                ],
@@ -117,7 +121,17 @@
            getDetail(this.$route.query.id).then(res => {
                this.form = res
                this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }]
                this.fileList = res.fileList
                if (res.feasibilityReportFiles && res.feasibilityReportFiles.length > 0) {
                    this.fileList = res.feasibilityReportFiles.map(file => ({
                        name: file.fileName,
                        url: getFullUrl(file.fileUrl),
                        uid: file.id
                    }))
                    this.form.feasibilityReportFiles = res.fileList
                } else {
                    this.fileList = []
                    this.form.feasibilityReportFiles = []
                }
            })
        },
        //获取选择项目组数据
@@ -125,6 +139,60 @@
            this.tableData = [data]
            this.$forceUpdate()
            this.showChoose = false
        },
        // 上传前校验
        beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            reportType: 3, // 可行性研究报告类型
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.feasibilityReportFiles.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
        },
        // 删除文件
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.feasibilityReportFiles.splice(index, 1);
            }
        },
        submit() {
            console.log(this.$refs.materialEditor.getContent());
@@ -186,16 +254,27 @@
                if (valid) {
                    this.loading = true
                    addData({ ...data }).then(res => {
                        if (res.code === 200) {
                            this.$message.success('提交成功')
                            this.$router.back()
                        } else {
                            this.$message.error(res.message)
                        }
                    }).finally(() => {
                        this.loading = false
                    })
                    if (this.$route.query.id) {
                        editData({ ...data, id: this.$route.query.id }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('修改成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        })
                    } else {
                        addData({ ...data }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('发布成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        }).finally(() => {
                            this.loading = false
                        })
                    }
                }
            })
        },
laboratory/src/views/reportLibrary/processDevelopment/components/approval/index.vue
@@ -78,7 +78,7 @@
                            <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                通过
                            </div>
                            <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3">
                            <div class="reject" :class="status == '4' && 'activeStatus'" @click.stop="status = 4">
                                驳回
                            </div>
                        </div>
@@ -96,7 +96,7 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">确定</el-button>
        </div>
    </el-dialog>
</template>
@@ -189,9 +189,10 @@
                if (data.status == 2 || data.status == 3) {
                    processData.push({
                        type: data.status === 2 ? "primary" : "danger",
                        type: "primary",
                        mode: "list",
                        fields: [
                        { label: "审核结果:", value: data.status == 4 ? '驳回' : "通过" || "" },
                            { label: "审批意见:", value: data.auditRemark || "" },
                            { label: "审核人:", value: data.auditPersonName || "" },
                            { label: "审核时间:", value: data.auditTime || "" },
@@ -220,7 +221,7 @@
                        type: "success",
                        mode: "list",
                        fields: [
                            { label: "已评定" },
                            { label: "评定状态:已评定" },
                            { label: "评定人:", value: data.evaluatePersonName || "" },
                            { label: "评定时间:", value: data.evaluateTime || "" }
                        ],
laboratory/src/views/reportLibrary/processDevelopment/index.vue
@@ -37,8 +37,8 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button type="default" style="margin-right: 10px;" @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
@@ -75,11 +75,12 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleApproval(row)"
                            v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button>
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button>
                        <el-button type="text" @click="handleDetail(row)" v-if="!isDraft">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button>
                             v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">编辑</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                             v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">删除</el-button>
                        <el-button type="text" @click="handleRevoke(row)"
                            v-if="row.status == 1 && roleType == 3">撤销审批</el-button>
                    </template>
@@ -216,6 +217,14 @@
            } else {
                data = this.form
            }
            // 处理日期范围
            if (this.form.date && this.form.date.length === 2) {
                data.startTime = this.form.date[0]
                data.endTime = this.form.date[1]
            } else {
                data.startTime = ''
                data.endTime = ''
            }
            getDataList(data).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records || []
@@ -237,6 +246,18 @@
                    this.getList()
                }
            })
        },
        handleReset() {
            this.form.pageNum = 1
            this.form.teamName = ''
            this.form.reportName = ''
            this.form.reportCode = ''
            this.form.date = ''
            this.form.status = ''
            this.getList()
        },
        handleSearch() {
            this.getList()
        }
    }
}
laboratory/src/views/reportLibrary/projectProposalLibrary/add.vue
@@ -28,7 +28,7 @@
                    </div>
                </div>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                    <el-input v-model="form.reportCode" disabled style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
@@ -58,8 +58,10 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
                </el-form-item>
@@ -78,6 +80,7 @@
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addData, getDetail, editData } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
        AiEditor,
@@ -89,15 +92,15 @@
            form: {
                reportCode: "",
                reportName: "",
                reportText: ""
                reportText: "", feasibilityReportFiles: [] // 添加附件数组
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            rules: {
                reportCode: [
                    { required: true, message: '请输入报告编号', trigger: 'blur' }
                ],
                // reportCode: [
                //     { required: true, message: '请输入报告编号', trigger: 'blur' }
                // ],
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
                ],
@@ -117,7 +120,18 @@
            getDetail(this.$route.query.id).then(res => {
                this.form = res
                this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }]
                this.fileList = res.fileList
                // 处理文件回显
                if (res.feasibilityReportFiles && res.feasibilityReportFiles.length > 0) {
                    this.fileList = res.feasibilityReportFiles.map(file => ({
                        name: file.fileName,
                        url: getFullUrl(file.fileUrl),
                        uid: file.id
                    }))
                    this.form.feasibilityReportFiles = res.fileList
                } else {
                    this.fileList = []
                    this.form.feasibilityReportFiles = []
                }
            })
        },
        //获取选择项目组数据
@@ -125,6 +139,61 @@
            this.tableData = [data]
            this.$forceUpdate()
            this.showChoose = false
        },
         // 上传前校验
         beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            reportType: 1, // 可行性研究报告类型
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.feasibilityReportFiles.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
        },
        // 删除文件
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.feasibilityReportFiles.splice(index, 1);
            }
        },
        submit() {
            console.log(this.$refs.materialEditor.getContent());
@@ -184,16 +253,27 @@
                if (valid) {
                    this.loading = true
                    addData({ ...data }).then(res => {
                        if (res.code === 200) {
                            this.$message.success('提交成功')
                            this.$router.back()
                        } else {
                            this.$message.error(res.message)
                        }
                    }).finally(() => {
                        this.loading = false
                    })
                    if (this.$route.query.id) {
                        editData({ ...data, id: this.$route.query.id }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('修改成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        })
                    } else {
                        addData({ ...data }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('发布成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        }).finally(() => {
                            this.loading = false
                        })
                    }
                }
            })
        },
laboratory/src/views/reportLibrary/projectProposalLibrary/components/approval/index.vue
@@ -78,7 +78,7 @@
                            <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                通过
                            </div>
                            <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3">
                            <div class="reject" :class="status == '4' && 'activeStatus'" @click.stop="status = 4">
                                驳回
                            </div>
                        </div>
@@ -96,7 +96,7 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">确定</el-button>
        </div>
    </el-dialog>
</template>
laboratory/src/views/reportLibrary/projectProposalLibrary/index.vue
@@ -36,8 +36,8 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button type="default" style="margin-right: 10px;" @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
@@ -73,11 +73,12 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleApproval(row)"
                            v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button>
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button>
                        <el-button type="text" @click="handleDetail(row)" v-if="!isDraft">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button>
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">编辑</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">删除</el-button>
                        <el-button type="text" @click="handleRevoke(row)"
                            v-if="row.status == 1 && roleType == 3">撤销审批</el-button>
                    </template>
@@ -211,6 +212,15 @@
            } else {
                data = this.form
            }
            // 处理日期范围
            if (this.form.date && this.form.date.length === 2) {
                data.startTime = this.form.date[0]
                data.endTime = this.form.date[1]
            } else {
                data.startTime = ''
                data.endTime = ''
            }
            getDataList(data).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records || []
@@ -232,6 +242,18 @@
                    this.getList()
                }
            })
        },
        handleReset() {
            this.form.pageNum = 1
            this.form.teamName = ''
            this.form.reportName = ''
            this.form.reportCode = ''
            this.form.date = ''
            this.form.status = ''
            this.getList()
        },
        handleSearch() {
            this.getList()
        }
    }
}
laboratory/src/views/reportLibrary/verificationRelease/add.vue
@@ -28,7 +28,7 @@
                    </div>
                </div>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                    <el-input v-model="form.reportCode" disabled style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
@@ -58,8 +58,10 @@
                    </div>
                </div>
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                    <el-upload action="#" :file-list="fileList" :http-request="handleUpload"
                        :before-upload="beforeUpload" :on-remove="handleRemove">
                        <el-button size="small" type="primary">点击上传</el-button>
                        <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                    </el-upload>
                </el-form-item>
@@ -78,6 +80,7 @@
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
import { addData, getDetail, editData } from './service'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
export default {
    components: {
        AiEditor,
@@ -89,15 +92,16 @@
            form: {
                reportCode: "",
                reportName: "",
                reportText: ""
                reportText: "",
                feasibilityReportFiles: [] // 添加附件数组
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            rules: {
                reportCode: [
                    { required: true, message: '请输入报告编号', trigger: 'blur' }
                ],
                // reportCode: [
                //     { required: true, message: '请输入报告编号', trigger: 'blur' }
                // ],
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
                ],
@@ -117,7 +121,18 @@
            getDetail(this.$route.query.id).then(res => {
                this.form = res
                this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }]
                this.fileList = res.fileList
                // 处理文件回显
                if (res.feasibilityReportFiles && res.feasibilityReportFiles.length > 0) {
                    this.fileList = res.feasibilityReportFiles.map(file => ({
                        name: file.fileName,
                        url: getFullUrl(file.fileUrl),
                        uid: file.id
                    }))
                    this.form.feasibilityReportFiles = res.fileList
                } else {
                    this.fileList = []
                    this.form.feasibilityReportFiles = []
                }
            })
        },
        //获取选择项目组数据
@@ -125,6 +140,61 @@
            this.tableData = [data]
            this.$forceUpdate()
            this.showChoose = false
        },
        // 上传前校验
        beforeUpload(file) {
            return true;
        },
        // 自定义上传处理
        handleUpload(options) {
            const { file, onSuccess, onError } = options;
            // 使用封装的customUploadRequest方法
            customUploadRequest({
                file,
                onSuccess: (res) => {
                    console.log()
                    if (res.code === 200) {
                        const fileObj = {
                            id: new Date().getTime(),
                            reportId: this.$route.query.id ? this.$route.query.id : '',
                            fileUrl: res.msg || res.data || '',
                            reportType: 4, // 可行性研究报告类型
                            fileName: file.name,
                            fileSize: file.size,
                        };
                        // 添加到文件列表显示
                        this.fileList.push({
                            name: file.name,
                            url: getFullUrl(fileObj.fileUrl),
                            uid: fileObj.id
                        });
                        // 添加到表单数据
                        this.form.feasibilityReportFiles.push(fileObj);
                        this.$message.success('文件上传成功');
                        onSuccess(res);
                    } else {
                        this.$message.error(res.message || '文件上传失败');
                        onError();
                    }
                },
                onError: (err) => {
                    this.$message.error('文件上传失败');
                    onError(err);
                }
            });
        },
        // 删除文件
        handleRemove(file) {
            const index = this.fileList.findIndex(item => item.name === file.name);
            if (index !== -1) {
                this.fileList.splice(index, 1);
                this.form.feasibilityReportFiles.splice(index, 1);
            }
        },
        submit() {
            console.log(this.$refs.materialEditor.getContent());
@@ -140,6 +210,7 @@
                }
                let data = {
                    ...this.form,
                    reportType: 4,
                    status: 1,
                    reportText: this.$refs.materialEditor.getContent(),
                    teamId: this.tableData[0].id
@@ -175,6 +246,7 @@
            this.$refs.form.validate((valid) => {
                let data = {
                    ...this.form,
                    reportType: 4,
                    status: -1,
                    reportText: this.$refs.materialEditor.getContent(),
                    teamId: this.tableData[0].id
@@ -184,16 +256,27 @@
                if (valid) {
                    this.loading = true
                    addData({ ...data }).then(res => {
                        if (res.code === 200) {
                            this.$message.success('提交成功')
                            this.$router.back()
                        } else {
                            this.$message.error(res.message)
                        }
                    }).finally(() => {
                        this.loading = false
                    })
                    if (this.$route.query.id) {
                        editData({ ...data, id: this.$route.query.id }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('修改成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        })
                    } else {
                        addData({ ...data }).then(res => {
                            if (res.code === 200) {
                                this.$message.success('发布成功')
                                this.$router.back()
                            } else {
                                this.$message.error(res.message)
                            }
                        }).finally(() => {
                            this.loading = false
                        })
                    }
                }
            })
        },
laboratory/src/views/reportLibrary/verificationRelease/components/approval/index.vue
@@ -1,7 +1,7 @@
<template>
    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog" :style="{height: obj.isDetail ? '50vh' : '40vh'}">
        <div class="approval-dialog" :style="{ height: obj.isDetail ? '50vh' : '40vh' }">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
@@ -78,7 +78,7 @@
                            <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                通过
                            </div>
                            <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3">
                            <div class="reject" :class="status == '4' && 'activeStatus'" @click.stop="status = 4">
                                驳回
                            </div>
                        </div>
@@ -95,8 +95,8 @@
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
            <el-button @click="handleClose">{{ obj.isDetail ? '关闭' : '取 消' }}</el-button>
            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">确定</el-button>
        </div>
    </el-dialog>
</template>
@@ -189,9 +189,10 @@
                if (data.status == 2 || data.status == 3) {
                    processData.push({
                        type: data.status === 2 ? "primary" : "danger",
                        type: "primary",
                        mode: "list",
                        fields: [
                            { label: "审核结果:", value: data.status == 4 ? '驳回' : "通过" || "" },
                            { label: "审批意见:", value: data.auditRemark || "" },
                            { label: "审核人:", value: data.auditPersonName || "" },
                            { label: "审核时间:", value: data.auditTime || "" },
@@ -220,7 +221,7 @@
                        type: "success",
                        mode: "list",
                        fields: [
                            { label: "已评定" },
                            { label: "评定状态:已评定" },
                            { label: "评定人:", value: data.evaluatePersonName || "" },
                            { label: "评定时间:", value: data.evaluateTime || "" }
                        ],
laboratory/src/views/reportLibrary/verificationRelease/index.vue
@@ -37,8 +37,8 @@
                        </el-select>
                    </el-form-item>
                    <el-form-item label="" style="margin-left: 63px;">
                        <el-button type="default" style="margin-right: 10px;">重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button type="default" style="margin-right: 10px;" @click="handleReset">重置</el-button>
                        <el-button type="primary"  @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
@@ -75,11 +75,12 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleApproval(row)"
                            v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button>
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button>
                        <el-button type="text" @click="handleDetail(row)" v-if="!isDraft">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)"
                            v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button>
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">编辑</el-button>
                        <el-button type="text" @click="handleDelete(row)"
                            v-if="([4, 5].includes(row.status) && roleType == 3) || isDraft">删除</el-button>
                        <el-button type="text" @click="handleRevoke(row)"
                            v-if="row.status == 1 && roleType == 3">撤销审批</el-button>
                    </template>
@@ -137,6 +138,18 @@
    },
    methods: {
        handleReset() {
            this.form.pageNum = 1
            this.form.teamName = ''
            this.form.reportName = ''
            this.form.reportCode = ''
            this.form.date = ''
            this.form.status = ''
            this.getList()
        },
        handleSearch() {
            this.getList()
        },
        handleApproval(row) {
            this.rowData = row
            this.showApproval = true
@@ -148,14 +161,14 @@
        },
        handleEdit(row) {
            this.$router.push({
                path: '/reportLibrary/',
                path: '/reportLibrary/editVerificationRelease',
                query: {
                    id: row.id
                }
            })
        },
        handleAddProject() {
            this.$router.push('/reportLibrary/addProjectProposalLibrary')
            this.$router.push('/reportLibrary/addVerificationRelease')
        },
        changeTab(status) {
            if (status == -1) {
@@ -214,6 +227,14 @@
            } else {
                data = this.form
            }
              // 处理日期范围
              if (this.form.date && this.form.date.length === 2) {
                data.startTime = this.form.date[0]
                data.endTime = this.form.date[1]
            } else {
                data.startTime = ''
                data.endTime = ''
            }
            getDataList(data).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records || []