董国庆
2025-06-25 d8d68a0aee93073b5ec3195368ca0ed1076f66a2
对接评定接口和中台待办事项
1个文件已删除
10个文件已添加
38个文件已修改
6660 ■■■■ 已修改文件
laboratory/src/components/SelectMemberSimple/index.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/router/index.js 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/editDispatch.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue 464 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/testResultReport/detail.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/testResultReport/list.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/QA/components/AssessmentDialog.vue 193 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/QA/index.vue 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/QA/service.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/assayTaskList/components/AssessmentDialog.vue 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/assayTaskList/index.vue 211 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/assayTaskList/service.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/chemistEvaluate/add.vue 255 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/chemistEvaluate/index.vue 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/chemistEvaluate/service.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/clinicalTrial/components/detail.vue 190 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/clinicalTrial/index.vue 90 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/clinicalTrial/service.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/experimentResults/service.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/experimenterJobEvaluation/index.vue 296 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/experimenterJobEvaluation/service.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/components/evaluation-dialog.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/index.vue 221 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/service.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/projectTeamIntegral/detail.vue 433 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/projectTeamIntegral/index.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/projectTeamIntegral/service.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/reportEvaluation/components/AssessmentDialog.vue 323 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/reportEvaluation/components/CraftDialog.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/reportEvaluation/index.vue 242 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/reportEvaluation/service.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/restsTask/components/detail.vue 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/restsTask/index.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/restsTask/service.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/taskList/components/AssessmentDialog.vue 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/taskList/index.vue 224 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/taskList/service.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/technicianJobEvaluation/index.vue 295 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/technicianJobEvaluation/service.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/add.vue 266 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/index.vue 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/service.js 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testingAndEvaluation/components/AssessmentDialog.vue 197 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testingAndEvaluation/components/approval/index.vue 486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testingAndEvaluation/index.vue 501 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/deliveryAssessment/testingAndEvaluation/service.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/middleground/index.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/middleground/service.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/system/role/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SelectMemberSimple/index.vue
@@ -1,32 +1,58 @@
<template>
    <el-dialog @open="openDialog" class="select-member" :visible.sync="visible" width="53.33%"
        :close-on-click-modal="false" :show-close="false">
  <el-dialog
    @open="openDialog"
    class="select-member"
    :visible.sync="visible"
    width="53.33%"
    :close-on-click-modal="false"
    :show-close="false"
  >
        <template #title>
            <div>选择实验人员</div>
      <div>{{ roleType==4 ? "选择化验师" : "选择实验人员" }}</div>
        </template>
        <div class="select-member-content">
            <div class="select-member-content-right">
                <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="searchKeyword" placeholder="请输入姓名" />
            <el-input
              clearable
              v-model="searchKeyword"
              placeholder="请输入姓名"
            />
                    </div>
                </div>
                <Table ref="memberTable" :height="null" :row-key="row => row.userId" :data="filteredTableData"
                    :total="0" @selection-change="handleSelectionChange" :row-class-name="tableRowClassName">
        <Table
          ref="memberTable"
          :height="null"
          :row-key="(row) => row.userId"
          :data="filteredTableData"
          :total="0"
          @selection-change="handleSelectionChange"
          :row-class-name="tableRowClassName"
        >
                    <el-table-column type="selection" width="55" />
                    <el-table-column label="角色" prop="roleType" >
                        <template #default="{ row }">
                            {{ row.roleType === 3 ? '工艺工程师' : row.roleType === 4 ? '化验师' : '实验员' }}
              {{
                row.roleType === 3
                  ? "工艺工程师"
                  : row.roleType === 4
                  ? "化验师"
                  : "实验员"
              }}
                        </template>
                    </el-table-column>
                    <el-table-column label="姓名" prop="nickName" />
                    <el-table-column label="头像" prop="avatar" width="80">
                        <template #default="{ row }">
                            <el-avatar :size="32" :src="row.avatar || require('../../assets/login/img1111.png')" />
              <el-avatar
                :size="32"
                :src="row.avatar || require('../../assets/login/img1111.png')"
              />
                        </template>
                    </el-table-column>
                    <el-table-column label="创建时间" prop="signTime" />
          <el-table-column label="创建时间" prop="createTime" />
                </Table>
            </div>
        </div>
@@ -42,16 +68,20 @@
    props: {
        memberList: {
            type: Array,
            default: () => []
        }
      default: () => [],
    },
    roleType: {
      type: String,
      default: () => "",
    },
    },
    data() {
        return {
            visible: false,
            searchKeyword: '',
      searchKeyword: "",
            selectData: [],
            defaultSelected: [] // 默认选中的行
        }
      defaultSelected: [], // 默认选中的行
    };
    },
    computed: {
        filteredTableData() {
@@ -59,63 +89,79 @@
                return this.memberList;
            }
            const keyword = this.searchKeyword.toLowerCase();
            return this.memberList.filter(item =>
      return this.memberList.filter(
        (item) =>
                (item.nickName && item.nickName.toLowerCase().includes(keyword)) ||
                (item.phone && item.phone.includes(keyword))
            );
        }
    },
    },
    methods: {
        setSelection(selected) {
            this.selectData = selected
      this.selectData = selected;
            this.$nextTick(() => {
                // 设置新选中
                this.memberList.forEach(row => {
                    if (selected.some(i => i.userId === row.userId)) {
                        this.$refs.memberTable.toggleRowSelection(row, true)
        this.memberList.forEach((row) => {
          if (selected.some((i) => i.userId === row.userId)) {
            this.$refs.memberTable.toggleRowSelection(row, true);
                    }
                })
            })
        });
      });
        },
        openDialog() {
            this.setSelection(this.selectData);
        },
        handleSelectionChange(val) {
            this.selectData = val
      this.selectData = val;
        },
        open(data = [], defaultSelected = []) {
            this.memberList = data
            this.visible = true
            this.defaultSelected = defaultSelected
      this.memberList = data;
      this.visible = true;
      this.defaultSelected = defaultSelected;
            // 在下一个tick中设置选中状态,确保表格已经渲染完成
            this.$nextTick(() => {
                this.setDefaultSelection();
            });
        },
        close() {
            this.visible = false
      this.visible = false;
        },
        submit() {
            this.$emit('submit', this.selectData)
      if (this.roleType) {
        if (this.selectData.length == 1) {
          this.$emit("submit", this.selectData);
        } else {
          this.$message.error(
            `请选择一个${this.roleType == 4 ? "化验师" : "实验员"}!`
          );
        }
      }else{
        this.$emit("submit", this.selectData);
      }
        },
        tableRowClassName({ row, rowIndex }) {
            if (this.selectData.findIndex(item => item.userId === row.userId) != -1) {
                return 'select-row';
      if (
        this.selectData.findIndex((item) => item.userId === row.userId) != -1
      ) {
        return "select-row";
            }
            return '';
      return "";
        },
        setDefaultSelection() {
            if (this.defaultSelected && this.defaultSelected.length > 0) {
                this.defaultSelected.forEach(row => {
                    const targetRow = this.memberList.find(item => item.userId === row.userId);
        this.defaultSelected.forEach((row) => {
          const targetRow = this.memberList.find(
            (item) => item.userId === row.userId
          );
                    if (targetRow) {
                        this.$refs.memberTable.toggleRowSelection(targetRow, true);
                    }
                });
            }
        }
    }
}
    },
  },
};
</script>
<style scoped lang="less">
@@ -136,7 +182,7 @@
                font-size: 16px;
                line-height: 16px;
                color: #222222;
                font-family: 'SourceHanSansCN-Medium';
        font-family: "SourceHanSansCN-Medium";
                margin-right: 20px;
            }
laboratory/src/router/index.js
@@ -679,6 +679,26 @@
                component: () => import("../views/deliveryAssessment/restsTask"),
            },
            {
                // 工艺工程师 审批人
                path: "processEngineerEvaluate",
                meta: {
                    title: "工艺工程师工作评定",
                     privilege:'deliveryAssessment_processEngineerEvaluate'
                },
                component: () => import("../views/deliveryAssessment/processEngineerEvaluate"),
            },
            {
                // 审批人
                path: "reportEvaluation",
                name: 'ReportEvaluation',
                meta: {
                    title: "专业报告库评定",
                    keepAlive: true,
                     privilege:'deliveryAssessment_reportEvaluation'
                },
                component: () => import("../views/deliveryAssessment/reportEvaluation"),
            },
            {
                // 超级管理员 工艺工程师 审批人
                path: "clinicalTrial",
                meta: {
@@ -686,6 +706,17 @@
                     privilege:'deliveryAssessment_clinicalTrial'
                },
                component: () => import("../views/deliveryAssessment/clinicalTrial"),
            },
            {
                // 审批人
                path: "technicianJobEvaluation",
                name: 'TechnicianJobEvaluation',
                meta: {
                    title: "化验师工作评定详情",
                    keepAlive: true,
                     privilege:'deliveryAssessment_technicianJobEvaluation'
                },
                component: () => import("../views/deliveryAssessment/technicianJobEvaluation"),
            },
            {
                // 化验师 审批人 工艺工程师
@@ -712,17 +743,10 @@
                    title: "课题评定列表",
                     privilege:'deliveryAssessment_assayTaskList'
                },
                // component: () => import("../views/deliveryAssessment/taskList"),
                component: () => import("../views/deliveryAssessment/assayTaskList"),
            },
            {
                // 工艺工程师 审批人
                path: "processEngineerEvaluate",
                meta: {
                    title: "工艺工程师工作评定详情",
                     privilege:'deliveryAssessment_processEngineerEvaluate'
                },
                component: () => import("../views/deliveryAssessment/processEngineerEvaluate"),
            },
            {
                // 工艺工程师
                path: "testerWorkerEvaluate",
@@ -785,28 +809,8 @@
                },
                component: () => import("../views/deliveryAssessment/experimenterJobEvaluation"),
            },
            {
                // 审批人
                path: "technicianJobEvaluation",
                name: 'TechnicianJobEvaluation',
                meta: {
                    title: "化验师工作评定详情",
                    keepAlive: true,
                     privilege:'deliveryAssessment_technicianJobEvaluation'
                },
                component: () => import("../views/deliveryAssessment/technicianJobEvaluation"),
            },
            {
                // 审批人
                path: "reportEvaluation",
                name: 'ReportEvaluation',
                meta: {
                    title: "专业报告库评定",
                    keepAlive: true,
                     privilege:'deliveryAssessment_reportEvaluation'
                },
                component: () => import("../views/deliveryAssessment/reportEvaluation"),
            },
        ]
    }
];
laboratory/src/views/dataManagement/dispatching/editDispatch.vue
@@ -365,7 +365,6 @@
      queryDetail().then(res=>{
        if(res){
          this.imgSrc=res.signPicture
          console.log('1111111111',getFullUrl(this.imgSrc),res.signPicture)
        }
      })
    },
@@ -513,10 +512,10 @@
    },
    handleSignatureConfirm(imageData) {
      this.signatureDialogVisible = false;
      // 模拟上传签名图片,实际应调用上传接口,成功后回显图片链接
      // TODO: 替换为实际上传接口
      // uploadSignature(imageData).then(url => { this.imgSrc = url })
      this.imgSrc = 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'; // 默认图片链接
      this.imgSrc = ""; // 先清空
      this.$nextTick(() => {
        this.imgSrc = imageData;
      });
    },
  },
};
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
@@ -1,7 +1,13 @@
<template>
  <Card>
    <template style="position: relative">
      <el-form ref="form" :model="form" :rules="rules" inline label-position="top">
      <el-form
        ref="form"
        :model="form"
        :rules="rules"
        inline
        label-position="top"
      >
        <div v-if="!isEdit">
          <div class="header-title" style="margin-bottom: 38px">
            <div style="display: flex; align-items: center; gap: 13px">
@@ -9,22 +15,57 @@
                <img src="@/assets/public/headercard.png" />
                <div>所属实验调度</div>
              </div>
              <el-button @click="showScheduling = true" class="el-icon-plus" type="primary">
                选择实验调度</el-button>
              <el-button
                @click="showScheduling = true"
                class="el-icon-plus"
                type="primary"
              >
                选择实验调度</el-button
              >
            </div>
          </div>
          <!-- //换到详情弹窗 -->
          <!-- <el-button @click="handleStopExperiment" type="danger">
            申请终止实验</el-button> -->
          <Table :data="groupTableData" :total="0" :height="null" class="groupTable">
            <el-table-column type="index" label="序号" width="80"></el-table-column>
            <el-table-column prop="projectName" label="所属项目课题方案"></el-table-column>
            <el-table-column prop="experimentCode" label="实验编号"></el-table-column>
            <el-table-column prop="experimentName" label="实验名称"></el-table-column>
            <el-table-column prop="experimentDate" label="通知时间"></el-table-column>
            <el-table-column prop="experimentStartTime" label="实验开始时间"></el-table-column>
            <el-table-column prop="experimentEndTime" label="实验结束时间"></el-table-column>
            <el-table-column prop="participantsName" label="参加人员"></el-table-column>
          <Table
            :data="groupTableData"
            :total="0"
            :height="null"
            class="groupTable"
          >
            <el-table-column
              type="index"
              label="序号"
              width="80"
            ></el-table-column>
            <el-table-column
              prop="projectName"
              label="所属项目课题方案"
            ></el-table-column>
            <el-table-column
              prop="experimentCode"
              label="实验编号"
            ></el-table-column>
            <el-table-column
              prop="experimentName"
              label="实验名称"
            ></el-table-column>
            <el-table-column
              prop="experimentDate"
              label="通知时间"
            ></el-table-column>
            <el-table-column
              prop="experimentStartTime"
              label="实验开始时间"
            ></el-table-column>
            <el-table-column
              prop="experimentEndTime"
              label="实验结束时间"
            ></el-table-column>
            <el-table-column
              prop="participantsName"
              label="参加人员"
            ></el-table-column>
            <el-table-column prop="status" label="状态">
              <template slot-scope="scope">
                <el-tag :type="getStatusType(scope.row.status)">
@@ -46,17 +87,30 @@
              <span>组别列表</span>
            </div>
            <Table :data="groupData" :total="0" :height="null" class="groupTable">
              <el-table-column type="index" label="序号" width="80"></el-table-column>
            <Table
              :data="groupData"
              :total="0"
              :height="null"
              class="groupTable"
            >
              <el-table-column
                type="index"
                label="序号"
                width="80"
              ></el-table-column>
              <el-table-column prop="groupName" label="组别"></el-table-column>
              <el-table-column prop="remark" label="备注"></el-table-column>
            </Table>
          </template>
          <div style="padding-left: 25px;margin-top: 28px;">
          <div style="padding-left: 25px; margin-top: 28px">
            <el-form-item prop="experimentDate" label="试验日期">
              <el-date-picker v-model="form.experimentDate" type="datetime" :disabled="isEdit" placeholder="选择日期时间">
              <el-date-picker
                v-model="form.experimentDate"
                type="datetime"
                :disabled="isEdit"
                placeholder="选择日期时间"
              >
              </el-date-picker>
            </el-form-item>
          </div>
@@ -70,12 +124,38 @@
          </div>
          <div class="content-box">
            <div class="content-box-left">
              <div>项目课题方案名称:{{ groupTableData && groupTableData.length > 0 ? groupTableData[0].projectName : '' }}</div>
              <div>实验编号:{{ groupTableData && groupTableData.length > 0 ? groupTableData[0].experimentCode : '' }}</div>
              <div>
                项目课题方案名称:{{
                  groupTableData && groupTableData.length > 0
                    ? groupTableData[0].projectName
                    : ""
                }}
              </div>
              <div>
                实验编号:{{
                  groupTableData && groupTableData.length > 0
                    ? groupTableData[0].experimentCode
                    : ""
                }}
              </div>
            </div>
            <div class="content-box-right">
              <div>项目课题方案编号: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].projectCode : '' }}</div>
              <div>实验名称: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].experimentName : '' }}</div>
              <div>
                项目课题方案编号:
                {{
                  groupTableData && groupTableData.length > 0
                    ? groupTableData[0].projectCode
                    : ""
                }}
              </div>
              <div>
                实验名称:
                {{
                  groupTableData && groupTableData.length > 0
                    ? groupTableData[0].experimentName
                    : ""
                }}
              </div>
            </div>
          </div>
        </div>
@@ -83,7 +163,9 @@
        <div class="add-group" v-if="!isEdit">
          <div>*</div>
          <span>参加人员</span>
          <el-button type="primary" class="el-icon-plus" @click="addMember" >选择参加人员</el-button>
          <el-button type="primary" class="el-icon-plus" @click="addMember"
            >选择参加人员</el-button
          >
        </div>
        <div class="add-group" v-else><span>实验人员</span> </div>
        <div class="member-list">
@@ -92,13 +174,23 @@
              <div class="member-title">实验员</div>
              <div class="flex">
                <div class="member-name-box-2">
                  <div v-for="i in selectedParticipants" :key="i.id" class="member-name">
                  <div
                    v-for="i in selectedParticipants"
                    :key="i.id"
                    class="member-name"
                  >
                    {{ i.nickName }}
                  </div>
                </div>
              </div>
              <div class="member-change">
                <div class="member-change-btn" @click="handleEditMember" v-if="!isEdit">修改</div>
                <div
                  class="member-change-btn"
                  @click="handleEditMember"
                  v-if="!isEdit"
                >
                  修改
                </div>
              </div>
            </div>
          </div>
@@ -110,7 +202,11 @@
          </div>
          <Table :data="groupData" :total="0" :height="null" class="groupTable">
            <el-table-column type="index" label="序号" width="80"></el-table-column>
            <el-table-column
              type="index"
              label="序号"
              width="80"
            ></el-table-column>
            <el-table-column prop="groupName" label="组别"></el-table-column>
            <el-table-column prop="remark" label="备注"></el-table-column>
          </Table>
@@ -123,8 +219,13 @@
          </div>
        </div>
        <div class="content-box">
          <AiEditor ref="purposeEditor" :readOnly="isEdit" :value="editorContents.purpose" height="200px"
            placeholder="请输入实验目的..." />
          <AiEditor
            ref="purposeEditor"
            :readOnly="isEdit"
            :value="editorContents.purpose"
            height="200px"
            placeholder="请输入实验目的..."
          />
        </div>
        <div class="header-title" style="margin-bottom: 38px">
@@ -134,8 +235,13 @@
          </div>
        </div>
        <div class="content-box">
          <AiEditor ref="processEditor" :readOnly="isEdit" :value="editorContents.process" height="200px"
            placeholder="请输入工艺参数及路线..." />
          <AiEditor
            ref="processEditor"
            :readOnly="isEdit"
            :value="editorContents.process"
            height="200px"
            placeholder="请输入工艺参数及路线..."
          />
        </div>
        <div class="header-title" style="margin-bottom: 38px">
@@ -144,18 +250,36 @@
            <div>三、实验材料及设备</div>
          </div>
        </div>
        <DynamicComponent ref="materialComponent" title="实验材料" :participants="participantsData"
          @submit="handleMaterialSubmit" :dataSource="form.experimentMaterial" :editable="!isEdit" />
        <DynamicComponent ref="equipmentComponent" title="实验所用设备" :participants="participantsData"
          @submit="handleEquipmentSubmit" :dataSource="form.experimentDevice" :editable="!isEdit" />
        <DynamicComponent
          ref="materialComponent"
          title="实验材料"
          :participants="participantsData"
          @submit="handleMaterialSubmit"
          :dataSource="form.experimentMaterial"
          :editable="!isEdit"
        />
        <DynamicComponent
          ref="equipmentComponent"
          title="实验所用设备"
          :participants="participantsData"
          @submit="handleEquipmentSubmit"
          :dataSource="form.experimentDevice"
          :editable="!isEdit"
        />
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <div>四、实验操作步骤记录</div>
          </div>
          <el-button @click="handleAddStep" class="el-icon-plus" type="primary" v-if="!isEdit">
            添加步骤</el-button>
          <el-button
            @click="handleAddStep"
            class="el-icon-plus"
            type="primary"
            v-if="!isEdit"
          >
            添加步骤</el-button
          >
        </div>
        <div class="step-list" v-for="(item, idx) in stepList" :key="idx">
@@ -164,28 +288,57 @@
              步骤{{ idx + 1 }}:{{ item.stepName }}
            </div>
            <div class="step-list-item-control">
              <div class="controlBtn edit" @click="handleEditStep(idx)" v-if="!isEdit">
                <img src="@/assets/public/edit.png" alt="编辑" class="edit-icon" />
              <div
                class="controlBtn edit"
                @click="handleEditStep(idx)"
                v-if="!isEdit"
              >
                <img
                  src="@/assets/public/edit.png"
                  alt="编辑"
                  class="edit-icon"
                />
                编辑
              </div>
              <div class="controlBtn delete" @click="handleDeleteStep(idx)" v-if="!isEdit">
                <img src="@/assets/public/delete.png" alt="删除" class="delete-icon" />
              <div
                class="controlBtn delete"
                @click="handleDeleteStep(idx)"
                v-if="!isEdit"
              >
                <img
                  src="@/assets/public/delete.png"
                  alt="删除"
                  class="delete-icon"
                />
                删除
              </div>
            </div>
          </div>
          <DynamicComponent :participants="participantsData" :ref="'stepContent' + idx" @submit="(content) => handleStepContentSubmit(idx, content)"
            :dataSource="item.content" :editable="!isEdit" />
          <DynamicComponent
            :participants="participantsData"
            :ref="'stepContent' + idx"
            @submit="(content) => handleStepContentSubmit(idx, content)"
            :dataSource="item.content"
            :editable="!isEdit"
          />
        </div>
        <div class="add-project-footer">
          <el-button type="primary" class="save-btn" @click="handleSave">{{userRole == 3 ? '发送' : '提交'}}</el-button>
          <el-button @click="handleSaveDraft" v-if="userRole == 3">存草稿</el-button>
          <el-button type="primary" class="save-btn" @click="handleSave">{{
            userRole == 3 ? "发送" : "提交"
          }}</el-button>
          <el-button @click="handleSaveDraft" v-if="userRole == 3"
            >存草稿</el-button
          >
        </div>
      </el-form>
    </template>
    <SelectMemberSimple ref="selectMember" @submit="handleMemberSubmit" />
    <experimentalScheduling :show="showScheduling" @submit="handleSchedulingSubmit" @close="handleSchedulingClose" />
    <experimentalScheduling
      :show="showScheduling"
      @submit="handleSchedulingSubmit"
      @close="handleSchedulingClose"
    />
    <AddStep ref="addStepDialog" @submit="handleStepSubmit" />
  </Card>
</template>
@@ -196,8 +349,12 @@
import DynamicComponent from "@/components/DynamicComponent";
import AddStep from "./components/add-step.vue";
import AiEditor from "@/components/AiEditor";
import { getGroupByDispatchId, getParticipantsByDispatchId, getDetail } from "./service";
import moment from 'moment';
import {
  getGroupByDispatchId,
  getParticipantsByDispatchId,
  getDetail,
} from "./service";
import moment from "moment";
import { add,update,updateTester } from "./service";
export default {
@@ -213,16 +370,16 @@
    return {
      showScheduling: false,
      form: {
        experimentDate: '', // 实验日期
        experimentDate: "", // 实验日期
        experimentMaterial: null,
        experimentDevice: null,
        experimentObjective: '', // 实验目的
        experimentParamRoute: '', // 工艺参数及路线
        experimentObjective: "", // 实验目的
        experimentParamRoute: "", // 工艺参数及路线
        experimentStepRecord: [], // 实验步骤记录
        experimentSchemePersons: [], // 实验方案人员
        dispatchId: '', // 实验调度id
        dispatchId: "", // 实验调度id
        status: -1, // 状态:-1=草稿箱 1=已发送
        commitTime: '', // 提交时间
        commitTime: "", // 提交时间
      },
      editorContents: {
        purpose: "",
@@ -241,7 +398,7 @@
          { required: true, message: "请添加实验设备", trigger: "change" },
        ],
      },
      userRole:'',
      userRole: "",
      groupTableData: [],
      groupData: [],
      taskTableData: [],
@@ -254,23 +411,23 @@
      // 状态映射表
      statusTypeMap: {
        "-1": "info",
        "1": "warning",
        "2": "success",
        "3": "info"
        1: "warning",
        2: "success",
        3: "info",
      },
      statusTextMap: {
        "-1": "草稿箱",
        "1": "待确认",
        "2": "已确认",
        "3": "已封存"
      }
        1: "待确认",
        2: "已确认",
        3: "已封存",
      },
    };
  },
  async created() {
    const userInfo=JSON.parse(sessionStorage.getItem('userInfo') || '{}');
    this.userRole=userInfo.roleType || '';
    const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
    this.userRole = userInfo.roleType || "";
    // 检查是否为编辑模式
    if (this.$route.query.type === 'edit' && this.$route.query.id) {
    if (this.$route.query.type === "edit" && this.$route.query.id) {
      this.isEdit = this.userRole==3?false:true;
      this.editId = this.$route.query.id;
      await this.loadEditData();
@@ -286,7 +443,10 @@
      this.$refs.selectMember.close();
    },
    handleEditMember() {
      this.$refs.selectMember.open(this.participantsData, this.selectedParticipants);
      this.$refs.selectMember.open(
        this.participantsData,
        this.selectedParticipants
      );
    },
    
    // ===== 步骤相关方法 =====
@@ -350,12 +510,12 @@
      // 获取所有步骤内容
      const stepContentRefs = Object.keys(this.$refs)
        .filter(key => key.startsWith('stepContent'))
        .map(key => this.$refs[key]);
        .filter((key) => key.startsWith("stepContent"))
        .map((key) => this.$refs[key]);
      
      stepContentRefs.forEach((ref) => {
        const editor = Array.isArray(ref) ? ref[0] : ref;
        if (editor && typeof editor.submit === 'function') {
        if (editor && typeof editor.submit === "function") {
          editor.submit();
        }
      });
@@ -368,32 +528,43 @@
          const experimentParamRoute = this.$refs.processEditor.getContent();
          
          // 构建实验步骤记录数据
          const experimentStepRecord = this.stepList.map(step => ({
          const experimentStepRecord = this.stepList.map((step) => ({
            stepName: step.stepName,
            content: step.content
            content: step.content,
          }));
          
          // 构建提交数据
          const formData = {
            ...this.form,
            experimentDate: moment(this.form.experimentDate).format('YYYY-MM-DD HH:mm:ss'),
            dispatchId: this.groupTableData && this.groupTableData.length > 0 ? this.groupTableData[0]?.id : '',
            experimentDate: moment(this.form.experimentDate).format(
              "YYYY-MM-DD HH:mm:ss"
            ),
            dispatchId:
              this.groupTableData && this.groupTableData.length > 0
                ? this.groupTableData[0]?.id
                : "",
            experimentObjective,
            experimentParamRoute,
            experimentSchemePersons: this.selectedParticipants.map(person => ({
            experimentSchemePersons: this.selectedParticipants.map(
              (person) => ({
              userId: person.userId,
              nickName: person.nickName,
              roleType: person.roleType,
              commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
            })),
                commitTime: moment().format("YYYY-MM-DD HH:mm:ss"),
              })
            ),
            status,
            commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
            commitTime: moment().format("YYYY-MM-DD HH:mm:ss"),
          };
          
          // 统一转换JSON字符串
          formData.experimentStepRecord = JSON.stringify(experimentStepRecord);
          formData.experimentDevice = JSON.stringify(this.form.experimentDevice);
          formData.experimentMaterial = JSON.stringify(this.form.experimentMaterial);
          formData.experimentDevice = JSON.stringify(
            this.form.experimentDevice
          );
          formData.experimentMaterial = JSON.stringify(
            this.form.experimentMaterial
          );
          
          // 编辑模式下添加id参数
          if (this.editId) {
@@ -401,25 +572,40 @@
          }
          
          // 根据是否为编辑模式调用不同接口
          const apiCall = this.editId ? update(formData) : this.isEdit? updateTester(formData): add(formData);
          const apiCall = this.editId
            ? update(formData)
            : this.isEdit
            ? updateTester(formData)
            : add(formData);
          
          apiCall.then(res => {
          apiCall
            .then((res) => {
            if (res.code === 200) {
              this.$message.success(status === 1 ? '保存成功' : '草稿保存成功');
                this.$message.success(
                  status === 1 ? "保存成功" : "草稿保存成功"
                );
              this.$router.go(-1);
            } else {
              this.$message.error(res.msg || (status === 1 ? '保存失败' : '草稿保存失败'));
                this.$message.error(
                  res.msg || (status === 1 ? "保存失败" : "草稿保存失败")
                );
            }
          }).catch(err => {
            this.$message.error(status === 1 ? '保存失败' : '草稿保存失败');
            console.error(status === 1 ? '保存失败:' : '草稿保存失败:', err);
            })
            .catch((err) => {
              this.$message.error(status === 1 ? "保存失败" : "草稿保存失败");
              console.error(status === 1 ? "保存失败:" : "草稿保存失败:", err);
          });
        } else {
          // 获取第一个错误字段并滚动到该位置
          const firstError = this.$refs.form.fields.find(field => field.validateState === 'error');
          const firstError = this.$refs.form.fields.find(
            (field) => field.validateState === "error"
          );
          if (firstError) {
            this.$nextTick(() => {
              firstError.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
              firstError.$el.scrollIntoView({
                behavior: "smooth",
                block: "center",
              });
            });
          }
        }
@@ -445,21 +631,24 @@
      }
      // 校验参与人员
      if (!this.selectedParticipants || this.selectedParticipants.length === 0) {
      if (
        !this.selectedParticipants ||
        this.selectedParticipants.length === 0
      ) {
        this.$message.error("请选择参与人员");
        return false;
      }
      // 校验实验目的
      const purpose = this.$refs.purposeEditor.getContent();
      if (!purpose || purpose === '<p></p>' || purpose.trim() === '<p></p>') {
      if (!purpose || purpose === "<p></p>" || purpose.trim() === "<p></p>") {
        this.$message.error("请填写实验目的");
        return false;
      }
      // 校验工艺参数及路线
      const process = this.$refs.processEditor.getContent();
      if (!process || process === '<p></p>' || process.trim() === '<p></p>') {
      if (!process || process === "<p></p>" || process.trim() === "<p></p>") {
        this.$message.error("请填写工艺参数及路线");
        return false;
      }
@@ -483,7 +672,7 @@
      }
      // 校验每个步骤是否都有内容
      const invalidStep = this.stepList.findIndex(step => !step.content);
      const invalidStep = this.stepList.findIndex((step) => !step.content);
      if (invalidStep !== -1) {
        this.$message.error(`请完善第${invalidStep + 1}个步骤的内容`);
        return false;
@@ -503,26 +692,30 @@
    handleSchedulingSubmit(data) {
      this.groupTableData = data || [];
      if (data && data.length > 0 && data[0].id) {
        getGroupByDispatchId({ dispatchId: data[0].id }).then(res => {
        getGroupByDispatchId({ dispatchId: data[0].id })
          .then((res) => {
          if (res) {
            this.groupData = res || [];
          } else {
            this.$message.error(res.msg || '获取组别列表失败');
              this.$message.error(res.msg || "获取组别列表失败");
          }
        }).catch(err => {
          this.$message.error('获取组别列表失败');
          console.error('获取组别列表失败:', err);
          })
          .catch((err) => {
            this.$message.error("获取组别列表失败");
            console.error("获取组别列表失败:", err);
        });
        getParticipantsByDispatchId({ dispatchId: data[0].id }).then(res => {
        getParticipantsByDispatchId({ dispatchId: data[0].id })
          .then((res) => {
          console.log("获取参加人员列表:", res);
          if (res) {
            this.participantsData = res || [];
          } else {
            this.$message.error(res.msg || '获取参加人员列表失败');
              this.$message.error(res.msg || "获取参加人员列表失败");
          }
        }).catch(err => {
          this.$message.error('获取参加人员列表失败');
          console.error('获取参加人员列表失败:', err);
          })
          .catch((err) => {
            this.$message.error("获取参加人员列表失败");
            console.error("获取参加人员列表失败:", err);
        });
      }
    },
@@ -534,11 +727,11 @@
      try {
        const res = await getDetail({ id: this.editId });
        if (!res) {
          this.$message.error('获取详情失败');
          this.$message.error("获取详情失败");
          return;
        }
        
        console.log('编辑数据', res);
        console.log("编辑数据", res);
        const data = res;
        // 填充基本表单数据
@@ -547,58 +740,66 @@
        // 填充实验调度信息
        if (data.experimentDispatch?.id) {
          this.form.dispatchId = data.experimentDispatch.id;
          console.log('experimentStepRecord experimentStepRecord',JSON.parse(data.experimentStepRecord))
          console.log(
            "experimentStepRecord experimentStepRecord",
            JSON.parse(data.experimentStepRecord)
          );
          this.groupTableData = [{ ...data.experimentDispatch }];
          
          // 获取组别信息
          try {
            const groupRes = await getGroupByDispatchId({ dispatchId: data.experimentDispatch.id });
            const groupRes = await getGroupByDispatchId({
              dispatchId: data.experimentDispatch.id,
            });
            this.groupData = groupRes || [];
          } catch (err) {
            console.error('获取组别列表失败:', err);
            console.error("获取组别列表失败:", err);
          }
        }
        // 填充参与人员
        this.selectedParticipants = Array.isArray(data.experimentSchemePersons)
          ? data.experimentSchemePersons
          : JSON.parse(data.experimentSchemePersons || '[]');
          : JSON.parse(data.experimentSchemePersons || "[]");
        // 填充富文本编辑器内容
        this.editorContents.purpose = data.experimentObjective || '';
        this.editorContents.process = data.experimentParamRoute || '';
        this.editorContents.purpose = data.experimentObjective || "";
        this.editorContents.process = data.experimentParamRoute || "";
        // 填充实验材料和设备
        try {
          this.form.experimentMaterial = typeof data.experimentMaterial === 'string'
          this.form.experimentMaterial =
            typeof data.experimentMaterial === "string"
            ? JSON.parse(data.experimentMaterial)
            : data.experimentMaterial;
        } catch (err) {
          console.error('解析实验材料数据失败:', err);
          console.error("解析实验材料数据失败:", err);
          this.form.experimentMaterial = [];
        }
        try {
          this.form.experimentDevice = typeof data.experimentDevice === 'string'
          this.form.experimentDevice =
            typeof data.experimentDevice === "string"
            ? JSON.parse(data.experimentDevice)
            : data.experimentDevice;
        } catch (err) {
          console.error('解析实验设备数据失败:', err);
          console.error("解析实验设备数据失败:", err);
          this.form.experimentDevice = [];
        }
        // 填充实验步骤
        try {
          const stepsData = typeof data.experimentStepRecord === 'string'
          const stepsData =
            typeof data.experimentStepRecord === "string"
            ? JSON.parse(data.experimentStepRecord)
            : data.experimentStepRecord;
          this.stepList = (stepsData || []).map(step => ({
          this.stepList = (stepsData || []).map((step) => ({
            stepName: step.stepName,
            content: step.content
            content: step.content,
          }));
        } catch (err) {
          console.error('解析实验步骤数据失败:', err);
          console.error("解析实验步骤数据失败:", err);
          this.stepList = [];
        }
@@ -633,20 +834,19 @@
          //   });
          // }
        });
      } catch (error) {
        this.$message.error('获取详情失败');
        console.error('获取详情失败:', error);
        this.$message.error("获取详情失败");
        console.error("获取详情失败:", error);
      }
    },
    // 转换数据格式为ViewDynamicComponent需要的格式
    convertToViewFormat(data) {
      if (!data || !Array.isArray(data)) return [];
      return data.map(item => ({
      return data.map((item) => ({
        id: item.id || Math.random().toString(36).substr(2, 9),
        type: item.type,
        data: item.data
        data: item.data,
      }));
    },
  },
@@ -777,27 +977,35 @@
    border: 1px solid #dcdfe6;
    &:nth-child(1) {
      background: linear-gradient(to bottom,
      background: linear-gradient(
        to bottom,
          rgba(4, 156, 154, 0.2) 0%,
          rgba(5, 242, 194, 0) 70%);
        rgba(5, 242, 194, 0) 70%
      );
    }
    &:nth-child(2) {
      background: linear-gradient(to bottom,
      background: linear-gradient(
        to bottom,
          rgba(5, 160, 193, 0.2) 0%,
          rgba(5, 242, 194, 0) 70%);
        rgba(5, 242, 194, 0) 70%
      );
    }
    &:nth-child(3) {
      background: linear-gradient(to bottom,
      background: linear-gradient(
        to bottom,
          rgba(255, 77, 79, 0.2) 0%,
          rgba(255, 242, 194, 0) 70%);
        rgba(255, 242, 194, 0) 70%
      );
    }
    &:nth-child(4) {
      background: linear-gradient(to bottom,
      background: linear-gradient(
        to bottom,
          rgba(250, 199, 20, 0.21) 0%,
          rgba(255, 242, 194, 0) 70%);
        rgba(255, 242, 194, 0) 70%
      );
    }
    .member-item {
laboratory/src/views/dataManagement/testResultReport/detail.vue
@@ -178,7 +178,7 @@
            </template>
            <template v-else>
              <div class="no-data">暂未评定</div>
              <!-- <div v-if="canEvaluate" class="to-evaluate" >去评价</div> -->
              <div v-if="canEvaluate" class="to-evaluate" @click="handleEvaluate('processEngineer')">去评价</div>
            </template>
          </template>
        </div>
@@ -187,7 +187,7 @@
        <el-button type="primary" class="save-btn" @click="handleSubmit(1)">提交</el-button>
        <el-button @click="handleSubmit(-1)">存草稿</el-button>
      </div>
      <div class="add-project-footer" v-if="isView && form.status == 2">
      <div class="add-project-footer" v-if="isView && form.status == 2 &&(userRole==1 || userRole==2)">
        <el-button type="primary" class="save-btn" @click="handleEvaluate('processEngineer')">工艺工程师评定</el-button>
        <!-- <el-button @click="handleSubmit(-1)">存草稿</el-button> -->
      </div>
@@ -289,6 +289,7 @@
        "3": "已封存"
      },
      currentEvaluationData: null, // 添加当前评价数据
      userRole:'',
    };
  },
  watch: {
@@ -308,6 +309,9 @@
    if (id) {
      this.getDetailData(id);
    }
    const userInfo = JSON.parse(sessionStorage.getItem("userInfo"));
    console.log('userInfo',userInfo)
    this.userRole = userInfo.roleType || '';
  },
  methods: {
    handleAddTask() {
@@ -469,7 +473,7 @@
    },
    // 去评价
    handleEvaluate(type) {
      if(this.$route.query.type == 'view' || type !='processEngineer'){
      if(this.$route.query.type == 'view' && type !='processEngineer'){
        this.$message.warning('当前为查看模式,无法进行评价');
        return;
      }
laboratory/src/views/dataManagement/testResultReport/list.vue
@@ -353,7 +353,6 @@
    // 处理评价提交
    handleEvaluationSubmit(evaluationData) {
      const { activeIndex } = evaluationData;
      // 将评分数据转换为后端需要的格式
      const evaluateData = {
        evaluateType: 1, // 1=工艺工程师
laboratory/src/views/deliveryAssessment/QA/components/AssessmentDialog.vue
@@ -1,6 +1,17 @@
<template>
    <el-dialog :visible.sync="dialogVisible" title="课题评定详情" width="70%" @close="handleClose">
        <el-form :model="form" inline label-position="top" :rules="rules" ref="formRef">
  <el-dialog
    :visible.sync="dialogVisible"
    :title="type === 'detail' ? '课题评定详情' : '课题评定'"
    width="70%"
    @close="handleClose"
  >
    <el-form
      :model="form"
      inline
      label-position="top"
      :rules="rules"
      ref="formRef"
    >
            <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告编号" prop="reportNo" required>
@@ -9,33 +20,55 @@
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告名称" prop="reportName">
                        <el-input v-model="form.reportName" placeholder="请输入" />
            <el-input v-model="form.reportName" disabled placeholder="请输入" />
                    </el-form-item>
                </el-col>
            </el-row>
        </el-form>
        <div class="content-box">
            <el-row :gutter="16">
                <el-col style="margin-top: 5px;" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
                    <Table :total="0" :height="null" :data="criteriaList" show-summary :summary-method="getSummaries"
                        :span-method="arraySpanMethod">
        <el-col
          style="margin-top: 5px"
          :xs="24"
          :sm="24"
          :md="24"
          :lg="24"
          :xl="24"
        >
          <Table
            :total="0"
            :height="null"
            :data="criteriaList"
            show-summary
            :summary-method="getSummaries"
            :span-method="arraySpanMethod"
          >
                        <el-table-column type="index" label="序号" width="80" />
                        <el-table-column prop="criteria" label="规程型课题评定标准" />
                        <el-table-column prop="fullScore" label="满分值" width="100" />
                        <el-table-column label="评定分值" prop="score" width="200">
                            <template #default="{ row }">
                                <el-input-number v-model="row.score" :min="0" :max="row.fullScore" :step="1" />
                <el-input-number
                  v-model="row.score"
                  :min="0"
                  :max="row.fullScore"
                  :step="1"
                />
                            </template>
                        </el-table-column>
                        <el-table-column label="创新型课题报告评分规则">
                            <template>
                                <div>
                                    <div>1、规程型课题评定总分的满分为5分。</div>
                                    <div>2、某分项工作完成,但出现以下三种错误中的1种,则减1分:</div>
                  <div>
                    2、某分项工作完成,但出现以下三种错误中的1种,则减1分:
                  </div>
                                    <div>①有缺项、漏项;</div>
                                    <div>②或不完整清晰;</div>
                                    <div>③或工作效率人为拖延。</div>
                                    <div>3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。</div>
                  <div>
                    3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。
                  </div>
                                </div>
                            </template>
                        </el-table-column>
@@ -43,93 +76,142 @@
                </el-col>
            </el-row>
        </div>
        <template #footer>
    <div class="assessed" style="display:flex" v-if="evaluateInfo.status == 3">
      <div style="margin-right: 20px">评定时间:{{ evaluateInfo.evaluateTime }}</div>
      <div>评定人:{{ evaluateInfo.evaluatePersonName }}</div>
    </div>
    <template #footer v-if="evaluateInfo.status === 2 && type=='approve'">
            <span class="select-member-footer">
                <el-button type="primary">提交评定结果</el-button>
        <el-button type="primary" @click="handleSubmit">提交评定结果</el-button>
            </span>
        </template>
    </el-dialog>
</template>
<script>
import { getDetailById, evaluate } from "../service.js";
export default {
    name: 'AssessmentDialog',
  name: "AssessmentDialog",
    props: {
        modelValue: {
            type: Boolean,
            default: false
      default: false,
        },
        reportData: {
            type: Object,
            default: () => { }
        }
    id: {
      type: String,
    //   required: true,
    default: () => "",
    },
    type: {
      type: String,
      default: "detail", // 'detail' 或 'evaluate'
    },
    },
    data() {
        return {
            dialogVisible: false,
            form: {
                reportNo: '',
                reportName: '',
        reportNo: "",
        reportName: "",
            },
            rules: {
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
          { required: true, message: "请输入报告名称", trigger: "blur" },
                ],
            },
            criteriaList: [
                {
                    criteria: '文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范',
          criteria: "文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范",
                    fullScore: 1,
                    score: 0,
                },
                {
                    criteria: '专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;',
          criteria:
            "专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;",
                    fullScore: 2,
                    score: 0,
                },
                {
                    criteria: '课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。',
          criteria:
            "课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。",
                    fullScore: 3,
                    score: 0,
                },
            ]
        }
      ],
      evaluateInfo: {},
    };
    },
    watch: {
        modelValue: {
            handler(val) {
                this.dialogVisible = val;
            },
            immediate: true
        },
        reportData: {
            handler(val) {
                if (val) {
                    this.form.reportNo = val.reportNo || '';
                    this.form.reportName = val.reportName || '';
          this.fetchDataById();
                }
            },
            immediate: true
      immediate: true,
    },
    id: {
      handler(val) {
        if (this.dialogVisible && val) {
          this.fetchDataById();
        }
      },
      immediate: true,
    },
    type: {
      handler(val) {
        // 可根据type切换详情/评定模式
      },
      immediate: true,
    },
    },
    methods: {
    async fetchDataById() {
      try {
        const res = await getDetailById({id:this.id});
        const data = res || {};
        this.form.reportNo = data.reportCode || "";
        this.form.reportName = data.reportTitle || "";
        this.evaluateInfo = { ...data };
        // 评定分数
        if (data.evaluateScore) {
          const scores = data.evaluateScore.split(",").map(Number);
          this.criteriaList.forEach((item, idx) => {
            item.score = scores[idx] || 0;
          });
        } else {
          this.criteriaList.forEach((item) => (item.score = 0));
        }
      } catch (e) {
        // 错误处理
      }
    },
        handleClose() {
            this.$emit('update:modelValue', false);
        this.$emit("close", false);
        },
        async handleSubmit() {
            try {
                await this.$refs.formRef.validate();
                const totalScore = this.criteriaList.reduce((sum, item) => sum + (item.score || 0), 0);
        const totalScore = this.criteriaList.reduce(
          (sum, item) => sum + (item.score || 0),
          0
        );
                const assessmentData = {
                    ...this.form,
                    totalScore,
                    criteriaScores: this.criteriaList.map(item => ({
                        criteria: item.criteria,
                        score: item.score || 0
                    }))
          id: this.evaluateInfo.id,
          evaluateScore: this.criteriaList
            .map((item) => item.score || 0)
            .join(","),
                };
                this.$emit('submit', assessmentData);
        // 这里可以调用evaluate接口
        evaluate(assessmentData).then((res) => {
          if (res.code == 200) {
            this.$message.success("提交成功");
                this.handleClose();
          }else{
            this.$message.error(res.message)
          }
        });
            } catch (error) {
                // 表单验证失败
            }
@@ -139,11 +221,11 @@
            const sums = [];
            columns.forEach((column, index) => {
                if (index === 0) {
                    sums[index] = '合计';
          sums[index] = "合计";
                    return;
                }
                const values = data.map(item => Number(item[column.property]));
                if (!values.every(value => isNaN(value))) {
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
                    sums[index] = values.reduce((prev, curr) => {
                        const value = Number(curr);
                        if (!isNaN(value)) {
@@ -152,9 +234,9 @@
                            return prev;
                        }
                    }, 0);
                    sums[index] += ' 分';
          sums[index] += " 分";
                } else {
                    sums[index] = '';
          sums[index] = "";
                }
            });
            return sums;
@@ -163,30 +245,29 @@
            if (columnIndex === 4 && rowIndex == 0) {
                return {
                    rowspan: 6,
                    colspan: 1
                }
          colspan: 1,
        };
            } else if (rowIndex !== 0 && columnIndex === 4) {
                return [0, 0]
        return [0, 0];
            }
        }
    }
}
    },
  },
};
</script>
<style lang="less" scoped>
.content-box {
    &-left {
        margin-top: 5px;
        display: flex;
        flex-direction: column;
        border: 1px solid #EBEEF5;
    border: 1px solid #ebeef5;
        border-radius: 8px 8px 0px 0px;
        font-size: 12px;
        &-th {
            line-height: 40px;
            background: #FAFAFA !important;
      background: #fafafa !important;
            color: #909399;
            padding: 0 10px;
            font-weight: bold;
laboratory/src/views/deliveryAssessment/QA/index.vue
@@ -1,111 +1,170 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="所属项目组:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="项目组名称:">
            <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="检测项名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="报告名称:">
            <el-input v-model="form.reportTitle" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="检测项编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="报告编号:">
            <el-input v-model="form.reportCode" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="报告内容:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="课题类型:">
            <el-select v-model="form.reportType" placeholder="请选择">
              <el-option label="中试" :value="1" />
              <el-option label="辅料" :value="2" />
              <el-option label="产品报告" :value="3" />
              <!-- <el-option label="验证与发布" :value="4" /> reportType    integer    报告类型 1=中试 2=辅料 3=产品报告-->
            </el-select>
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="草稿箱" :value="-1" />
              <el-option label="待审核" :value="1" />
              <el-option label="待评定" :value="2" />
              <el-option label="已评定" :value="3" />
              <el-option label="已驳回" :value="4" />
              <el-option label="已撤回" :value="5" />
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-button @click="handleReset">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="tableTitle">
                    <div class="title active">
                        化验师QA专题报告列表</div>
          <div class="title active">化验师QA专题报告列表</div>
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="报告类型" />
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="报告名称" />
                <el-table-column prop="age" label="报告编号" />
                <el-table-column prop="age" label="制定人" />
                <el-table-column prop="age" label="制定日期" />
                <el-table-column prop="age" label="评定人" />
                <el-table-column prop="age" label="评定时间" />
                <el-table-column prop="age" label="状态">
        <el-table-column prop="reportType" label="报告类型">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
            <span v-if="row.reportType == 1">中试</span>
            <span v-else-if="row.reportType == 2">辅料</span>
            <span v-else-if="row.reportType == 3">产品报告</span>
            <span v-else>--</span>
          </template>
        </el-table-column>
        <el-table-column prop="teamName" label="所属项目组" />
        <el-table-column prop="reportTitle" label="报告名称" />
        <el-table-column prop="reportCode" label="报告编号" />
        <el-table-column prop="developPerson" label="制定人" />
        <el-table-column prop="developDate" label="制定日期" />
        <el-table-column prop="evaluatePersonName" label="评定人" />
        <el-table-column prop="evaluateTime" label="评定时间" />
        <el-table-column prop="status" label="状态">
          <template #default="{ row }">
            <el-tag v-if="row.status == 3" type="info" color="#fff"
              >已评定</el-tag
            >
            <el-tag v-else-if="row.status == 2" type="success">待评定</el-tag>
            <el-tag v-else-if="row.status == 1" type="warning">待审核</el-tag>
            <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag>
            <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag>
            <el-tag v-else type="default">草稿箱</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
            <el-button type="text" v-if="row.status == 3" @click="handleDetail(row)">详情</el-button>
            <el-button v-if="row.status == 2" type="text" @click="handleAssessment(row)">评定</el-button>
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <!-- 工艺工程师 -->
        <AssessmentDialog :modelValue="assessmentVisible" :reportData="currentReport" />
    <AssessmentDialog
      :modelValue="assessmentVisible"
      :id="currentReport.id"
      :type="currentType"
      @close="closeAssessmentDialog"
    />
    </div>
</template>
<script>
import AssessmentDialog from './components/AssessmentDialog.vue'
import AssessmentDialog from "./components/AssessmentDialog.vue";
import { evaluateList } from "./service.js";
export default {
    name: 'QAList',
  name: "QAList",
    components: {
        AssessmentDialog,
    },
    data() {
        return {
            form: {
            },
      form: {},
            tableData: [],
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
            total: 0,
            assessmentVisible: true,
      assessmentVisible: false,
      currentType: "",
            currentReport: {},
        }
    };
    },
    methods: {
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
    async getList() {
      const params = { ...this.queryForm, ...this.form };
      const res = await evaluateList(params);
      if (res && res.data) {
        this.tableData = res.data.records || [];
        this.total = res.data.total || 0;
      }
    },
    handleSearch() {
      this.queryForm.pageNum = 1;
      this.getList();
    },
    handleReset() {
      this.form = {};
      this.queryForm = { pageSize: 10, pageNum: 1 };
      this.getList();
        },
        handleDetail(row) {
            // 处理详情
      this.currentReport = row;
      this.currentType = "detail";
      this.assessmentVisible = true;
        },
        handleAssessment(row) {
            this.currentReport = row;
      this.currentType = "approve";
            this.assessmentVisible = true;
        },
        handleAssessmentSubmit(data) {
            console.log('评定提交数据:', data);
            // 处理评定提交
        }
    }
}
    closeAssessmentDialog() {
      this.assessmentVisible = false;
      this.currentReport = {};
      this.currentType = "";
      this.getList();
    },
  },
  mounted() {
    this.getList();
  },
};
</script>
<style scoped lang="less">
@@ -121,23 +180,23 @@
    &-card {
        flex: 1;
        background: #E8FAF6;
    background: #e8faf6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
      font-family: "SourceHanSansCN-Medium";
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
        }
        &-num {
            font-family: 'SF Compact Display Black';
      font-family: "SF Compact Display Black";
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
      color: #049c9a;
            line-height: 60px;
        }
    }
laboratory/src/views/deliveryAssessment/QA/service.js
New file
@@ -0,0 +1,19 @@
import axios from '@/utils/request';
// 获取中试、生产验证分析报告;辅料;产品报告管理评定列表
export function evaluateList(data) {
  return axios.post('/api/t-qa-produce-report/evaluateList', { ...data })
}
// 获取中试、生产验证分析报告;辅料;产品报告管理评定列表
export function evaluateCount(data) {
  return axios.post('/api/t-qa-produce-report/evaluateCount', { ...data })
}
// 查看中试、生产验证分析报告;辅料;产品报告管理详情
export function getDetailById(data) {
  return axios.get('/open/t-qa-produce-report/getDetailById', { params:data })
}
export function evaluate(data) {
  return axios.post(`/api/t-qa-produce-report/evaluate`, { ...data })
}
laboratory/src/views/deliveryAssessment/assayTaskList/components/AssessmentDialog.vue
@@ -1,6 +1,17 @@
<template>
    <el-dialog :visible.sync="dialogVisible" title="课题评定详情" width="70%" @close="handleClose">
        <el-form :model="form" inline label-position="top" :rules="rules" ref="formRef">
  <el-dialog
    :visible.sync="dialogVisible"
    title="课题评定详情"
    width="70%"
    @close="handleClose"
  >
    <el-form
      :model="form"
      inline
      label-position="top"
      :rules="rules"
      ref="formRef"
    >
            <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告编号" prop="reportNo" required>
@@ -9,33 +20,56 @@
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告名称" prop="reportName">
                        <el-input v-model="form.reportName" placeholder="请输入" />
            <el-input v-model="form.reportName" disabled placeholder="请输入" />
                    </el-form-item>
                </el-col>
            </el-row>
        </el-form>
        <div class="content-box">
            <el-row :gutter="16">
                <el-col style="margin-top: 5px;" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
                    <Table :total="0" :height="null" :data="criteriaList" show-summary :summary-method="getSummaries"
                        :span-method="arraySpanMethod">
        <el-col
          style="margin-top: 5px"
          :xs="24"
          :sm="24"
          :md="24"
          :lg="24"
          :xl="24"
        >
          <Table
            :total="0"
            :height="null"
            :data="criteriaList"
            show-summary
            :summary-method="getSummaries"
            :span-method="arraySpanMethod"
          >
                        <el-table-column type="index" label="序号" width="80" />
                        <el-table-column prop="criteria" label="规程型课题评定标准" />
                        <el-table-column prop="fullScore" label="满分值" width="100" />
                        <el-table-column label="评定分值" prop="score" width="200">
                            <template #default="{ row }">
                                <el-input-number v-model="row.score" :min="0" :max="row.fullScore" :step="1" />
                <el-input-number
                  v-model="row.score"
                  :min="0"
                  :max="row.fullScore"
                  :step="1"
                  disabled
                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="rule" label="创新型课题报告评分规则">
                            <template>
                                <div>
                                    <div>1、规程型课题评定总分的满分为5分。</div>
                                    <div>2、某分项工作完成,但出现以下三种错误中的1种,则减1分:</div>
                  <div>
                    2、某分项工作完成,但出现以下三种错误中的1种,则减1分:
                  </div>
                                    <div>①有缺项、漏项;</div>
                                    <div>②或不完整清晰;</div>
                                    <div>③或工作效率人为拖延。</div>
                                    <div>3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。</div>
                  <div>
                    3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。
                  </div>
                                </div>
                            </template>
                        </el-table-column>
@@ -43,106 +77,120 @@
                </el-col>
            </el-row>
        </div>
        <div class="assessed">
            <div>评定时间:2025-2-20 11:08:00</div>
            <div>评定人:张三</div>
    <div class="assessed" v-if="evaluateInfo.status == 3">
      <div>评定时间:{{ evaluateInfo.evaluateTime || "" }}</div>
      <div>评定人:{{ evaluateInfo.evaluatePersonName || "" }}</div>
        </div>
    </el-dialog>
</template>
<script>
import { getDetailById, evaluate } from "../service.js";
export default {
    name: 'AssessmentDialog',
  name: "AssessmentDialog",
    props: {
        modelValue: {
            type: Boolean,
            default: false
      default: false,
        },
        reportData: {
            type: Object,
            default: () => { }
        }
    id: {
      type: [String, Number],
      default: "",
    //   required: true,
    },
    },
    data() {
        return {
            dialogVisible: false,
            form: {
                reportNo: '',
                reportName: '',
        reportNo: "",
        reportName: "",
            },
      evaluateInfo: {},
            rules: {
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
          { required: true, message: "请输入报告名称", trigger: "blur" },
                ],
            },
            criteriaList: [
                {
                    criteria: '文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范',
          criteria: "文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范",
                    fullScore: 1,
                    score: 0,
                },
                {
                    criteria: '专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;',
          criteria:
            "专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;",
                    fullScore: 2,
                    score: 0,
                },
                {
                    criteria: '课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。',
          criteria:
            "课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。",
                    fullScore: 3,
                    score: 0,
                },
            ]
        }
      ],
    };
    },
    watch: {
        modelValue: {
            handler(val) {
                this.dialogVisible = val;
            },
            immediate: true
        },
        reportData: {
            handler(val) {
                if (val) {
                    this.form.reportNo = val.reportNo || '';
                    this.form.reportName = val.reportName || '';
        if (val && this.id) {
          this.fetchDetail();
                }
            },
            immediate: true
      immediate: true,
    },
    id(val) {
      if (this.modelValue && val) {
        this.fetchDetail();
        }
    },
    },
    methods: {
        handleClose() {
            this.$emit('update:modelValue', false);
        },
        async handleSubmit() {
    async fetchDetail() {
            try {
                await this.$refs.formRef.validate();
                const totalScore = this.criteriaList.reduce((sum, item) => sum + (item.score || 0), 0);
                const assessmentData = {
                    ...this.form,
                    totalScore,
                    criteriaScores: this.criteriaList.map(item => ({
                        criteria: item.criteria,
                        score: item.score || 0
                    }))
                };
                this.$emit('submit', assessmentData);
                this.handleClose();
            } catch (error) {
                // 表单验证失败
        const res = await getDetailById({ id: this.id });
        if (res) {
          this.evaluateInfo = { ...res };
          this.form.reportNo = res.reportCode || "";
          this.form.reportName = res.reportName || "";
          // 详情回显分数
          if (res.evaluateScore) {
            if (
              this.type === "detail" &&
              typeof res.evaluateScore === "string"
            ) {
              const scoreArr = res.evaluateScore
                .split(",")
                .map((s) => Number(s));
              this.criteriaList.forEach((item, idx) => {
                item.score = scoreArr[idx] || 0;
              });
            }
          }
        }
      } catch (e) {
        this.$message && this.$message.error("获取详情失败");
            }
        },
    handleClose() {
      this.$emit("update:modelValue", false);
      this.$emit("close");
    },
        getSummaries(param) {
            const { columns, data } = param;
            const sums = [];
            columns.forEach((column, index) => {
                if (index === 0) {
                    sums[index] = '合计';
          sums[index] = "合计";
                    return;
                }
                const values = data.map(item => Number(item[column.property]));
                if (!values.every(value => isNaN(value))) {
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
                    sums[index] = values.reduce((prev, curr) => {
                        const value = Number(curr);
                        if (!isNaN(value)) {
@@ -151,9 +199,9 @@
                            return prev;
                        }
                    }, 0);
                    sums[index] += ' 分';
          sums[index] += " 分";
                } else {
                    sums[index] = '';
          sums[index] = "";
                }
            });
            return sums;
@@ -162,30 +210,29 @@
            if (columnIndex === 4 && rowIndex == 0) {
                return {
                    rowspan: 6,
                    colspan: 1
                }
          colspan: 1,
        };
            } else if (rowIndex !== 0 && columnIndex === 4) {
                return [0, 0]
        return [0, 0];
            }
        }
    }
}
    },
  },
};
</script>
<style lang="less" scoped>
.content-box {
    &-left {
        margin-top: 5px;
        display: flex;
        flex-direction: column;
        border: 1px solid #EBEEF5;
    border: 1px solid #ebeef5;
        border-radius: 8px 8px 0px 0px;
        font-size: 12px;
        &-th {
            line-height: 40px;
            background: #FAFAFA !important;
      background: #fafafa !important;
            color: #909399;
            padding: 0 10px;
            font-weight: bold;
laboratory/src/views/deliveryAssessment/assayTaskList/index.vue
@@ -1,120 +1,227 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="项目组名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="课题类型:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-select v-model="form.reportType" placeholder="请选择">
              <el-option label="中试" :value="1" />
              <el-option label="辅料" :value="2" />
              <el-option label="产品报告" :value="3" />
              <!-- <el-option label="验证与发布" :value="4" /> reportType    integer    报告类型 1=中试 2=辅料 3=产品报告-->
            </el-select>
                    </el-form-item>
                    <el-form-item label="课题名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="报告名称:">
            <el-input v-model="form.reportTitle" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="提交人:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.staffNames" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="草稿箱" :value="-1" />
              <el-option label="待审核" :value="1" />
              <el-option label="待评定" :value="2" />
              <el-option label="已评定" :value="3" />
              <el-option label="已驳回" :value="4" />
              <el-option label="已撤回" :value="5" />
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-button @click="handleReset">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="top-box-integral">
        <!-- <div class="top-box-integral">
                    <div style="background-color:rgba(232, 250, 246, 1)" v-for="item in 3" :key="item"
                        class="top-box-integral-card">
                        <div class="top-box-integral-card-title">{{ ['课题合计数量', '待评定', '已评定'][item - 1] }}</div>
                        <div style="color:rgba(4, 156, 154, 1)" class="top-box-integral-card-num">99.9</div>
                    </div>
                </div> -->
        <div class="top-box-integral">
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">课题合计数量</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.totalCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">待评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.toEvaluatedCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">已评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.evaluatedCount || 0 }}
            </div>
          </div>
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="课题类型" />
                <el-table-column prop="age" label="报告编号" />
                <el-table-column prop="age" label="报告名称" />
                <el-table-column prop="age" label="提交人" />
                <el-table-column prop="age" label="评定结果" />
                <el-table-column prop="age" label="累积分值" />
                <el-table-column prop="age" label="评定时间" />
                <el-table-column prop="age" label="状态">
        <el-table-column prop="teamName" label="所属项目组" />
        <el-table-column prop="reportType" label="课题类型">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
            <span v-if="row.reportType == 1">中试</span>
            <span v-else-if="row.reportType == 2">辅料</span>
            <span v-else-if="row.reportType == 3">产品报告</span>
            <span v-else>--</span>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
        <el-table-column prop="reportCode" label="报告编号" />
        <el-table-column prop="reportTitle" label="报告名称" />
        <el-table-column prop="createBy" label="提交人" />
        <!-- <el-table-column prop="evaluatePersonName" label="评定人员" /> -->
        <el-table-column prop="evaluateScore" label="评定结果" />
        <el-table-column prop="totalScore" label="累积分值" />
        <el-table-column prop="evaluateTime" label="评定时间" />
        <el-table-column prop="status" label="状态">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
            <el-tag v-if="row.status == 3" type="info" color="#fff"
              >已评定</el-tag
            >
            <el-tag v-else-if="row.status == 2" type="success">待评定</el-tag>
            <el-tag v-else-if="row.status == 1" type="warning">待审核</el-tag>
            <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag>
            <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag>
            <el-tag v-else type="default">草稿箱</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template #default="{ row }">
            <el-button type="text" @click="handleDetail(row)">详情</el-button>
            <!-- <el-button
              type="text"
              @click="handleAssessment(row)"
              v-if="row.status == 2"
              >评定</el-button
            > -->
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <!-- 化验师 审批人 -->
        <AssessmentDialog :modelValue="assessmentVisible" :reportData="currentReport" />
    <AssessmentDialog
      :modelValue="assessmentVisible"
      :id="currentReport.id"
      @close="closeAssessmentDialog"
    />
        <!-- 工艺工程师 -->
        <CraftDialog :modelValue="craftVisible" :reportData="currentReport" />
    <!-- <CraftDialog :modelValue="craftVisible" :reportData="currentReport" /> -->
    </div>
</template>
<script>
import AssessmentDialog from './components/AssessmentDialog.vue'
import CraftDialog from './components/CraftDialog.vue'
import AssessmentDialog from "./components/AssessmentDialog.vue";
// import CraftDialog from "./components/CraftDialog.vue";
import { evaluateList, evaluateCount } from "./service.js";
export default {
    name: 'AssayTaskList',
  name: "AssayTaskList",
    components: {
        AssessmentDialog,
        CraftDialog
    // CraftDialog,
    },
    data() {
        return {
            form: {
            },
      form: {},
            tableData: [],
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
            total: 0,
            assessmentVisible: false,
            currentReport: {},
            craftVisible: false,
        }
      statistics: {
        totalCount: 0,
        toEvaluatedCount: 0,
        evaluatedCount: 0,
      },
    };
    },
    methods: {
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
    async getList() {
      const params = { ...this.queryForm, ...this.form };
      const res = await evaluateList(params);
      if (res && res.data) {
        this.tableData = res.data.records || [];
        this.total = res.data.total || 0;
      }
    },
    async getStatistics() {
      const params = { ...this.queryForm, ...this.form };
      const res = await evaluateCount(params);
      if (res && res.data) {
        this.statistics = res.data;
      }
    },
    handleSearch() {
      this.queryForm.pageNum = 1;
      this.getList();
      this.getStatistics();
    },
    handleReset() {
      this.form = {};
      this.queryForm = { pageSize: 10, pageNum: 1 };
      this.getList();
      this.getStatistics();
        },
        handleDetail(row) {
            // 处理详情
        },
        handleAssessment(row) {
            this.currentReport = row;
            this.assessmentVisible = true;
        },
        handleAssessmentSubmit(data) {
            console.log('评定提交数据:', data);
            // 处理评定提交
    closeAssessmentDialog(){
      this.assessmentVisible = false;
        }
    }
}
  },
  mounted() {
    this.getList();
    this.getStatistics();
  },
};
</script>
<style scoped lang="less">
@@ -130,23 +237,23 @@
    &-card {
        flex: 1;
        background: #E8FAF6;
    background: #e8faf6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
      font-family: "SourceHanSansCN-Medium";
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
        }
        &-num {
            font-family: 'SF Compact Display Black';
      font-family: "SF Compact Display Black";
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
      color: #049c9a;
            line-height: 60px;
        }
    }
laboratory/src/views/deliveryAssessment/assayTaskList/service.js
@@ -6,8 +6,11 @@
export function evaluateList(data) {
  return axios.post('/api/t-qa-produce-report/evaluateList', { ...data })
}
// 获取中试、生产验证分析报告;辅料;产品报告管理评定列表
export function evaluateCount(data) {
  return axios.post('/api/t-qa-produce-report/evaluateCount', { ...data })
}
// 查看中试、生产验证分析报告;辅料;产品报告管理详情
export function getDetailById(data) {
  return axios.post('/open/t-qa-produce-report/getDetailById', { ...data })
  return axios.get('/open/t-qa-produce-report/getDetailById', { params:data })
}
laboratory/src/views/deliveryAssessment/chemistEvaluate/add.vue
@@ -1,80 +1,259 @@
<template>
    <Card>
        <template>
            <div class="header-title" style="margin-bottom: 18px;">
      <div class="header-title" style="margin-bottom: 18px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>所属实验调度</div>
                </div>
                <el-button class="el-icon-plus" type="primary" @click="showScheduling = true"> 选择实验调度</el-button>
        <el-button
          class="el-icon-plus"
          type="primary"
          v-if="isEdit"
          @click="showScheduling = true"
        >
          选择实验调度</el-button
        >
            </div>
            <Table :tableData="tableData" :total="total" :height="null">
      <Table :data="tableData" :total="0" :height="null">
                <template>
                    <el-table-column prop="planCode" label="所属项目课题方案"></el-table-column>
                    <el-table-column prop="planName" label="实验编号"></el-table-column>
                    <el-table-column prop="planName" label="实验名称"></el-table-column>
                    <el-table-column prop="stage" label="通知时间"></el-table-column>
                    <el-table-column prop="stage" label="实验开始时间"></el-table-column>
                    <el-table-column prop="stage" label="实验结束时间"></el-table-column>
                    <el-table-column prop="stage" label="参加人员"></el-table-column>
                    <el-table-column prop="creator" label="状态"></el-table-column>
          <el-table-column
            type="index"
            label="序号"
            width="80"
          ></el-table-column>
          <el-table-column
            prop="projectName"
            label="所属项目课题方案"
          ></el-table-column>
          <el-table-column
            prop="experimentCode"
            label="实验编号"
          ></el-table-column>
          <el-table-column
            prop="experimentName"
            label="实验名称"
          ></el-table-column>
          <el-table-column
            prop="experimentDate"
            label="通知时间"
          ></el-table-column>
          <el-table-column
            prop="experimentStartTime"
            label="实验开始时间"
          ></el-table-column>
          <el-table-column
            prop="experimentEndTime"
            label="实验结束时间"
          ></el-table-column>
          <el-table-column
            prop="participantsName"
            label="参加人员"
          ></el-table-column>
          <el-table-column prop="status" label="状态">
            <template slot-scope="scope">
              <el-tag :type="getStatusType(scope.row.status)">
                {{ getStatusText(scope.row.status) }}
              </el-tag>
            </template>
          </el-table-column>
                </template>
            </Table>
            <div class="header-title" style="margin-top: 60px;">
      <div class="header-title" style="margin-top: 60px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>被评定化验师</div>
                </div>
                <el-button class="el-icon-plus" type="primary" @click="addMember"> 选择化验师</el-button>
        <el-button class="el-icon-plus" v-if="isEdit" type="primary" @click="addMember">
          选择化验师</el-button
        >
            </div>
            <div class="member-list">
                <div class="member-list-card">
                    <div class="member-item">
                        <div class="member-title">化验师</div>
                        <div class="member-name-box-2">
                            <div v-for="i in [1, 2, 3, 4, 5, 6, 7, 8]" :key="i" class="member-name">张三</div>
              <div
                v-for="i in selectedParticipants"
                :key="i.id"
                class="member-name"
              >
                {{ i.nickName }}
                        </div>
                        <div class="member-edit" @click="addMember">修改</div>
            </div>
            <div class="member-edit" @click="handleEditMember" v-if="isEdit">
              修改
                    </div>
                </div>
            </div>
            <div class="header-title" style="margin-bottom: 18px;margin-top: 60px;">
      </div>
      <div class="header-title" style="margin-bottom: 18px; margin-top: 60px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>工作标准评定</div>
                </div>
            </div>
            <EvaluateTable :type="1" />
      <EvaluateTable :type="1" ref="evaluateTable" />
            <div class="add-project-footer">
                <el-button type="primary">保存</el-button>
                <el-button>存草稿</el-button>
        <el-button type="primary" @click="submitForm()">保存</el-button>
        <!-- <el-button>存草稿</el-button> -->
            </div>
        </template>
        <SelectMember ref="selectMember" />
        <ExperimentalScheduling :show="showScheduling" />
    <SelectMemberSimple ref="selectMember" @submit="handleMemberSubmit" roleType="4" />
    <ExperimentalScheduling
      :show="showScheduling"
      @submit="handleSchedulingSubmit"
      @close="handleSchedulingClose"
    />
    </Card>
</template>
<script>
import ExperimentalScheduling from "@/views/dataManagement/confirmation-sheet/components/experimental-scheduling";
import SelectMemberSimple from "@/components/SelectMemberSimple/index.vue";
import ExperimentalScheduling from "@/views/dataManagement/schemeManagement/components/experimental-scheduling";
import { getEvaluateChemist, add } from "./service.js";
import moment from "moment";
export default {
    name: 'AddchemistEvaluate',
  name: "AddchemistEvaluate",
    components: {
        ExperimentalScheduling,
    SelectMemberSimple,
    },
    data() {
        return {
            showScheduling: false,
      participantsData: [],
      selectedParticipants: [],
      tableData: [],
      isEdit: true, // 是否为编辑模式
      // 状态映射表
      statusTypeMap: {
        "-1": "info",
        1: "warning",
        2: "success",
        3: "info",
      },
      statusTextMap: {
        "-1": "草稿箱",
        1: "待确认",
        2: "已确认",
        3: "已封存",
      },
    };
  },
  async created() {
    // const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
    // this.userRole = userInfo.roleType || "";
    // 检查是否为编辑模式
    this.participantsData = [];
    this.selectedParticipants = [];
    this.tableData = [];
    this.isEdit = true; // 是否为编辑模式
    if (this.$route.query.id) {
      this.isEdit = this.$route.query.type === "view" ? false : true;
      this.editId = this.$route.query.id;
      await this.loadEditData();
        }
    },
    methods: {
        submitForm() {
    handleSchedulingClose() {
      this.showScheduling = false;
        },
    handleSchedulingSubmit(data) {
      console.log("data data", data);
      this.tableData = data || [];
      if (data && data.length > 0 && data[0].id) {
        getEvaluateChemist({ dispatchId: data[0].id })
          .then((res) => {
            console.log("获取参加人员列表:", res);
            if (res) {
              this.participantsData = res.map(item=>{
                return {
                  ...item,roleType:4
                }
              });
            } else {
              this.$message.error(res.msg || "获取参加人员列表失败");
            }
          })
          .catch((err) => {
            this.$message.error("获取参加人员列表失败");
            console.error("获取参加人员列表失败:", err);
          });
      }
    },
    getStatusType(status) {
      return this.statusTypeMap[status] || "info";
    },
    getStatusText(status) {
      return this.statusTextMap[status] || "未知";
    },
    handleEditMember() {
      this.$refs.selectMember.open(
        this.participantsData,
        this.selectedParticipants
      );
    },
    // ===== 人员相关方法 =====
        addMember() {
            this.$refs.selectMember.open()
      if (this.tableData.length == 0) {
        this.$message.error("请先选择所属实验调度");
        return;
      }
      this.$refs.selectMember.open(this.participantsData, []);
        },
    handleMemberSubmit(selectedMembers) {
      this.selectedParticipants = selectedMembers;
      this.$refs.selectMember.close();
    },
    // 将分数转换为评定值
    getEvaluateValue(score) {
      // 2分 = 良好(1), 1分 = 正确(2), 0分 = 失误(3)
      const scoreMap = {
        2: 1, // 良好
        1: 2, // 正确
        0: 3, // 失误
      };
      return scoreMap[score] || 3; // 默认返回失误
    },
    submitForm() {
      const evaluateTable = this.$refs.evaluateTable;
      if (!evaluateTable) {
        this.$message.warning("评价表格未加载完成");
        return;
    }
      const activeIndex = evaluateTable.activeIndex;
      const evaluateData = {
        evaluateOne: this.getEvaluateValue(activeIndex[0].score),
        evaluateTwo: this.getEvaluateValue(activeIndex[1].score),
        evaluateThree: this.getEvaluateValue(activeIndex[2].score),
        evaluateFour: this.getEvaluateValue(activeIndex[3].score),
        evaluateFive: this.getEvaluateValue(activeIndex[4].score),
        evaluateSix: this.getEvaluateValue(activeIndex[5].score),
        evaluateTime: moment().format("YYYY-MM-DD HH:mm:ss"),
        resultEvaluateJson: JSON.stringify(activeIndex),
        dispatchId: this.tableData[0]?.id,
        evaluateType:2,
        userId: this.selectedParticipants[0].userId,
        dispatchId:this.tableData[0]?.id,
        status: 1
      };
      console.log("11111111111", evaluateTable.activeIndex);
      console.log("2222222222222222", evaluateData);
      add(evaluateData).then(res=>{
        if(res.code==200){
          this.$message.success("保存成功");
          this.$router.back();
        }else{
          this.$message.error(res.msg||"保存失败");
}
      })
    },
  },
};
</script>
<style scoped lang="less">
@@ -104,11 +283,11 @@
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: 'Source Han Sans CN Bold Bold';
      font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: '*';
                color: #F56C6C;
        content: "*";
        color: #f56c6c;
                margin-right: 4px;
            }
        }
@@ -126,8 +305,12 @@
        width: 340px;
        height: 400px;
        border-radius: 8px;
        border: 1px solid #DCDFE6;
        background: linear-gradient(to bottom, rgba(255, 77, 79, 0.20) 0%, rgba(255, 242, 194, 0) 70%);
    border: 1px solid #dcdfe6;
    background: linear-gradient(
      to bottom,
      rgba(255, 77, 79, 0.2) 0%,
      rgba(255, 242, 194, 0) 70%
    );
        .member-item {
            height: 100%;
@@ -137,7 +320,7 @@
            .member-title {
                margin-top: 20px;
                width: 100%;
                font-family: 'Source Han Sans CN Bold Bold';
        font-family: "Source Han Sans CN Bold Bold";
                font-weight: bold;
                font-size: 16px;
                color: rgba(0, 0, 0, 0.8);
@@ -159,13 +342,13 @@
            .member-name {
                width: 60px;
                height: 60px;
                background: #7D8B79;
        background: #7d8b79;
                border-radius: 50%;
                text-align: center;
                line-height: 60px;
                font-weight: 500;
                font-size: 16px;
                color: #FFFFFF;
        color: #ffffff;
            }
            .member-edit {
@@ -176,12 +359,12 @@
                transform: translateX(-50%);
                font-weight: 400;
                font-size: 12px;
                color: #FF4D4F;
        color: #ff4d4f;
                line-height: 22px;
                width: 40px;
                background: #FFF1F0;
        background: #fff1f0;
                border-radius: 4px;
                border: 1px solid #FFCCC7;
        border: 1px solid #ffccc7;
                text-align: center;
            }
        }
laboratory/src/views/deliveryAssessment/chemistEvaluate/index.vue
@@ -5,54 +5,47 @@
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="所属项目课题方案:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.projectName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="实验编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.experimentNo" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="实验名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.experimentName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="评定时间:">
                        <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始日期"
                        <el-date-picker v-model="form.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
                            end-placeholder="结束日期">
                        </el-date-picker>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="tableTitle">
                    <div class="flex a-center">
                        <div class="title" :class="{ active: currentType === 'list' }"
                            @click="handleTypeChange('list')">
                        <div class="title active">
                            化验师工作评定列表</div>
                        <div class="drafts" :class="{ active: currentType === 'draft' }"
                            @click="handleTypeChange('draft')">草稿箱</div>
                    </div>
                    <el-button @click="handleAdd" class="el-icon-plus" type="primary">
                        新增化验师工作评定</el-button>
                </div> 
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="检测项名称" />
                <el-table-column prop="age" label="检测项编号" />
                <el-table-column prop="age" label="备注" />
                <el-table-column prop="age" label="创建人" />
                <el-table-column prop="age" label="创建时间" />
                <el-table-column prop="age" label="状态">
                <el-table-column prop="teamName" label="所属项目课题方案" />
                <el-table-column prop="experimentCode" label="实验编号" />
                <el-table-column prop="experimentName" label="实验名称" />
                <el-table-column prop="chemistName" label="被评定化验师" />
                <el-table-column prop="chemistIntegral" label="评定分数" />
                <el-table-column prop="evaluateTime" label="评定时间" />
                <el-table-column label="操作" width="180">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                    <template #default="{ row }">
                        <el-button type="text" @click="assessmentVisible = true">详情</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleEdit(row)">编辑</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleDelete(row)">删除</el-button>
                    </template>
                </el-table-column>
            </template>
@@ -61,13 +54,17 @@
</template>
<script>
import { chemistEvaluateList } from './service'
export default {
    name: 'TesterWorkerEvaluate',
    name: 'ChemistEvaluate',
    data() {
        return {
            currentType: 'list', // 当前显示类型:list-列表,draft-草稿箱
            form: {
                projectName: '',
                experimentNo: '',
                experimentName: '',
                dateRange: []
            },
            tableData: [],
            queryForm: {
@@ -75,13 +72,50 @@
                pageNum: 1
            },
            total: 0,
            loading: false
        }
    },
    methods: {
        handleAdd() {
            this.$router.push({
                path: '/deliveryAssessment/addTesterWorkerEvaluate'
        async getList() {
            this.loading = true
            const params = {
                ...this.queryForm,
                projectName: this.form.projectName,
                experimentNo: this.form.experimentNo,
                experimentName: this.form.experimentName,
                startTime: this.form.dateRange && this.form.dateRange[0] ? this.form.dateRange[0] : '',
                endTime: this.form.dateRange && this.form.dateRange[1] ? this.form.dateRange[1] : ''
            }
            try {
                const res = await chemistEvaluateList(params)
                this.tableData = (res.data?.records || []).map(item => {
                  let score = '';
                  try {
                    const json = typeof item.resultEvaluateJson === 'string'
                      ? JSON.parse(item.resultEvaluateJson)
                      : item.resultEvaluateJson;
                    score = json?.score || '';
                  } catch (e) {}
                  return { ...item, score };
            })
                this.total = res.data?.total || 0
            } finally {
                this.loading = false
            }
        },
        handleSearch() {
            this.queryForm.pageNum = 1
            this.getList()
        },
        handleReset() {
            this.form = {
                projectName: '',
                experimentNo: '',
                experimentName: '',
                dateRange: []
            }
            this.queryForm.pageNum = 1
            this.getList()
        },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
@@ -91,13 +125,23 @@
            this.queryForm.pageSize = size
            this.getList()
        },
        getList() {
        handleAdd() {
            this.$router.push({
                path: '/deliveryAssessment/addchemistEvaluate'
            })
        },
        handleTypeChange(type) {
            this.currentType = type;
            this.getList();
        handleDetail(row) {
            // 详情逻辑后续补充
        },
        handleEdit(row) {
            // 编辑逻辑后续补充
        },
        handleDelete(row) {
            // 删除逻辑后续补充
        }
    },
    mounted() {
        this.getList()
    }
}
</script>
laboratory/src/views/deliveryAssessment/chemistEvaluate/service.js
New file
@@ -0,0 +1,29 @@
import axios from '@/utils/request';
// 获取化验师工作评定分页列表
export const chemistEvaluateList = (data) => {
    return axios.post('/api/t-result-work-evaluate/chemistEvaluateList', { ...data })
}
export const add = (data) => {
    return axios.post('/api/t-result-work-evaluate/add', { ...data })
}
export const getEvaluateChemist = (data) => {
    return axios.get('/open/t-result-work-evaluate/getEvaluateChemist', { params:data })
}
// export const getEvaluateChemist = (data) => {
//     return axios.get('/open/t-result-work-evaluate/getEvaluateTester', { params:data })
//   }
// export const update = (data) => {
//     return axios.post('/api/t-tester-other-task/update', { ...data })
// }
// export const deleteById = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteById', { params:data })
// }
// export const deleteByIds = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteByIds', { params:data })
// }
laboratory/src/views/deliveryAssessment/clinicalTrial/components/detail.vue
@@ -1,92 +1,186 @@
<template>
    <el-dialog :visible.sync="dialogVisible" title="新增临床试验" width="50%" @close="handleClose">
  <el-dialog
    :visible.sync="dialogVisible"
    :title="type === 'add' ? '新增临床试验' : '临床试验详情'"
    width="50%"
    @open='open'
    @close="handleClose"
  >
        <div class="content-box">
            <div class="header-title-left">
                <img src="@/assets/public/headercard.png" />
                <div>所属项目组</div>
            </div>
            <Table :data="criteriaList" :height="null">
                <el-table-column prop="name" label="项目组名称" />
                <el-table-column prop="name" label="项目负责人" />
                <el-table-column prop="name" label="项目组成员" />
                <el-table-column prop="name" label="创建时间" />
      <Table :data="projectTeamList" :height="null">
        <el-table-column prop="teamName" label="项目组名称" />
        <el-table-column prop="personCharge" label="项目负责人" />
        <el-table-column prop="staffName" label="项目组成员" />
        <el-table-column prop="createTime" label="创建时间" />
            </Table>
            <div class="header-title-left">
                <img src="@/assets/public/headercard.png" />
                <div>临床试验内容</div>
            </div>
            <el-input type="textarea" :rows="4" placeholder="请输入" v-model="form.textarea" />
            <div class="header-title-left">
                <img src="@/assets/public/headercard.png" />
                <div>临床试验时间</div>
            </div>
            <el-date-picker v-model="form.value1" type="datetime" placeholder="请选择" />
            <div class="header-title-left">
                <img src="@/assets/public/headercard.png" />
                <div>评定积分</div>
            </div>
            <el-input-number placeholder="请输入" v-model="form.score" :min="0" :max="form.fullScore" :precision="1"
                :step="1" />
      <el-row>
        <el-col :span="2"> </el-col>
        <el-col :span="12" :offset="1">
          <el-form
            :model="form"
            :rules="rules"
            ref="formRef"
            label-width="100px"
            :span="12"
            label-position="top"
            style="margin-top: 20px"
          >
            <el-form-item label="临床试验内容" prop="trialContent" required>
              <el-input
              type="textarea"
                v-model="form.trialContent"
                placeholder="请输入"
                :disabled="type === 'detail'"
              />
            </el-form-item>
            <el-form-item label="临床试验时间" prop="trialTime" required>
              <el-date-picker
                v-model="form.trialTime"
                type="datetime"
                placeholder="请选择"
                style="width: 100%"
                :disabled="type === 'detail'"
              />
            </el-form-item>
            <el-form-item label="评定积分" prop="evaluateScore" required>
              <el-input
              type="number"
                v-model="form.evaluateScore"
                placeholder="请输入"
                :disabled="type === 'detail'"
              />
            </el-form-item>
          </el-form>
        </el-col>
      </el-row>
        </div>
        <template #footer>
            <span class="dialog-footer select-member-footer">
                <el-button type="primary">确认</el-button>
        <el-button v-if="!isDetail" type="primary" @click="handleConfirm"
          >确认</el-button
        >
            </span>
        </template>
    </el-dialog>
</template>
<script>
import { getDetailById, add, getDetailByUserId } from "../service.js";
import moment from "moment";
export default {
    name: 'Detail',
  name: "Detail",
    props: {
        modelValue: {
            type: Boolean,
            default: false
      default: false,
        },
        reportData: {
            type: Object,
            default: () => { }
        }
    type: {
      type: String,
      default: "add",
    },
    id: {
      type: [String, Number],
      default: "",
    },
    },
    data() {
        return {
            dialogVisible: false,
            form: {
                textarea: '',
                value1: '',
                score: null,
                fullScore: 3
        trialContent: "",
        trialTime: "",
        evaluateScore: null,
        processEngineerId: "",
        // fullScore: 3,
            },
            rules: {
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
        trialContent: [
          { required: true, message: "请输入任务内容", trigger: "blur" },
                ],
        trialTime: [
          { required: true, message: "请选择任务时间", trigger: "change" },
        ],
        evaluateScore: [{ required: true, message: "请输入评定积分", trigger: "blur" }],
            },
            criteriaList: []
        }
      projectTeamList: [],
      isDetail: false,
    };
    },
    watch: {
        modelValue: {
            handler(val) {
                this.dialogVisible = val;
        if (val) this.initForm();
            },
            immediate: true
      immediate: true,
        },
        reportData: {
            handler(val) {
                if (val) {
                    this.form = val || {};
                }
    type: {
      handler() {
        this.initForm();
            },
            immediate: true
        }
      immediate: true,
    },
    id: {
      handler() {
        this.initForm();
      },
      immediate: true,
    },
    },
    methods: {
        handleClose() {
    open() {
        const teamRes = getDetailByUserId();
        this.projectTeamList = [{ ...teamRes }];
        },
    async initForm() {
      this.isDetail = this.type === "detail";
      // 获取项目组信息
      if (this.type === "add") {
        // 新增,清空表单
        this.form = {
          trialContent: "",
          trialTime: "",
          evaluateScore: null,
          fullScore: 3,
        };
      } else if (this.type === "detail" && this.id) {
        // 详情,查详情接口
        const res = await getDetailById({ id: this.id });
        if (res && res.data) {
          this.form = {
            ...res.data,
            fullScore: 3,
          };
    }
}
    },
    handleClose() {
      this.$emit("close");
    },
    async handleConfirm() {
      let processEngineer = this.projectTeamList[0]?.staffs?.filter(
        (item) => item.roleType == 3
      );
      // 新增提交
      const params = {
        trialContent: this.form.trialContent,
        trialTime: moment(this.form.trialTime).format("YYYY-MM-DD HH:mm:ss"),
        evaluateScore: this.form.evaluateScore,
        processEngineerId:
          processEngineer.length > 0 ? processEngineer[0].userId : "",
        teamId: this.projectTeamList[0]?.id || "",
      };
      await add(params);
      this.$emit("close");
    },
  },
};
</script>
<style lang="less" scoped>
@@ -107,9 +201,7 @@
        font-size: 18px;
        color: #222222;
        line-height: 27px;
        font-family: 'Source Han Sans CN Bold Bold';
    font-family: "Source Han Sans CN Bold Bold";
    }
}
</style>
laboratory/src/views/deliveryAssessment/clinicalTrial/index.vue
@@ -1,47 +1,52 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
        <TableCustom :queryForm="queryForm" :tableData="tableData" :height='null' :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="项目组名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="任务内容:">
                        <el-input v-model="form.name" placeholder="请输入" />
                    <el-form-item label="试验内容:">
                        <el-input v-model="form.trialContent" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <el-button @click="assessmentVisible = true, currentReport = {}" class="el-icon-plus" type="primary">
                <el-button v-if="roleType==2" @click="handleAssessment" class="el-icon-plus" type="primary">
                    新增临床试验</el-button>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="临床试验内容" />
                <el-table-column prop="age" label="    临床试验时间" />
                <el-table-column prop="age" label="添加人" />
                <el-table-column prop="age" label="评定积分" />
                <el-table-column prop="age" label="累计分数" />
                <el-table-column prop="age" label="评定时间" />
                <el-table-column prop="age" label="操作">
                <el-table-column prop="projectTeam" label="所属项目组" >
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
                        <el-tag v-if="row.teamName" type="info">{{ row.teamName }}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="trialContent" label="临床试验内容" />
                <el-table-column prop="trialTime" label="临床试验时间" />
                <el-table-column prop="createBy" label="添加人" />
                <el-table-column prop="evaluateScore" label="评定积分" />
                <el-table-column prop="totalScore" label="累计分数" />
                <el-table-column prop="createTime" label="评定时间" />
                <el-table-column label="操作">
                    <template #default="{ row }">
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <Detail :modelValue="assessmentVisible" :reportData="currentReport" />
        <Detail :modelValue="assessmentVisible" :type="dialogType" :id="currentId" @close="closeDetail" />
    </div>
</template>
<script>
import Detail from './components/detail.vue'
import { pageList, getDetailByUserId } from './service.js'
export default {
    name: 'ClinicalTrial',
@@ -51,6 +56,8 @@
    data() {
        return {
            form: {
                teamName: '',
                trialContent: ''
            },
            tableData: [],
            queryForm: {
@@ -59,8 +66,15 @@
            },
            total: 0,
            assessmentVisible: false,
            currentReport: {}
            dialogType: '',
            roleType: '',
            currentId: '',
        }
    },
    mounted() {
        const userInfo = JSON.parse(sessionStorage.getItem('userInfo'));
        this.roleType = userInfo?.roleType;
        this.getList();
    },
    methods: {
        handleCurrentChange(page) {
@@ -72,15 +86,45 @@
            this.getList()
        },
        getList() {
            const params = { ...this.form, ...this.queryForm }
            pageList(params).then(res => {
                if(res && res.data) {
                    this.tableData = res.data.records || [];
                    this.total = res.data.total || 0;
                }
            })
        },
        handleDetail(row) {
            // 处理详情
        handleSearch() {
            this.queryForm.pageNum = 1;
            this.getList();
        },
        handleAssessment(row) {
            this.currentReport = row;
        handleReset() {
            this.form = { name: '', content: '' };
            this.queryForm.pageNum = 1;
            this.getList();
        },
        async openDialog(type, id = '') {
            this.dialogType = type;
            this.currentId = id;
            this.assessmentVisible = true;
        },
        handleDetail(row) {
            this.openDialog('detail', row.id);
        },
        handleAssessment() {
            this.openDialog('add');
        },
        closeDetail() {
            this.assessmentVisible = false;
            this.getList();
        },
    },
    watch: {
        assessmentVisible(val) {
            if (!val) {
                this.dialogType = '';
            }
        }
    }
}
</script>
laboratory/src/views/deliveryAssessment/clinicalTrial/service.js
@@ -1,6 +1,6 @@
import axios from '@/utils/request';
// 项目组总积分分页列表
// 列表
export const pageList = (data) => {
    return axios.post('/api/t-clinical-trial-points/pageList', { ...data })
}
@@ -20,3 +20,8 @@
export const getDetailById = (data) => {
    return axios.get('/open/t-clinical-trial-points/getDetailById', { params:data })
}
//查询项目组信息
export const getDetailByUserId = (data) => {
    return axios.get('/open/t-project-team/getDetailByUserId', { params:data })
}
laboratory/src/views/deliveryAssessment/experimentResults/service.js
@@ -1,22 +1,29 @@
import axios from '@/utils/request';
// 获取实验结果汇报评定列表-审批人使用
export const evaluatePageList = (data) => {
    return axios.post('/api/t-experiment-result-report/evaluatePageList', { ...data })
// 查询化验师评定列表-化验师使用
export const getEvaluateChemistPageList = (data) => {
    return axios.post('/api/t-result-work-evaluate/getEvaluateChemistPageList', { ...data })
}
// 查询实验员评定列表-实验员使用
export const getEvaluateTesterPageList = (data) => {
    return axios.post('/api/t-result-work-evaluate/getEvaluateTesterPageList', { ...data })
}
export const add = (data) => {
    return axios.post('/api/t-tester-other-task/add', { ...data })
}
export const update = (data) => {
    return axios.post('/api/t-tester-other-task/update', { ...data })
}
export const deleteById = (data) => {
    return axios.delete('/open/t-tester-other-task/deleteById', { params:data })
}
export const deleteByIds = (data) => {
    return axios.delete('/open/t-tester-other-task/deleteByIds', { params:data })
}
export const getDetailById = (data) => {
    return axios.get('/open/t-tester-other-task/getDetailById', { params:data })
}
// export const add = (data) => {
//     return axios.post('/api/t-result-work-evaluate/add', { ...data })
// }
// export const getEvaluateChemist = (data) => {
//     return axios.get('/open/t-result-work-evaluate/getEvaluateChemist', { params:data })
// }
// export const update = (data) => {
//     return axios.post('/api/t-tester-other-task/update', { ...data })
// }
// export const deleteById = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteById', { params:data })
// }
// export const deleteByIds = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteByIds', { params:data })
// }
laboratory/src/views/deliveryAssessment/experimenterJobEvaluation/index.vue
@@ -1,49 +1,118 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
      <TableCustom
        :queryForm="form"
        :tableData="tableData"
        :total="total"
        :height="null"
        @handlePageChange="handlePageChange"
        @handleSizeChange="handleSizeChange"
      >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
          <el-form :model="form" labelWidth="auto" inline>
                    <el-form-item label="所属项目课题方案:">
                        <el-input v-model="form.name" placeholder="请输入" />
              <el-input
                v-model="form.projectName"
                placeholder="请输入"
              ></el-input>
                    </el-form-item>
                    <el-form-item label="实验编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
              <el-input
                v-model="form.experimentCode"
                placeholder="请输入"
              ></el-input>
                    </el-form-item>
                    <el-form-item label="创建时间:">
                        <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始日期"
                            end-placeholder="结束日期">
                        </el-date-picker>
            <el-form-item label="实验名称:">
              <el-input
                v-model="form.experimentName"
                placeholder="请输入"
              ></el-input>
            </el-form-item>
            <el-form-item label="创建日期:">
              <el-date-picker
                v-model="dateRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
                @change="handleDateChange"
              ></el-date-picker>
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.status" placeholder="请选择">
                            <el-option label="是" value="1"></el-option>
                            <el-option label="否" value="0"></el-option>
                <el-option label="全部" value=""></el-option>
                <el-option label="待提交" :value="1"></el-option>
                <el-option label="待评定" :value="2"></el-option>
                <el-option label="已评定" :value="3"></el-option>
                <el-option label="已封存" :value="4"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-form-item label="">
              <el-button type="default" @click="resetForm">重置</el-button>
              <el-button
                type="primary"
                style="margin-left: 10px"
                @click="handleSearch"
                >查询</el-button
              >
                    </el-form-item>
                </el-form>
            </template>
        <template #setting>
          <div class="tableTitle">
            <div class="flex a-center">
              <div
                class="title active"
              >
                实验结果汇报列表
              </div>
            </div>
          </div>
        </template>
            <template #table>
                <el-table-column prop="name" label="所属项目课题方案" />
                <el-table-column prop="age" label="实验编号" />
                <el-table-column prop="age" label="工艺工程师" />
                <el-table-column prop="age" label="化验师" />
                <el-table-column prop="age" label="实验员" />
                <el-table-column prop="age" label="创建日期" />
                <el-table-column prop="age" label="状态">
                    <template #default="{ row }">
                        <span :style="{ color: ['green', 'red'][row.status - 1] }">{{ ['是', '否'][row.status - 1]
                            }}</span>
          <el-table-column
            prop="projectName"
            label="所属项目课题方案"
          ></el-table-column>
          <el-table-column
            prop="experimentCode"
            label="实验编号"
          ></el-table-column>
          <el-table-column
            prop="experimentName"
            label="实验名称"
          ></el-table-column>
          <el-table-column
            prop="processEngineerName"
            label="工艺工程师"
          ></el-table-column>
          <el-table-column
            prop="laboratoryChemistName"
            label="化验师"
          ></el-table-column>
          <el-table-column
            prop="experimenterName"
            label="实验员"
          ></el-table-column>
          <el-table-column
            prop="createTime"
            label="创建日期"
            width="180"
          ></el-table-column>
          <el-table-column prop="status" label="状态">
            <template slot-scope="scope">
              <el-tag :type="getStatusType(scope.row.status)">
                {{ getStatusText(scope.row.status) }}
              </el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
                        <el-button type="text">评定</el-button>
          <el-table-column label="操作" width="180">
            <template slot-scope="scope">
              <el-button type="text" @click="handleDetail(scope.row.id)"
                >详情</el-button
              >
                    </template>
                </el-table-column>
            </template>
@@ -53,83 +122,154 @@
</template>
<script>
  import { getList} from "./service";
export default {
    name: 'ExperimenterJobEvaluation',
    components: {
    },
    name: "TestResultReport",
    data() {
        return {
            form: {
            },
            tableData: [],
            queryForm: {
          projectName: "",
          experimentCode: "",
          experimentName: "",
          startTime: "",
          endTime: "",
          status: "",
          pageNum: 1,
                pageSize: 10,
                pageNum: 1
            },
        dateRange: [],
        tableData: [],
            total: 0,
        }
      };
    },
    created() {
      this.getTableData();
    },
    methods: {
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      resetForm() {
        this.form = {
          projectName: "",
          experimentCode: "",
          experimentName: "",
          startTime: "",
          endTime: "",
          status: "",
          pageNum: 1,
          pageSize: 10,
        };
        this.dateRange = [];
        this.getTableData();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      handleSearch() {
        this.getTableData();
        },
        getList() {
      handleDetail(id) {
        this.$router.push({
          path: "/dataManagement/testResultReport/detail",
          query: {
            id: id,
            type: "view",
        },
        handleDetail(row) {
            // 处理详情
        });
        },
        handleAssessment(row) {
            this.currentReport = row;
            this.assessmentVisible = true;
        },
      getTableData() {
        const params = {
          ...this.form,
        };
        getList(params)
          .then((res) => {
            if (res.code === 200) {
              this.tableData = res.data.records || [];
              this.total = res.data.total || 0;
            } else {
              this.$message.error(res.msg || "获取数据失败");
    }
          })
          .catch(() => {
            this.$message.error("获取数据失败");
          });
      },
      handleDateChange(val) {
        if (val) {
          this.form.startTime = val[0];
          this.form.endTime = val[1];
        } else {
          this.form.startTime = "";
          this.form.endTime = "";
}
      },
      getStatusType(status) {
        const statusMap = {
          "-1": "info",
          1: "warning",
          2: "warning",
          3: "success",
          4: "info",
          5: "warning",
        };
        return statusMap[status] || "info";
      },
      getStatusText(status) {
        const statusMap = {
          "-1": "草稿箱",
          1: "待提交",
          2: "待评定",
          3: "已评定",
          4: "已封存",
          5: "已解封",
        };
        return statusMap[status] || "未知";
      },
      handlePageChange(pageNum) {
        this.form.pageNum = pageNum;
        this.getTableData();
      },
      handleSizeChange(pageSize) {
        this.form.pageSize = pageSize;
        this.getTableData();
      },
    },
  };
</script>
<style scoped lang="less">
.list {
    height: 100%;
}
.top-box-integral {
  .flex {
    display: flex;
    align-items: center;
  }
  .tableTitle {
    display: flex;
    padding-bottom: 20px;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 28px;
    &-card {
        flex: 1;
        background: #E8FAF6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
    align-items: center;
    .title,
    .drafts {
      background: #fafafc;
      border-radius: 8px 8px 0px 0px;
      border: 1px solid #dcdfe6;
      padding: 16px 29px;
      font-size: 18px;
      color: #606266;
      cursor: pointer;
      font-weight: 400;
        }
        &-num {
            font-family: 'SF Compact Display Black';
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
            line-height: 60px;
    .title {
      padding: 16px 29px;
        }
    .drafts {
      padding: 16px 65px;
      margin-left: 16px;
    }
    .active {
      color: #049c9a;
      background: #ffffff;
      border-radius: 8px 8px 0px 0px;
      border: 1px solid #049c9a;
      font-weight: bold;
}
.tip-warring {
    margin-top: 20px;
    color: rgba(255, 73, 85, 1);
}
</style>
laboratory/src/views/deliveryAssessment/experimenterJobEvaluation/service.js
New file
@@ -0,0 +1,6 @@
import axios from '@/utils/request';
// 列表
export const getList = (data) => {
  return axios.post('/api/t-experiment-result-report/pageList', { ...data })
}
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/components/evaluation-dialog.vue
New file
@@ -0,0 +1,88 @@
<template>
  <el-dialog
    :visible.sync="dialogVisible"
    :title="dialogTitle"
    width="79.17%"
    @close="handleClose"
  >
    <EvaluateTable ref="evaluateTable" :viewJson="viewJson" />
    <div slot="footer" class="dialog-footer">
      <el-button type="primary" @click="handleSubmit" class="submit-btn">确认评定结果</el-button>
    </div>
  </el-dialog>
</template>
<script>
const EVALUATION_TYPES = ['labTechnician', 'experimenter'];
export default {
  name: "EvaluationDialog",
  props: {
    modelValue: {
      type: Boolean,
      default: false,
    },
    type: {
      type: String,
      default: 'labTechnician'
    },
    viewJson: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      dialogVisible: false,
    };
  },
  computed: {
    dialogTitle() {
      return this.type === 'labTechnician' ? '化验师工作评定' : this.type === 'experimenter' ? '实验员工作评定' : '工艺工程师工作评定';
    }
  },
  watch: {
    modelValue: {
      handler(val) {
        this.dialogVisible = val;
      },
      immediate: true,
    },
    dialogVisible(val) {
      if (!val) {
        this.$emit('update:modelValue', false);
      }
    }
  },
  methods: {
    handleClose() {
      this.$emit('update:modelValue', false);
    },
    handleSubmit() {
      const evaluateTable = this.$refs.evaluateTable;
      if (!evaluateTable) {
        this.$message.warning('评价表格未加载完成');
        return;
      }
      const evaluateData = {
        type: this.type,
        activeIndex: evaluateTable.activeIndex
      };
      this.$emit('submit', evaluateData);
    },
  },
};
</script>
<style lang="less" scoped>
.dialog-footer {
  padding: 20px;
  border-top: 1px solid #eee;
  .submit-btn {
    min-width: 80px;
  }
}
</style>
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/index.vue
@@ -1,88 +1,225 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="所属项目课题方案:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.projectName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="实验编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.experimentCode" placeholder="请输入" />
          </el-form-item>
          <el-form-item label="实验名称:">
            <el-input v-model="form.experimentName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="创建日期:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.createTime" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option label="待提交" :value="1"></el-option>
              <el-option label="待评定" :value="2"></el-option>
              <el-option label="已评定" :value="3"></el-option>
              <el-option label="已封存" :value="4"></el-option>
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-button @click="resetForm">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="table-title">
                    实验结果汇报列表
                </div>
        <div class="table-title">实验结果汇报列表</div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目课题方案" />
                <el-table-column prop="age" label="实验编号" />
                <el-table-column prop="age" label="工艺工程师" />
                <el-table-column prop="age" label="化验师" />
                <el-table-column prop="age" label="实验员" />
                <el-table-column prop="age" label="创建日期" />
                <el-table-column prop="age" label="状态">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
        <el-table-column prop="projectName" label="所属项目课题方案" />
        <el-table-column prop="experimentCode" label="实验编号" />
        <el-table-column prop="experimentName" label="实验名称" />
        <el-table-column prop="processEngineerName" label="工艺工程师" />
        <el-table-column prop="laboratoryChemistName" label="化验师" />
        <el-table-column prop="experimenterName" label="实验员" />
        <el-table-column prop="createTime" label="创建日期" />
        <el-table-column prop="status" label="状态">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.status)">
              {{ getStatusText(scope.row.status) }}
            </el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
        <el-table-column prop="operation" label="操作">
                    <template #default="{ row }">
                        <el-button type="text" @click="assessmentVisible = true">详情</el-button>
            <el-button type="text" @click="handleDetail(row)">详情</el-button>
            <el-button
              v-if="row.status === 2"
              type="text"
              @click="handleEvaluate(row)"
              >评定</el-button
            >
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
    <evaluation-dialog
      :modelValue="evaluationDialogVisible"
      :type="'processEngineer'"
      :viewJson="currentEvaluationData"
      @update:modelValue="updateEvaluationDialogVisible"
      @submit="handleEvaluationSubmit"
    />
    </div>
</template>
<script>
import EvaluationDialog from "./components/evaluation-dialog.vue";
import { evaluatePageList,evaluateProcess } from './service.js';
export default {
    name: 'ProcessEngineerEvaluate',
  name: "ProcessEngineerEvaluate",
  components: {
    EvaluationDialog,
  },
    data() {
        return {
            form: {
        projectName: '',
        experimentCode: '',
        experimentName: '',
        createTime: '',
        status: '',
            },
            tableData: [],
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
            total: 0,
        }
      evaluationDialogVisible: false,
      currentEvaluationData: null,
    };
  },
  created() {
    this.getList();
    },
    methods: {
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
      const params = {
        ...this.form,
        pageNum: this.queryForm.pageNum,
        pageSize: this.queryForm.pageSize,
      };
      evaluatePageList(params).then(res => {
        if (res && res.code === 200) {
          this.tableData = res.data.records || [];
          this.total = res.data.total || 0;
        } else {
          this.$message.error(res.msg || '获取数据失败');
        }
      }).catch(() => {
        this.$message.error('获取数据失败');
      });
        },
        handleDetail(row) {
            // 处理详情
      this.$router.push({
        path: "/dataManagement/testResultReport/detail",
        query: {
          id: row.id,
          type: "view",
        },
      });
    },
    handleEvaluate(row) {
      this.currentEvaluationData = row; // 可根据实际需要传递数据
      this.evaluationDialogVisible = true;
    },
    updateEvaluationDialogVisible(val) {
      this.evaluationDialogVisible = val;
      if (!val) this.currentEvaluationData = null;
    },
     // 处理评价提交
     handleEvaluationSubmit(evaluationData) {
      const { activeIndex } = evaluationData;
      // 将评分数据转换为后端需要的格式
      const evaluateData = {
        evaluateType: 1, // 1=工艺工程师
        evaluateOne: this.getEvaluateValue(activeIndex[0].score),
        evaluateTwo: this.getEvaluateValue(activeIndex[1].score),
        evaluateThree: this.getEvaluateValue(activeIndex[2].score),
        evaluateFour: this.getEvaluateValue(activeIndex[3].score),
        evaluateFive: this.getEvaluateValue(activeIndex[4].score),
        evaluateSix: this.getEvaluateValue(activeIndex[5].score),
        evaluateTime: moment().format('YYYY-MM-DD HH:mm:ss'),
        resultEvaluateJson: JSON.stringify(activeIndex),
        resultReportId: this.currentOperationRow.id,
        dispatchId: this.currentOperationRow.dispatchId,
        status: 1
      };
      console.log('evaluateData',evaluateData)
      evaluateProcess(evaluateData).then(res => {
        if (res.code == 200) {
          this.$message.success('评定成功');
          this.evaluationDialogVisible = false;
          this.getList(); // 重新获取列表数据
        } else {
          this.$message.error(res.msg || '评定失败');
    }
}
      }).catch(err => {
        this.$message.error('评定失败');
      });
    },
    resetForm() {
      this.form = {
        projectName: '',
        experimentCode: '',
        experimentName: '',
        createTime: '',
        status: '',
      };
      this.getList();
    },
    handleSearch() {
      this.getList();
    },
    getStatusType(status) {
      const statusMap = {
        '-1': 'info',
        '1': 'warning',
        '2': 'warning',
        '3': 'success',
        '4': 'info',
        '5': 'warning'
      };
      return statusMap[status] || 'info';
    },
    getStatusText(status) {
      const statusMap = {
        '-1': '草稿箱',
        '1': '待提交',
        '2': '待评定',
        '3': '已评定',
        '4': '已封存',
        '5': '已解封'
      };
      return statusMap[status] || '未知';
    },
  },
};
</script>
<style scoped lang="less">
@@ -98,23 +235,23 @@
    &-card {
        flex: 1;
        background: #E8FAF6;
    background: #e8faf6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
      font-family: "SourceHanSansCN-Medium";
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
        }
        &-num {
            font-family: 'SF Compact Display Black';
      font-family: "SF Compact Display Black";
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
      color: #049c9a;
            line-height: 60px;
        }
    }
@@ -128,28 +265,28 @@
.table-title {
    width: 220px;
    height: 50px;
    background: #FFFFFF;
  background: #ffffff;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #049C9A;
  border: 1px solid #049c9a;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #049C9A;
  color: #049c9a;
    line-height: 27px;
}
.expand-box {
    padding: 20px;
    background: linear-gradient(180deg, #049C9A 0%, #0ACBCA 100%);
  background: linear-gradient(180deg, #049c9a 0%, #0acbca 100%);
    border-radius: 20px;
    &-title {
        font-weight: 500;
        font-size: 16px;
        color: #FFFFFF;
    color: #ffffff;
        line-height: 24px;
        margin-bottom: 20px;
    }
laboratory/src/views/deliveryAssessment/processEngineerEvaluate/service.js
New file
@@ -0,0 +1,10 @@
import axios from '@/utils/request';
// 获取实验结果汇报评定列表-审批人使用
export const evaluatePageList = (data) => {
    return axios.post('/api/t-experiment-result-report/evaluatePageList', { ...data })
  }
  // 评定工艺工程师实验
  export const evaluateProcess = (data) => {
    return axios.post('/api/t-experiment-result-report/evaluateProcess', { ...data })
  }
laboratory/src/views/deliveryAssessment/projectTeamIntegral/detail.vue
@@ -4,51 +4,81 @@
            <div class="top-box-header-title">
                <div>项目组总积分表</div>
                <div class="top-box-header-time">
                    <div>评定开始时间:2024-02-09</div>
                    <div>评定结束始时间:2024-02-09</div>
                    <div>评定开始时间:{{ topData.startTime || '-' }}</div>
                    <div>评定结束时间:{{ topData.endTime || '-' }}</div>
                </div>
            </div>
            <div class="top-box-integral">
                <div :style="{ backgroundColor: ['rgba(232, 250, 246, 1)', 'rgba(255, 243, 213, 1)', 'rgba(254, 237, 220, 1)', 'rgba(239, 248, 255, 1)', 'rgba(255, 237, 238, 1)'][item - 1] }"
                    v-for="item in 5" :key="item" class="top-box-integral-card">
                    v-for="(item,index) in 5" :key="index" class="top-box-integral-card">
                    <div class="top-box-integral-card-title">{{ ['项目组总积分', '工艺工程师积分', '化验师积分', '实验员积分', '实验终止次数'][item -
                        1] }}</div>
                    <div :style="{ color: ['rgba(4, 156, 154, 1)', 'rgba(255, 197, 61, 1)', 'rgba(255, 147, 0, 1)', 'rgba(23, 119, 213, 1)', 'rgba(255, 73, 85, 1)'][item - 1] }"
                        class="top-box-integral-card-num">99.9</div>
                        class="top-box-integral-card-num">{{
                          [
                            topData.teamIntegral ?? '0',
                            topData.engineerIntegral ?? '0',
                            topData.chemistIntegral ?? '0',
                            topData.testerIntegral ?? '0',
                            topData.termination ?? '0'
                          ][item - 1]
                        }}</div>
                </div>
            </div>
        </div>
        <div class="integral-content">
            <div class="integral-content-box">
                <div class="integral-content-box-left">
                    <div @click="changeActiveItem(item)" class="integral-content-box-left-item"
                        :class="actionsLeftTab == item && 'activeItem'" v-for="item in 3" :key="item">
                        <div>{{ ['工艺工程师', '化验师', '实验员'][item - 1] }}</div>
                    <div @click="changeActiveItem(item.value)" class="integral-content-box-left-item"
                        :class="actionsLeftTab == item.value && 'activeItem'" v-for="item in leftTabs" :key="item.value">
                        <div>{{ item.label }}</div>
                        <div>工作内容评定</div>
                    </div>
                </div>
                <div class="integral-content-box-right">
                    <div v-show="actionsLeftTab != 1" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
                    <div v-show="actionsLeftTab == 2" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
                        <div
                            v-for="(item, idx) in chemistTabList"
                            :key="item.userName || idx"
                            @click="changeActiveName(idx)"
                            :class="activeNameTab == idx && 'activeName'"
                            class="integral-content-box-right-nameTab-name"
                        >
                            {{ item.userName }}
                        </div>
                    </div>
                    <!-- <div v-show="actionsLeftTab != 1 && actionsLeftTab != 2" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
                        <div @click="changeActiveName(item)" :class="activeNameTab == item && 'activeName'" class="integral-content-box-right-nameTab-name" v-for="item in 8" :key="item">张三</div>
                    </div> -->
                    <div v-show="actionsLeftTab == 3" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
                        <div
                            v-for="(item, idx) in testerTabList"
                            :key="item.userName || idx"
                            @click="changeActiveName(idx)"
                            :class="activeNameTab == idx && 'activeName'"
                            class="integral-content-box-right-nameTab-name"
                        >
                            {{ item.userName }}
                        </div>
                    </div>
                    <div class="integral-content-box-right-thead">
                        <div>评定项</div>
                        <div>评定情况</div>
                        <div>开始时间</div>
                        <div>结束时间</div>
                        <div>操作</div>
                        <div v-if="roleType == 1 || roleType == 2">操作</div>
                    </div>
                    <div class="integral-content-box-right-body">
                        <div v-for="item in itemList" :key="item" class="integral-content-box-right-body-item">
                        <div v-for="(item, idx) in itemList" :key="item.id || idx" class="integral-content-box-right-body-item">
                            <div>{{ item.gainer }}</div>
                            <div>
                                <div v-if="item.situationOne">{{ item.situationOne }}</div>
                                <div v-if="item.situationTwo">{{ item.situationTwo }}</div>
                            </div>
                            <div></div>
                            <div></div>
                            <div v-if="item.startTime">{{item.startTime}}</div>
                            <div v-if="item.endTime">{{item.endTime}}</div>
                            <div>
                                <el-button type="text">修改</el-button>
                                <el-button  type="text" v-if="roleType == 1 || roleType == 2" @click.stop='toChange(item.url)'>{{item.url? '修改':''}}</el-button>
                            </div>
                        </div>
                    </div>
@@ -59,142 +89,274 @@
</template>
<script>
import {
  getDetailById,
  getDetailByIdLeftOne,
  getDetailByIdLeftTwo,
  getDetailByIdLeftThree,
} from "./service";
export default {
    data() {
        return {
            actionsLeftTab: 1,
            activeNameTab: 1,
            actionspPersonnel: null,
      roleType: null,
      leftTabs: [],
      detailId: null,
      topData: {},
      tabData: [],
      chemistTabList: [], // 化验师tab的人员列表
      testerTabList: [], // 实验员tab的人员列表
            craftList: [
                {
                    gainer: '1、项目可研报告',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "1、项目可研报告",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '2、项目可行报告',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "2、项目可行报告",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '3、项目实验室开发阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "3、项目实验室开发阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '4、项目中试试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "4、项目中试试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '5、项目生产验证试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "5、项目生产验证试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '6、工艺开发工具',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "6、工艺开发工具",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '7、验证与开发',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "7、验证与开发",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '8、立项报告',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "8、立项报告",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '9、临床实验积分',
                    situationTwo: '积分数:',
          gainer: "9、临床实验积分",
          situationTwo: "积分数:",
          url:'/deliveryAssessment/clinicalTrial'
                },
            ],//工艺工程师-工作内容评定
            assayList: [
                {
                    gainer: '1、项目开发阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "1、项目开发阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '2、项目中试试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "2、项目中试试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '3、项目生产验证试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "3、项目生产验证试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '4、项目检测项、检验包评定',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "4、项目检测项、检验包评定",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '5、中试、生产验证试验检验分析报告评定',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "5、中试、生产验证试验检验分析报告评定",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '6、原辅料、包材、竞品检验分析报告评定',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "6、原辅料、包材、竞品检验分析报告评定",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '7、产品报批及项目工作总结报告评定',
                    situationOne: '课题数:',
                    situationTwo: '积分数:',
          gainer: "7、产品报批及项目工作总结报告评定",
          situationOne: "课题数:",
          situationTwo: "积分数:",
                },
            ],//化验师-工作内容评定
            experimentList: [
                {
                    gainer: '1、项目实验室开发阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "1、项目实验室开发阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '2、项目中试试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "2、项目中试试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '3、项目生产验证试验阶段',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "3、项目生产验证试验阶段",
          situationOne: "实验数:",
          situationTwo: "积分数:",
                },
                {
                    gainer: '4、其他任务',
                    situationOne: '实验数:',
                    situationTwo: '积分数:',
          gainer: "4、其他任务",
          situationOne: "实验数:",
          situationTwo: "积分数:",
          url:'/deliveryAssessment/restsTask'
                },
            ],//实验员-工作内容评定
        }
    };
    },
    computed: {
        itemList() {
            switch (this.actionsLeftTab) {
                case 1:
                    return this.craftList
                case 2:
                    return this.assayList
                case 3:
                    return this.experimentList
                default:
                    return this.craftList
            }
        }
      return this.tabData || [];
    },
    },
    created() {
    const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
    this.roleType = userInfo.roleType;
    this.initTabs();
    this.detailId = this.$route.query.id || this.$route.params.id;
    this.fetchTopData();
    this.fetchTabData(this.actionsLeftTab);
    },
    methods: {
        changeActiveItem(item) {
            this.actionsLeftTab = item
    initTabs() {
      if (this.roleType == 3) {
        // 工艺工程师
        this.leftTabs = [
          { label: "工艺工程师", value: 1 },
          { label: "化验师", value: 2 },
          { label: "实验员", value: 3 },
        ];
      } else if (this.roleType == 4) {
        // 化验师
        this.leftTabs = [{ label: "化验师", value: 2 }];
        this.actionsLeftTab = 2;
      } else if (this.roleType == 5) {
        // 实验员
        this.leftTabs = [{ label: "实验员", value: 3 }];
        this.actionsLeftTab = 3;
      } else {
        // 超级管理员、审批人或其他
        this.leftTabs = [
          { label: "工艺工程师", value: 1 },
          { label: "化验师", value: 2 },
          { label: "实验员", value: 3 },
        ];
        this.actionsLeftTab = 1;
      }
        },
        changeActiveName(item) {
            this.activeNameTab = item
    fetchTopData() {
      if (!this.detailId) return;
      getDetailById({ id: this.detailId }).then((res) => {
        if (res && res.data) {
          this.topData = res.data;
        }
      });
    },
    fetchTabData(tabType) {
      if (!this.detailId) return;
      let api;
      if (tabType == 1) api = getDetailByIdLeftOne;
      else if (tabType == 2) api = getDetailByIdLeftTwo;
      else if (tabType == 3) api = getDetailByIdLeftThree;
      else return;
      api({ id: this.detailId }).then((res) => {
        if (res) {
          if (tabType == 1) {
            const list = res.engineerList || [];
            this.craftList = this.craftList.map((item, idx) => {
              const apiItem = list[idx] || {};
              let label =
                item.situationOne && item.situationOne.includes("课题")
                  ? "课题数:"
                  : "实验数:";
              return {
                ...item,
                situationOne: label + (apiItem.count ?? "0"),
                situationTwo: "积分数:" + (apiItem.integral ?? "0"),
                startTime: apiItem.startTime || "-",
                endTime: apiItem.endTime || "-",
              };
            });
            console.log("craftList craftList", this.craftList);
            this.tabData = this.craftList;
          } else if (tabType == 2) {
            // 化验师
            const chemistList = res.chemistList || [];
            this.chemistTabList = chemistList;
            this.activeNameTab = 0;
            this.updateAssayListByChemist(0);
          } else if (tabType == 3) {
            const testerList = res.testerList || [];
            this.testerTabList = testerList;
            this.activeNameTab = 0;
            this.updateExperimentListByTester(0);
          }
          // 其他tab后续再做
        }
      });
    },
    updateAssayListByChemist(idx) {
      const chemist = this.chemistTabList[idx];
      if (!chemist) {
        this.tabData = [];
        return;
      }
      const list = chemist.list || [];
      this.tabData = this.assayList.map((item, i) => {
        const apiItem = list[i] || {};
        let label = item.situationOne && item.situationOne.includes("课题") ? "课题数:" : "实验数:";
        return {
          ...item,
          situationOne: label + (apiItem.count ?? "0"),
          situationTwo: "积分数:" + (apiItem.integral ?? "0"),
          startTime: apiItem.startTime || "-",
          endTime: apiItem.endTime || "-",
        };
      });
    },
    updateExperimentListByTester(idx) {
      const tester = this.testerTabList[idx];
      if (!tester) {
        this.tabData = [];
        return;
      }
      const list = tester.list || [];
      this.tabData = this.experimentList.map((item, i) => {
        const apiItem = list[i] || {};
        let label = item.situationOne && item.situationOne.includes("课题") ? "课题数:" : "实验数:";
        return {
          ...item,
          situationOne: label + (apiItem.count ?? "0"),
          situationTwo: "积分数:" + (apiItem.integral ?? "0"),
          startTime: apiItem.startTime || "-",
          endTime: apiItem.endTime || "-",
        };
      });
    },
    changeActiveItem(item) {
      this.actionsLeftTab = item;
      this.fetchTabData(item);
    },
    changeActiveName(idx) {
      this.activeNameTab = idx;
      if (this.actionsLeftTab == 2) {
        this.updateAssayListByChemist(idx);
      } else if (this.actionsLeftTab == 3) {
        this.updateExperimentListByTester(idx);
      }
        },
        handleWheel(e) {
            if (this.scrollTimer) {
@@ -212,15 +374,20 @@
            };
            this.scrollTimer = setTimeout(scroll, 8); // 减少延迟时间
    },
    toChange(url){
        if(url){
            this.$router.push(url)
        }
    }
}
  },
};
</script>
<style scope lang="less">
.top-box-header {
    &-title {
        color: #FFFFFF;
    color: #ffffff;
        padding: 0 20px;
        display: flex;
        align-items: center;
@@ -229,16 +396,16 @@
        min-height: 58px;
        padding-bottom: 12px;
        font-size: 20px;
        background: linear-gradient(180deg, #05A0C1 0%, #05F2C2 100%);
    background: linear-gradient(180deg, #05a0c1 0%, #05f2c2 100%);
        border-radius: 16px 16px 0px 0px;
        font-family: 'Source Han Sans CN Bold Bold';
    font-family: "Source Han Sans CN Bold Bold";
    }
    &-time {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        font-family: 'SourceHanSansCN-Medium';
    font-family: "SourceHanSansCN-Medium";
        font-size: 16px;
        div:first-child {
@@ -249,10 +416,14 @@
    .top-box-integral {
        padding: 42px 30px 38px 30px;
        margin-top: -12px;
        background: linear-gradient(180deg, #FFFFFF 0%, rgba(255, 255, 255, 0.2) 100%);
    background: linear-gradient(
      180deg,
      #ffffff 0%,
      rgba(255, 255, 255, 0.2) 100%
    );
        box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06);
        border-radius: 16px;
        border: 4px solid #FFFFFF;
    border: 4px solid #ffffff;
        display: flex;
        justify-content: space-between;
        flex-wrap: wrap;
@@ -260,23 +431,23 @@
        &-card {
            flex: 1;
            background: #E8FAF6;
      background: #e8faf6;
            box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
            border-radius: 10px;
            padding: 21px 20px;
            &-title {
                font-family: 'SourceHanSansCN-Medium';
        font-family: "SourceHanSansCN-Medium";
                font-size: 14px;
                color: rgba(0, 0, 0, 0.8);
            }
            &-num {
                font-family: 'SF Compact Display Black';
        font-family: "SF Compact Display Black";
                text-align: center;
                font-weight: 900;
                font-size: 50px;
                color: #049C9A;
        color: #049c9a;
                line-height: 60px;
            }
        }
@@ -289,7 +460,7 @@
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06);
    border-radius: 16px;
    border: 4px solid #FFFFFF;
  border: 4px solid #ffffff;
    &-box {
        display: flex;
@@ -302,8 +473,17 @@
            margin-top: 50px;
            .activeItem {
                background: linear-gradient(180deg, rgba(5, 160, 193, 0.4) 0%, rgba(5, 242, 194, 0) 100%);
                border-image: linear-gradient(180deg, rgba(10, 203, 202, 1), rgba(4, 156, 154, 0.2)) 1 1;
        background: linear-gradient(
          180deg,
          rgba(5, 160, 193, 0.4) 0%,
          rgba(5, 242, 194, 0) 100%
        );
        border-image: linear-gradient(
            180deg,
            rgba(10, 203, 202, 1),
            rgba(4, 156, 154, 0.2)
          )
          1 1;
                clip-path: inset(0 round 10px);
                filter: hue-rotate(360deg);
            }
@@ -312,25 +492,39 @@
                cursor: pointer;
                width: 160px;
                height: 170px;
                font-family: 'Source Han Sans CN Bold Bold';
        font-family: "Source Han Sans CN Bold Bold";
                font-weight: bold;
                font-size: 20px;
                color: #049C9A;
        color: #049c9a;
                display: flex;
                text-align: center;
                flex-direction: column;
                justify-content: center;
                line-height: 30px;
                background: #EFF8FA;
        background: #eff8fa;
                border-radius: 10px;
                border: 1px solid;
                clip-path: inset(0px round 10px);
                filter: hue-rotate(360deg);
                border-image: linear-gradient(180deg, rgba(220, 223, 230, 1), rgba(220, 223, 230, 1)) 1 1;
        border-image: linear-gradient(
            180deg,
            rgba(220, 223, 230, 1),
            rgba(220, 223, 230, 1)
          )
          1 1;
                &:hover {
                    background: linear-gradient(180deg, rgba(5, 160, 193, 0.4) 0%, rgba(5, 242, 194, 0) 100%);
                    border-image: linear-gradient(180deg, rgba(10, 203, 202, 1), rgba(4, 156, 154, 0.2)) 1 1;
          background: linear-gradient(
            180deg,
            rgba(5, 160, 193, 0.4) 0%,
            rgba(5, 242, 194, 0) 100%
          );
          border-image: linear-gradient(
              180deg,
              rgba(10, 203, 202, 1),
              rgba(4, 156, 154, 0.2)
            )
            1 1;
                    clip-path: inset(0 round 10px);
                    filter: hue-rotate(360deg);
                }
@@ -357,20 +551,20 @@
                    font-weight: 400;
                    font-size: 18px;
                    color: #606266;
                    background: #FAFAFC;
          background: #fafafc;
                    border-radius: 8px 8px 0px 0px;
                    border: 1px solid #DCDFE6;
          border: 1px solid #dcdfe6;
                    line-height: 50px;
                    min-width: 94px;
                    margin-bottom: 10px;
                }
                .activeName {
                    border: 1px solid #049C9A;
                    background: #FFFFFF;
          border: 1px solid #049c9a;
          background: #ffffff;
                    font-weight: bold;
                    font-size: 18px;
                    color: #049C9A;
          color: #049c9a;
                }
            }
@@ -379,14 +573,14 @@
                flex-wrap: wrap;
                div {
                    font-family: 'SourceHanSansCN-Medium';
          font-family: "SourceHanSansCN-Medium";
                    font-weight: 500;
                    font-size: 20px;
                    color: #FFFFFF;
          color: #ffffff;
                    text-align: center;
                    line-height: 40px;
                    flex: 1;
                    background: linear-gradient(270deg, #0ACBCA 0%, #049C9A 100%);
          background: linear-gradient(270deg, #0acbca 0%, #049c9a 100%);
                    box-shadow: 0px 6px 10px 0px rgba(4, 156, 154, 0.09);
                    border-radius: 10px;
                }
@@ -404,7 +598,7 @@
                    &>div {
                        padding-left: 23px;
                        font-family: 'SourceHanSansCN-Medium';
            font-family: "SourceHanSansCN-Medium";
                        flex: 1;
                        font-weight: 500;
                        font-size: 16px;
@@ -412,7 +606,7 @@
                        display: flex;
                        align-items: center;
                        min-height: 50px;
                        background: #D7EFF4;
            background: #d7eff4;
                        box-shadow: 0px 6px 10px 0px rgba(4, 156, 154, 0.09);
                        border-radius: 10px;
@@ -428,7 +622,6 @@
                            }
                        }
                    }
                }
            }
        }
laboratory/src/views/deliveryAssessment/projectTeamIntegral/index.vue
@@ -26,17 +26,21 @@
                </el-form>
            </template>
            <template #table>
                <el-table-column prop="name" label="项目组名称" />
                <el-table-column prop="age" label="项目组总积分" />
                <el-table-column prop="age" label="工艺工程师积分" />
                <el-table-column prop="age" label="化验师积分" />
                <el-table-column prop="age" label="实验员积分" />
                <el-table-column prop="age" label="评定开始时间" />
                <el-table-column prop="age" label="评定结束时间" />
                <el-table-column prop="age" label="状态" />
                <el-table-column prop="age" label="操作">
                <el-table-column prop="teamName" label="项目组名称" />
                <el-table-column prop="teamIntegral" label="项目组总积分" />
                <el-table-column prop="engineerIntegral" label="工艺工程师积分" />
                <el-table-column prop="chemistIntegral" label="化验师积分" />
                <el-table-column prop="testerIntegral" label="实验员积分" />
                <el-table-column prop="startTime" label="评定开始时间" />
                <el-table-column prop="endTime" label="评定结束时间" />
                <el-table-column prop="status" label="状态">
                    <template #default="{ row }">
                        <el-button @click="goDetail" type="text">详情</el-button>
                        <span>{{ formatStatus(row.status) }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作">
                    <template #default="{ row }">
                        <el-button @click="goDetail(row)" type="text">详情</el-button>
                    </template>
                </el-table-column>
            </template>
@@ -65,9 +69,10 @@
        }
    },
    methods: {
        goDetail() {
        goDetail(row) {
            this.$router.push({
                path: '/deliveryAssessment/projectTeamIntegral-detail'
                path: '/deliveryAssessment/projectTeamIntegral-detail',
                query: { id: row.id }
            })
        },
        handleCurrentChange(page) {
@@ -106,17 +111,22 @@
                params.startTime = this.value1[0]
                params.endTime = this.value1[1]
            } else {
                params.startTime = undefined
                params.endTime = undefined
                params.startTime = ''
                params.endTime = ''
            }
            try {
                const res = await pageList(params)
                this.tableData = res.records || []
                this.total = res.total || 0
                this.tableData = res.data.records || []
                this.total = res.data.total || 0
            } catch (e) {
                this.tableData = []
                this.total = 0
            }
        },
        formatStatus(status) {
            if (status === -1) return '草稿箱'
            if (status === 1) return '已提交'
            return '全部'
        }
    },
    mounted() {
laboratory/src/views/deliveryAssessment/projectTeamIntegral/service.js
@@ -4,3 +4,27 @@
export const pageList = (data) => {
    return axios.post('/api/t-result-work-evaluate/pageList', { ...data })
}
// 项查看详情-顶部数据
export const getDetailById = (data) => {
    return axios.get('/open/t-result-work-evaluate/getDetailById', { params:data })
}
// 查看详情-左侧数据-工艺工程师工作内容评定
export const getDetailByIdLeftOne = (data) => {
    return axios.get('/open/t-result-work-evaluate/getDetailByIdLeftOne', { params:data })
}
// 查看详情-左侧数据-化验师工作内容评定
export const getDetailByIdLeftTwo = (data) => {
    return axios.get('/open/t-result-work-evaluate/getDetailByIdLeftTwo', { params:data })
}
// 查看详情-左侧数据-实验员工作内容评定
export const getDetailByIdLeftThree = (data) => {
    return axios.get('/open/t-result-work-evaluate/getDetailByIdLeftThree', { params:data })
}
// 查询可评定的化验师
export const getEvaluateChemist = (data) => {
    return axios.get('/open/t-result-work-evaluate/getEvaluateChemist', { params:data })
}
// 查询可评定的实验员
export const getEvaluateTester = (data) => {
    return axios.get('/open/t-result-work-evaluate/getEvaluateTester', { params:data })
}
laboratory/src/views/deliveryAssessment/reportEvaluation/components/AssessmentDialog.vue
New file
@@ -0,0 +1,323 @@
<template>
  <el-dialog
    :visible.sync="dialogVisible"
    title="课题评定详情"
    width="70%"
    @close="handleClose"
  >
    <el-form
      :model="form"
      inline
      label-position="top"
      :rules="rules"
      ref="formRef"
    >
      <el-row :gutter="20">
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="报告编号" prop="reportNo" required>
            <el-input v-model="form.reportNo" disabled placeholder="自动生成" />
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="报告名称" prop="reportName">
            <el-input v-model="form.reportName" disabled placeholder="请输入" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <div class="content-box">
      <el-row :gutter="16">
        <el-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
          <div class="content-box-left">
            <div class="content-box-left-th">设立课题规则</div>
            <div
              class="content-box-left-body"
              :style="{ height: `calc(${$baseTableHeight()}px - 40px)` }"
            >
              1、根据可研报告、产品构思设计的工艺研究路线,一条工艺路线设立一个课题。如果一个课题中有多个化合物需要开发研究,则每个化合物作为一个分题;分题归集到该课题中,最终形成课题报告。不同课题报告中的分题不能重复使用。
              2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题
            </div>
          </div>
        </el-col>
        <el-col
          style="margin-top: 5px"
          :xs="24"
          :sm="24"
          :md="20"
          :lg="20"
          :xl="20"
        >
          <Table
            :total="0"
            :height="null"
            :data="criteriaList"
            show-summary
            :summary-method="getSummaries"
            :span-method="arraySpanMethod"
          >
            <el-table-column type="index" label="序号" width="80" />
            <el-table-column prop="criteria" label="创新型课题标准" />
            <el-table-column prop="fullScore" label="满分值" width="100" />
            <el-table-column label="评定分值" prop="score" width="200">
              <template #default="{ row }">
                <el-input-number
                  v-model="row.score"
                  :min="0"
                  :max="row.fullScore"
                  :step="1"
                  :disabled="type === 'detail'"
                />
              </template>
            </el-table-column>
            <el-table-column prop="rule" label="创新型课题报告评分规则">
              <template>
                <div>
                  <div>1、各分项评满分,应满足以下四项要求:</div>
                  <div>①分项内容:清晰、系统、完整,结构逻辑清晰,无缺项;</div>
                  <div>②团队工作运行顺畅、计划时间高效。</div>
                  <div>③工作结果完成度高。</div>
                  <div>④课题文档报告完成度高。</div>
                  <div>
                    2、某分项工作完成,但出现以下三种错误中的1种,则减1分:
                  </div>
                  <div>①有缺项、漏项;</div>
                  <div>②或不完整清晰;</div>
                  <div>③或工作效率人为拖延。</div>
                  <div>
                    3、某分项工作基本完成,但出现三种错误中的2-3种,则减2分:
                  </div>
                  <div>①有缺项、漏项;</div>
                  <div>②或不完整清晰;</div>
                  <div>③或工作效率人为拖延。</div>
                  <div>
                    4、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。
                  </div>
                </div>
              </template>
            </el-table-column>
          </Table>
        </el-col>
      </el-row>
    </div>
    <div class="assessed" v-if="evaluateInfo.status == 3">
      <div>评定时间:{{ evaluateInfo.evaluateTime || "" }}</div>
      <div>评定人:{{ evaluateInfo.evaluatePersonName || "" }}</div>
    </div>
    <template #footer>
      <span class="dialog-footer select-member-footer" v-if="type !== 'detail'">
        <el-button type="primary" @click="handleSubmit">提交评定结果</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script>
import { evaluateDetail, evaluate } from "../service.js";
export default {
  name: "AssessmentDialog",
  props: {
    modelValue: {
      type: Boolean,
      default: false,
    },
    id: {
      type: [String, Number],
      // required: true,
      default: () => "",
    },
    type: {
      type: String,
      default: "assessment",
    },
  },
  data() {
    return {
      dialogVisible: false,
      form: {
        reportNo: "",
        reportName: "",
      },
      evaluateInfo: {},
      rules: {
        reportName: [
          { required: true, message: "请输入报告名称", trigger: "blur" },
        ],
      },
      criteriaList: [
        {
          criteria:
            "课题名称依准确性、报告内容完整性:研究目标是否完整、是否研究工作内容合理性、是否围绕目标展开开、是否具有逻辑性和条理性",
          fullScore: 3,
          score: 0,
        },
        {
          criteria: "文献资料调查:全面性、系统性编辑逻辑顺畅,表达规范",
          fullScore: 2,
          score: 0,
        },
        {
          criteria:
            "专业/技术路线与方法:合理性、可行性;实验设计科学、能完成研究目标、方法完整、完整、可靠;",
          fullScore: 3,
          score: 0,
        },
        {
          criteria:
            "实验验证工作可行性强,团队工作调度支持实验设备、材料等条件的准备良好,时间计划合理,能效按时完成",
          fullScore: 2,
          score: 0,
        },
        {
          criteria:
            "实验设计合理性:①对照设置,重复次数,样本量足够。②变量控制:自变量控制,因变量测量,干扰因素分析识别;确保结果的准确性③验证结果解释分析:符合科学原理、逻辑严密、不存在漏洞。具有实际应用价值,解决了实际问题或实现了研究目的。",
          fullScore: 3,
          score: 0,
        },
        {
          criteria:
            "课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。",
          fullScore: 2,
          score: 0,
        },
      ],
    };
  },
  watch: {
    modelValue: {
      handler(val) {
        this.dialogVisible = val;
        if (val && this.id) {
          this.fetchDetail();
        }
      },
      immediate: true,
    },
    id(val) {
      if (this.modelValue && val) {
        this.fetchDetail();
      }
    },
  },
  methods: {
    async fetchDetail() {
      try {
        const res = await evaluateDetail({ id: this.id });
        if (res) {
          this.evaluateInfo = { ...res };
          this.form.reportNo = res.reportCode || "";
          this.form.reportName = res.reportName || "";
          // 详情回显分数
          if (res.evaluateScore) {
            if (
              this.type === "detail" &&
              typeof res.evaluateScore === "string"
            ) {
              const scoreArr = res.evaluateScore
                .split(",")
                .map((s) => Number(s));
              this.criteriaList.forEach((item, idx) => {
                item.score = scoreArr[idx] || 0;
              });
            }
          }
        }
      } catch (e) {
        this.$message && this.$message.error("获取详情失败");
      }
    },
    handleClose() {
      this.$emit("update:modelValue", false);
      this.$emit("close");
    },
    async handleSubmit() {
      try {
        // 拼接分数
        const evaluateScore = this.criteriaList
          .map((item) => item.score)
          .join(",");
        const params = {
          id: this.id,
          evaluateScore,
        };
        evaluate(params).then((res) => {
          if (res) {
            this.$message && this.$message.success("评定成功");
            this.handleClose();
          }
        });
      } catch (error) {
        this.$message && this.$message.error("评定失败");
      }
    },
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr);
            if (!isNaN(value)) {
              return prev + curr;
            } else {
              return prev;
            }
          }, 0);
          sums[index] += " 分";
        } else {
          sums[index] = "";
        }
      });
      return sums;
    },
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 4 && rowIndex == 0) {
        return {
          rowspan: 6,
          colspan: 1,
        };
      } else if (rowIndex !== 0 && columnIndex === 4) {
        return [0, 0];
      }
    },
  },
};
</script>
<style lang="less" scoped>
.content-box {
  &-left {
    margin-top: 5px;
    display: flex;
    flex-direction: column;
    border: 1px solid #ebeef5;
    border-radius: 8px 8px 0px 0px;
    font-size: 12px;
    &-th {
      line-height: 40px;
      background: #fafafa !important;
      color: #909399;
      padding: 0 10px;
      font-weight: bold;
    }
    &-body {
      padding: 0 10px;
      line-height: 23px;
    }
  }
}
.assessed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 25px;
  margin-top: 20px;
}
</style>
laboratory/src/views/deliveryAssessment/reportEvaluation/components/CraftDialog.vue
File was deleted
laboratory/src/views/deliveryAssessment/reportEvaluation/index.vue
@@ -1,115 +1,240 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="项目组名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="课题类型:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-select v-model="form.reportType" placeholder="请选择">
              <el-option label="可研报告" :value="1" />
              <el-option label="可行报告" :value="2" />
              <el-option label="工艺开发工具" :value="3" />
              <el-option label="验证与发布" :value="4" />
            </el-select>
                    </el-form-item>
                    <el-form-item label="课题名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="报告名称:">
            <el-input v-model="form.reportName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="提交人:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.staffNames" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="草稿箱" :value="-1" />
              <el-option label="待审核" :value="1" />
              <el-option label="待评定" :value="2" />
              <el-option label="已评定" :value="3" />
              <el-option label="已驳回" :value="4" />
              <el-option label="已撤回" :value="5" />
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-button @click="handleReset">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="top-box-integral">
                    <div style="background-color:rgba(232, 250, 246, 1)" v-for="item in 3" :key="item"
                        class="top-box-integral-card">
                        <div class="top-box-integral-card-title">{{ ['课题合计数量', '待评定', '已评定'][item - 1] }}</div>
                        <div style="color:rgba(4, 156, 154, 1)" class="top-box-integral-card-num">99.9</div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">课题合计数量</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.totalCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">待评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.toEvaluatedCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">已评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.evaluatedCount || 0 }}
            </div>
          </div>
        </div>
        <div class="tip-warring">
          <div>【注意】每个课题交付评分标准:</div>
          <div>
            1、课题由工程师/化验师设定,并清晰完整完成课题目标,评优秀3分;
          </div>
          <div>
            2、课题由工程师/化验师设定,并清晰完整完成课题目标,评优秀3分;
          </div>
          <div>
            3、课题由上级设定,工程师/化验师清晰完整完成课题目标,评正常2分;
          </div>
          <div>
            4、课题由上级设定,工程师/化验师只能阐述课题内容,无法延伸工作思路,无开发思维的运行能力、创新能力,无法实现专题目标,评失误0分;
                    </div>
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="课题类型" />
                <el-table-column prop="age" label="报告编号" />
                <el-table-column prop="age" label="报告名称" />
                <el-table-column prop="age" label="提交人" />
                <el-table-column prop="age" label="评定结果" />
                <el-table-column prop="age" label="累积分值" />
                <el-table-column prop="age" label="评定时间" />
                <el-table-column prop="age" label="状态">
        <el-table-column prop="teamName" label="所属项目组" />
        <el-table-column prop="reportType" label="课题类型">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
            <span v-if="row.reportType == 1">可研报告</span>
            <span v-else-if="row.reportType == 2">可行报告</span>
            <span v-else-if="row.reportType == 3">工艺开发工具</span>
            <span v-else-if="row.reportType == 4">验证与发布</span>
            <span v-else>--</span>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
        <el-table-column prop="reportCode" label="报告编号" />
        <el-table-column prop="reportName" label="报告名称" />
        <el-table-column prop="createBy" label="提交人" />
        <el-table-column prop="evaluatePersonName" label="评定人员" />
        <el-table-column prop="evaluateScore" label="评定分数" />
        <el-table-column prop="totalScore" label="累积分值" />
        <el-table-column prop="evaluateTime" label="评定时间" />
        <el-table-column prop="status" label="状态">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
                        <el-button type="text">评定</el-button>
            <el-tag v-if="row.status == 3" type="info" color="#fff"
              >已评定</el-tag
            >
            <el-tag v-else-if="row.status == 2" type="success">待评定</el-tag>
            <el-tag v-else-if="row.status == 1" type="warning">待审核</el-tag>
            <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag>
            <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag>
            <el-tag v-else type="default">草稿箱</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template #default="{ row }">
            <el-button type="text" @click="handleDetail(row)">详情</el-button>
            <el-button
              type="text"
              @click="handleAssessment(row)"
              v-if="row.status == 2"
              >评定</el-button
            >
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <!-- 审批人 -->
        <CraftDialog :modelValue="craftVisible" :reportData="currentReport" />
    <AssessmentDialog
      :modelValue="assessmentVisible"
      :id="currentId"
      :type="dialogType"
      @close="handleAssessmentSubmit"
      @submit="handleAssessmentSubmit"
    />
    </div>
</template>
<script>
import CraftDialog from './components/CraftDialog.vue'
import AssessmentDialog from "./components/AssessmentDialog.vue";
import { pageList, evaluateCount, evaluateDetail } from "./service.js";
export default {
    name: 'ReportEvaluation',
  name: "TaskList",
    components: {
        CraftDialog
    AssessmentDialog,
    },
    data() {
        return {
            form: {
            },
      form: {},
            tableData: [],
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
            total: 0,
            currentReport: {},
            craftVisible: false,
        }
      assessmentVisible: false,
      currentId: null,
      dialogType: '',
      statistics: {
        totalCount: 0,
        toEvaluatedCount: 0,
        evaluatedCount: 0,
      },
    };
    },
    methods: {
    async getList() {
      const params = { ...this.queryForm, ...this.form };
      const res = await pageList(params);
      if (res && res.data) {
        this.tableData = res.data.records || [];
        this.total = res.data.total || 0;
      }
    },
    async getStatistics() {
      const params = { ...this.queryForm, ...this.form };
      const res = await evaluateCount(params);
      if (res && res.data) {
        this.statistics = res.data;
      }
    },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
    handleSearch() {
      this.queryForm.pageNum = 1;
      this.getList();
      this.getStatistics();
    },
    handleReset() {
      this.form = {};
      this.queryForm = { pageSize: 10, pageNum: 1 };
      this.getList();
      this.getStatistics();
        },
        handleDetail(row) {
            // 处理详情
      this.currentId = row.id;
      this.dialogType = 'detail';
      this.assessmentVisible = true;
        },
        handleAssessment(row) {
            this.currentReport = row;
      this.currentId = row.id;
      this.dialogType = 'assessment';
            this.assessmentVisible = true;
        },
        handleAssessmentSubmit(data) {
            console.log('评定提交数据:', data);
            // 处理评定提交
        }
    }
}
      this.assessmentVisible=false;
      this.getList();
      this.getStatistics();
    },
  },
  mounted() {
    this.getList();
    this.getStatistics();
  },
};
</script>
<style scoped lang="less">
@@ -125,25 +250,30 @@
    &-card {
        flex: 1;
        background: #E8FAF6;
    background: #e8faf6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
      font-family: "SourceHanSansCN-Medium";
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
        }
        &-num {
            font-family: 'SF Compact Display Black';
      font-family: "SF Compact Display Black";
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
      color: #049c9a;
            line-height: 60px;
        }
    }
}
.tip-warring {
  margin-top: 20px;
  color: rgba(255, 73, 85, 1);
}
</style>
laboratory/src/views/deliveryAssessment/reportEvaluation/service.js
New file
@@ -0,0 +1,18 @@
import axios from '@/utils/request';
// 项目组总积分分页列表
export const pageList = (data) => {
    return axios.post('/api/t-feasibility-study-report/pageList', { ...data })
}
// 评定
export const evaluate = (data) => {
    return axios.put(`/open/t-feasibility-study-report/evaluate?id=${data.id}&evaluateScore=${data.evaluateScore}`, { params:data })
}
// 查看详情
export const evaluateDetail = (data) => {
    return axios.get('/open/t-feasibility-study-report/evaluateDetail', { params:data })
}
// 统计
export const evaluateCount = (data) => {
    return axios.post('/api/t-feasibility-study-report/evaluateCount', {...data })
}
laboratory/src/views/deliveryAssessment/restsTask/components/detail.vue
@@ -3,6 +3,7 @@
    :visible.sync="dialogVisible"
    :title="type === 'add' ? '新增其他任务' : '其他任务详情'"
    width="70%"
    @open='open'
    @close="handleClose"
  >
    <div class="content-box">
@@ -11,10 +12,10 @@
        <div>所属项目组</div>
      </div>
      <Table :data="criteriaList" :height="null">
        <el-table-column prop="name" label="项目组名称" />
        <el-table-column prop="name" label="项目负责人" />
        <el-table-column prop="name" label="项目组成员" />
        <el-table-column prop="name" label="创建时间" />
        <el-table-column prop="teamName" label="项目组名称" />
        <el-table-column prop="personCharge" label="项目负责人" />
        <el-table-column prop="staffName" label="项目组成员" />
        <el-table-column prop="createTime" label="创建时间" />
      </Table>
      <el-row>
@@ -37,14 +38,15 @@
              >
                <el-option
                  v-for="member in memberList"
                  :key="member.id"
                  :label="member.name"
                  :value="member.id"
                  :key="member.userId"
                  :label="member.nickName"
                  :value="member.userId"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="任务内容" prop="taskContent" required>
              <el-input
              type="textarea"
                v-model="form.taskContent"
                placeholder="请输入"
                :disabled="type === 'detail'"
@@ -61,6 +63,7 @@
            </el-form-item>
            <el-form-item label="评定积分" prop="score" required>
              <el-input
              type="number"
                v-model="form.score"
                placeholder="请输入"
                :disabled="type === 'detail'"
@@ -70,10 +73,15 @@
        </el-col>
      </el-row>
    </div>
    <template v-slot:footer>
      <el-button v-if="type === 'add'" type="primary" @click="handleSave">确认</el-button>
    </template>
  </el-dialog>
</template>
<script>
import {getDetailByUserId, add, update, getDetailById} from '../service.js'
import moment from 'moment'
export default {
  name: "Detail",
  props: {
@@ -81,9 +89,9 @@
      type: Boolean,
      default: false,
    },
    reportData: {
      type: Object,
      default: () => ({}),
    id: {
      type: String,
      default: () => (''),
    },
    type: {
      type: String,
@@ -94,10 +102,12 @@
    return {
      dialogVisible: false,
      form: {
        assignee: "",
        id: '',
        teamId: '',
        assignee: "", // 实际为 testerId
        taskContent: "",
        taskTime: "",
        score: "",
        score: "", // 实际为 evaluateScore
      },
      rules: {
        assignee: [
@@ -122,22 +132,61 @@
      },
      immediate: true,
    },
    reportData: {
      handler(val) {
        if (val) {
          this.form = {
            assignee: val.assignee || "",
            taskContent: val.taskContent || "",
            taskTime: val.taskTime || "",
            score: val.score || "",
          };
          this.memberList = val.memberList || [];
        }
      },
      immediate: true,
    },
  },
  methods: {
    open(){
      getDetailByUserId().then(res=>{
        this.criteriaList=[{...res}]
        this.memberList=res.staffs.filter(item => item.roleType == '5') || []
        this.form.teamId = res.id || ''
      })
      // 如果是详情,获取详情数据
      if(this.type === 'detail' && this.id){
        getDetailById({id: this.id}).then(res => {
          if(res && res){
            this.form = {
              id: res.id || '',
              teamId: res.teamId || '',
              assignee: res.testerId || '',
              taskContent: res.taskContent || '',
              taskTime: res.taskTime || '',
              score: res.evaluateScore || '',
            }
          }
        })
      } else if(this.type === 'add') {
        // 新增时清空表单
        this.form = {
          id: '',
          teamId: this.form.teamId,
          assignee: '',
          taskContent: '',
          taskTime: '',
          score: '',
        }
      }
    },
    handleSave() {
      this.$refs.formRef.validate(valid => {
        if (!valid) return;
        const params = {
          id: this.form.id,
          teamId: this.form.teamId,
          taskContent: this.form.taskContent,
          taskTime: this.form.taskTime ? moment(this.form.taskTime).format('YYYY-MM-DD HH:mm:ss') : '',
          testerId: this.form.assignee,
          evaluateScore: this.form.score,
        };
        const api = this.type === 'add' ? add : update;
        api(params).then(res => {
          if(res && res.code === 200){
            this.$message.success('保存成功');
            this.$emit('close');
            this.$emit('update:modelValue', false);
          }
        })
      })
    },
    handleClose() {
      this.$emit("update:modelValue", false);
    },
laboratory/src/views/deliveryAssessment/restsTask/index.vue
@@ -1,11 +1,11 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" :loading="loading" :height='null' @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="项目组名称:">
                        <el-input v-model="form.groupName" placeholder="请输入" />
                        <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="任务内容:">
                        <el-input v-model="form.taskContent" placeholder="请输入" />
@@ -21,17 +21,21 @@
                <el-button v-if="roleType==3" @click="handleAdd" class="el-icon-plus" type="primary">新增其他任务</el-button>
            </template>
            <template #table>
                <el-table-column :prop="'projectTeam.teamName'" label="所属项目组" />
                <el-table-column prop="projectTeam" label="所属项目组" >
                    <template #default="{ row }">
                        <el-tag v-if="row.teamName" type="info">{{ row.teamName }}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="taskContent" label="任务内容" />
                <el-table-column prop="taskTime" label="任务时间" />
                <el-table-column prop="testerName" label="添加人" />
                <el-table-column prop="createBy" label="添加人" />
                <el-table-column prop="evaluateScore" label="评定积分" />
                <el-table-column label="累计分数">
                  <template #default>
                    <!-- 累计分数接口未返回,留空或后端补充 -->
                  </template>
                </el-table-column>
                <el-table-column prop="evaluateTime" label="评定时间" />
                <el-table-column prop="createTime" label="评定时间" />
                <el-table-column label="操作">
                    <template #default="{ row }">
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
@@ -40,13 +44,13 @@
            </template>
        </TableCustom>
        <Detail :modelValue="assessmentVisible" :reportData="currentReport" :type="detailType" @close="assessmentVisible = false" />
        <Detail :modelValue="assessmentVisible" :type="detailType" :id="currentId" @close="closeDetail" />
    </div>
</template>
<script>
import Detail from './components/detail.vue'
import { pageList, getDetailById } from './service.js'
import { pageList } from './service.js'
export default {
    name: 'RestsTask',
@@ -66,8 +70,8 @@
            },
            total: 0,
            assessmentVisible: false,
            currentReport: {},
            detailType: 'detail',
            detailType: '',
            currentId: null,
            loading: false,
            roleType:'',
        }
@@ -109,29 +113,19 @@
            this.queryForm.pageNum = 1;
            this.getList();
        },
        closeDetail() {
            this.assessmentVisible = false;
            this.getList();
        },
        handleAdd() {
            this.currentReport = {
                assignee: '',
                taskContent: '',
                taskTime: '',
                score: '',
                memberList: [] // 这里需要你根据实际情况传入项目组成员
            };
            this.detailType = 'add';
            this.currentId = null;
            this.assessmentVisible = true;
        },
        handleDetail(row) {
            if (!row || !row.id) return;
            getDetailById({ id: row.id }).then(res => {
                if (res && res.data) {
                    this.currentReport = res.data;
                    this.detailType = 'detail';
                    this.assessmentVisible = true;
                }
            });
        },
        handleAssessment(row) {
            this.currentReport = row;
            this.currentId = row.id;
            this.assessmentVisible = true;
        },
    }
laboratory/src/views/deliveryAssessment/restsTask/service.js
@@ -20,3 +20,7 @@
export const getDetailById = (data) => {
    return axios.get('/open/t-tester-other-task/getDetailById', { params:data })
}
//查询项目组信息
export const getDetailByUserId = (data) => {
    return axios.get('/open/t-project-team/getDetailByUserId', { params:data })
}
laboratory/src/views/deliveryAssessment/taskList/components/AssessmentDialog.vue
@@ -1,6 +1,17 @@
<template>
    <el-dialog :visible.sync="dialogVisible" title="课题评定详情" width="70%" @close="handleClose">
        <el-form :model="form" inline label-position="top" :rules="rules" ref="formRef">
  <el-dialog
    :visible.sync="dialogVisible"
    title="课题评定详情"
    width="70%"
    @close="handleClose"
  >
    <el-form
      :model="form"
      inline
      label-position="top"
      :rules="rules"
      ref="formRef"
    >
            <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告编号" prop="reportNo" required>
@@ -9,7 +20,7 @@
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="报告名称" prop="reportName">
                        <el-input v-model="form.reportName" placeholder="请输入" />
            <el-input v-model="form.reportName" disabled placeholder="请输入" />
                    </el-form-item>
                </el-col>
            </el-row>
@@ -19,20 +30,43 @@
                <el-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
                    <div class="content-box-left">
                        <div class="content-box-left-th">设立课题规则</div>
                        <div class="content-box-left-body" :style="{ height: `calc(${$baseTableHeight()}px - 40px)` }">
            <div
              class="content-box-left-body"
              :style="{ height: `calc(${$baseTableHeight()}px - 40px)` }"
            >
                            1、根据可研报告、产品构思设计的工艺研究路线,一条工艺路线设立一个课题。如果一个课题中有多个化合物需要开发研究,则每个化合物作为一个分题;分题归集到该课题中,最终形成课题报告。不同课题报告中的分题不能重复使用。
                            2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题</div>
              2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题
            </div>
                    </div>
                </el-col>
                <el-col style="margin-top: 5px;" :xs="24" :sm="24" :md="20" :lg="20" :xl="20">
                    <Table :total="0" :height="null" :data="criteriaList" show-summary :summary-method="getSummaries"
                        :span-method="arraySpanMethod">
        <el-col
          style="margin-top: 5px"
          :xs="24"
          :sm="24"
          :md="20"
          :lg="20"
          :xl="20"
        >
          <Table
            :total="0"
            :height="null"
            :data="criteriaList"
            show-summary
            :summary-method="getSummaries"
            :span-method="arraySpanMethod"
          >
                        <el-table-column type="index" label="序号" width="80" />
                        <el-table-column prop="criteria" label="创新型课题标准" />
                        <el-table-column prop="fullScore" label="满分值" width="100" />
                        <el-table-column label="评定分值" prop="score" width="200">
                            <template #default="{ row }">
                                <el-input-number v-model="row.score" :min="0" :max="row.fullScore" :step="1" />
                <el-input-number
                  v-model="row.score"
                  :min="0"
                  :max="row.fullScore"
                  :step="1"
                  :disabled="type === 'detail'"
                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="rule" label="创新型课题报告评分规则">
@@ -43,15 +77,21 @@
                                    <div>②团队工作运行顺畅、计划时间高效。</div>
                                    <div>③工作结果完成度高。</div>
                                    <div>④课题文档报告完成度高。</div>
                                    <div>2、某分项工作完成,但出现以下三种错误中的1种,则减1分:</div>
                  <div>
                    2、某分项工作完成,但出现以下三种错误中的1种,则减1分:
                  </div>
                                    <div>①有缺项、漏项;</div>
                                    <div>②或不完整清晰;</div>
                                    <div>③或工作效率人为拖延。</div>
                                    <div>3、某分项工作基本完成,但出现三种错误中的2-3种,则减2分:</div>
                  <div>
                    3、某分项工作基本完成,但出现三种错误中的2-3种,则减2分:
                  </div>
                                    <div> ①有缺项、漏项;</div>
                                    <div>②或不完整清晰;</div>
                                    <div>③或工作效率人为拖延。</div>
                                    <div>4、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。</div>
                  <div>
                    4、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。
                  </div>
                                </div>
                            </template>
                        </el-table-column>
@@ -59,12 +99,12 @@
                </el-col>
            </el-row>
        </div>
        <div class="assessed">
            <div>评定时间:2025-2-20 11:08:00</div>
            <div>评定人:张三</div>
    <div class="assessed" v-if="evaluateInfo.status == 3">
      <div>评定时间:{{ evaluateInfo.evaluateTime || "" }}</div>
      <div>评定人:{{ evaluateInfo.evaluatePersonName || "" }}</div>
        </div>
        <template #footer>
            <span class="dialog-footer select-member-footer">
      <span class="dialog-footer select-member-footer" v-if="type !== 'detail'">
                <el-button type="primary" @click="handleSubmit">提交评定结果</el-button>
            </span>
        </template>
@@ -72,101 +112,140 @@
</template>
<script>
import { evaluateDetail, evaluate } from "../service.js";
export default {
    name: 'AssessmentDialog',
  name: "AssessmentDialog",
    props: {
        modelValue: {
            type: Boolean,
            default: false
      default: false,
        },
        reportData: {
            type: Object,
            default: () => { }
        }
    id: {
      type: [String, Number],
      required: true,
    },
    type: {
      type: String,
      default: "assessment",
    },
    },
    data() {
        return {
            dialogVisible: false,
            form: {
                reportNo: '',
                reportName: '',
        reportNo: "",
        reportName: "",
            },
      evaluateInfo: {},
            rules: {
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
          { required: true, message: "请输入报告名称", trigger: "blur" },
                ],
            },
            criteriaList: [
                {
                    criteria: '课题名称依准确性、报告内容完整性:研究目标是否完整、是否研究工作内容合理性、是否围绕目标展开开、是否具有逻辑性和条理性',
          criteria:
            "课题名称依准确性、报告内容完整性:研究目标是否完整、是否研究工作内容合理性、是否围绕目标展开开、是否具有逻辑性和条理性",
                    fullScore: 3,
                    score: 0,
                },
                {
                    criteria: '文献资料调查:全面性、系统性编辑逻辑顺畅,表达规范',
          criteria: "文献资料调查:全面性、系统性编辑逻辑顺畅,表达规范",
                    fullScore: 2,
                    score: 0,
                },
                {
                    criteria: '专业/技术路线与方法:合理性、可行性;实验设计科学、能完成研究目标、方法完整、完整、可靠;',
          criteria:
            "专业/技术路线与方法:合理性、可行性;实验设计科学、能完成研究目标、方法完整、完整、可靠;",
                    fullScore: 3,
                    score: 0,
                },
                {
                    criteria: '实验验证工作可行性强,团队工作调度支持实验设备、材料等条件的准备良好,时间计划合理,能效按时完成',
          criteria:
            "实验验证工作可行性强,团队工作调度支持实验设备、材料等条件的准备良好,时间计划合理,能效按时完成",
                    fullScore: 2,
                    score: 0,
                },
                {
                    criteria: '实验设计合理性:①对照设置,重复次数,样本量足够。②变量控制:自变量控制,因变量测量,干扰因素分析识别;确保结果的准确性③验证结果解释分析:符合科学原理、逻辑严密、不存在漏洞。具有实际应用价值,解决了实际问题或实现了研究目的。',
          criteria:
            "实验设计合理性:①对照设置,重复次数,样本量足够。②变量控制:自变量控制,因变量测量,干扰因素分析识别;确保结果的准确性③验证结果解释分析:符合科学原理、逻辑严密、不存在漏洞。具有实际应用价值,解决了实际问题或实现了研究目的。",
                    fullScore: 3,
                    score: 0,
                },
                {
                    criteria: '课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。',
          criteria:
            "课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。",
                    fullScore: 2,
                    score: 0,
                }
            ]
        }
        },
      ],
    };
    },
    watch: {
        modelValue: {
            handler(val) {
                this.dialogVisible = val;
            },
            immediate: true
        },
        reportData: {
            handler(val) {
                if (val) {
                    this.form.reportNo = val.reportNo || '';
                    this.form.reportName = val.reportName || '';
        if (val && this.id) {
          this.fetchDetail();
                }
            },
            immediate: true
      immediate: true,
    },
    id(val) {
      if (this.modelValue && val) {
        this.fetchDetail();
        }
    },
    },
    methods: {
    async fetchDetail() {
      try {
        const res = await evaluateDetail({ id: this.id });
        if (res) {
          this.evaluateInfo = { ...res };
          this.form.reportNo = res.reportCode || "";
          this.form.reportName = res.reportName || "";
          // 详情回显分数
          if (res.evaluateScore) {
            if (
              this.type === "detail" &&
              typeof res.evaluateScore === "string"
            ) {
              const scoreArr = res.evaluateScore
                .split(",")
                .map((s) => Number(s));
              this.criteriaList.forEach((item, idx) => {
                item.score = scoreArr[idx] || 0;
              });
            }
          }
        }
      } catch (e) {
        this.$message && this.$message.error("获取详情失败");
      }
    },
        handleClose() {
            this.$emit('update:modelValue', false);
      this.$emit("update:modelValue", false);
      this.$emit("close");
        },
        async handleSubmit() {
            try {
                await this.$refs.formRef.validate();
                const totalScore = this.criteriaList.reduce((sum, item) => sum + (item.score || 0), 0);
                const assessmentData = {
                    ...this.form,
                    totalScore,
                    criteriaScores: this.criteriaList.map(item => ({
                        criteria: item.criteria,
                        score: item.score || 0
                    }))
        // 拼接分数
        const evaluateScore = this.criteriaList
          .map((item) => item.score)
          .join(",");
        const params = {
          id: this.id,
          evaluateScore,
                };
                this.$emit('submit', assessmentData);
        evaluate(params).then((res) => {
          if (res) {
            this.$message && this.$message.success("评定成功");
                this.handleClose();
          }
        });
            } catch (error) {
                // 表单验证失败
        this.$message && this.$message.error("评定失败");
            }
        },
        getSummaries(param) {
@@ -174,11 +253,11 @@
            const sums = [];
            columns.forEach((column, index) => {
                if (index === 0) {
                    sums[index] = '合计';
          sums[index] = "合计";
                    return;
                }
                const values = data.map(item => Number(item[column.property]));
                if (!values.every(value => isNaN(value))) {
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
                    sums[index] = values.reduce((prev, curr) => {
                        const value = Number(curr);
                        if (!isNaN(value)) {
@@ -187,9 +266,9 @@
                            return prev;
                        }
                    }, 0);
                    sums[index] += ' 分';
          sums[index] += " 分";
                } else {
                    sums[index] = '';
          sums[index] = "";
                }
            });
            return sums;
@@ -198,30 +277,29 @@
            if (columnIndex === 4 && rowIndex == 0) {
                return {
                    rowspan: 6,
                    colspan: 1
                }
          colspan: 1,
        };
            } else if (rowIndex !== 0 && columnIndex === 4) {
                return [0, 0]
        return [0, 0];
            }
        }
    }
}
    },
  },
};
</script>
<style lang="less" scoped>
.content-box {
    &-left {
        margin-top: 5px;
        display: flex;
        flex-direction: column;
        border: 1px solid #EBEEF5;
    border: 1px solid #ebeef5;
        border-radius: 8px 8px 0px 0px;
        font-size: 12px;
        &-th {
            line-height: 40px;
            background: #FAFAFA !important;
      background: #fafafa !important;
            color: #909399;
            padding: 0 10px;
            font-weight: bold;
laboratory/src/views/deliveryAssessment/taskList/index.vue
@@ -1,42 +1,88 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="项目组名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.teamName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="课题类型:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-select v-model="form.reportType" placeholder="请选择">
              <el-option label="可研报告" :value="1" />
              <el-option label="可行报告" :value="2" />
              <el-option label="工艺开发工具" :value="3" />
              <el-option label="验证与发布" :value="4" />
            </el-select>
                    </el-form-item>
                    <el-form-item label="课题名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item label="报告名称:">
            <el-input v-model="form.reportName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="提交人:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.staffNames" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="草稿箱" :value="-1" />
              <el-option label="待审核" :value="1" />
              <el-option label="待评定" :value="2" />
              <el-option label="已评定" :value="3" />
              <el-option label="已驳回" :value="4" />
              <el-option label="已撤回" :value="5" />
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
            <el-button @click="handleReset">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="top-box-integral">
                    <div style="background-color:rgba(232, 250, 246, 1)" v-for="item in 3" :key="item"
                        class="top-box-integral-card">
                        <div class="top-box-integral-card-title">{{ ['课题合计数量', '待评定', '已评定'][item - 1] }}</div>
                        <div style="color:rgba(4, 156, 154, 1)" class="top-box-integral-card-num">99.9</div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">课题合计数量</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.totalCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">待评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.toEvaluatedCount || 0 }}
            </div>
          </div>
          <div
            style="background-color: rgba(232, 250, 246, 1)"
            class="top-box-integral-card"
          >
            <div class="top-box-integral-card-title">已评定</div>
            <div
              style="color: rgba(4, 156, 154, 1)"
              class="top-box-integral-card-num"
            >
              {{ statistics.evaluatedCount || 0 }}
            </div>
                    </div>
                </div>
                <div class="tip-warring">
                    <div>
                        【注意】每个课题交付评分标准:
                    </div>
          <div>【注意】每个课题交付评分标准:</div>
                    <div>
                        1、课题由工程师/化验师设定,并清晰完整完成课题目标,评优秀3分;
                    </div>
@@ -52,81 +98,143 @@
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="课题类型" />
                <el-table-column prop="age" label="报告编号" />
                <el-table-column prop="age" label="报告名称" />
                <el-table-column prop="age" label="提交人" />
                <el-table-column prop="age" label="评定结果" />
                <el-table-column prop="age" label="累积分值" />
                <el-table-column prop="age" label="评定时间" />
                <el-table-column prop="age" label="状态">
        <el-table-column prop="teamName" label="所属项目组" />
        <el-table-column prop="reportType" label="课题类型">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
            <span v-if="row.reportType == 1">可研报告</span>
            <span v-else-if="row.reportType == 2">可行报告</span>
            <span v-else-if="row.reportType == 3">工艺开发工具</span>
            <span v-else-if="row.reportType == 4">验证与发布</span>
            <span v-else>--</span>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
        <el-table-column prop="reportCode" label="报告编号" />
        <el-table-column prop="reportName" label="报告名称" />
        <el-table-column prop="createBy" label="提交人" />
        <el-table-column prop="evaluatePersonName" label="评定人员" />
        <el-table-column prop="evaluateScore" label="评定分数" />
        <el-table-column prop="totalScore" label="累积分值" />
        <el-table-column prop="evaluateTime" label="评定时间" />
        <el-table-column prop="status" label="状态">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
                        <el-button type="text">评定</el-button>
            <el-tag v-if="row.status == 3" type="info" color="#fff"
              >已评定</el-tag
            >
            <el-tag v-else-if="row.status == 2" type="success">待评定</el-tag>
            <el-tag v-else-if="row.status == 1" type="warning">待审核</el-tag>
            <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag>
            <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag>
            <el-tag v-else type="default">草稿箱</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template #default="{ row }">
            <el-button type="text" @click="handleDetail(row)">详情</el-button>
            <el-button
              type="text"
              @click="handleAssessment(row)"
              v-if="row.status == 2"
              >评定</el-button
            >
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <AssessmentDialog :modelValue="assessmentVisible" :reportData="currentReport"
            @submit="handleAssessmentSubmit" />
    <AssessmentDialog
      :modelValue="assessmentVisible"
      :id="currentId"
      :type="dialogType"
      @close="handleAssessmentSubmit"
      @submit="handleAssessmentSubmit"
    />
    </div>
</template>
<script>
import AssessmentDialog from './components/AssessmentDialog.vue'
import AssessmentDialog from "./components/AssessmentDialog.vue";
import { pageList, evaluateCount, evaluateDetail } from "./service.js";
export default {
    name: 'TaskList',
  name: "TaskList",
    components: {
        AssessmentDialog
    AssessmentDialog,
    },
    data() {
        return {
            form: {
            },
      form: {},
            tableData: [],
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
            total: 0,
            assessmentVisible: false,
            currentReport: {}
        }
      currentId: null,
      dialogType: '',
      statistics: {
        totalCount: 0,
        toEvaluatedCount: 0,
        evaluatedCount: 0,
      },
    };
    },
    methods: {
    async getList() {
      const params = { ...this.queryForm, ...this.form };
      const res = await pageList(params);
      if (res && res.data) {
        this.tableData = res.data.records || [];
        this.total = res.data.total || 0;
      }
    },
    async getStatistics() {
      const params = { ...this.queryForm, ...this.form };
      const res = await evaluateCount(params);
      if (res && res.data) {
        this.statistics = res.data;
      }
    },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
    handleSearch() {
      this.queryForm.pageNum = 1;
      this.getList();
      this.getStatistics();
    },
    handleReset() {
      this.form = {};
      this.queryForm = { pageSize: 10, pageNum: 1 };
      this.getList();
      this.getStatistics();
        },
        handleDetail(row) {
            // 处理详情
      this.currentId = row.id;
      this.dialogType = 'detail';
      this.assessmentVisible = true;
        },
        handleAssessment(row) {
            this.currentReport = row;
      this.currentId = row.id;
      this.dialogType = 'assessment';
            this.assessmentVisible = true;
        },
        handleAssessmentSubmit(data) {
            console.log('评定提交数据:', data);
            // 处理评定提交
        }
    }
}
      this.assessmentVisible=false;
      this.getList();
      this.getStatistics();
    },
  },
  mounted() {
    this.getList();
    this.getStatistics();
  },
};
</script>
<style scoped lang="less">
@@ -142,23 +250,23 @@
    &-card {
        flex: 1;
        background: #E8FAF6;
    background: #e8faf6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
      font-family: "SourceHanSansCN-Medium";
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
        }
        &-num {
            font-family: 'SF Compact Display Black';
      font-family: "SF Compact Display Black";
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
      color: #049c9a;
            line-height: 60px;
        }
    }
laboratory/src/views/deliveryAssessment/taskList/service.js
New file
@@ -0,0 +1,18 @@
import axios from '@/utils/request';
// 项目组总积分分页列表
export const pageList = (data) => {
    return axios.post('/api/t-feasibility-study-report/pageList', { ...data })
}
// 评定
export const evaluate = (data) => {
    return axios.put(`/open/t-feasibility-study-report/evaluate?id=${data.id}&evaluateScore=${data.evaluateScore}`, { params:data })
}
// 查看详情
export const evaluateDetail = (data) => {
    return axios.get('/open/t-feasibility-study-report/evaluateDetail', { params:data })
}
// 统计
export const evaluateCount = (data) => {
    return axios.post('/api/t-feasibility-study-report/evaluateCount', {...data })
}
laboratory/src/views/deliveryAssessment/technicianJobEvaluation/index.vue
@@ -1,49 +1,117 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="form"
      :tableData="tableData"
      :total="total"
      :height="null"
      @handlePageChange="handlePageChange"
      @handleSizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
        <el-form :model="form" labelWidth="auto" inline>
                    <el-form-item label="所属项目课题方案:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input
              v-model="form.projectName"
              placeholder="请输入"
            ></el-input>
                    </el-form-item>
                    <el-form-item label="实验编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input
              v-model="form.experimentCode"
              placeholder="请输入"
            ></el-input>
                    </el-form-item>
                    <el-form-item label="创建时间:">
                        <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始日期"
                            end-placeholder="结束日期">
                        </el-date-picker>
          <el-form-item label="实验名称:">
            <el-input
              v-model="form.experimentName"
              placeholder="请输入"
            ></el-input>
          </el-form-item>
          <el-form-item label="创建日期:">
            <el-date-picker
              v-model="dateRange"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd"
              @change="handleDateChange"
            ></el-date-picker>
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.status" placeholder="请选择">
                            <el-option label="是" value="1"></el-option>
                            <el-option label="否" value="0"></el-option>
              <el-option label="全部" value=""></el-option>
              <el-option label="待提交" :value="1"></el-option>
              <el-option label="待评定" :value="2"></el-option>
              <el-option label="已评定" :value="3"></el-option>
              <el-option label="已封存" :value="4"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
          <el-form-item label="">
            <el-button type="default" @click="resetForm">重置</el-button>
            <el-button
              type="primary"
              style="margin-left: 10px"
              @click="handleSearch"
              >查询</el-button
            >
                    </el-form-item>
                </el-form>
            </template>
      <template #setting>
        <div class="tableTitle">
          <div class="flex a-center">
            <div
              class="title active">
              实验结果汇报列表
            </div>
          </div>
        </div>
      </template>
            <template #table>
                <el-table-column prop="name" label="所属项目课题方案" />
                <el-table-column prop="age" label="实验编号" />
                <el-table-column prop="age" label="工艺工程师" />
                <el-table-column prop="age" label="化验师" />
                <el-table-column prop="age" label="实验员" />
                <el-table-column prop="age" label="创建日期" />
                <el-table-column prop="age" label="状态">
                    <template #default="{ row }">
                        <span :style="{ color: ['green', 'red'][row.status - 1] }">{{ ['是', '否'][row.status - 1]
                            }}</span>
        <el-table-column
          prop="projectName"
          label="所属项目课题方案"
        ></el-table-column>
        <el-table-column
          prop="experimentCode"
          label="实验编号"
        ></el-table-column>
        <el-table-column
          prop="experimentName"
          label="实验名称"
        ></el-table-column>
        <el-table-column
          prop="processEngineerName"
          label="工艺工程师"
        ></el-table-column>
        <el-table-column
          prop="laboratoryChemistName"
          label="化验师"
        ></el-table-column>
        <el-table-column
          prop="experimenterName"
          label="实验员"
        ></el-table-column>
        <el-table-column
          prop="createTime"
          label="创建日期"
          width="180"
        ></el-table-column>
        <el-table-column prop="status" label="状态">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.status)">
              {{ getStatusText(scope.row.status) }}
            </el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                    <template #default="{ row }">
                        <el-button type="text">详情</el-button>
                        <el-button type="text">评定</el-button>
        <el-table-column label="操作" width="180">
          <template slot-scope="scope">
            <el-button type="text" @click="handleDetail(scope.row.id)"
              >详情</el-button
            >
                    </template>
                </el-table-column>
            </template>
@@ -53,83 +121,154 @@
</template>
<script>
import { getList} from "./service";
export default {
    name: 'TechnicianJobEvaluation',
    components: {
    },
  name: "TestResultReport",
    data() {
        return {
            form: {
            },
            tableData: [],
            queryForm: {
        projectName: "",
        experimentCode: "",
        experimentName: "",
        startTime: "",
        endTime: "",
        status: "",
        pageNum: 1,
                pageSize: 10,
                pageNum: 1
            },
      dateRange: [],
      tableData: [],
            total: 0,
        }
    };
  },
  created() {
    this.getTableData();
    },
    methods: {
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
    resetForm() {
      this.form = {
        projectName: "",
        experimentCode: "",
        experimentName: "",
        startTime: "",
        endTime: "",
        status: "",
        pageNum: 1,
        pageSize: 10,
      };
      this.dateRange = [];
      this.getTableData();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
    handleSearch() {
      this.getTableData();
        },
        getList() {
    handleDetail(id) {
      this.$router.push({
        path: "/dataManagement/testResultReport/detail",
        query: {
          id: id,
          type: "view",
        },
        handleDetail(row) {
            // 处理详情
      });
        },
        handleAssessment(row) {
            this.currentReport = row;
            this.assessmentVisible = true;
        },
    getTableData() {
      const params = {
        ...this.form,
      };
      getList(params)
        .then((res) => {
          if (res.code === 200) {
            this.tableData = res.data.records || [];
            this.total = res.data.total || 0;
          } else {
            this.$message.error(res.msg || "获取数据失败");
    }
        })
        .catch(() => {
          this.$message.error("获取数据失败");
        });
    },
    handleDateChange(val) {
      if (val) {
        this.form.startTime = val[0];
        this.form.endTime = val[1];
      } else {
        this.form.startTime = "";
        this.form.endTime = "";
}
    },
    getStatusType(status) {
      const statusMap = {
        "-1": "info",
        1: "warning",
        2: "warning",
        3: "success",
        4: "info",
        5: "warning",
      };
      return statusMap[status] || "info";
    },
    getStatusText(status) {
      const statusMap = {
        "-1": "草稿箱",
        1: "待提交",
        2: "待评定",
        3: "已评定",
        4: "已封存",
        5: "已解封",
      };
      return statusMap[status] || "未知";
    },
    handlePageChange(pageNum) {
      this.form.pageNum = pageNum;
      this.getTableData();
    },
    handleSizeChange(pageSize) {
      this.form.pageSize = pageSize;
      this.getTableData();
    },
  },
};
</script>
<style scoped lang="less">
.list {
    height: 100%;
}
.top-box-integral {
.flex {
    display: flex;
  align-items: center;
}
.tableTitle {
  display: flex;
  padding-bottom: 20px;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 28px;
    &-card {
        flex: 1;
        background: #E8FAF6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
  align-items: center;
  .title,
  .drafts {
    background: #fafafc;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #dcdfe6;
    padding: 16px 29px;
    font-size: 18px;
    color: #606266;
    cursor: pointer;
    font-weight: 400;
        }
        &-num {
            font-family: 'SF Compact Display Black';
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
            line-height: 60px;
  .title {
    padding: 16px 29px;
        }
  .drafts {
    padding: 16px 65px;
    margin-left: 16px;
    }
  .active {
    color: #049c9a;
    background: #ffffff;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #049c9a;
    font-weight: bold;
}
.tip-warring {
    margin-top: 20px;
    color: rgba(255, 73, 85, 1);
}
</style>
laboratory/src/views/deliveryAssessment/technicianJobEvaluation/service.js
New file
@@ -0,0 +1,6 @@
import axios from '@/utils/request';
// 列表
export const getList = (data) => {
  return axios.post('/api/t-experiment-result-report/pageList', { ...data })
}
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/add.vue
@@ -1,80 +1,270 @@
<template>
    <Card>
        <template>
            <div class="header-title" style="margin-bottom: 18px;">
      <div class="header-title" style="margin-bottom: 18px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>所属实验调度</div>
                </div>
                <el-button class="el-icon-plus" type="primary" @click="showScheduling = true"> 选择实验调度</el-button>
        <el-button
          class="el-icon-plus"
          type="primary"
          v-if="isEdit"
          @click="showScheduling = true"
        >
          选择实验调度</el-button
        >
            </div>
            <Table :tableData="tableData" :total="total" :height="null">
      <Table :data="tableData" :total="0" :height="null">
                <template>
                    <el-table-column prop="planCode" label="所属项目课题方案"></el-table-column>
                    <el-table-column prop="planName" label="实验编号"></el-table-column>
                    <el-table-column prop="planName" label="实验名称"></el-table-column>
                    <el-table-column prop="stage" label="通知时间"></el-table-column>
                    <el-table-column prop="stage" label="实验开始时间"></el-table-column>
                    <el-table-column prop="stage" label="实验结束时间"></el-table-column>
                    <el-table-column prop="stage" label="参加人员"></el-table-column>
                    <el-table-column prop="creator" label="状态"></el-table-column>
          <el-table-column
            type="index"
            label="序号"
            width="80"
          ></el-table-column>
          <el-table-column
            prop="projectName"
            label="所属项目课题方案"
          ></el-table-column>
          <el-table-column
            prop="experimentCode"
            label="实验编号"
          ></el-table-column>
          <el-table-column
            prop="experimentName"
            label="实验名称"
          ></el-table-column>
          <el-table-column
            prop="experimentDate"
            label="通知时间"
          ></el-table-column>
          <el-table-column
            prop="experimentStartTime"
            label="实验开始时间"
          ></el-table-column>
          <el-table-column
            prop="experimentEndTime"
            label="实验结束时间"
          ></el-table-column>
          <el-table-column
            prop="participantsName"
            label="参加人员"
          ></el-table-column>
          <el-table-column prop="status" label="状态">
            <template slot-scope="scope">
              <el-tag :type="getStatusType(scope.row.status)">
                {{ getStatusText(scope.row.status) }}
              </el-tag>
            </template>
          </el-table-column>
                </template>
            </Table>
            <div class="header-title" style="margin-top: 60px;">
      <div class="header-title" style="margin-top: 60px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>被评定实验员</div>
                </div>
                <el-button class="el-icon-plus" type="primary" @click="addMember"> 选择实验员</el-button>
        <el-button
          class="el-icon-plus"
          v-if="isEdit"
          type="primary"
          @click="addMember"
        >
          选择实验员</el-button
        >
            </div>
            <div class="member-list">
                <div class="member-list-card">
                    <div class="member-item">
                        <div class="member-title">实验员</div>
                        <div class="member-name-box-2">
                            <div v-for="i in [1, 2, 3, 4, 5, 6, 7, 8]" :key="i" class="member-name">张三</div>
              <div
                v-for="i in selectedParticipants"
                :key="i.id"
                class="member-name"
              >
                {{ i.nickName }}
                        </div>
                        <div class="member-edit" @click="addMember">修改</div>
            </div>
            <div class="member-edit" @click="handleEditMember" v-if="isEdit">
              修改
                    </div>
                </div>
            </div>
            <div class="header-title" style="margin-bottom: 18px;margin-top: 60px;">
      </div>
      <div class="header-title" style="margin-bottom: 18px; margin-top: 60px">
                <div class="header-title-left">
                    <img src="@/assets/public/headercard.png" />
                    <div>工作标准评定</div>
                </div>
            </div>
            <EvaluateTable :type="2" />
      <EvaluateTable :type="2" ref="evaluateTable" />
            <div class="add-project-footer">
                <el-button type="primary">保存</el-button>
                <el-button>存草稿</el-button>
        <el-button type="primary" @click="submitForm()">保存</el-button>
        <!-- <el-button>存草稿</el-button> -->
            </div>
        </template>
        <SelectMember ref="selectMember" />
        <ExperimentalScheduling :show="showScheduling" />
    <SelectMemberSimple
      ref="selectMember"
      @submit="handleMemberSubmit"
      roleType="5"
    />
    <ExperimentalScheduling
      :show="showScheduling"
      @submit="handleSchedulingSubmit"
      @close="handleSchedulingClose"
    />
    </Card>
</template>
<script>
import ExperimentalScheduling from "@/views/dataManagement/confirmation-sheet/components/experimental-scheduling";
import SelectMemberSimple from "@/components/SelectMemberSimple/index.vue";
import ExperimentalScheduling from "@/views/dataManagement/schemeManagement/components/experimental-scheduling";
import { getEvaluateChemist, add } from "./service.js";
import moment from "moment";
export default {
    name: 'AddTesterWorkerEvaluate',
  name: "AddTesterWorkerEvaluate",
    components: {
        ExperimentalScheduling,
    SelectMemberSimple,
    },
    data() {
        return {
            showScheduling: false,
      participantsData: [],
      selectedParticipants: [],
      tableData: [],
      isEdit: true, // 是否为编辑模式
      // 状态映射表
      statusTypeMap: {
        "-1": "info",
        1: "warning",
        2: "success",
        3: "info",
      },
      statusTextMap: {
        "-1": "草稿箱",
        1: "待确认",
        2: "已确认",
        3: "已封存",
      },
    };
  },
  async created() {
    // const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
    // this.userRole = userInfo.roleType || "";
    // 检查是否为编辑模式
    this.participantsData = [];
    this.selectedParticipants = [];
    this.tableData = [];
    this.isEdit = true; // 是否为编辑模式
    if (this.$route.query.id) {
      this.isEdit = this.$route.query.type === "view" ? false : true;
      this.editId = this.$route.query.id;
      await this.loadEditData();
        }
    },
    methods: {
        submitForm() {
    handleSchedulingClose() {
      this.showScheduling = false;
        },
    handleSchedulingSubmit(data) {
      console.log("data data", data);
      this.tableData = data || [];
      if (data && data.length > 0 && data[0].id) {
        getEvaluateChemist({ dispatchId: data[0].id })
          .then((res) => {
            console.log("获取参加人员列表:", res);
            if (res) {
              this.participantsData = res.map((item) => {
                return {
                  ...item,
                  roleType: 5,
                };
              });
            } else {
              this.$message.error(res.msg || "获取参加人员列表失败");
            }
          })
          .catch((err) => {
            this.$message.error("获取参加人员列表失败");
            console.error("获取参加人员列表失败:", err);
          });
      }
    },
    getStatusType(status) {
      return this.statusTypeMap[status] || "info";
    },
    getStatusText(status) {
      return this.statusTextMap[status] || "未知";
    },
    handleEditMember() {
      this.$refs.selectMember.open(
        this.participantsData,
        this.selectedParticipants
      );
    },
    // ===== 人员相关方法 =====
        addMember() {
            this.$refs.selectMember.open()
      if (this.tableData.length == 0) {
        this.$message.error("请先选择所属实验调度");
        return;
      }
      this.$refs.selectMember.open(this.participantsData, []);
        },
    handleMemberSubmit(selectedMembers) {
      this.selectedParticipants = selectedMembers;
      this.$refs.selectMember.close();
    },
    // 将分数转换为评定值
    getEvaluateValue(score) {
      // 2分 = 良好(1), 1分 = 正确(2), 0分 = 失误(3)
      const scoreMap = {
        2: 1, // 良好
        1: 2, // 正确
        0: 3, // 失误
      };
      return scoreMap[score] || 3; // 默认返回失误
    },
    submitForm() {
      const evaluateTable = this.$refs.evaluateTable;
      if (!evaluateTable) {
        this.$message.warning("评价表格未加载完成");
        return;
    }
      const activeIndex = evaluateTable.activeIndex;
      const evaluateData = {
        evaluateOne: this.getEvaluateValue(activeIndex[0].score),
        evaluateTwo: this.getEvaluateValue(activeIndex[1].score),
        evaluateThree: this.getEvaluateValue(activeIndex[2].score),
        evaluateFour: this.getEvaluateValue(activeIndex[3].score),
        evaluateFive: this.getEvaluateValue(activeIndex[4].score),
        evaluateSix: this.getEvaluateValue(activeIndex[5].score),
        evaluateTime: moment().format("YYYY-MM-DD HH:mm:ss"),
        resultEvaluateJson: JSON.stringify(activeIndex),
        dispatchId: this.tableData[0]?.id,
        evaluateType: 3,
        userId: this.selectedParticipants[0].userId,
        dispatchId: this.tableData[0]?.id,
        status: 1,
      };
      console.log("11111111111", evaluateTable.activeIndex);
      console.log("2222222222222222", evaluateData);
      add(evaluateData).then((res) => {
        if (res.code == 200) {
          this.$message.success("保存成功");
          this.$router.back();
        } else {
          this.$message.error(res.msg || "保存失败");
}
      });
    },
  },
};
</script>
<style scoped lang="less">
@@ -104,11 +294,11 @@
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: 'Source Han Sans CN Bold Bold';
      font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: '*';
                color: #F56C6C;
        content: "*";
        color: #f56c6c;
                margin-right: 4px;
            }
        }
@@ -126,8 +316,12 @@
        width: 340px;
        height: 400px;
        border-radius: 8px;
        border: 1px solid #DCDFE6;
        background: linear-gradient(to bottom, rgba(255, 77, 79, 0.20) 0%, rgba(255, 242, 194, 0) 70%);
    border: 1px solid #dcdfe6;
    background: linear-gradient(
      to bottom,
      rgba(255, 77, 79, 0.2) 0%,
      rgba(255, 242, 194, 0) 70%
    );
        .member-item {
            height: 100%;
@@ -137,7 +331,7 @@
            .member-title {
                margin-top: 20px;
                width: 100%;
                font-family: 'Source Han Sans CN Bold Bold';
        font-family: "Source Han Sans CN Bold Bold";
                font-weight: bold;
                font-size: 16px;
                color: rgba(0, 0, 0, 0.8);
@@ -159,13 +353,13 @@
            .member-name {
                width: 60px;
                height: 60px;
                background: #7D8B79;
        background: #7d8b79;
                border-radius: 50%;
                text-align: center;
                line-height: 60px;
                font-weight: 500;
                font-size: 16px;
                color: #FFFFFF;
        color: #ffffff;
            }
            .member-edit {
@@ -176,12 +370,12 @@
                transform: translateX(-50%);
                font-weight: 400;
                font-size: 12px;
                color: #FF4D4F;
        color: #ff4d4f;
                line-height: 22px;
                width: 40px;
                background: #FFF1F0;
        background: #fff1f0;
                border-radius: 4px;
                border: 1px solid #FFCCC7;
        border: 1px solid #ffccc7;
                text-align: center;
            }
        }
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/index.vue
@@ -5,54 +5,48 @@
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="所属项目课题方案:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.projectName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="实验编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.experimentNo" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="实验名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
                        <el-input v-model="form.experimentName" placeholder="请输入" />
                    </el-form-item>
                    <el-form-item label="评定时间:">
                        <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始日期"
                        <el-date-picker v-model="form.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
                            end-placeholder="结束日期">
                        </el-date-picker>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
                        <el-button @click="handleReset">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-form>
            </template>
            <template #setting>
                <div class="tableTitle">
                    <div class="flex a-center">
                        <div class="title" :class="{ active: currentType === 'list' }"
                            @click="handleTypeChange('list')">
                        <div class="title active" >
                            实验员工作评定列表</div>
                        <div class="drafts" :class="{ active: currentType === 'draft' }"
                            @click="handleTypeChange('draft')">草稿箱</div>
                    </div>
                    <el-button @click="handleAdd" class="el-icon-plus" type="primary">
                        新增实验员工作评定</el-button>
                </div>
            </template>
            <template #table>
                <el-table-column prop="name" label="所属项目组" />
                <el-table-column prop="age" label="检测项名称" />
                <el-table-column prop="age" label="检测项编号" />
                <el-table-column prop="age" label="备注" />
                <el-table-column prop="age" label="创建人" />
                <el-table-column prop="age" label="创建时间" />
                <el-table-column prop="age" label="状态">
                <el-table-column prop="teamName" label="所属项目课题方案" />
                <el-table-column prop="experimentCode" label="实验编号" />
                <el-table-column prop="experimentName" label="实验名称" />
                <el-table-column prop="chemistName" label="被评定实验员" />
                <el-table-column prop="chemistIntegral" label="评定分数" />
                <el-table-column prop="evaluateTime" label="评定时间" />
                <el-table-column label="操作" width="180">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                        <el-tag v-else type="success">待评定</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                    <template #default="{ row }">
                        <el-button type="text" @click="assessmentVisible = true">详情</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleEdit(row)">编辑</el-button>
                        <el-button type="text" style="color: #1890ff" @click="handleDelete(row)">删除</el-button>
                    </template>
                </el-table-column>
            </template>
@@ -61,13 +55,17 @@
</template>
<script>
import { chemistEvaluateList } from './service'
export default {
    name: 'TesterWorkerEvaluate',
    data() {
        return {
            currentType: 'list', // 当前显示类型:list-列表,draft-草稿箱
            form: {
                projectName: '',
                experimentNo: '',
                experimentName: '',
                dateRange: []
            },
            tableData: [],
            queryForm: {
@@ -75,14 +73,52 @@
                pageNum: 1
            },
            total: 0,
            loading: false
        }
    },
    methods: {
        handleAdd() {
            this.$router.push({
                path: '/deliveryAssessment/addTesterWorkerEvaluate'
        async getList() {
            this.loading = true
            const params = {
                ...this.queryForm,
                projectName: this.form.projectName,
                experimentNo: this.form.experimentNo,
                experimentName: this.form.experimentName,
                startTime: this.form.dateRange && this.form.dateRange[0] ? this.form.dateRange[0] : '',
                endTime: this.form.dateRange && this.form.dateRange[1] ? this.form.dateRange[1] : ''
            }
            try {
                const res = await chemistEvaluateList(params)
                this.tableData = (res.data?.records || []).map(item => {
                  let score = '';
                  try {
                    const json = typeof item.resultEvaluateJson === 'string'
                      ? JSON.parse(item.resultEvaluateJson)
                      : item.resultEvaluateJson;
                    score = json?.score || '';
                  } catch (e) {}
                  return { ...item, score };
            })
                this.total = res.data?.total || 0
            } finally {
                this.loading = false
            }
        },
        handleSearch() {
            this.queryForm.pageNum = 1
            this.getList()
        },
        handleReset() {
            this.form = {
                projectName: '',
                experimentNo: '',
                experimentName: '',
                dateRange: []
            }
            this.queryForm.pageNum = 1
            this.getList()
        },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
@@ -91,13 +127,24 @@
            this.queryForm.pageSize = size
            this.getList()
        },
        getList() {
        handleAdd() {
            this.$router.push({
                path: '/deliveryAssessment/addTesterWorkerEvaluate'
            })
        },
        handleDetail(row) {
            // 详情逻辑后续补充
        },
        handleEdit(row) {
            // 编辑逻辑后续补充
        },
        handleDelete(row) {
            // 删除逻辑后续补充
        }
        },
        handleTypeChange(type) {
            this.currentType = type;
            this.getList();
        },
    mounted() {
        this.getList()
    }
}
</script>
laboratory/src/views/deliveryAssessment/testerWorkerEvaluate/service.js
@@ -1,22 +1,29 @@
import axios from '@/utils/request';
// 项目组总积分分页列表
export const pageList = (data) => {
// 获取化验师工作评定分页列表
export const chemistEvaluateList = (data) => {
    return axios.post('/api/t-result-work-evaluate/testerEvaluateList', { ...data })
}
export const add = (data) => {
    return axios.post('/api/t-result-work-evaluate/add', { ...data })
}
export const update = (data) => {
    return axios.post('/api/t-tester-other-task/update', { ...data })
export const getEvaluateChemist = (data) => {
    return axios.get('/open/t-result-work-evaluate/getEvaluateTester', { params:data })
}
export const deleteById = (data) => {
    return axios.delete('/open/t-tester-other-task/deleteById', { params:data })
}
export const deleteByIds = (data) => {
    return axios.delete('/open/t-tester-other-task/deleteByIds', { params:data })
}
export const getDetailById = (data) => {
    return axios.delete('/open/t-tester-other-task/getDetailById', { params:data })
}
// export const getEvaluateChemist = (data) => {
//     return axios.get('/open/t-result-work-evaluate/getEvaluateTester', { params:data })
//   }
// export const update = (data) => {
//     return axios.post('/api/t-tester-other-task/update', { ...data })
// }
// export const deleteById = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteById', { params:data })
// }
// export const deleteByIds = (data) => {
//     return axios.delete('/open/t-tester-other-task/deleteByIds', { params:data })
// }
laboratory/src/views/deliveryAssessment/testingAndEvaluation/components/AssessmentDialog.vue
@@ -1,6 +1,17 @@
<template>
    <el-dialog :visible.sync="dialogVisible" title="检测项评定详情" width="70%" @close="handleClose">
        <el-form :model="form" inline label-position="top" :rules="rules" ref="formRef">
  <el-dialog
    :visible.sync="dialogVisible"
    :title="type === 'detail' ? '检测项评定详情' : '检测项评定'"
    width="70%"
    @close="handleClose"
  >
    <el-form
      :model="form"
      inline
      label-position="top"
      :rules="rules"
      ref="formRef"
    >
            <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="检测项编号" prop="reportNo" required>
@@ -9,33 +20,56 @@
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                    <el-form-item label="检测项名称" prop="reportName">
                        <el-input v-model="form.reportName" placeholder="请输入" />
            <el-input v-model="form.reportName" disabled placeholder="请输入" />
                    </el-form-item>
                </el-col>
            </el-row>
        </el-form>
        <div class="content-box">
            <el-row :gutter="16">
                <el-col style="margin-top: 5px;" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
                    <Table :total="0" :height="null" :data="criteriaList" show-summary :summary-method="getSummaries"
                        :span-method="arraySpanMethod">
        <el-col
          style="margin-top: 5px"
          :xs="24"
          :sm="24"
          :md="24"
          :lg="24"
          :xl="24"
        >
          <Table
            :total="0"
            :height="null"
            :data="criteriaList"
            show-summary
            :summary-method="getSummaries"
            :span-method="arraySpanMethod"
          >
                        <el-table-column type="index" label="序号" width="80" />
                        <el-table-column prop="criteria" label="规程型课题评定标准" />
                        <el-table-column prop="fullScore" label="满分值" width="100" />
                        <el-table-column label="评定分值" prop="score" width="200">
                            <template #default="{ row }">
                                <el-input-number v-model="row.score" :min="0" :max="row.fullScore" :step="1" />
                <el-input-number
                  v-model="row.score"
                  :min="0"
                  :max="row.fullScore"
                  :step="1"
                  :disabled="type === 'detail'"
                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="rule" label="创新型课题报告评分规则">
                            <template>
                                <div>
                                    <div>1、规程型课题评定总分的满分为5分。</div>
                                    <div>2、某分项工作完成,但出现以下三种错误中的1种,则减1分:</div>
                  <div>
                    2、某分项工作完成,但出现以下三种错误中的1种,则减1分:
                  </div>
                                    <div>①有缺项、漏项;</div>
                                    <div>②或不完整清晰;</div>
                                    <div>③或工作效率人为拖延。</div>
                                    <div>3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。</div>
                  <div>
                    3、不能完成某分项的全部工作,或课题不涉及该分项内容,则该分项评0分。
                  </div>
                                </div>
                            </template>
                        </el-table-column>
@@ -44,98 +78,146 @@
            </el-row>
        </div>
        <!-- 化验师 审批人 -->
        <div class="assessed">
            <div>评定时间:2025-2-20 11:08:00</div>
            <div>评定人:张三</div>
    <div class="assessed" v-if="evaluateInfo.status == 3">
      <div>评定时间:{{ evaluateInfo.evaluateTime }}</div>
      <div>评定人:{{ evaluateInfo.evaluatePersonName }}</div>
        </div>
        <!-- 工艺工程师 -->
        <!-- <template #footer>
    <template #footer v-if="evaluateInfo.status === 2 && type=='approve'">
            <span class="select-member-footer">
                <el-button type="primary">提交评定结果</el-button>
        <el-button type="primary" @click="handleSubmit">提交评定结果</el-button>
            </span>
        </template> -->
    </template>
    </el-dialog>
</template>
<script>
import { getDetail, evaluate } from "../service.js";
export default {
    name: 'AssessmentDialog',
  name: "AssessmentDialog",
    props: {
        modelValue: {
            type: Boolean,
            default: false
      default: false,
        },
        reportData: {
            type: Object,
            default: () => { }
        }
      default: () => {},
    },
    id: {
      type: [String, Number],
      required: true,
    },
    type: {
      type: String,
      default: "detail", // 'detail' 或 'evaluate'
    },
    },
    data() {
        return {
            dialogVisible: false,
            form: {
                reportNo: '',
                reportName: '',
        reportNo: "",
        reportName: "",
            },
            rules: {
                reportName: [
                    { required: true, message: '请输入报告名称', trigger: 'blur' }
          { required: true, message: "请输入报告名称", trigger: "blur" },
                ],
            },
            criteriaList: [
                {
                    criteria: '文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范',
          criteria: "文献资料调查:全面性,系统性 编辑逻辑清晰,表达规范",
                    fullScore: 1,
                    score: 0,
                },
                {
                    criteria: '专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;',
          criteria:
            "专业/技术路线与方法:合理性、可行性;实验设计科学、能实现研究目标,方法先进、完整、可靠;",
                    fullScore: 2,
                    score: 0,
                },
                {
                    criteria: '课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。',
          criteria:
            "课题报告完成度高,预期研究结果果是否具有技术价值和应用价值。风险识别:识别了潜在的技术风险、市场风险和管理风险。",
                    fullScore: 3,
                    score: 0,
                },
            ]
        }
      ],
      evaluateInfo: {},
    };
    },
    watch: {
        modelValue: {
            handler(val) {
                this.dialogVisible = val;
            },
            immediate: true
        },
        reportData: {
            handler(val) {
                if (val) {
                    this.form.reportNo = val.reportNo || '';
                    this.form.reportName = val.reportName || '';
          this.fetchDataById();
                }
            },
            immediate: true
      immediate: true,
    },
    id: {
      handler(val) {
        if (this.dialogVisible && val) {
          this.fetchDataById();
        }
      },
      immediate: true,
    },
    type: {
      handler(val) {
        // 可根据type切换详情/评定模式
      },
      immediate: true,
    },
    },
    methods: {
    async fetchDataById() {
      try {
        const res = await getDetail(this.id);
        const data = res || {};
        this.form.reportNo = data.itemCode || "";
        this.form.reportName = data.itemName || "";
        this.evaluateInfo = { ...data };
        // 评定分数
        if (data.evaluateScore) {
          const scores = data.evaluateScore.split(",").map(Number);
          this.criteriaList.forEach((item, idx) => {
            item.score = scores[idx] || 0;
          });
        } else {
          this.criteriaList.forEach((item) => (item.score = 0));
        }
      } catch (e) {
        // 错误处理
      }
    },
        handleClose() {
            this.$emit('update:modelValue', false);
      this.$emit("close", false);
        },
        async handleSubmit() {
            try {
                await this.$refs.formRef.validate();
                const totalScore = this.criteriaList.reduce((sum, item) => sum + (item.score || 0), 0);
        const totalScore = this.criteriaList.reduce(
          (sum, item) => sum + (item.score || 0),
          0
        );
                const assessmentData = {
                    ...this.form,
                    totalScore,
                    criteriaScores: this.criteriaList.map(item => ({
                        criteria: item.criteria,
                        score: item.score || 0
                    }))
          id: this.evaluateInfo.id,
          evaluateScore: this.criteriaList
            .map((item) => item.score || 0)
            .join(","),
                };
                this.$emit('submit', assessmentData);
        // 这里可以调用evaluate接口
        evaluate(assessmentData).then((res) => {
          if (res.code == 200) {
            this.$message.success("提交成功");
                this.handleClose();
          }else{
            this.$message.error(res.message)
          }
        });
            } catch (error) {
                // 表单验证失败
            }
@@ -145,11 +227,11 @@
            const sums = [];
            columns.forEach((column, index) => {
                if (index === 0) {
                    sums[index] = '合计';
          sums[index] = "合计";
                    return;
                }
                const values = data.map(item => Number(item[column.property]));
                if (!values.every(value => isNaN(value))) {
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
                    sums[index] = values.reduce((prev, curr) => {
                        const value = Number(curr);
                        if (!isNaN(value)) {
@@ -158,9 +240,9 @@
                            return prev;
                        }
                    }, 0);
                    sums[index] += ' 分';
          sums[index] += " 分";
                } else {
                    sums[index] = '';
          sums[index] = "";
                }
            });
            return sums;
@@ -169,30 +251,29 @@
            if (columnIndex === 4 && rowIndex == 0) {
                return {
                    rowspan: 6,
                    colspan: 1
                }
          colspan: 1,
        };
            } else if (rowIndex !== 0 && columnIndex === 4) {
                return [0, 0]
        return [0, 0];
            }
        }
    }
}
    },
  },
};
</script>
<style lang="less" scoped>
.content-box {
    &-left {
        margin-top: 5px;
        display: flex;
        flex-direction: column;
        border: 1px solid #EBEEF5;
    border: 1px solid #ebeef5;
        border-radius: 8px 8px 0px 0px;
        font-size: 12px;
        &-th {
            line-height: 40px;
            background: #FAFAFA !important;
      background: #fafafa !important;
            color: #909399;
            padding: 0 10px;
            font-weight: bold;
laboratory/src/views/deliveryAssessment/testingAndEvaluation/components/approval/index.vue
New file
@@ -0,0 +1,486 @@
<template>
    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" po :close-on-click-modal="false"
        @close="handleClose">
        <div class="approval-dialog">
            <!-- 左侧审批内容 -->
            <div class="approval-content">
                <Card class="approval-content-card">
                    <template style="position: relative">
                        <div class="header-title" style="width: 100%;">
                            <div class="header-title-left">
                                <img src="@/assets/public/headercard.png" />
                                <div>所属检测项</div>
                            </div>
                        </div>
                        <Table :height="null" :total="0" :data="tableData">
                            <template>
                                <el-table-column prop="teamName" label="所属项目组" />
                                <el-table-column prop="itemName" label="检测项名称" />
                                <el-table-column prop="itemCode" label="检测项编号" />
                                <el-table-column prop="remark" label="备注" />
                                <el-table-column prop="createBy" label="创建人" />
                                <el-table-column prop="createTime" label="创建时间" />
                            </template>
                        </Table>
                        <el-form ref="form" :model="form" :rules="rules" inline label-position="top"
                            style="margin-top: 18px">
                            <el-form-item prop="name" label="报告内容">
                                <el-select v-model="form.reportContent" style="width: 100%;" disabled
                                    placeholder="请选择报告内容">
                                    <el-option label="国家标准" :value="1" />
                                    <el-option label="分析方法开发" :value="2" />
                                    <el-option label="方法验证报告" :value="3" />
                                    <el-option label="方法确认" :value="4" />
                                    <el-option label="操作规程" :value="5" />
                                    <el-option label="方法转移记录清单" :value="6" />
                                </el-select>
                            </el-form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <div>报告正文</div>
                                </div>
                            </div>
                            <el-form-item prop="name" style="margin-top: 18px">
                                <ai-editor :value="form.reportText" :readOnly="true" style="width: 100%;"
                                    placeholder="请输入报告编号" />
                            </el-form-item>
                            <div class="header-title" style="width: 100%;">
                                <div class="header-title-left">
                                    <img src="@/assets/public/headercard.png" />
                                    <span>附件</span>
                                </div>
                            </div>
                            <el-form-item prop="name" style="margin-top: 18px">
                                <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                                    <!-- <el-button size="small" type="primary">点击上传</el-button> -->
                                </el-upload>
                            </el-form-item>
                        </el-form>
                    </template>
                    <!-- <SelectMember ref="selectMember" /> -->
                </Card>
            </div>
            <!-- 右侧审批流程 -->
            <div class="approval-flow">
                <div class="flow-content">
                    <approval-process :processData="form.processData" />
                </div>
            </div>
        </div>
        <div class="approval-dialog-approve" v-if="type === 'approve'">
            <el-row :span="24">
                <el-col :span="12">
                    <div class="status">
                        <div class="status-title">审批结果</div>
                        <div class="status-content">
                            <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1">
                                通过
                            </div>
                            <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2">
                                驳回
                            </div>
                        </div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="remark">
                        <div class="remark-title">审批意见</div>
                        <el-input type="textarea" v-model="remark" placeholder="请输入审批意见" />
                    </div>
                </el-col>
            </el-row>
        </div>
        <div slot="footer" class="dialog-footer">
            <el-button @click="handleClose">取 消</el-button>
            <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">确认</el-button>
        </div>
    </el-dialog>
</template>
<script>
import ApprovalProcess from '@/components/approvalProcess'
import AiEditor from '@/components/AiEditor'
import { getDetailInfo, getDetail, detailAuditReport } from '../../service'
export default {
    name: "ApprovalDialog",
    components: {
        ApprovalProcess,
        AiEditor
    },
    props: {
        visible: {
            type: Boolean,
            default: false,
        },
        type: {
            type: String,
            default: "approve", // approve-审批,view-查看
        },
        data: {
            type: Object,
            default: () => ({}),
        },
        id: {
            type: String,
            default: "",
        },
    },
    data() {
        return {
            form: {
                reportText: "",
                reportContent: "",
                qaReportFiles: [],
                processData: [],
            },
            tableData: [],
            fileList: [],
            radio1: 1,
            rules: {},
            status: "1",
            remark: "",
        };
    },
    computed: {
        dialogTitle() {
            return this.type === "approve" ? "方法验证报告审批" : "方法验证报告详情";
        },
    },
    watch: {
        visible: {
            handler(val) {
                if (val && this.data.id) {
                    this.getDetailInfo()
                }
                if (val && this.data.itemId) {
                    this.getDetail()
                }
            },
            immediate: true,
        },
    },
    methods: {
        getDetailInfo() {
            getDetailInfo({ id: this.data.id }).then(res => {
                if (res) {
                    this.form = { ...res, reportContent: Number(res.reportContent), processData: [] }
                    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 = [];
                    // 提交节点
                    processData.push({
                        type: "primary",
                        mode: "list",
                        fields: [
                            { label: "提交人:", value: res.updateBy || "" },
                            { label: "提交时间:", value: res.createTime || "" },
                        ],
                    });
                    if (res.status == 2 || res.status == 3) {
                        processData.push({
                            type:
                                res.status === 2
                                    ? "primary"
                                    : res.status === 3
                                        ? "danger"
                                        : "warning",
                            mode: "list",
                            fields: [
                                {
                                    label: "审核结果:",
                                    value:
                                        res.status === 2
                                            ? "通过"
                                            : res.status === 3
                                                ? "驳回"
                                                : "待审批",
                                },
                                { label: "审批意见:", value: res.auditRemark || "" },
                                { label: "审核人:", value: res.auditPersonName || "" },
                                { label: "审核时间:", value: res.auditTime || "" },
                            ],
                        });
                    } else {
                        processData.push({
                            type: "warning",
                            mode: "list",
                            fields: [
                                { label: "等待审核" },
                            ],
                        });
                    }
                    // 如有卡片模式,按前述结构 push
                    this.$nextTick(() => {
                        this.form.processData = processData;
                    })
                }
            })
        },
        getDetail() {
            getDetail(this.data.itemId).then(res => {
                if (res) {
                    this.tableData = [{ ...res, teamName: res.projectTeamVO.teamName }]
                }
            })
        },
        handleClose() {
            this.$emit("close");
            this.form.approvalComment = "";
        },
        handleApprove() {
            if (!this.remark) {
                this.$message.warning("请输入审批意见");
                return;
            }
            const params = {
                id: this.data.id,
                auditRemark: this.remark,
                auditStatus: this.status === '1' ? 2 : 3
            };
            detailAuditReport(params).then(res => {
                if (res) {
                    this.$message.success('审核成功');
                    this.$emit("close");
                }
            }).catch(err => {
                this.$message.error(err.message || '审核失败');
            });
        },
        handleReject() {
            if (!this.form.approvalComment) {
                this.$message.warning("请输入审批意见");
                return;
            }
            this.$emit("reject", {
                ...this.form,
                status: "rejected",
            });
        },
    },
};
</script>
<style scoped lang="less">
::v-deep .el-dialog__header {
    border-bottom: 1px solid #e4e7ed;
}
.approval-dialog {
    display: flex;
    height: 40vh;
    .approval-content {
        flex: 3;
        margin-right: 20px;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
    }
    .approval-flow {
        padding: 40px 20px;
        // width: 405px;
        flex: 2;
        background: #ffffff;
        box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
        border-radius: 10px;
        .flow-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 20px;
            color: #303133;
        }
        .flow-content {
            height: calc(100% - 40px);
            overflow-y: auto;
            .el-form--inline .el-form-item {
                margin-right: 83px;
            }
        }
    }
}
.approval-content-card {
    height: calc(100% - 100px) !important;
    box-shadow: none !important;
}
.header-title {
    // display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 20px;
    gap: 13px;
    .header-title-left {
        display: flex;
        align-items: center;
        gap: 13px;
        margin-top: 18px;
        img {
            width: 12px;
            height: 19px;
        }
        div {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
            &:before {
                content: "*";
                color: #f56c6c;
                margin-right: 4px;
            }
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
            font-size: 18px;
            color: #222222;
            line-height: 27px;
            font-family: "Source Han Sans CN Bold Bold";
        }
    }
    .header-title-left :first-child {
        margin-top: 0;
    }
}
.header-title:first-child {
    .header-title-left {
        margin-top: 0;
    }
}
.item-title {
    padding-left: 25px;
    span {
        flex-shrink: 0;
        font-weight: bold;
        font-size: 14px;
        color: #222222;
        line-height: 27px;
        font-family: "Source Han Sans CN Bold Bold";
        margin: 18px 0;
        &:before {
            content: "*";
            color: #f56c6c;
            margin-right: 4px;
        }
    }
}
.approval-dialog-approve {
    padding: 18px 20px;
    // display: flex;
    align-content: center;
    .status {
        margin-right: 40px;
        max-width: 60%;
    }
    //   align-items: center;
    .status-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
    .status-content {
        display: flex;
        align-items: center;
        width: 100%;
        gap: 16px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid rgba(4, 156, 154, 0.5);
        .resolve {
            border-radius: 10px;
            flex: 1;
            font-size: 16px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            line-height: 32px;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .reject {
            flex: 1;
            border-radius: 10px;
            font-size: 16px;
            line-height: 32px;
            // padding: 5px 55px;
            font-weight: 400;
            color: #333333;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center
        }
        .activeStatus {
            background: #ebfefd;
            color: #049c9a;
            box-shadow: 0px 0px 6px 0px rgba(10, 109, 108, 0.25);
            border-radius: 10px;
        }
    }
    .remark-title {
        color: #222222;
        font-family: "SourceHanSansCN-Medium";
        line-height: 14px;
        margin-bottom: 16px;
    }
}
.dialog-footer {
    align-items: center;
    display: flex;
    justify-content: center;
    gap: 20px;
    button {
        width: 150px;
    }
}
</style>
laboratory/src/views/deliveryAssessment/testingAndEvaluation/index.vue
@@ -1,212 +1,505 @@
<template>
    <div class="list">
        <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :height="0"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
            <template #search>
                <el-form :model="form" label-width="140px" inline>
        <el-form
          ref="searchForm"
          :model="form"
          :rules="rules"
          label-width="auto"
          inline
        >
                    <el-form-item label="所属项目组:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.teamName" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="检测项名称:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.itemName" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="检测项编号:">
                        <el-input v-model="form.name" placeholder="请输入" />
            <el-input v-model="form.itemCode" placeholder="请输入"></el-input>
          </el-form-item>
          <el-form-item label="报告内容:">
            <el-select v-model="form.reportContent" placeholder="请选择">
              <el-option label="国家标准" value="1"></el-option>
              <el-option label="分析方法开发" value="2"></el-option>
              <el-option label="方法验证报告" value="3"></el-option>
              <el-option label="方法确认" value="4"></el-option>
              <el-option label="操作规程" value="5"></el-option>
              <el-option label="方法转移记录清单" value="6"></el-option>
            </el-select>
                    </el-form-item>
                    <el-form-item label="状态:">
                        <el-select v-model="form.name" placeholder="请选择" />
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option label="草稿箱" value="-1"></el-option>
              <el-option label="已提交" value="1"></el-option>
              <el-option label="待评定" value="2"></el-option>
              <el-option label="已评定" value="3"></el-option>
            </el-select>
                    </el-form-item>
                    <el-form-item class="search-btn-box">
                        <el-button>重置</el-button>
                        <el-button type="primary">查询</el-button>
          <el-form-item label="" style="margin-left: 63px">
            <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>
            <template #setting>
                <div class="table-title">
                    项目检查项、检验包
        <div class="table-setting">
          <div class="flex a-center">
            <div class="table-title active">项目检测项、检验包列表</div>
          </div>
                </div>
            </template>
            <template #tableCustom>
                <Table :data="tableData" :total="0" @row-click="handleRowClick" row-key="id"
                    :expand-row-keys="expandRowKeys">
        <Table
          :data="tableData"
          :total="total"
          @row-click="handleRowClick"
          row-key="id"
          :height="null"
          @currentChange="handleCurrentChange"
          @sizeChange="handleSizeChange"
          :expand-row-keys="expandRowKeys"
        >
                    <el-table-column type="expand" width="1">
                        <template #default="{ row }">
                            <div class="expand-box">
                <div style="display: flex; align-items: center">
                                <div class="expand-box-title">报告列表</div>
                                <Table :total="0" :height="null">
                                    <el-table-column prop="name" label="报告内容" />
                                    <el-table-column prop="name" label="制订人" />
                                    <el-table-column prop="name" label="制订日期" />
                                    <el-table-column prop="name" label="检测项编号" />
                                    <el-table-column prop="name" label="审批人" />
                                    <el-table-column prop="name" label="审批时间" />
                                    <el-table-column prop="age" label="状态">
                </div>
                <Table
                  :data="reportList[row.id] || []"
                  :total="0"
                  :height="null"
                >
                  <el-table-column prop="reportContent" label="报告内容">
                                        <template #default="{ row }">
                                            <el-tag v-if="row.status == 1" type="info" color="#fff">已通过</el-tag>
                                            <el-tag v-else type="success">未通过</el-tag>
                      <span>{{ getReportContentText(row.reportContent) }}</span>
                    </template>
                  </el-table-column>
                  <el-table-column prop="developPerson" 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 }">
                      <el-tag v-if="row.status == 1" type="info" color="#fff"
                        >待审核</el-tag
                      >
                      <el-tag v-if="row.status == 2" type="success" color="#fff"
                        >已通过</el-tag
                      >
                      <el-tag v-if="row.status == 3" type="danger"
                        >已驳回</el-tag
                      >
                      <el-tag v-if="row.status == 4" type="danger"
                        >已撤销</el-tag
                      >
                                        </template>
                                    </el-table-column>
                                    <el-table-column prop="age" label="操作">
                                        <template #default="{ row }">
                                            <el-button type="text">详情</el-button>
                      <el-button type="text" v-if="row.status == 2" @click="handleApprove(row)"
                        >详情</el-button
                      >
                                        </template>
                                    </el-table-column>
                                </Table>
                            </div>
                        </template>
                    </el-table-column>
                    <el-table-column prop="name" label="所属项目组" />
                    <el-table-column prop="age" label="检测项名称" />
                    <el-table-column prop="age" label="检测项编号" />
                    <el-table-column prop="age" label="备注" />
                    <el-table-column prop="age" label="创建人" />
                    <el-table-column prop="age" label="创建时间" />
          <el-table-column prop="teamName" label="所属项目组" />
          <el-table-column prop="itemName" label="检测项名称" />
          <el-table-column prop="itemCode" label="检测项编号" />
          <el-table-column prop="remark" label="备注" />
          <el-table-column prop="createBy" label="创建人" />
          <el-table-column prop="createTime" label="创建时间" />
                    <el-table-column prop="age" label="状态">
                        <template #default="{ row }">
                            <el-tag v-if="row.status == 1" type="info" color="#fff">已评定</el-tag>
                            <el-tag v-else type="success">待评定</el-tag>
              <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>
                    </el-table-column>
                    <el-table-column prop="age" label="操作">
                        <template #default="{ row }">
                            <!-- 工艺工程师 -->
                            <!-- <el-button type="text" @click="assessmentVisible = true">评定</el-button> -->
                            <el-button type="text" @click="assessmentVisible = true">详情</el-button>
              <template>
                <el-button
                  v-if="row.status == 2 && isProcessEngineer"
                  type="text"
                  @click="handleReportDetail(row, 'approve')"
                  >评定</el-button
                >
                <el-button
                  v-else
                  type="text"
                  @click="handleReportDetail(row, 'detail')"
                  >详情</el-button
                >
              </template>
                        </template>
                    </el-table-column>
                </Table>
            </template>
        </TableCustom>
        <AssessmentDialog :modelValue="assessmentVisible" :reportData="currentReport"
            @submit="handleAssessmentSubmit" />
    <Approval
      :visible="showApproval"
      @close="closeApproval"
      :data="rowData"
      :type="approvalType"
    />
    <AssessmentDialog
      :modelValue="showAssessmentDialog"
      :reportData="assessmentDialogData"
      :id="assessmentDialogId"
      :type="assessmentDialogType"
      @close="handleCloseAssessmentDialog"
    />
    </div>
</template>
<script>
import AssessmentDialog from './components/AssessmentDialog.vue'
import Approval from "./components/approval";
import AssessmentDialog from "./components/AssessmentDialog.vue";
import { getDataList, getListByItemId } from "./service";
export default {
    name: 'TestingAndEvaluation',
  name: "ProjectList",
    components: {
        AssessmentDialog
    Approval,
    AssessmentDialog,
    },
    data() {
        return {
            form: {
        itemCode: "", // 检测项编号
        itemName: "", // 检测项名称
        reportContent: "", // 报告内容
        status: "", // 状态,默认为空字符串表示全部
        teamName: "", // 项目组名称
        pageNum: 1,
        pageSize: 10,
            },
            tableData: [{ id: 1 }, { id: 2 }],
      rules: {
        itemCode: [
          { max: 50, message: "检测项编号不能超过50个字符", trigger: "blur" },
        ],
        itemName: [
          { max: 100, message: "检测项名称不能超过100个字符", trigger: "blur" },
        ],
        teamName: [
          { max: 100, message: "项目组名称不能超过100个字符", trigger: "blur" },
        ],
      },
      showSubmitConfirm: false,
      showDelConfirm: false,
      confirmTitle: "", // 确认框标题
      confirmTip: "", // 确认框提示
      confirmType: "", // 确认框类型:'deleteReport'-删除报告, 'deleteItem'-删除检测项, 'revoke'-撤销审批
      rowId: "",
      showApproval: false,
      approvalType: "", // 新增:审批类型
      submitTitle: "", // 新增:提交评定确认框标题
      submitTip: "", // 新增:提交评定确认框提示
            queryForm: {
                pageSize: 10,
                pageNum: 1
        pageNum: 1,
            },
      tableData: [],
      expandRowKeys: [],
            total: 0,
            assessmentVisible: false,
            currentReport: {},
            expandRowKeys: []
        }
      rowData: {},
      reportList: {}, // 修改为对象,用行ID作为key
      currentRow: null,
      currentAction: "",
      showItemApproval: false,
      loading: false,
      showAssessmentDialog: false,
      assessmentDialogData: {},
      assessmentDialogId: "",
      assessmentDialogType: "detail",
    };
  },
  computed: {
    isChemist() {
      const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
      return userInfo.roleType == 4; // 2是化验师
    },
    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: {
        handleRowClick(row, column, event) {
            if (column.label === '操作') return
            if (this.expandRowKeys.includes(row.id)) {
                this.expandRowKeys = this.expandRowKeys.filter(key => key !== row.id);
    closeApproval() {
      this.showApproval = false;
      this.rowData = {};
      this.approvalType = "";
      this.getList();
    },
    handleCloseAssessmentDialog(){
      this.showAssessmentDialog = false;
      this.assessmentDialogData = {};
      this.assessmentDialogId = '';
      this.assessmentDialogType = ''; // 或 'evaluate',根据业务调整
      this.getList();
    },
    async handleRowClick(row, column, event) {
      if (column.label == "操作") return;
      const currentOpenId = this.expandRowKeys[0];
      if (currentOpenId === row.id) {
        // 如果点的是当前已展开的,关闭它
        this.expandRowKeys = [];
        delete this.reportList[row.id];
            } else {
                this.expandRowKeys = [row.id];
        // 如果有其他已展开的,先关闭
        if (currentOpenId) {
          this.expandRowKeys = [];
          delete this.reportList[currentOpenId];
            }
        // 展开新行
        this.expandRowKeys = [row.id];
        try {
          const res = await getListByItemId({ id: row.id });
          if (res) {
            this.$set(this.reportList, row.id, res || []);
          } else {
            this.msgError(res.msg || "获取报告列表失败");
          }
        } catch (error) {
          console.error("获取报告列表失败:", error);
          this.msgError("获取报告列表失败");
        }
      }
    },
    handleApprove(row) {
      this.showApproval = true;
      this.rowId = row.id;
      this.rowData = row;
      this.approvalType = "detail";
        },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            this.getList()
      this.queryForm.pageNum = page;
      this.getList();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            this.getList()
      this.queryForm.pageSize = size;
      this.getList();
        },
        getList() {
        },
        handleDetail(row) {
            // 处理详情
        },
        handleAssessment(row) {
            this.currentReport = row;
            this.assessmentVisible = true;
        },
        handleAssessmentSubmit(data) {
            console.log('评定提交数据:', data);
            // 处理评定提交
    async getList() {
      if (this.loading) return;
      try {
        this.loading = true;
        const params = {
          ...this.form,
          pageNum: this.queryForm.pageNum,
          pageSize: this.queryForm.pageSize,
        };
        let res;
        res = await getDataList(params);
        if (res.code === 200) {
          this.tableData = res.data.records || [];
          this.total = res.data.total || 0;
        } else {
          this.$message.error(res.msg || "获取列表失败");
        }
      } catch (error) {
        console.error("获取列表失败:", error);
        this.$message.error("获取列表失败,请重试");
      } finally {
        this.loading = false;
    }
    },
    // 打开评定弹窗
    handleReportDetail(row, type) {
      this.assessmentDialogData = row;
      this.assessmentDialogId = row.id;
      this.assessmentDialogType = type; // 或 'evaluate',根据业务调整
      this.showAssessmentDialog = true;
    },
    getReportContentText(value) {
      const contentMap = {
        1: "国家标准",
        2: "分析方法开发",
        3: "方法验证报告",
        4: "方法确认",
        5: "操作规程",
        6: "方法转移记录清单",
      };
      return contentMap[value] || value;
    },
    async handleSearch() {
      try {
        console.log("111111111");
        // this.loading = true;
        await this.$refs.searchForm.validate();
        this.queryForm.pageNum = 1;
        await this.getList();
      } catch (error) {
        // 如果是校验失败,error会是false,此时不做任何处理,因为el-form会展示错误信息
        if (error !== false) {
          this.$message.error("查询失败,请重试");
}
      } finally {
        this.loading = false;
      }
    },
    async handleReset() {
      try {
        // this.loading = true;
        this.$refs.searchForm.resetFields();
        // resetFields会把status也置为初始值'',需要根据当前tab重新设置
        this.form = {
          itemCode: "",
          itemName: "",
          reportContent: "",
          status: "",
          teamName: "",
          pageNum: 1,
          pageSize: 10,
        };
        this.queryForm.pageNum = 1;
        await this.getList();
      } catch (error) {
        this.$message.error("重置失败,请重试");
      } finally {
        this.loading = false;
      }
    },
  },
  mounted() {
    this.getList();
  },
};
</script>
<style scoped lang="less">
.list {
    height: 100%;
.el-icon-plus {
  margin-bottom: 20px;
}
.top-box-integral {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 28px;
    &-card {
        flex: 1;
        background: #E8FAF6;
        box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
        border-radius: 10px;
        padding: 21px 20px;
        &-title {
            font-family: 'SourceHanSansCN-Medium';
.header-content {
  font-family: PingFangSC, PingFang SC;
  font-weight: 400;
            font-size: 14px;
            color: rgba(0, 0, 0, 0.8);
  color: rgba(0, 0, 0, 0.88);
  margin-left: 30px;
        }
        &-num {
            font-family: 'SF Compact Display Black';
            text-align: center;
            font-weight: 900;
            font-size: 50px;
            color: #049C9A;
            line-height: 60px;
        }
    }
.box-title {
  font-family: SourceHanSansCN, SourceHanSansCN;
  font-weight: bold;
  font-size: 18px;
  color: #222222;
  line-height: 27px;
  display: flex;
  align-items: center;
}
.tip-warring {
    margin-top: 20px;
    color: rgba(255, 73, 85, 1);
.header-icon {
  width: 20px;
  height: 20px;
  margin-right: 10px;
}
.header-box {
  border-radius: 16px;
  margin-bottom: 30px;
}
.table-setting {
  display: flex;
  padding-bottom: 20px;
  justify-content: space-between;
  align-items: center;
}
.flex {
  display: flex;
  align-items: center;
}
.table-title {
    width: 220px;
    height: 50px;
    background: #FFFFFF;
  background: #fafafc;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #049C9A;
  border: 1px solid #dcdfe6;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: SourceHanSansCN, SourceHanSansCN;
    font-weight: bold;
    font-size: 18px;
    color: #049C9A;
  color: #606266;
    line-height: 27px;
  cursor: pointer;
  transition: all 0.3s ease;
  &.active {
    color: #049c9a;
    background: #ffffff;
    border: 1px solid #049c9a;
  }
}
.table-tit {
  width: 166px;
  height: 50px;
  background: #fafafc;
  border-radius: 8px 8px 0px 0px;
  border: 1px solid #dcdfe6;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: SourceHanSansCN, SourceHanSansCN;
  font-weight: bold;
  font-size: 18px;
  color: #606266;
  line-height: 27px;
  margin-left: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
  &.active {
    color: #049c9a;
    background: #ffffff;
    border: 1px solid #049c9a;
  }
}
.list {
  height: 100%;
}
.expand-box {
    padding: 20px;
    background: linear-gradient(180deg, #049C9A 0%, #0ACBCA 100%);
  background: linear-gradient(180deg, #049c9a 0%, #0acbca 100%);
    border-radius: 20px;
    &-title {
        font-weight: 500;
        font-size: 16px;
        color: #FFFFFF;
    color: #ffffff;
        line-height: 24px;
        margin-bottom: 20px;
    }
laboratory/src/views/deliveryAssessment/testingAndEvaluation/service.js
@@ -2,7 +2,7 @@
// 查询列表
export function getDataList(data) {
  return axios.post('/api/t-qa-test-item/pageList', { ...data })
  return axios.post('/api/t-qa-test-item/evaluateList', { ...data })
}
@@ -14,7 +14,7 @@
//评定QA检测项管理
export function evaluate(data) {
  return axios.put(`/api/t-qa-test-item/evaluate`, { ...data })
  return axios.post(`/api/t-qa-test-item/evaluate`, { ...data })
}
laboratory/src/views/middleground/index.vue
@@ -40,20 +40,20 @@
          <div class="title">待办事项</div>
          <!-- 待办事项列表将放置在这里 -->
          <div class="todo-list">
            <div class="todo-item" v-for="i in 6" :key="i">
            <div class="todo-item" v-for="(item,index) in list" :key="index" @click.stop="toDetail(item)">
              <div class="todo-details">
                <div class="notice-card">
                  <div class="todo-icon"></div>
                  <div class="red-notice"></div>
                  <div class="red-notice" v-if="item.isRead==0"></div>
                </div>
                <span class="todo-title">您有 [1] 条 【项目课题方案】 等待审批</span>
                <span class="todo-title" :title="item.content || ''">{{item.content||''}}</span>
              </div>
              <div class="todo-meta">
                <div class="me"></div>
                <span class="todo-submitter">提交人: 王晓晓</span>
                <span class="todo-submitter">提交人: {{item.commitName||''}}</span>
                <div class="time"></div>
                <span class="todo-submitter">2023.12.10 08:00</span>
                <span class="todo-submitter">{{item.commitTime||''}}</span>
              </div>
            </div>
          </div>
@@ -64,7 +64,7 @@
</template>
<script>
import { Calendar } from "ant-design-vue";
import { loginReq } from "./service";
import { getList,read } from "./service";
import HeaderNav from "../../layouts/components/HeaderNav.vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
// 引入 Element UI 的日历组件
@@ -88,6 +88,7 @@
      date: new Date(),
      viewWidth: "",
      scale: 1,
      list:[],
      // 审批人
      moduleList2: [
        {
@@ -225,6 +226,11 @@
  created() {
    // 初始化时检查窗口大小
    this.handleResize();
    getList().then(res=>{
      console.log('22222222',res)
      this.list = res
    })
  },
  mounted() {
    // 监听窗口大小变化
@@ -249,6 +255,14 @@
        });
      }
    },
    toDetail(item){
      console.log('item item',item)
      read({id:item.id}).then(res=>{
        console.log('res',res)
      })
    }
  },
  computed: {
    currentModuleList() {
@@ -975,6 +989,7 @@
      .todo-list {
        flex: 1;
        height: 100%;
        max-height: 264px;
        overflow: auto;
      }
@@ -1026,11 +1041,18 @@
          font-size: 14px;
          color: #303133;
          line-height: 24px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          max-width: 400px;
          cursor: pointer;
        }
        .todo-meta {
          display: flex;
          align-items: center;
          justify-content: space-between;
          min-width:260px;
        }
        .time {
laboratory/src/views/middleground/service.js
@@ -1,6 +1,9 @@
import axios from '@/utils/request';
// 登录
export const loginReq = (data) => {
    return axios.post('/login', { ...data })
export const getList = (data) => {
    return axios.get('/open/t-notice/list', { ...data })
}
export const read = (data) => {
    return axios.get(`/open/t-notice/read?id=${data.id}`, { ...data })
}
laboratory/src/views/system/role/index.vue
@@ -13,9 +13,9 @@
          </el-form-item>
        </el-form>
      </template>
      <template #setting>
      <!-- <template #setting>
        <el-button icon="el-icon-plus" @click="add" type="primary">添加角色</el-button>
      </template>
      </template> -->
      <template #table>
        <el-table-column type="index" width="55" label="序号"></el-table-column>
        <el-table-column prop="roleName" label="角色名称"></el-table-column>