pyt
9 天以前 6e48606ee4721482f2f754b21f462704fff7ccbc
Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory
20个文件已修改
3个文件已添加
3093 ■■■■ 已修改文件
laboratory/src/App.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SelectMember/index.vue 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SignatureCanvas.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/TableSlot/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/approvalProcess/index.vue 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/chooseProject/index.vue 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/chooseProject/servce.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/add-test-item.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue 313 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/confirm-dialog.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/experimental-scheduling.vue 165 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/components/review-dialog.vue 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/index.vue 203 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/confirmation-sheet/service.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/addDispatch.vue 835 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/components/AddTaskDialog.vue 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/editDispatch.vue 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/list.vue 318 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/dispatching/service.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/add.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/components/approval/index.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/index.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/reportLibrary/feasibilityStudy/service.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/App.vue
@@ -125,6 +125,16 @@
      border-radius: 6px;
      border: 1px solid rgba(0, 0, 0, 0.15);
    }
    .el-date-editor{
      .el-input__inner {
        width: 260px;
      padding: 0 12px 0 30px;
      border-radius: 6px;
      border: 1px solid rgba(0, 0, 0, 0.15);
    }
    }
  }
  .el-dialog {
@@ -135,6 +145,16 @@
    .el-input__inner {
      width: 200px;
    }
    .el-pagination__sizes{
      .el-input__inner {
      width: 100px;
    }
    }
    .el-pagination__jump{
      .el-input__inner {
      width: 50px;
    }
    }
  }
}
laboratory/src/components/SelectMember/index.vue
@@ -61,6 +61,12 @@
<script>
import { getRoleList, getUserList } from './service'
export default {
    props: {
        projectId: {
            type: [String, Number],
            default: null
        }
    },
    data() {
        return {
            visible: false,
@@ -85,9 +91,15 @@
            })
        },
        openDialog() {
            // 获取角色列表并根据项目组ID进行过滤
            getRoleList().then(res => {
                this.roleList = res;
            })
                if (this.projectId) {
                    // 过滤出实验员和化验师角色
                    this.roleList = res.filter(item => item.roleId == 4 || item.roleId == 5);
                } else {
                    this.roleList = res;
                }
            });
            this.searchUserList(null);
        },
        handleSelectionChange(val) {
@@ -95,8 +107,23 @@
        },
        async searchUserList(roleId) {
            this.roleId = roleId
            const res = await getUserList({ roleIds: roleId ? [roleId] : [], nickNameOrPhone: this.searchName, pageSize: 9999, pageNum: 1 })
            this.tableData = res.records
            // 根据是否有项目组ID来决定调用不同的接口
            const params = {
                roleIds: roleId ? [roleId] : [],
                nickNameOrPhone: this.searchName,
                pageSize: 9999,
                pageNum: 1
            };
            if (this.projectId) {
                params.projectId = this.projectId;
                // TODO: 这里需要替换为新的接口调用
                // const res = await getProjectUserList(params);
            } else {
                const res = await getUserList(params);
                this.tableData = res.records;
            }
            // 数据加载完成后重新应用选中状态
            this.setSelection(this.selectData)
        },
laboratory/src/components/SignatureCanvas.vue
@@ -6,7 +6,7 @@
    :close-on-click-modal="false"
    custom-class="signature-dialog"
    append-to-body
    @close="$emit('update:visible', false)"
    @close="$emit('close', false)"
  >
    <div class="signature-container">
      <div class="signature-content">
laboratory/src/components/TableSlot/index.vue
@@ -13,7 +13,9 @@
            </template>
            <template v-if="$slots.table">
                <Table :data="tableData" :total="total" :height="height" :queryForm="queryForm"
                    @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange">
                    @handleCurrentChange="handleCurrentChange"
                    @handleSizeChange="handleSizeChange"
                    @selection-change="handleSelectionChange">
                    <slot name="table"></slot>
                </Table>
            </template>
@@ -60,6 +62,9 @@
        },
        handleSizeChange(size) {
            this.$emit('handleSizeChange', size)
        },
        handleSelectionChange(selection) {
            this.$emit('selection-change', selection)
        }
    }
}
laboratory/src/components/approvalProcess/index.vue
@@ -1,44 +1,25 @@
<template>
  <div class="approval-process">
    <el-timeline>
      <el-timeline-item
        v-for="(activity, index) in processData"
        :key="index"
        :type="activity.type"
      >
      <el-timeline-item v-for="(activity, index) in processData" :key="index" :type="activity.type">
        <div v-if="activity.mode === 'card'">
          <div
            class="member-list-card"
            v-for="(group, groupIndex) in activity.groups"
            :key="groupIndex"
          >
          <div class="member-list-card" v-for="(group, groupIndex) in activity.groups" :key="groupIndex">
            <div class="member-item">
              <div class="member-title">
                {{ group.title }}
              </div>
              <div class="flex-over">
                <div
                  class="people-list"
                  v-for="(member, memberIndex) in group.members"
                  :key="memberIndex"
                >
                <div class="people-list" v-for="(member, memberIndex) in group.members" :key="memberIndex">
                  <div class="people-item">
                    <img :src="member.avatar" alt="" class="people-img" />
                    <div class="member-name">{{ member.name }}</div>
                  </div>
                  <div class="member-status">
                    <div
                      class="member-status-text"
                      :class="
                        member.status === 'approved' ? 'success' : 'warning'
                      "
                    >
                      {{ member.status === "approved" ? "同意" : "待审批" }}
                    <div class="member-status-text" :class="member.status === 'approved' ? 'success' : 'warning'
                      ">
                      {{ member.status }}
                    </div>
                    <div
                      v-if="member.status === 'approved'"
                      class="member-status-time"
                    >
                    <div v-if="member.status === '已确认'" class="member-status-time">
                      {{ member.approveTime }}
                    </div>
                  </div>
@@ -47,18 +28,17 @@
            </div>
          </div>
        </div>
        <div
          v-else
          class="approval-process-item"
          :class="activity.type === 'primary' ? '' : 'approval-process-item1'"
        >
          <div
            v-for="(field, idx) in activity.fields"
            :key="idx"
            style="margin-bottom: 6px"
          >
            <span>{{ field.label }}</span>
            <span>{{ field.value }}</span>
        <div v-else class="approval-process-item" :class="activity.type === 'primary' ? '' : 'approval-process-item1'">
          <div v-for="(field, idx) in activity.fields" :key="idx" style="margin-bottom: 6px">
            <span v-if="field.type == 'img'">
              <el-image style="width: 50px; height: 50px;margin-left: 40px;" v-if="field.value" :src="field.value"
                    :preview-src-list="[field.value]">
                  </el-image>
            </span>
            <span v-else>
              <span>{{ field.label }}</span>
              <span>{{ field.value }}</span>
            </span>
          </div>
        </div>
      </el-timeline-item>
@@ -108,19 +88,16 @@
      //       {
      //         title: '工艺工程师',
      //         members: [
      //           {
      //             fields: [
      //               { label: '姓名', value: '张三' },
      //               { label: '状态', value: '同意' },
      //               { label: '审批时间', value: '2025-04-08 12:30' }
      //             ],
      // {
      //           name:'',
      //           status:'',
      //           approveTime:'',
      //             avatar: '' // 头像地址,可选
      //           },
      //           {
      //             fields: [
      //               { label: '姓名', value: '李四' },
      //               { label: '状态', value: '待审批' }
      //             ],
      //             name:'',
      //             status:'',
      //             approveTime:'',
      //             avatar: ''
      //           }
      //         ]
@@ -129,15 +106,13 @@
      //         title: '实验员',
      //         members: [
      //           {
      //             fields: [
      //               { label: '姓名', value: '王五' },
      //               { label: '状态', value: '同意' },
      //               { label: '审批时间', value: '2025-04-08 13:00' }
      //             ],
      //             name:'',
      //             status:'',
      //             approveTime:'',
      //             avatar: ''
      //           }
      //         ]
      //       }
      //       }
      //     ]
      //   }
      // ]
@@ -213,36 +188,30 @@
    border: 1px solid #dcdfe6;
    margin-top: 10px;
    // &:nth-child(1) {
    //   background: linear-gradient(
    //     to bottom,
    //     rgba(4, 156, 154, 0.2) 0%,
    //     rgba(5, 242, 194, 0) 70%
    //   );
    // }
    &:nth-child(1) {
      background: linear-gradient(
        to bottom,
        rgba(4, 156, 154, 0.2) 0%,
        rgba(5, 242, 194, 0) 70%
      );
      background: linear-gradient(to bottom,
          rgba(5, 160, 193, 0.2) 0%,
          rgba(5, 242, 194, 0) 70%);
    }
    &:nth-child(2) {
      background: linear-gradient(
        to bottom,
        rgba(5, 160, 193, 0.2) 0%,
        rgba(5, 242, 194, 0) 70%
      );
      background: linear-gradient(to bottom,
          rgba(255, 77, 79, 0.2) 0%,
          rgba(255, 242, 194, 0) 70%);
    }
    &:nth-child(3) {
      background: linear-gradient(
        to bottom,
        rgba(255, 77, 79, 0.2) 0%,
        rgba(255, 242, 194, 0) 70%
      );
    }
    &:nth-child(4) {
      background: linear-gradient(
        to bottom,
        rgba(250, 199, 20, 0.21) 0%,
        rgba(255, 242, 194, 0) 70%
      );
      background: linear-gradient(to bottom,
          rgba(250, 199, 20, 0.21) 0%,
          rgba(255, 242, 194, 0) 70%);
    }
    .member-item {
@@ -261,12 +230,14 @@
        text-align: left;
        padding-left: 17px;
      }
      .flex-over {
        margin-top: 12px;
        flex: 1;
        overflow: auto;
        height: 100%;
      }
      .people-list {
        display: flex;
        justify-content: space-between;
@@ -275,6 +246,7 @@
        margin-top: 12px;
        display: flex;
        .people-item {
          display: flex;
          align-items: center;
@@ -286,12 +258,14 @@
          border-radius: 50%;
          margin-right: 10px;
        }
        .member-status {
          align-items: flex-end;
          display: flex;
          flex-direction: column;
          justify-content: space-between;
        }
        .member-status-text {
          width: 52px;
          height: 22px;
@@ -300,6 +274,7 @@
          text-align: center;
          border: 1px solid rgba(0, 0, 0, 0.15);
        }
        .warning {
          background: #fffbe6;
          border-radius: 4px;
@@ -309,12 +284,14 @@
          font-size: 12px;
          color: #faad14;
        }
        .success {
          font-family: PingFangSC, PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: rgba(0, 0, 0, 0.88);
        }
        .member-status-time {
          font-family: PingFang-SC, PingFang-SC;
          font-weight: 500;
laboratory/src/components/chooseProject/index.vue
New file
@@ -0,0 +1,118 @@
<template>
    <div>
        <el-dialog title="选择项目组" :visible.sync="show" width="80%" @open="open" @close="$emit('close')">
            <TableCustom :queryForm="form" :total="total" :height="null">
                <template #search>
                    <el-form :model="form" label-width="140px" inline>
                        <el-form-item label="项目组名称:">
                            <el-input v-model="form.teamName" placeholder="请输入"></el-input>
                        </el-form-item>
                        <el-form-item label="项目负责人:">
                            <el-input v-model="form.personCharge" placeholder="请输入"></el-input>
                        </el-form-item>
                        <el-form-item label="创建日期:">
                            <el-date-picker v-model="form.date" type="daterange" range-separator="至"
                                start-placeholder="开始日期" end-placeholder="结束日期"
                                value-format="yyyy-MM-dd"></el-date-picker>
                        </el-form-item>
                        <el-form-item label="" class="search-btn-box">
                            <el-button type="default" @click="resetForm">重置</el-button>
                            <el-button type="primary" @click="handleSearch">查询</el-button>
                        </el-form-item>
                    </el-form>
                </template>
                <template #tableCustom>
                    <Table ref="memberTable" :height="null" :row-key="row => row.id" :data="tableData" :total="0"
                        highlight-current-row @current-change="handleCurrentChange">
                        <!-- <el-table-column type="selection" width="55" /> -->
                        <el-table-column prop="teamName" label="项目组名称"></el-table-column>
                        <el-table-column prop="personCharge" label="项目负责人"></el-table-column>
                        <el-table-column prop="staffName" label="项目组成员"></el-table-column>
                        <el-table-column prop="createTime" label="创建时间"></el-table-column>
                    </Table>
                </template>
            </TableCustom>
            <span slot="footer" class="select-member-footer">
                <el-button @click="$emit('close')">取 消</el-button>
                <el-button type="primary" @click="submitData">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>
<script>
import { getDataList } from './servce'
export default {
    props: {
        show: {
            type: Boolean,
            default: false
        },
        selectedData: {
            type: Object,
            default: () => ({})
        }
    },
    data() {
        return {
            form: {
                date: '',
                personCharge: '',
                pageNum: 1,
                pageSize: 10,
                startTime: '',
                endTime: '',
                teamName: '',
            },
            selectData: [],
            tableData: [],
            total: 0
        }
    },
    methods: {
        open() {
            getDataList({ ...this.form }).then(res => {
                console.log('/////////////', res);
                this.tableData = res.data.records || []
                this.total = res.data.total || 0
                if (this.selectedData && this.selectedData.id) {
                    this.selectData = this.selectedData
                    this.$nextTick(() => {
                        const row = this.tableData.find(item => item.id === this.selectedData.id)
                        if (row) {
                            this.$refs.memberTable.toggleRowSelection(row, true)
                        }
                    })
                }
            })
        },
        resetForm() {
            this.form = {
                date: '',
                personCharge: '',
                pageNum: 1,
                pageSize: 10,
                startTime: '',
                endTime: '',
                teamName: '',
            }
            this.handleSearch()
        },
        handleSearch() {
            console.log('shuju',this.form);
            this.open()
        },
        submitData(){
            this.$emit('submit',this.selectData)
        },
        handleCurrentChange(val) {
            this.selectData = val;
        },
    }
}
</script>
<style lang="less" scoped></style>
laboratory/src/components/chooseProject/servce.js
New file
@@ -0,0 +1,6 @@
import axios from '@/utils/request';
// 添加项目课题方案
export function getDataList(data) {
  return axios.post('/api/t-project-team/pageList', { ...data })
}
laboratory/src/views/dataManagement/confirmation-sheet/components/add-test-item.vue
@@ -49,6 +49,10 @@
    dialogVisible: {
      type: Boolean,
      default: false
    },
    editData: {
      type: Object,
      default: () => null
    }
  },
  data() {
@@ -59,7 +63,9 @@
        termType: 1,
        termMethodCode: '',
        termMethod: '',
        sampleRequire: ''
        sampleRequire: '',
        status: 1,
        testId: ''
      },
      rules: {
        termCode: [
@@ -83,17 +89,48 @@
      }
    }
  },
  watch: {
    dialogVisible(val) {
      if (val && this.editData) {
        // 编辑模式,回显数据
        this.$nextTick(() => {
          this.form = {
            ...this.editData,
            termType: Number(this.editData.termType) // 确保termType是数字类型
          }
        })
      } else if (!val) {
        // 关闭对话框时重置表单
        this.resetForm()
      }
    }
  },
  methods: {
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.$emit('confirm', this.form)
          // 提交前确保termType是数字类型
          const submitData = {
            ...this.form,
            termType: Number(this.form.termType)
          }
          this.$emit('confirm', submitData)
          this.resetForm()
        }
      })
    },
    resetForm() {
      this.$refs.form.resetFields()
      this.form = {
        termCode: '',
        termName: '',
        termType: 1,
        termMethodCode: '',
        termMethod: '',
        sampleRequire: '',
        status: 1,
        testId: ''
      }
    }
  }
}
laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue
@@ -6,16 +6,16 @@
      <el-button @click="showScheduling = true" class="el-icon-plus" type="primary">
        选择实验调度</el-button>
    </div>
    <Table :tableData="tableData" :total="total" :height="null">
    <Table :data="tableData" :total="total" :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 prop="testName" label="实验名称"></el-table-column>
        <el-table-column prop="notifyTime" label="通知时间"></el-table-column>
        <el-table-column prop="startTime" label="实验开始时间"></el-table-column>
        <el-table-column prop="endTime" label="实验结束时间"></el-table-column>
        <el-table-column prop="participants" label="参加人员"></el-table-column>
        <el-table-column prop="status" label="状态"></el-table-column>
      </template>
    </Table>
    <div class="header-title-left" style="margin-top: 60px;">
@@ -25,25 +25,35 @@
        新增检测项</el-button>
      <span>【注意:这里有多少个检测项 系统就会自动创建对应数量的《检测项的检验方法及数据记录》】</span>
    </div>
    <Table :tableData="tableData" :total="total" :height="null">
    <Table :data="testItems" :total="testItems.length" :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="termName" label="检测项名称"></el-table-column>
        <el-table-column prop="termCode" label="检测项编号"></el-table-column>
        <el-table-column prop="termType" label="定性/定量">
          <template slot-scope="scope">
            {{ scope.row.termType === 1 ? '定性' : '定量' }}
          </template>
        </el-table-column>
        <el-table-column prop="termMethodCode" label="检测方法编号"></el-table-column>
        <el-table-column prop="termMethod" label="检测方法"></el-table-column>
        <el-table-column prop="sampleRequire" label="收样要求"></el-table-column>
        <el-table-column label="操作" width="150">
          <template slot-scope="scope">
            <el-button type="text" @click="handleEditTestItem(scope.row)">编辑</el-button>
            <el-button type="text" @click="handleDeleteTestItem(scope.$index)" class="delete-btn">删除</el-button>
          </template>
        </el-table-column>
      </template>
    </Table>
    <div class="btn_box flex ">
      <el-button type="primary" @click="handleSubmit">提交确认单</el-button>
      <el-button @click="$router.go(-1)">存草稿</el-button>
      <el-button @click="handleSaveDraft">存草稿</el-button>
    </div>
    <experimentalScheduling :show="showScheduling"/>
    <experimentalScheduling :show="showScheduling" @close="showScheduling = false" @submit="setSelectedScheduling"/>
    <add-test-item
      :dialogVisible="testItemDialogVisible"
      :editData="currentTestItem"
      @close="handleTestItemDialogClose"
      @confirm="handleTestItemConfirm"
    />
@@ -60,6 +70,7 @@
import experimentalScheduling from './experimental-scheduling.vue';
import AddTestItem from './add-test-item.vue'
import ConfirmDialog from './confirm-dialog.vue'
import { add, update, getDetail } from '../service'
export default {
  name: 'AddConfirmationSheet',
@@ -93,6 +104,16 @@
        testName: '', // 实验名称
        sampleCode: '' // 取样单编号
      },
      selectedScheduling: null, // 添加选中的实验调度数据
      currentTestItem: null, // 当前编辑的检测项
      formData: {
        id: '', // 确认单ID
        dispatchId: '', // 实验调度ID
        auditStatus: -1, // 审核状态,默认草稿
        testMethodConfirmSheetTerms: [], // 确认单检测项
        confirmSign: '', // 签字
        signTime: '', // 签字时间
      }
    };
  },
  computed: {
@@ -102,10 +123,52 @@
  },
  watch: {},
  created() {
    // 判断是否是编辑模式
    const id = this.$route.query.id
    if (id) {
      this.getDetailData(id)
    }
  },
  mounted() { },
  methods: {
    setSelectedScheduling(data) {
      console.log('data',data)
      if (!data || data.length === 0) return;
      const selectedData = data[0]; // 获取选中的第一条数据
      this.selectedScheduling = selectedData;
      // 更新表格数据
      this.tableData = [{
        planCode: selectedData.projectName || '', // 所属项目课题方案
        planName: selectedData.experimentCode || '', // 实验编号
        testName: selectedData.experimentName || '', // 实验名称
        notifyTime: selectedData.experimentDate || '', // 通知时间
        startTime: selectedData.experimentStartTime || '', // 实验开始时间
        endTime: selectedData.experimentEndTime || '', // 实验结束时间
        participants: selectedData.participantsName || '', // 参加人员
        status: this.getStatusText(selectedData.status) // 状态
      }];
      this.total = this.tableData.length;
      // 更新确认表单数据
      this.confirmFormData = {
        planName: selectedData.projectName || '',
        testCode: selectedData.experimentCode || '',
        testName: selectedData.experimentName || '',
        sampleCode: selectedData.experimentCode || '' // 使用实验编号作为取样单编号
      };
    },
    // 添加状态转换方法
    getStatusText(status) {
      const statusMap = {
        "-1": "草稿箱",
        "1": "待确认",
        "2": "已确认",
        "3": "已封存"
      };
      return statusMap[status] || "未知";
    },
    setSelectedIds(arr, selectKeyList) {
      function traverse(item) {
        item.selected = selectKeyList.includes(item.menuId);
@@ -235,37 +298,213 @@
      })
    },
    showAddTestItem() {
      this.currentTestItem = null // 清空当前编辑项
      this.testItemDialogVisible = true
    },
    handleTestItemDialogClose() {
      this.testItemDialogVisible = false
      this.currentTestItem = null
    },
    handleTestItemConfirm(formData) {
      // 将新增的检测项添加到列表中
      this.testItems.push({
        ...formData,
        index: this.testItems.length + 1
      })
      if (this.currentTestItem) {
        // 编辑模式
        const index = this.testItems.findIndex(item => item.termCode === this.currentTestItem.termCode)
        if (index !== -1) {
          this.testItems.splice(index, 1, {
            ...formData,
            id: this.currentTestItem.id // 保留原有ID
          })
        }
      } else {
        // 新增模式
        this.testItems.push({
          ...formData,
          id: this.generateUniqueId() // 生成唯一ID
        })
      }
      this.testItemDialogVisible = false
      this.$message.success('添加成功')
      this.currentTestItem = null
      this.$message.success(this.currentTestItem ? '编辑成功' : '添加成功')
    },
    handleEditTestItem(row) {
      this.currentTestItem = { ...row } // 深拷贝当前行数据
      this.testItemDialogVisible = true
    },
    handleDeleteTestItem(index) {
      this.$confirm('确认删除该检测项吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.testItems.splice(index, 1)
        this.$message.success('删除成功')
      }).catch(() => {})
    },
    generateUniqueId() {
      return 'test_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
    },
    handleSubmit() {
      // 这里可以添加表单验证逻辑
      if (this.testItems.length === 0) {
        this.$message.warning('请至少添加一个检测项')
        return
      }
      if (!this.selectedScheduling) {
        this.$message.warning('请选择实验调度')
        return
      }
      // 设置确认弹窗的数据
      this.confirmFormData = {
        planName: '项目名称示例',
        testCode: '实验编号示例',
        testName: '实验名称示例',
        sampleCode: '取样单编号示例'
        planName: this.selectedScheduling.projectName || '', // 所属项目课题方案
        testCode: this.selectedScheduling.experimentCode || '', // 实验编号
        testName: this.selectedScheduling.experimentName || '', // 实验名称
        sampleCode: this.selectedScheduling.experimentCode || '' // 取样单编号
      }
      this.confirmDialogVisible = true
    },
    handleConfirmSubmit(signatureImage) {
      // 处理最终提交逻辑
      console.log('提交确认单,签名图片:', signatureImage)
      // TODO: 调用提交API
      this.$message.success('提交成功')
      this.$router.push('/dataManagement/confirmation-sheet')
    }
    async handleConfirmSubmit(signatureImage) {
      try {
        // 构建提交数据
        const submitData = {
          dispatchId: this.selectedScheduling.id, // 实验调度ID
          auditStatus: 1, // 待确认状态
          confirmSign:'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'|| signatureImage, // 签字图片
          signTime: new Date().toISOString(), // 签字时间
          testMethodConfirmSheetTerms: this.testItems.map(item => ({
            id: item.id, // 保留原有ID(编辑时使用)
            termCode: item.termCode,
            termName: item.termName,
            termType: item.termType,
            termMethodCode: item.termMethodCode,
            termMethod: item.termMethod,
            sampleRequire: item.sampleRequire,
            status: 2, // 已填写状态
            testId: item.testId
          }))
        }
        // 打印提交参数
        console.log('提交确认单参数:', JSON.stringify(submitData, null, 2))
        // 根据是否有 id 决定调用新增还是更新接口
        if (this.formData.id) {
          submitData.id = this.formData.id
          console.log('调用更新接口,参数:', JSON.stringify(submitData, null, 2))
          await update(submitData)
          this.$message.success('更新成功')
        } else {
          console.log('调用新增接口,参数:', JSON.stringify(submitData, null, 2))
          await add(submitData)
          this.$message.success('提交成功')
        }
        this.confirmDialogVisible = false // 关闭弹窗
        this.$router.go(-1)
      } catch (error) {
        this.$message.error((this.formData.id ? '更新' : '提交') + '失败:' + (error.message || '未知错误'))
      }
    },
    async handleSaveDraft() {
      try {
        if (!this.selectedScheduling) {
          this.$message.warning('请选择实验调度')
          return
        }
        // 构建草稿数据
        const draftData = {
          dispatchId: this.selectedScheduling.id,
          auditStatus: -1, // 草稿箱状态
          testMethodConfirmSheetTerms: this.testItems.map(item => ({
            id: item.id, // 保留原有ID(编辑时使用)
            termCode: item.termCode,
            termName: item.termName,
            termType: item.termType,
            termMethodCode: item.termMethodCode,
            termMethod: item.termMethod,
            sampleRequire: item.sampleRequire,
            status: -1, // 草稿箱状态
            testId: item.testId
          }))
        }
        // 打印草稿参数
        console.log('保存草稿参数:', JSON.stringify(draftData, null, 2))
        // 根据是否有 id 决定调用新增还是更新接口
        if (this.formData.id) {
          draftData.id = this.formData.id
          console.log('调用更新草稿接口,参数:', JSON.stringify(draftData, null, 2))
          await update(draftData)
          this.$message.success('更新草稿成功')
        } else {
          console.log('调用新增草稿接口,参数:', JSON.stringify(draftData, null, 2))
          await add(draftData)
          this.$message.success('保存草稿成功')
        }
        this.$router.push('/dataManagement/confirmation-sheet')
      } catch (error) {
        this.$message.error((this.formData.id ? '更新' : '保存') + '草稿失败:' + (error.message || '未知错误'))
      }
    },
    async getDetailData(id) {
      try {
        const res = await getDetail({ id })
        if (res.data) {
          // 设置实验调度数据
          this.selectedScheduling = {
            id: res.data.dispatchId,
            // ... 其他调度相关字段
          }
          // 设置检测项数据
          this.testItems = res.data.testMethodConfirmSheetTerms.map(item => ({
            ...item,
            id: item.id // 使用后端返回的ID
          }))
          // 设置表单数据
          this.formData = {
            id: res.data.id,
            dispatchId: res.data.dispatchId,
            auditStatus: res.data.auditStatus,
            confirmSign: res.data.confirmSign,
            signTime: res.data.signTime
          }
        }
      } catch (error) {
        this.$message.error('获取详情失败:' + (error.message || '未知错误'))
      }
    },
    async handleEditSubmit(signatureImage) {
      try {
        const submitData = {
          id: this.formData.id,
          dispatchId: this.selectedScheduling.id,
          auditStatus: 1,
          confirmSign: signatureImage,
          signTime: new Date().toISOString(),
          testMethodConfirmSheetTerms: this.testItems.map(item => ({
            id: item.id, // 保留原有ID
            termCode: item.termCode,
            termName: item.termName,
            termType: item.termType,
            termMethodCode: item.termMethodCode,
            termMethod: item.termMethod,
            sampleRequire: item.sampleRequire,
            status: item.status,
            testId: item.testId
          }))
        }
        await update(submitData)
        this.$message.success('更新成功')
        this.$router.push('/dataManagement/confirmation-sheet')
      } catch (error) {
        this.$message.error('更新失败:' + (error.message || '未知错误'))
      }
    },
  },
};
</script>
laboratory/src/views/dataManagement/confirmation-sheet/components/confirm-dialog.vue
@@ -23,19 +23,19 @@
        </div>
      </div>
      <Table :tableData="sampleData" :total="0" :height="null">
      <Table :data="sampleData" :total="0" :height="null">
        <template>
          <el-table-column prop="index" label="序号" width="60" align="center"></el-table-column>
          <el-table-column prop="testName" label="检测项名称"></el-table-column>
          <el-table-column prop="testCode" label="检测项编号"></el-table-column>
          <el-table-column prop="testType" label="定性/定量" align="center">
          <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
          <el-table-column prop="termName" label="检测项名称"></el-table-column>
          <el-table-column prop="termCode" label="检测项编号"></el-table-column>
          <el-table-column prop="termType" label="定性/定量" align="center">
            <template slot-scope="scope">
              {{ scope.row.testType === 1 ? '定性' : '定量' }}
              {{ scope.row.termType === 1 ? '定性' : '定量' }}
            </template>
          </el-table-column>
          <el-table-column prop="methodCode" label="检测方法编号"></el-table-column>
          <el-table-column prop="methodName" label="检测方法"></el-table-column>
          <el-table-column prop="requirements" label="收样要求" show-overflow-tooltip></el-table-column>
          <el-table-column prop="termMethodCode" label="检测方法编号"></el-table-column>
          <el-table-column prop="termMethod" label="检测方法"></el-table-column>
          <el-table-column prop="sampleRequire" label="收样要求" show-overflow-tooltip></el-table-column>
        </template>
      </Table>
@@ -53,7 +53,7 @@
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" @click="handleConfirm" :disabled="!imgSrc">确 认</el-button>
      <el-button type="primary" @click="handleConfirm">确 认</el-button>
    </div>
    <SignatureCanvas
@@ -115,8 +115,12 @@
    },
    handleConfirm() {
      if (!this.imgSrc) {
        this.$message.warning("请先完成签名确认");
        return;
        this.$message({
          type: 'warning',
          message: '请先完成签名确认',
          duration: 2000
        })
        return
      }
      this.$emit("confirm", this.imgSrc);
      this.handleClose();
laboratory/src/views/dataManagement/confirmation-sheet/components/experimental-scheduling.vue
@@ -1,27 +1,33 @@
<template>
    <div>
        <el-dialog title="选择实验调度" :visible.sync="show" width="80%">
            <TableCustom :queryForm="form" :tableData="tableData" :total="total" :height="null">
        <el-dialog title="选择实验调度" :visible.sync="show" width="80%" @close="$emit('close', false)">
            <TableCustom
            :queryForm="form" :tableData="tableData"
            :total="total" :height="null"
             @handleCurrentChange="handleCurrentChange"
             @selection-change="changeSelectedRows"
             @handleSizeChange="handleSizeChange">
                <template #search>
                    <el-form :model="form" label-width="140px" inline>
                        <el-form-item label="所属项目课题方案:">
                            <el-input v-model="form.planName" placeholder="请输入"></el-input>
                            <el-input v-model="form.projectName" placeholder="请输入"></el-input>
                        </el-form-item>
                        <el-form-item label="实验编号:">
                            <el-input v-model="form.planCode" placeholder="请输入"></el-input>
                            <el-input v-model="form.experimentCode" placeholder="请输入"></el-input>
                        </el-form-item>
                        <el-form-item label="实验名称:">
                            <el-input v-model="form.creator" placeholder="请输入"></el-input>
                            <el-input v-model="form.experimentName" placeholder="请输入"></el-input>
                        </el-form-item>
                        <el-form-item label="通知时间:">
                            <el-date-picker v-model="form.createTime" type="daterange" range-separator="至"
                                start-placeholder="开始日期" end-placeholder="结束日期"
                                value-format="yyyy-MM-dd"></el-date-picker>
                                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="待确认"></el-option>
                                <el-option label="已确认" value="已确认"></el-option>
                                <el-option label="全部" value=""></el-option>
                                <el-option label="待确认" value="1"></el-option>
                                <el-option label="已确认" value="2"></el-option>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="" class="search-btn-box">
@@ -32,44 +38,157 @@
                </template>
                
                <template #table>
                    <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="selection" width="55"></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>
            </TableCustom>
            <span slot="footer" class="select-member-footer">
                <el-button @click="show = false">取 消</el-button>
                <el-button type="primary" @click="show = false">确 定</el-button>
                <el-button @click="$emit('close', false)">取 消</el-button>
                <el-button type="primary" @click="handleConfirm">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>
<script>
import { getDispatchList } from "../service";
export default {
    props: ['show'],
    props: {
        show: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            form: {},
            form: {
                projectName: "",
                experimentCode: "",
                experimentName: "",
                startTime: "",
                endTime: "",
                status: "",
                pageNum: 1,
                pageSize: 10
            },
            tableData: [],
            total: 0
            total: 0,
            selectedRows: []
        }
    },
    watch: {
        show(val) {
            if (val) {
                this.getTableData();
            }
        }
    },
    methods: {
        handleDateChange(val) {
            if (val) {
                this.form.startTime = val[0];
                this.form.endTime = val[1];
            } else {
                this.form.startTime = "";
                this.form.endTime = "";
            }
        },
        resetForm() {
            this.form = {
                projectName: "",
                experimentCode: "",
                experimentName: "",
                startTime: "",
                endTime: "",
                status: "",
                pageNum: 1,
                pageSize: 10
            };
            this.getTableData();
        },
        handleSearch() {
            this.form.pageNum = 1;
            this.getTableData();
        },
        getStatusType(status) {
            const statusMap = {
                "-1": "info",
                "1": "warning",
                "2": "success",
                "3": "info"
            };
            return statusMap[status] || "info";
        },
        getStatusText(status) {
            const statusMap = {
                "-1": "草稿箱",
                "1": "待确认",
                "2": "已确认",
                "3": "已封存"
            };
            return statusMap[status] || "未知";
        },
        getTableData() {
            const params = {
                ...this.form
            };
            getDispatchList(params).then(res => {
                console.log('222222222222',res)
                if (res) {
                    this.tableData = res || [];
                    this.total = res.length || 0;
                }
            });
        },
        handleCurrentChange(val) {
            this.form.pageNum = val;
            this.getTableData();
        },
        handleSizeChange(val) {
            this.form.pageSize = val;
            this.form.pageNum = 1;
            this.getTableData();
        },
        changeSelectedRows(val) {
            console.log('val',val)
            this.selectedRows = val;
        },
        handleCancel() {
            this.$emit('update:show', false);
        },
        handleConfirm() {
            if (!this.selectedRows || this.selectedRows.length === 0) {
                this.$message.warning('请至少选择一条数据');
                return;
            }
            if (this.selectedRows.length != 1) {
                this.$message.warning('请选择一条数据');
                return;
            }
            this.$emit('submit', this.selectedRows);
            this.$emit('close', false);
        }
    }
}
</script>
<style lang="less" scoped>
.select-member-footer {
    display: flex;
    justify-content: flex-end;
}
</style>
laboratory/src/views/dataManagement/confirmation-sheet/components/review-dialog.vue
@@ -1,11 +1,6 @@
<template>
  <el-dialog
    title="审核检测方法确认单"
    :visible.sync="visible"
    width="80%"
    :close-on-click-modal="false"
    @close="handleClose"
  >
  <el-dialog title="审核检测方法确认单" :visible="dialogVisible" width="80%" :close-on-click-modal="false" @close="handleClose"
    v-loading="loading">
    <div class="approval-dialog">
      <div class="approval-content">
        <div class="approval-content-card">
@@ -14,39 +9,46 @@
            <div class="basic-info">
              <div class="info-header">
                <div class="info-item">
                  <span class="label">所属项目课题方案:{{ formData.planName }}</span>
                  <span class="label">所属项目课题方案:{{ formData.projectName }}</span>
                </div>
                <div class="info-item">
                  <span class="label">实验名称:{{ formData.testName }}</span>
                  <span class="label">实验名称:{{ formData.experimentName }}</span>
                </div>
                <div class="info-item">
                  <span class="label">所属实验编号:{{ formData.testCode }}</span>
                  <span class="label">所属实验编号:{{ formData.experimentCode }}</span>
                </div>
              </div>
              <div class="info-header">
                <div class="info-item">
                  <span class="label">提交人:{{ formData.submitter }}</span>
                  <span class="label">提交人:{{ formData.createBy }}</span>
                </div>
                <div class="info-item">
                  <span class="label">提交人签名:{{ formData.submitterSignature }}</span>
                  <span class="label">提交人签名:</span>
                  <el-image style="width: 50px; height: 50px" v-if="formData.confirmSign" :src="formData.confirmSign"
                    :preview-src-list="[formData.confirmSign]">
                  </el-image>
                </div>
                <div class="info-item">
                  <span class="label">提交时间:{{ formData.submitTime }}</span>
                  <span class="label">提交时间:{{ formData.signTime }}</span>
                </div>
              </div>
            </div>
            <!-- 检测项表格 -->
            <div class="table-wrapper">
              <Table :tableData="sampleData" :total="0" :height="null">
              <Table :data="formData.testMethodConfirmSheetTerms" :total="0" :height="null">
                <template>
                  <el-table-column prop="index" label="序号" width="60" fixed></el-table-column>
                  <el-table-column prop="processTime" label="检验项名称"></el-table-column>
                  <el-table-column prop="sampleName" label="检验项编号"></el-table-column>
                  <el-table-column prop="sampleCode" label="定性/定量"></el-table-column>
                  <el-table-column prop="temperature" label="检测方法编号"></el-table-column>
                  <el-table-column prop="ph" label="检测方法"></el-table-column>
                  <el-table-column prop="waterAmount" label="收样要求"></el-table-column>
                  <el-table-column type="index" label="序号" width="60" fixed></el-table-column>
                  <el-table-column prop="termName" label="检验项名称"></el-table-column>
                  <el-table-column prop="termCode" label="检验项编号"></el-table-column>
                  <el-table-column prop="termType" label="定性/定量">
                    <template slot-scope="scope">
                      {{ scope.row.termType === 1 ? '定性' : '定量' }}
                    </template>
                  </el-table-column>
                  <el-table-column prop="termMethodCode" label="检测方法编号"></el-table-column>
                  <el-table-column prop="termMethod" label="检测方法"></el-table-column>
                  <el-table-column prop="sampleRequire" label="收样要求"></el-table-column>
                </template>
              </Table>
            </div>
@@ -56,12 +58,7 @@
      <div class="approval-flow">
        <div class="flow-content">
          <approval-process
            :status="formData.status"
            :submit-time="formData.submitTime"
            :approver="formData.approver"
            :approve-time="formData.approveTime"
          />
          <approval-process :processData="formData.processData" />
        </div>
      </div>
    </div>
@@ -72,29 +69,22 @@
        <span>签字确认</span>
        <el-button type="primary" class="el-icon-plus" @click="openSignature">签名</el-button>
      </div>
      <img
        v-if="imgSrc"
        :src="imgSrc"
        alt="签名"
        class="signature-preview"
      />
      <img v-if="imgSrc" :src="imgSrc" alt="签名" class="signature-preview" />
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" @click="handleConfirm" :disabled="!imgSrc">确 认</el-button>
      <el-button type="primary" @click="handleConfirm" :disabled="!imgSrc" v-if="type === 'review'">确 认</el-button>
    </div>
    <SignatureCanvas
      :visible="signatureDialogVisible"
      @confirm="handleSignatureConfirm"
    />
    <SignatureCanvas :visible="signatureDialogVisible" @confirm="handleSignatureConfirm" />
  </el-dialog>
</template>
<script>
import SignatureCanvas from "@/components/SignatureCanvas.vue";
import ApprovalProcess from "@/components/approvalProcess";
import { getDetail, sign } from '../service';
export default {
  name: "ReviewDialog",
@@ -111,63 +101,149 @@
      type: String,
      default: "review",
    },
    formData: {
      type: Object,
      default: () => ({
        planName: '',
        testCode: '',
        testName: '',
        submitter: '',
        submitterSignature: '',
        submitTime: '',
        status: '',
        approver: '',
        approveTime: ''
      }),
    },
    sampleData: {
      type: Array,
      default: () => [],
    },
    id: {
      type: String,
      default: '',
    }
  },
  data() {
    return {
      dialogVisible: false,
      signatureDialogVisible: false,
      imgSrc: "",
      formData: {
        projectName: '',
        experimentCode: '',
        experimentName: '',
        auditPersonId: '',
        auditSign: '',
        auditStatus: '',
        auditTime: '',
        confirmSign: '',
        dispatchId: '',
        signTime: '',
        testMethodConfirmSheetTerms: [],
        processData: []
      },
      loading: false
    };
  },
  watch: {
    visible(val) {
      this.dialogVisible = val;
      if (val && this.id) {
        this.getDetailData();
      }
    }
  },
  methods: {
    async getDetailData() {
      try {
        this.loading = true;
        const res = await getDetail({ id: this.id });
        console.log('res', res)
        if (res) {
          this.formData = res
          // 组装流程数据
          let processData = [];
          // 提交节点
          processData.push({
            type: "primary",
            mode: "list",
            fields: [
              { label: "提交人:", value: res.createBy || "" },
              { label: ' ', value: res.confirmSign || "", type: 'img' },
              { label: "提交时间:", value: res.createTime || "" },
            ],
          });
          if (res.auditStatus == 2) {
            processData.push({
              type: "primary",
              mode: "list",
              fields: [
                { label: "审核人:", value: res.auditPersonName || "" },
                { label: ' ', value: res.auditSign || "", type: 'img' },
                { label: "审核时间:", value: res.auditTime || "" },
              ],
            });
          } else if (res.auditStatus == 1) {
            processData.push({
              type: "warning",
              mode: "list",
              fields: [
                { label: "等待审核" },
              ],
            });
          }
          this.formData.processData = processData
        } else {
          this.$message.error(res.msg || '获取详情失败');
        }
      } catch (error) {
        console.error('获取详情失败:', error);
        this.$message.error('获取详情失败');
      } finally {
        this.loading = false;
      }
    },
    handleClose() {
      this.$emit("update:visible", false);
      this.dialogVisible = false;
      this.$emit("close", false);
      this.imgSrc = "";
      this.formData = {
        projectName: '',
        experimentCode: '',
        experimentName: '',
        auditPersonId: '',
        auditSign: '',
        auditStatus: '',
        auditTime: '',
        confirmSign: '',
        dispatchId: '',
        signTime: '',
        testMethodConfirmSheetTerms: [],
        processData: []
      };
    },
    openSignature() {
      this.signatureDialogVisible = true;
    },
    handleSignatureConfirm(imageData) {
      this.signatureDialogVisible = false;
      this.imgSrc = imageData;
      this.imgSrc = 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg';
    },
    handleConfirm() {
      if (!this.imgSrc) {
        this.$message.warning("请先完成签名确认");
        return;
      }
      this.$emit("confirm", this.imgSrc);
      this.handleClose();
      // 组装签名数据
      const params = {
        testMethodConfirmSheetId: this.id, // 传递当前确认单id
        confirmSign: this.imgSrc, // 签名图片
      };
      sign(params).then(res => {
        if (res && res.code === 200) {
          this.$message.success('签字成功');
          this.handleClose();
        } else {
          this.$message.error(res.msg || '签字失败');
        }
      }).catch(() => {
        this.$message.error('签字失败');
      });
    },
  },
};
</script>
<style lang="less" scoped>
.approval-dialog {
  display: flex;
  min-height: 60vh;
  max-height: 80vh;
  overflow: hidden;
  @media screen and (max-width: 1024px) {
    flex-direction: column;
  }
@@ -176,7 +252,7 @@
    flex: 1;
    margin: 20px;
    background: #ffffff;
    box-shadow: 0px 4px 12px 4px rgba(0,0,0,0.08);
    box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    overflow-y: auto;
@@ -190,11 +266,12 @@
  .approval-flow {
    width: 405px;
    background: #ffffff;
    box-shadow: 0px 4px 12px 4px rgba(0,0,0,0.08);
    box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    padding: 40px 20px;
    margin: 20px;
    margin-left: 0;
    @media screen and (max-width: 1024px) {
      width: 100%;
      padding: 20px;
@@ -209,7 +286,7 @@
.basic-info {
  padding: 28px 20px;
  background: linear-gradient( 180deg, #05A0C1 0%, #05F2C2 100%);
  background: linear-gradient(180deg, #05A0C1 0%, #05F2C2 100%);
  border-radius: 10px 10px 0 0;
  color: #fff;
@@ -231,6 +308,7 @@
    .info-item {
      flex: 1;
      min-width: 250px;
      display: flex;
      @media screen and (max-width: 768px) {
        min-width: 100%;
@@ -238,8 +316,8 @@
      .label {
        font-size: 14px;
        white-space: normal;
        word-break: break-all;
        // white-space: normal;
        // word-break: break-all;
      }
    }
  }
@@ -250,6 +328,7 @@
  background: #ffffff;
  border-radius: 4px;
  overflow-x: auto;
  ::v-deep .el-table {
    width: 100%;
    min-width: 800px;
@@ -302,8 +381,10 @@
  height: calc(100% - 100px) !important;
  box-shadow: none !important;
}
::v-deep .el-dialog__body {
  padding: 0;
  @media screen and (max-width: 768px) {
    padding: 15px;
  }
@@ -322,4 +403,12 @@
    line-height: 1.5;
  }
}
</style>
.signature-image {
  max-width: 200px;
  max-height: 100px;
  margin-top: 8px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
}
</style>
laboratory/src/views/dataManagement/confirmation-sheet/index.vue
@@ -1,6 +1,7 @@
<template>
    <div class="list">
        <TableCustom :queryForm="form" :tableData="tableData" :total="total">
        <TableCustom :queryForm="form" :height="null" :tableData="tableData" :total="total"
            @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange">
            <template #search>
                <el-form :model="form" label-width="140px" inline>
                    <el-form-item label="所属项目课题方案:">
@@ -14,11 +15,10 @@
                    </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"
                            start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd"
                            @change="handleDateChange"></el-date-picker>
                    </el-form-item>
                    <el-form-item label="状态:" v-if="!isDrafts">
                    <el-form-item label="状态:">
                        <el-select v-model="form.auditStatus" placeholder="请选择">
                            <el-option label="待确认" :value="1"></el-option>
                            <el-option label="已通过" :value="2"></el-option>
@@ -36,48 +36,86 @@
            <template #setting>
                <div class="tableTitle">
                    <div class="flex a-center" style="gap: 16px;">
                        <div class="title pointer" :class="{ active: !isDrafts }" @click="switchToDrafts(false)">检验方法确认单列表</div>
                        <div class="drafts pointer" :class="{ active: isDrafts }" @click="switchToDrafts(true)">草稿箱</div>
                        <div class="title pointer" :class="{ active: !isDrafts }" @click="switchToDrafts(false)">
                            检验方法确认单列表</div>
                        <div class="drafts pointer" :class="{ active: isDrafts }" @click="switchToDrafts(true)">草稿箱
                        </div>
                    </div>
                    <el-button @click="handleAddPlan" class="el-icon-plus" type="primary">
                        新增检测方法确认单</el-button>
                </div>
            </template>
            <template #table>
                <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="creator" label="状态"></el-table-column>
                <el-table-column label="操作" width="150">
                <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="createTime" label="提交时间"></el-table-column>
                <el-table-column prop="createBy" label="提交人"></el-table-column>
                <el-table-column label="状态" width="100">
                    <template slot-scope="scope">
                        <el-button type="text" @click="handleReview(scope.row)">审核</el-button>
                        <el-button type="text" @click="handleRevoke(scope.row)">撤销</el-button>
                        <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
                        <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
                        <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
                        <el-tag :type="getStatusType(scope.row.auditStatus)">
                            {{ getStatusText(scope.row.auditStatus) }}
                        </el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="200">
                    <template slot-scope="scope">
                        <!-- 超级管理员(1)和审批人(2) -->
                        <template v-if="userRole == '1' || userRole == '2'">
                            <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
                        </template>
                        <!-- 工艺工程师(3) -->
                        <template v-if="userRole == '3'">
                            <el-button type="text" @click="handleReview(scope.row)"
                                v-if="scope.row.auditStatus == 1">审核</el-button>
                            <el-button type="text" @click="handleDetail(scope.row)"
                                v-if="scope.row.auditStatus == 2">详情</el-button>
                        </template>
                        <!-- 化验师(4) -->
                        <template v-if="userRole == '4'">
                            <el-button type="text" @click="handleRevoke(scope.row)"
                                v-if="scope.row.auditStatus == 1">撤销</el-button>
                            <el-button type="text" @click="handleDetail(scope.row)"
                                v-if="scope.row.auditStatus === 2 || scope.row.auditStatus === 3">详情</el-button>
                            <el-button type="text" @click="handleEdit(scope.row)"
                                v-if="scope.row.auditStatus === 3">编辑</el-button>
                            <el-button type="text" @click="handleDelete(scope.row)"
                                v-if="scope.row.auditStatus === 3">删除</el-button>
                        </template>
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <ShowDelConfirm :show="showRevoke" btnType="primary" @close="showRevoke = false" tip="撤销后,工艺工程师将无法收到此审批信息" okText="确定" title="确认要撤销这条确认单吗?"/>
        <review-dialog
            :visible.sync="reviewDialogVisible"
            :type="dialogType"
            :formData="currentRow"
            :sampleData="sampleData"
            @confirm="handleConfirmSubmit"
        />
        <ShowDelConfirm
            :show="showRevoke"
            btnType="primary"
            v-on:close="showRevoke = false"
            tip="撤销后,工艺工程师将无法收到此审批信息"
            okText="确定"
            title="确认要撤销这条确认单吗?"
            v-on:confirm="handleRevokeConfirm" />
        <ShowDelConfirm
            :show="showDelete"
            :title="deleteTitle"
            :tip="deleteTip"
            v-on:close="showDelete = false"
            v-on:confirm="handleDeleteConfirm" />
        <review-dialog :visible.sync="reviewDialogVisible" :type="dialogType" :id="currentRow.id"
             @close="handleClose" />
    </div>
</template>
<script>
import reviewDialog from './components/review-dialog.vue';
import { getList } from './service'
import ShowDelConfirm from "@/components/showDelConfirm/index.vue";
import { getList, deleteById, revokedSheet } from './service'
export default {
    name: "ConfirmationSheet",
    components: {
        reviewDialog
        reviewDialog,
        ShowDelConfirm
    },
    data() {
        return {
@@ -96,34 +134,43 @@
            showRevoke: false,
            tableData: [],
            total: 0,
            editorContent: '',
            reviewDialogVisible: false,
            dialogType: 'review',
            currentRow: {},
            sampleData: [],
            userRole: null,
            showDelete: false,
            deleteTitle: "",
            deleteTip: "",
            currentDeleteRow: null,
        };
    },
    mounted() {
        // 获取用户角色
        const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
        this.userRole = userInfo.roleType;
        this.getTableData();
    },
    methods: {
        async getTableData() {
            try {
                const params = { ...this.form };
                if (this.isDrafts) {
                    params.auditStatus = -1;
                }
                const params = {
                    ...this.form,
                    pageNum: Number(this.form.pageNum),
                    pageSize: Number(this.form.pageSize),
                    auditStatus: this.isDrafts ? -1 : Number(this.form.auditStatus) || ''
                };
                const res = await getList(params);
                if (res.code === 200) {
                    this.tableData = res.data.list || [];
                    this.tableData = res.data.records || [];
                    this.total = res.data.total || 0;
                }
            } catch (error) {
                console.error('获取列表数据失败:', error);
                this.$message.error('获取列表数据失败');
            }
        },
        handleDateChange(val) {
            if (val) {
            if (val && val.length === 2) {
                this.form.startTime = val[0];
                this.form.endTime = val[1];
            } else {
@@ -149,25 +196,37 @@
            this.form.pageNum = 1;
            this.getTableData();
        },
        handleCurrentChange(val) {
            this.form.pageNum = val;
            this.getTableData();
        },
        handleSizeChange(val) {
            this.form.pageSize = val;
            this.getTableData();
        },
        switchToDrafts(isDrafts) {
            this.isDrafts = isDrafts;
            this.resetForm();
        },
        getStatusType(status) {
            const statusMap = {
                pending: "warning",
                rejected: "danger",
                approved: "success",
                archived: "info",
                1: "warning",    // 待确认
                2: "success",    // 已通过
                3: "danger",     // 已驳回
                4: "info",       // 已撤回
                5: "info",       // 已封存
                '-1': "info"     // 草稿箱
            };
            return statusMap[status] || "info";
        },
        getStatusText(status) {
            const statusMap = {
                pending: "待审批",
                rejected: "已驳回",
                approved: "已通过",
                archived: "已封存",
                1: "待确认",
                2: "已通过",
                3: "已驳回",
                4: "已撤回",
                5: "已封存",
                '-1': "草稿箱"
            };
            return statusMap[status] || "未知";
        },
@@ -186,21 +245,52 @@
            this.showRevoke = true;
        },
        handleDetail(row) {
            // 实现查看详情逻辑
            console.log("查看详情:", row);
            this.currentRow = row;
            this.dialogType = 'view';
            this.reviewDialogVisible = true;
        },
        handleEdit(row) {
            // 实现编辑逻辑
            console.log("编辑:", row);
            this.$router.push({
                path: "/dataManagement/confirmation-sheet/edit",
                query: { id: row.id }
            });
        },
        handleDelete(row) {
            // 实现删除逻辑
            console.log("删除:", row);
            this.currentDeleteRow = row;
            this.deleteTitle = "确认要删除该确认单吗?";
            this.deleteTip = "删除后信息无法找回";
            this.showDelete = true;
        },
        handleConfirmSubmit(data) {
            // 处理确认提交后的逻辑
            console.log("确认提交:", data);
        handleDeleteConfirm() {
            if (!this.currentDeleteRow) return;
            deleteById({
                id: this.currentDeleteRow.id
            }).then(() => {
                this.$message.success("删除成功");
                this.showDelete = false;
                this.getTableData();
            }).catch(error => {
                this.$message.error("删除失败");
            });
        },
        handleClose() {
            this.reviewDialogVisible = false;
            this.getTableData();
        },
        async handleRevokeConfirm() {
            if (!this.currentRow) return;
            try {
                await revokedSheet({ id: this.currentRow.id });
                this.$message.success("撤销成功");
                this.showRevoke = false;
                this.getTableData();
            } catch (error) {
                console.error('撤销失败:', error);
                this.$message.error("撤销失败");
            }
        }
    },
};
</script>
@@ -224,7 +314,9 @@
    padding-bottom: 20px;
    justify-content: space-between;
    align-items: center;
    .title, .drafts {
    .title,
    .drafts {
        background: #ffffff;
        border-radius: 8px 8px 0px 0px;
        padding: 16px 29px;
@@ -244,9 +336,8 @@
    .drafts {
        padding: 16px 65px;
        &:not(.active) {
        }
        &:not(.active) {}
    }
}
laboratory/src/views/dataManagement/confirmation-sheet/service.js
@@ -2,5 +2,37 @@
// 列表
export const getList = (data) => {
  return axios.post('/t-experiment-dispatch/api/t-experiment-dispatch/pageList', { ...data })
}
  return axios.post('/api/t-test-method-confirm-sheet/pageList', { ...data })
}
// 详情
export const getDetail = (data) => {
  return axios.get('/open/t-test-method-confirm-sheet/getDetailById', { params:data })
}
//添加
export const add = (data) => {
  return axios.post('/api/t-test-method-confirm-sheet/add', { ...data })
}
//修改
export const update = (data) => {
  return axios.post('/api/t-test-method-confirm-sheet/update', { ...data })
}
//删除
export const deleteById = (data) => {
  return axios.delete('/open/t-test-method-confirm-sheet/deleteById', { params:data })
}
//批量删除
export const deleteByIds = (data) => {
  return axios.delete('/open/t-test-method-confirm-sheet/deleteByIds', { params:data })
}
// 签名
export const sign = (data) => {
  return axios.post('/api/t-test-method-confirm-sheet/sign', { ...data })
}
// 获取实验调度列表
export const getDispatchList = (data) => {
  return axios.get('/open/t-experiment-dispatch/chemistSignList', { params:data })
}
// 撤销
export const revokedSheet = (data) => {
  return axios.get('/open/t-test-method-confirm-sheet/revokedSheet', { params:data })
}
laboratory/src/views/dataManagement/dispatching/addDispatch.vue
@@ -15,129 +15,183 @@
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="项目课题方案名称">
            <el-input v-model="form.name" placeholder="请输入" />
          <el-form-item prop="projectName" label="项目课题方案名称">
            <el-select
              ref="projectNameSelect"
              v-model="form.projectName"
              filterable
              remote
              :remote-method="debouncedSearch"
              :loading="projectLoading"
              placeholder="请输入方案名称"
              @change="handleProjectNameChange"
              @focus="handleProjectFocus"
            >
              <el-option
                v-for="item in projectOptions"
                :key="item.id"
                :label="item.projectName"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
          <el-form-item prop="description" label="项目课题方案编号">
            <el-input v-model="form.description" placeholder="请输入" />
          <el-form-item prop="proposalId" label="项目课题方案编号">
            <el-select
              ref="proposalIdSelect"
              v-model="form.proposalId"
              filterable
              remote
              :remote-method="debouncedSearch"
              :loading="projectLoading"
              placeholder="请输入方案编号"
              @change="handleProposalIdChange"
              @focus="handleProjectFocus"
            >
              <el-option
                v-for="item in projectOptions"
                :key="item.id"
                :label="item.projectCode"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
          <el-form-item prop="description" label="项目阶段">
            <el-input v-model="form.description" placeholder="请输入" />
          <el-form-item prop="projectStage" label="项目阶段">
            <el-select v-model="form.projectStage" disabled placeholder="请选择">
              <el-option label="实验室开发阶段" :value="1" />
              <el-option label="中式试验阶段" :value="2" />
              <el-option label="生产验证试验阶段" :value="3" />
            </el-select>
          </el-form-item>
        </div>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>二 、实验信息</span>
          </div>
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
          <img src="@/assets/public/headercard.png" />
          <span>二 、实验信息</span>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验日期">
            <el-input v-model="form.name" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="实验名称">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="实验编号">
            <el-input v-model="form.description" placeholder="请输入" />
          </el-form-item>
        </div>
      </div>
      <div style="padding-left: 25px">
        <el-form-item prop="experimentDate" label="试验日期">
          <el-date-picker
            name="data-test"
            v-model="form.experimentDate"
            type="date"
            placeholder="选择日期"
            @change="handleDateChange"
          ></el-date-picker>
        </el-form-item>
        <el-form-item prop="experimentName" label="实验名称">
          <el-input v-model="form.experimentName" placeholder="请输入" />
        </el-form-item>
        <el-form-item prop="experimentCode" label="实验编号">
          <el-input v-model="form.experimentCode" placeholder="请输入" disabled/>
        </el-form-item>
      </div>
        <div class="add-group">
          <span>实验分组</span>
          <el-button type="primary" class="el-icon-plus" @click="handleAddGroup">添加组别</el-button>
        </div>
        <Table
          :data="groupTableData"
          :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>
          <el-table-column label="操作" width="200">
            <template slot-scope="scope">
              <el-button type="text" @click="handleEditGroup(scope.row)">编辑</el-button>
              <el-button type="text" @click="handleDeleteGroup(scope.row)">移除</el-button>
            </template>
          </el-table-column>
        </Table>
      <div class="add-group">
        <span>实验分组</span>
        <el-button type="primary" class="el-icon-plus" @click="handleAddGroup">添加组别</el-button>
      </div>
      <Table
        :data="groupTableData"
        :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>
        <el-table-column label="操作" width="200">
          <template slot-scope="scope">
            <el-button type="text" @click="handleEditGroup(scope.row)">编辑</el-button>
            <el-button type="text" @click="handleDeleteGroup(scope.row)">移除</el-button>
          </template>
        </el-table-column>
      </Table>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>三 、计划时间及人员</span>
          </div>
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
          <img src="@/assets/public/headercard.png" />
          <span>三 、计划时间及人员</span>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验时间">
            <el-input v-model="form.name" placeholder="请输入" />
          </el-form-item>
        </div>
        <div class="add-group">
          <div>*</div>
          <span>参加人员</span>
          <el-button type="primary" class="el-icon-plus" @click="addMember">选择参加人员</el-button>
        </div>
        <div class="member-list">
          <div v-for="item in 3" :key="item" class="member-list-card">
            <div class="member-item">
              <div class="member-title">
                {{ ["工艺工程师", "实验员", "化验师"][item - 1] }}
              </div>
      </div>
      <div style="padding-left: 25px">
        <el-form-item prop="experimentTime" label="试验时间">
          <el-date-picker
            style="width: 100%"
            v-model="form.experimentTime"
            type="datetimerange"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            value-format="yyyy-MM-dd HH:mm:ss"
            :default-time="['00:00:00', '23:59:59']"
            @change="handleTimeRangeChange"
          ></el-date-picker>
        </el-form-item>
      </div>
      <div class="add-group">
        <div>*</div>
        <span>参加人员</span>
        <el-button type="primary" class="el-icon-plus" @click="addMember">选择参加人员</el-button>
      </div>
      <div class="member-list">
        <div v-for="item in [3,4,5]" :key="item" class="member-list-card">
          <div class="member-item">
            <div class="member-title">
              {{ ["工艺工程师",  "化验师","实验员"][item - 3] }}
            </div>
            <div
              :class="item == 3 ? 'member-name-box' : 'flex1'"
            >
              <div
                :class="item == 1 || item == 2 ? 'member-name-box' : 'flex1'"
                :class="
                  item == 3
                    ? 'member-name-box'
                    : 'member-name-box-2'
                "
              >
                <div
                  :class="
                    item == 1 || item == 2
                      ? 'member-name-box'
                      : 'member-name-box-2'
                  "
                  v-for="i in memberList(item)"
                  :key="i.userId"
                  class="member-name"
                >
                  <div
                    v-for="i in memberList(item)"
                    :key="i"
                    class="member-name"
                  >
                    张三
                  </div>
                  {{ i.nickName }}
                </div>
              </div>
              <div class="member-change">
                <div class="member-change-btn">修改</div>
              </div>
            </div>
            <div class="member-change">
              <div class="member-change-btn" @click="editUserList(item)" v-if="item == 4 || item == 5">修改</div>
            </div>
          </div>
        </div>
      </div>
        <div class="header-title" style="margin-bottom: 38px">
          <div class="header-title-left">
            <img src="@/assets/public/headercard.png" />
            <span>四 、任务分解</span>
          </div>
          <el-button type="primary" class="el-icon-plus" @click="handleAddTask">新增任务</el-button>
      <div class="header-title" style="margin-bottom: 38px">
        <div class="header-title-left">
          <img src="@/assets/public/headercard.png" />
          <span>四 、任务分解</span>
        </div>
        <el-button type="primary" class="el-icon-plus" @click="handleAddTask">新增任务</el-button>
      </div>
        <Table
          :data="taskTableData"
          :total="0"
          :height="null"
          class="rwuTable"
        >
          <el-table-column type="index" label="序号" width="80"></el-table-column>
          <el-table-column prop="taskName" label="任务名称"></el-table-column>
          <el-table-column prop="leader" label="负责人"></el-table-column>
          <el-table-column prop="startTime" label="开始时间"></el-table-column>
          <el-table-column label="操作" width="200">
            <template slot-scope="scope">
              <el-button type="text" @click="handleEditTask(scope.row)">编辑</el-button>
              <el-button type="text" @click="handleDeleteTask(scope.row)">移除</el-button>
            </template>
          </el-table-column>
        </Table>
      <Table
        :data="taskTableData"
        :total="0"
        :height="null"
        class="rwuTable"
      >
        <el-table-column type="index" label="序号" width="80"></el-table-column>
        <el-table-column prop="taskName" label="任务名称"></el-table-column>
        <el-table-column prop="personCharge" label="负责人"></el-table-column>
        <el-table-column prop="startTime" label="开始时间"></el-table-column>
        <el-table-column label="操作" width="200">
          <template slot-scope="scope">
            <el-button type="text" @click="handleEditTask(scope.row)">编辑</el-button>
            <el-button type="text" @click="handleDeleteTask(scope.row)">移除</el-button>
          </template>
        </el-table-column>
      </Table>
        <div class="header-title">
          <div class="header-title-left">
@@ -145,14 +199,22 @@
            <span>五 、关键节点</span>
          </div>
        </div>
        <div style="padding: 20px 55px 20px 25px">
          <AIEditor
            ref="keyNodesEditor"
            :value="form.keyNodes"
            :min-height="200"
            placeholder="请输入关键节点内容"
          />
        </div>
        <div class="add-project-footer">
          <el-button type="primary" class="save-btn">发送</el-button>
          <el-button>存草稿</el-button>
          <el-button type="primary" class="save-btn" @click="sendDispatch">保存</el-button>
          <el-button @click="saveDraft">存草稿</el-button>
        </div>
      </el-form>
    </template>
    <SelectMember ref="selectMember" />
    <SelectMember ref="selectMember"  @submit="selectUser" />
    <AddGroupDialog ref="addGroupDialog" @submit="handleGroupSubmit" />
    <AddTaskDialog ref="addTaskDialog" @submit="handleTaskSubmit" />
  </Card>
@@ -162,53 +224,246 @@
import SelectMember from '@/components/SelectMember'
import AddGroupDialog from './components/AddGroupDialog'
import AddTaskDialog from './components/AddTaskDialog'
import AIEditor from '@/components/AiEditor'
import { getProposalList, addDispatch, updateDispatch } from './service'
export default {
  name: "AddProject",
  components: {
    SelectMember,
    AddGroupDialog,
    AddTaskDialog
    AddTaskDialog,
    AIEditor
  },
  data() {
    return {
      form: {},
      id: '', // 用于编辑时存储id
      form: {
        projectName: '', // 课题方案名称
        proposalId: '', // 项目课题方案id
        projectStage: '', // 项目阶段
        experimentName: '', // 实验名称
        experimentCode: '', // 实验编号
        experimentDate: '', // 实验日期
        experimentTime: [], // 实验时间范围
        status: -1, // 状态 -1=草稿箱 1=待确认 2=已确认 3=已封存
        experimentDispatchGroups: [], // 组别列表
        experimentDispatchParticipants: [], // 参与人员
        experimentDispatchTasks: [], // 任务列表
        keyNodes: '' // 关键节点
      },
      rules: {
        name: [
          { required: true, message: "请输入项目组名称", trigger: "blur" },
        projectName: [
          { required: true, message: "请输入项目课题方案名称", trigger: "blur" },
        ],
        description: [
          { required: true, message: "请输入项目组描述", trigger: "blur" },
        proposalId: [
          { required: true, message: "请输入项目课题方案编号", trigger: "blur" },
        ],
        experimentName: [
          { required: true, message: "请输入实验名称", trigger: "blur" },
        ],
        experimentDate: [
          { required: true, message: "请选择实验日期", trigger: "change" },
        ],
        experimentTime: [
          { required: true, message: "请选择实验时间范围", trigger: "change" },
        ],
      },
      groupTableData: [],
      taskTableData: []
      taskTableData: [],
      members: {
        processEngineer: [], // 工艺工程师
        experimenter: [], // 实验员
        analyst: [] // 化验师
      },
      selectMemberData: [],
      ROLE_CONFIG: {
        "3": { label: "工艺工程师", limit: 1, default: true }, // 工艺工程师
        "5": { label: "实验员", limit: 8 }, // 实验员
        "4": { label: "化验师", limit: 8 }  // 化验师
      },
      currentEditRoleId: null,
      // 下拉框数据
      projectOptions: [], // 所有方案数据
      projectLoading: false, // 加载状态
      // 缓存数据
      projectDataMap: new Map(), // 缓存方案数据,key为方案ID
    };
  },
  methods: {
    // 获取当前用户信息
    getCurrentUser() {
      const userInfo = sessionStorage.getItem('userInfo');
      return userInfo ? JSON.parse(userInfo) : null;
    },
    addMember() {
      // 判断是否选择了项目课题方案
      if (!this.form.proposalId) {
        this.$message.warning('请先选择项目课题方案');
        return;
      }
      // 获取当前用户信息
      const currentUser = this.getCurrentUser();
      // 如果当前用户是工艺工程师,则自动添加到工艺工程师列表中
      if (currentUser && !this.members.processEngineer.length) {
        this.members.processEngineer = [{
          userId: currentUser.userId,
          nickName: currentUser.nickName,
          avatar: currentUser.avatar,
          roleId: 3,
          roleName: '工艺工程师'
        }];
        // 同时更新selectMemberData
        this.selectMemberData = [...this.members.processEngineer];
      }
      // 设置当前编辑角色为null,表示是新增操作
      this.currentEditRoleId = null;
      // 打开选择弹窗,并传入项目ID
      this.$refs.selectMember.open();
      // 设置项目ID
      this.$refs.selectMember.projectId = this.form.proposalId;
      // 设置已选中的成员
      this.$nextTick(() => {
        const selectedMembers = [
          ...this.members.processEngineer,
          ...this.members.experimenter,
          ...this.members.analyst
        ];
        this.$refs.selectMember.setSelection(selectedMembers);
      });
    },
    editUserList(roleId) {
      // 判断是否选择了项目课题方案
      if (!this.form.proposalId) {
        this.$message.warning('请先选择项目课题方案');
        return;
      }
      // 如果是工艺工程师,不允许修改
      if (roleId === 3) {
        this.$message.warning('工艺工程师不可修改');
        return;
      }
      // 保存当前正在编辑的角色ID
      this.currentEditRoleId = roleId;
      // 打开选择弹窗,并传入项目ID
      this.$refs.selectMember.open();
      // 设置项目ID
      this.$refs.selectMember.projectId = this.form.proposalId;
      // 设置已选中的成员(只设置当前角色的成员)
      this.$nextTick(() => {
        let selectedMembers = [];
        switch (roleId) {
          case 5: // 实验员
            selectedMembers = [...this.members.experimenter];
            break;
          case 4: // 化验师
            selectedMembers = [...this.members.analyst];
            break;
        }
        this.$refs.selectMember.setSelection(selectedMembers);
      });
    },
    selectUser(data) {
      // 检查每个角色的选择数量限制
      for (const [roleId, config] of Object.entries(this.ROLE_CONFIG)) {
        const members = data.filter(item => item.roleId === parseInt(roleId));
        if (members.length > config.limit) {
          this.$message.error(`${config.label}最多只能选择${config.limit}个`);
          return;
        }
      }
      // 获取当前正在编辑的角色ID
      const currentRoleId = this.currentEditRoleId;
      if (currentRoleId === null) {
        // 如果是新增操作,更新所有角色的数据
        this.members = {
          processEngineer: this.members.processEngineer, // 保持工艺工程师不变
          experimenter: data.filter(item => item.roleId === 5), // 实验员
          analyst: data.filter(item => item.roleId === 4) // 化验师
        };
      } else {
        // 如果是编辑操作,只更新当前编辑的角色数据
        if (currentRoleId === 5) { // 实验员
          this.members.experimenter = data.filter(item => item.roleId === 5);
        } else if (currentRoleId === 4) { // 化验师
          this.members.analyst = data.filter(item => item.roleId === 4);
        }
      }
      // 更新selectMemberData,合并所有角色的数据
      this.selectMemberData = [
        ...this.members.processEngineer,
        ...this.members.experimenter,
        ...this.members.analyst
      ];
      this.$refs.selectMember.close();
      // 清理选择数据
      this.$nextTick(() => {
        this.$refs.selectMember.setSelection([]);
      });
    },
    memberList(type) {
      switch (type) {
        case 3: // 工艺工程师
          return this.members.processEngineer;
        case 5: // 实验员
          return this.members.experimenter;
        case 4: // 化验师
          return this.members.analyst;
        default:
          return [];
      }
    },
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          console.log("submit!");
          // 构建提交数据
          const submitData = {
            ...this.form,
            experimentDispatchGroups: this.groupTableData.map(item => ({
              groupName: item.groupName,
              remark: item.remark
            })),
            experimentDispatchTasks: this.taskTableData.map(item => ({
              taskName: item.taskName,
              personCharge: item.leader,
              startTime: item.startTime
            })),
            experimentDispatchParticipants: [
              ...this.members.processEngineer.map(userId => ({
                userId,
                roleType: 3, // 工艺工程师
                status: 1 // 待确认
              })),
              ...this.members.experimenter.map(userId => ({
                userId,
                roleType: 5, // 实验员
                status: 1 // 待确认
              })),
              ...this.members.analyst.map(userId => ({
                userId,
                roleType: 4, // 化验师
                status: 1 // 待确认
              }))
            ]
          };
          // TODO: 调用接口提交数据
          console.log('提交数据:', submitData);
        }
      });
    },
    addMember() {
      this.$refs.selectMember.open();
    },
    memberList(i) {
      switch (i) {
        case 1:
          return [1];
        case 2:
          return [1];
        case 3:
          return [1, 2, 3, 4, 5, 6, 7, 8];
        case 4:
          return [1, 2, 3, 4, 5, 6, 7, 8];
        default:
          break;
      }
    },
    handleAddGroup() {
      this.$refs.addGroupDialog.open()
    },
@@ -235,12 +490,26 @@
      } else {
        this.groupTableData.push(form)
      }
      // 更新表单数据
      this.form.experimentDispatchGroups = this.groupTableData;
    },
    handleAddTask() {
      this.$refs.addTaskDialog.open()
      // 获取所有参与人员数据
      const allParticipants = [
        ...this.members.processEngineer,
        ...this.members.experimenter,
        ...this.members.analyst
      ];
      this.$refs.addTaskDialog.open(null, allParticipants);
    },
    handleEditTask(row) {
      this.$refs.addTaskDialog.open(row)
      // 获取所有参与人员数据
      const allParticipants = [
        ...this.members.processEngineer,
        ...this.members.experimenter,
        ...this.members.analyst
      ];
      this.$refs.addTaskDialog.open(row, allParticipants);
    },
    handleDeleteTask(row) {
      this.$confirm('确认删除该任务吗?', '提示', {
@@ -256,18 +525,312 @@
      }).catch(() => {})
    },
    handleTaskSubmit(form) {
      const index = this.taskTableData.findIndex(item => item.taskName === form.taskName)
      const index = this.taskTableData.findIndex(item => item.taskName === form.taskName);
      const taskData = {
        id: form.id || '', // 编辑时使用原id,新增时为空
        taskName: form.taskName,
        personCharge: form.leader, // 负责人名称
        startTime: form.startTime,
        dispatchId: this.id || '', // 实验调度id
        selectedUsers: form.selectedUsers // 保存选中的用户ID数组
      };
      if (index > -1) {
        this.taskTableData.splice(index, 1, form)
        this.taskTableData.splice(index, 1, taskData);
      } else {
        this.taskTableData.push(form)
        this.taskTableData.push(taskData);
      }
      // 更新表单数据
      this.form.experimentDispatchTasks = this.taskTableData;
    },
    // 获取所有编辑器的内容
    getAllEditorContent() {
      return {
        keyNodes: this.$refs.keyNodesEditor.getContent()
      }
    },
    // 统一处理方法
    handleSubmit(type) {
      this.$refs.form.validate((valid) => {
        if (valid) {
          // 获取所有编辑器内容
          const editorContents = this.getAllEditorContent()
          // 检查编辑器内容是否为空
          const isEmptyContent = (content) => {
            return !content || content === '<p></p>' || content.trim() === '<p></p>'
          }
          if (isEmptyContent(editorContents.keyNodes)) {
            this.$message.warning('请填写关键节点')
            return false
          }
          // 构建提交数据
          const formData = {
            ...this.form,
            keyNodes: editorContents.keyNodes,
            // 移除不需要传递给后端的字段
            projectStage: undefined,
            experimentDispatchGroups: this.groupTableData.map(item => ({
              groupName: item.groupName,
              remark: item.remark,
              dispatchId: this.id || '',
              id: item.id || ''
            })),
            experimentDispatchTasks: this.taskTableData.map(item => ({
              taskName: item.taskName,
              personCharge: item.personCharge,
              startTime: item.startTime,
              dispatchId: this.id || '',
              id: item.id || ''
            })),
            experimentDispatchParticipants: [
              ...this.members.processEngineer.map(user => ({
                userId: user.userId,
                roleType: 3, // 工艺工程师
                status: 1, // 待确认
                dispatchId: this.id || '',
                id: user.id || '',
                nickName: user.nickName,
                avatar: user.avatar
              })),
              ...this.members.experimenter.map(user => ({
                userId: user.userId,
                roleType: 5, // 实验员
                status: 1, // 待确认
                dispatchId: this.id || '',
                id: user.id || '',
                nickName: user.nickName,
                avatar: user.avatar
              })),
              ...this.members.analyst.map(user => ({
                userId: user.userId,
                roleType: 4, // 化验师
                status: 1, // 待确认
                dispatchId: this.id || '',
                id: user.id || '',
                nickName: user.nickName,
                avatar: user.avatar
              }))
            ],
            status: type === 'draft' ? -1 : 1, // 草稿箱:-1, 待确认:1
            experimentStartTime: this.form.experimentTime ? this.form.experimentTime[0] : '',
            experimentEndTime: this.form.experimentTime ? this.form.experimentTime[1] : ''
          };
          if (this.id) {
            formData.id = this.id;
          }
          const request = this.id ? updateDispatch : addDispatch;
          request(formData).then(res => {
            if (res.code === 200) {
              const successMsg = type === 'draft' ? '草稿保存成功' : (this.id ? '更新成功' : '保存成功');
              this.$message.success(successMsg);
              this.$router.back();
            } else {
              const errorMsg = type === 'draft' ? '草稿保存失败' : (this.id ? '更新失败' : '保存失败');
              this.$message.error(res.msg || errorMsg);
            }
          }).catch(err => {
            console.error('接口错误:', err);
            const errorMsg = type === 'draft' ? '草稿保存失败' : (this.id ? '更新失败' : '保存失败');
            this.$message.error(errorMsg);
          });
        } else {
          this.$message.warning('请填写必填项');
          return false;
        }
      });
    },
    // 保存
    sendDispatch() {
      this.handleSubmit('save');
    },
    // 保存草稿
    saveDraft() {
      this.handleSubmit('draft');
    },
    handleDateChange(value) {
      // 处理日期变化后的逻辑
    },
    handleTimeRangeChange(value) {
      if (value) {
        this.form.experimentStartTime = value[0];
        this.form.experimentEndTime = value[1];
      } else {
        this.form.experimentStartTime = '';
        this.form.experimentEndTime = '';
      }
    },
    // 统一的搜索方法
    async handleProjectSearch(query) {
      if (query) {
        this.projectLoading = true;
        try {
          // 根据当前激活的输入框决定使用哪个参数
          const params = {};
          if (this.$refs.projectNameSelect && this.$refs.projectNameSelect.$el.contains(document.activeElement)) {
            params.projectName = query;
          } else if (this.$refs.proposalIdSelect && this.$refs.proposalIdSelect.$el.contains(document.activeElement)) {
            params.projectCode = query;
          }
          const res = await getProposalList(params);
          if (res) {
            this.projectOptions = res.map(item => ({
              id: item.id,
              projectName: item.projectName,
              projectCode: item.projectCode,
              projectStage: item.projectStage
            }));
            // 更新缓存
            this.projectOptions.forEach(item => {
              this.projectDataMap.set(item.id, item);
            });
          }
        } catch (error) {
          console.error('获取方案列表失败:', error);
          this.$message.error('获取方案列表失败');
        } finally {
          this.projectLoading = false;
        }
      } else {
        this.projectOptions = [];
      }
    },
    // 方案名称选择变化
    handleProjectNameChange(value) {
      const selectedProject = this.projectOptions.find(item => item.id === value);
      if (selectedProject) {
        this.updateFormWithProject(selectedProject);
      }
    },
    // 方案编号选择变化
    handleProposalIdChange(value) {
      const selectedProject = this.projectOptions.find(item => item.id === value);
      if (selectedProject) {
        this.updateFormWithProject(selectedProject);
      }
    },
    // 统一的表单更新方法
    updateFormWithProject(project) {
      this.form.projectName = project.projectName;
      this.form.proposalId = project.id;
      this.form.projectStage = project.projectStage;
    },
    // 防抖处理
    debounce(fn, delay) {
      let timer = null;
      return function (...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, args);
        }, delay);
      };
    },
    // 获取详情
    getDetail() {
      if (this.id) {
        getDetailById({ id: this.id }).then(res => {
          if (res.code === 200 && res.data) {
            const data = res.data
            // 设置表单数据
            this.form = {
              projectName: data.projectName,
              proposalId: data.proposalId,
              projectStage: data.projectStage,
              experimentName: data.experimentName,
              experimentCode: data.experimentCode,
              experimentDate: data.experimentDate,
              experimentTime: [data.experimentStartTime, data.experimentEndTime],
              status: data.status,
              experimentDispatchGroups: data.experimentDispatchGroups || [],
              experimentDispatchParticipants: data.experimentDispatchParticipants || [],
              experimentDispatchTasks: data.experimentDispatchTasks || [],
              keyNodes: data.keyNodes || ''
            }
            // 设置表格数据
            this.groupTableData = data.experimentDispatchGroups || []
            this.taskTableData = data.experimentDispatchTasks || []
          }
        }).catch(err => {
          console.error('获取详情失败:', err)
        })
      }
    },
    // 处理项目选择框获得焦点
    async handleProjectFocus() {
      // 如果已经有数据,则不重复请求
      if (this.projectOptions.length > 0) {
        return;
      }
      this.projectLoading = true;
      try {
        const res = await getProposalList({});
        if (res) {
          this.projectOptions = res.map(item => ({
            id: item.id,
            projectName: item.projectName,
            projectCode: item.projectCode,
            projectStage: item.projectStage
          }));
          // 更新缓存
          this.projectOptions.forEach(item => {
            this.projectDataMap.set(item.id, item);
          });
        }
      } catch (error) {
        console.error('获取方案列表失败:', error);
        this.$message.error('获取方案列表失败');
      } finally {
        this.projectLoading = false;
      }
    }
  },
  created() {
    // 从路由参数中获取id
    this.id = this.$route.query.id;
    if (this.id) {
      // TODO: 获取详情
      this.getDetail();
    }
    // 创建防抖的搜索方法
    this.debouncedSearch = this.debounce(this.handleProjectSearch, 300);
    // 初始化时自动添加当前用户为工艺工程师(如果是工艺工程师角色)
    const currentUser = this.getCurrentUser();
    if (currentUser) {
      this.members.processEngineer = [{
        userId: currentUser.userId,
        nickName: currentUser.nickName,
        avatar: currentUser.avatar,
        roleId: 3,
        roleName: '工艺工程师'
      }];
      // 同时更新selectMemberData
      this.selectMemberData = [...this.members.processEngineer];
    }
  }
};
</script>
<style scoped lang="less">
.data-test{
  .el-input__inner{
    background-color: #F5F7FA;
    padding-left: 20px !important;
  }
}
.el-form--inline .el-form-item {
  margin-right: 83px;
}
@@ -492,11 +1055,9 @@
.add-project-footer {
  margin-top: 43px;
  button {
    width: 220px;
  }
  .save-btn {
    margin-right: 20px;
  }
laboratory/src/views/dataManagement/dispatching/components/AddTaskDialog.vue
@@ -10,7 +10,8 @@
          <Table 
            ref="table"
            :data="tableData" 
            :total="0"
           :total="0"
          :height="null"
            class="rwuTable" 
            @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55"></el-table-column>
@@ -43,7 +44,7 @@
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleClose">关闭</el-button>
      <el-button type="primary" @click="handleSubmit">保存</el-button>
      <el-button type="primary" @click="handleSubmit" style="margin-left: 10px;">保存</el-button>
    </div>
  </el-dialog>
</template>
@@ -56,6 +57,7 @@
      dialogVisible: false,
      title: "新增任务",
      form: {
        id: "", // 任务id
        taskName: "",
        startTime: "",
        selectedUsers: [], // 存储选中用户的id数组
@@ -69,7 +71,7 @@
          { required: true, message: "请选择开始时间", trigger: "change" }
        ]
      },
      tableData: [],
      tableData: [], // 参与人员列表
      pickerOptions: {
        shortcuts: [
          {
@@ -103,24 +105,43 @@
    };
  },
  methods: {
    open(row) {
    open(row, participants) {
      this.dialogVisible = true;
      this.getAvailableUsers();
      // 使用传入的参与人员数据
      this.tableData = participants.map(user => ({
        id: user.userId,
        role: user.roleName,
        name: user.nickName,
        avatar: user.avatar,
        createTime: new Date().toLocaleString()
      }));
      
      if (row) {
        this.title = "编辑任务";
        // 处理负责人数据
        const selectedNames = row.personCharge ? row.personCharge.split('、') : [];
        const selectedUsers = [];
        // 根据负责人名称找到对应的用户ID
        this.tableData.forEach(user => {
          if (selectedNames.includes(user.name)) {
            selectedUsers.push(user.id);
          }
        });
        this.form = { 
          id: row.id || '',
          taskName: row.taskName || '',
          startTime: row.startTime || '',
          selectedUsers: row.selectedUsers || [],
          leader: row.leader || ''
          selectedUsers: selectedUsers,
          leader: row.personCharge || ''
        };
        
        // 在表格数据加载完成后设置选中状态
        this.$nextTick(() => {
          if (this.$refs.table && this.form.selectedUsers.length) {
          if (this.$refs.table) {
            this.tableData.forEach(row => {
              if (this.form.selectedUsers.includes(row.id)) {
              if (selectedNames.includes(row.name)) {
                this.$refs.table.toggleRowSelection(row, true);
              }
            });
@@ -129,6 +150,7 @@
      } else {
        this.title = "新增任务";
        this.form = {
          id: "",
          taskName: "",
          startTime: "",
          selectedUsers: [],
@@ -143,6 +165,7 @@
        this.$refs.table.clearSelection();
      }
      this.form = {
        id: "",
        taskName: "",
        startTime: "",
        selectedUsers: [],
@@ -163,6 +186,7 @@
          }
          const submitData = {
            id: this.form.id,
            taskName: this.form.taskName,
            startTime: this.form.startTime,
            selectedUsers: this.form.selectedUsers,
@@ -173,32 +197,6 @@
          this.handleClose();
        }
      });
    },
    getAvailableUsers() {
      // 这里可以调用接口获取人员列表
      this.tableData = [
        {
          id: 1,
          role: "实验师",
          name: "曾奇胜",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        },
        {
          id: 2,
          role: "实验师",
          name: "李四",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        },
        {
          id: 3,
          role: "实验师",
          name: "王五",
          avatar: "",
          createTime: "2024-09-18 00:00:00"
        }
      ];
    }
  }
};
laboratory/src/views/dataManagement/dispatching/editDispatch.vue
@@ -27,14 +27,30 @@
                  </div>
                </div>
                <div style="padding-left: 25px">
                  <el-form-item prop="planName" label="项目课题方案名称">
                    <el-input v-model="form.planName" placeholder="请输入" />
                  <el-form-item prop="projectName" label="项目课题方案名称">
                    <el-input
                      v-model="form.projectName"
                      placeholder="请输入"
                      :disabled="true"
                    />
                  </el-form-item>
                  <el-form-item prop="planCode" label="项目课题方案编号">
                    <el-input v-model="form.planCode" placeholder="请输入" />
                  <el-form-item prop="projectCode" label="项目课题方案编号">
                    <el-input
                      v-model="form.projectCode"
                      placeholder="请输入"
                      :disabled="true"
                    />
                  </el-form-item>
                  <el-form-item prop="stage" label="项目阶段">
                    <el-input v-model="form.stage" placeholder="请输入" />
                  <el-form-item prop="projectStage" label="项目阶段">
                    <el-select
                      v-model="form.projectStage"
                      disabled
                      placeholder="请选择"
                    >
                      <el-option label="实验室开发阶段" :value="1" />
                      <el-option label="中式试验阶段" :value="2" />
                      <el-option label="生产验证试验阶段" :value="3" />
                    </el-select>
                  </el-form-item>
                </div>
@@ -45,19 +61,30 @@
                  </div>
                </div>
                <div style="padding-left: 25px">
                  <el-form-item prop="testDate" label="试验日期">
                  <el-form-item prop="experimentDate" label="实验日期">
                    <el-date-picker
                      v-model="form.testDate"
                      name="data-test"
                      style="width: 100%"
                      v-model="form.experimentDate"
                      type="date"
                      placeholder="选择日期"
                      value-format="yyyy-MM-dd"
                      :disabled="true"
                    ></el-date-picker>
                  </el-form-item>
                  <el-form-item prop="experimentName" label="实验名称">
                    <el-input
                      v-model="form.experimentName"
                      placeholder="请输入"
                      :disabled="true"
                    />
                  </el-form-item>
                  <el-form-item prop="testName" label="实验名称">
                    <el-input v-model="form.testName" placeholder="请输入" />
                  </el-form-item>
                  <el-form-item prop="testCode" label="实验编号">
                    <el-input v-model="form.testCode" placeholder="请输入" />
                  <el-form-item prop="experimentCode" label="实验编号">
                    <el-input
                      v-model="form.experimentCode"
                      placeholder="请输入"
                      :disabled="true"
                    />
                  </el-form-item>
                </div>
@@ -89,50 +116,49 @@
                  </div>
                </div>
                <div style="padding-left: 25px">
                  <el-form-item prop="testTime" label="试验时间">
                  <el-form-item prop="experimentTime" label="试验时间">
                    <el-date-picker
                      v-model="form.testTime"
                      type="datetime"
                      placeholder="选择日期时间"
                      style="width: 100%"
                      v-model="form.experimentTime"
                      type="datetimerange"
                      range-separator="至"
                      start-placeholder="开始时间"
                      end-placeholder="结束时间"
                      value-format="yyyy-MM-dd HH:mm:ss"
                    />
                      :default-time="['00:00:00', '23:59:59']"
                      :disabled="true"
                    ></el-date-picker>
                  </el-form-item>
                </div>
                <div class="add-group">
                  <div>*</div>
                  <span>参加人员</span>
                </div>
                <div class="member-list">
                  <div v-for="item in 3" :key="item" class="member-list-card">
                  <div
                    v-for="item in [3, 4, 5]"
                    :key="item"
                    class="member-list-card"
                  >
                    <div class="member-item">
                      <div class="member-title">
                        {{ ["工艺工程师", "实验员", "化验师"][item - 1] }}
                        {{ ["工艺工程师", "化验师", "实验员"][item - 3] }}
                      </div>
                      <div
                        :class="
                          item == 1 || item == 2 || item == 3
                            ? 'member-name-box'
                            : 'flex1'
                        "
                      >
                      <div :class="item == 3 ? 'member-name-box' : 'flex1'">
                        <div
                          :class="
                            item == 1 || item == 2 || item == 3
                              ? 'member-name-box'
                              : 'member-name-box-2'
                            item == 3 ? 'member-name-box' : 'member-name-box-2'
                          "
                        >
                          <div
                            v-for="i in memberList(item)"
                            :key="i"
                            :key="i.userId"
                            class="member-name"
                          >
                            张三
                            {{ i.nickName }}
                          </div>
                        </div>
                      </div>
                      <div class="member-change" v-if="type !== 'view'">
                        <div class="member-change-btn">修改</div>
                      </div>
                    </div>
                  </div>
@@ -161,7 +187,7 @@
                    label="任务名称"
                  ></el-table-column>
                  <el-table-column
                    prop="leader"
                    prop="personCharge"
                    label="负责人"
                  ></el-table-column>
                  <el-table-column
@@ -176,6 +202,14 @@
                    <span>五 、关键节点</span>
                  </div>
                </div>
                <div style="padding-left: 25px">
                  <AIEditor
                    ref="keyNodesEditor"
                    :readOnly="true"
                    :value="form.keyNodes"
                    height="200"
                  />
                </div>
              </el-form>
            </template>
          </Card>
@@ -183,13 +217,7 @@
        <!-- 右侧审批流程 -->
        <div class="approval-flow" v-if="type === 'view'">
          <div class="flow-content">
            <approval-process
              mode="card"
              :status="form.status"
              :submit-time="form.createTime"
              :approver="form.approver"
              :approve-time="form.approveTime"
            />
            <approval-process :processData="form.processData" />
          </div>
        </div>
      </div>
@@ -225,6 +253,7 @@
    <SignatureCanvas
      :visible="signatureDialogVisible"
      @confirm="handleSignatureConfirm"
      @close="signatureDialogVisible = false"
    />
  </div>
</template>
@@ -232,12 +261,15 @@
<script>
import ApprovalProcess from "@/components/approvalProcess";
import SignatureCanvas from "@/components/SignatureCanvas.vue";
import AIEditor from "@/components/AiEditor";
import { getDetailById, sign } from "./service";
export default {
  name: "ApprovalDialog",
  components: {
    ApprovalProcess,
    SignatureCanvas,
    AIEditor,
  },
  props: {
    visible: {
@@ -256,55 +288,57 @@
  data() {
    return {
      form: {
        planName: "",
        planCode: "",
        stage: "",
        testDate: "",
        testName: "",
        testCode: "",
        testTime: "",
        creator: "",
        createTime: "",
        approvalComment: "",
        status: "approved",
        approver: "",
        approveTime: "",
        projectName: "",
        projectCode: "",
        projectStage: "",
        experimentName: "",
        experimentCode: "",
        experimentDate: "",
        experimentTime: [],
        status: "",
        experimentDispatchGroups: [],
        experimentDispatchParticipants: [],
        experimentDispatchTasks: [],
        keyNodes: "",
        processData: [],
      },
      rules: {
        planName: [
        projectName: [
          {
            required: true,
            message: "请输入项目课题方案名称",
            trigger: "blur",
          },
        ],
        planCode: [
        projectCode: [
          {
            required: true,
            message: "请输入项目课题方案编号",
            trigger: "blur",
          },
        ],
        stage: [{ required: true, message: "请输入项目阶段", trigger: "blur" }],
        testDate: [
          { required: true, message: "请选择试验日期", trigger: "change" },
        ],
        testName: [
        experimentName: [
          { required: true, message: "请输入实验名称", trigger: "blur" },
        ],
        testCode: [
        experimentCode: [
          { required: true, message: "请输入实验编号", trigger: "blur" },
        ],
        testTime: [
          { required: true, message: "请选择试验时间", trigger: "change" },
        experimentDate: [
          { required: true, message: "请选择实验日期", trigger: "change" },
        ],
        experimentTime: [
          { required: true, message: "请选择实验时间范围", trigger: "change" },
        ],
      },
      imgSrc: "",
      signatureDialogVisible: false,
      status: "1",
      remark: "",
      groupTableData: [],
      taskTableData: [],
      members: {
        processEngineer: [], // 工艺工程师
        experimenter: [], // 实验员
        analyst: [], // 化验师
      },
    };
  },
  computed: {
@@ -316,75 +350,155 @@
    data: {
      handler(val) {
        if (val) {
          this.form = { ...val };
          this.getDetail(val.id);
        }
      },
      immediate: true,
    },
  },
  methods: {
    memberList(i) {
      switch (i) {
        case 1:
          return [1];
        case 2:
          return [1];
        case 3:
          return [1, 2, 3, 4, 5, 6, 7, 8];
        case 4:
          return [1, 2, 3, 4, 5, 6, 7, 8];
    // 获取详情
    getDetail(id) {
      getDetailById({ id })
        .then((res) => {
          if (res) {
            const data = res;
            // 设置表单数据
            this.form = {
              projectName: data.projectName,
              projectCode: data.projectCode,
              projectStage: data.projectStage,
              experimentName: data.experimentName,
              experimentCode: data.experimentCode,
              experimentDate: data.experimentDate,
              experimentTime: [
                data.experimentStartTime,
                data.experimentEndTime,
              ],
              status: data.status,
              experimentDispatchGroups: data.experimentDispatchGroups || [],
              experimentDispatchParticipants:
                data.experimentDispatchParticipants || [],
              experimentDispatchTasks: data.experimentDispatchTasks || [],
              keyNodes: data.keyNodes,
              processData: [],
            };
            // 设置表格数据
            this.groupTableData = data.experimentDispatchGroups || [];
            this.taskTableData = data.experimentDispatchTasks || [];
            // 处理参与人员数据
            this.members = {
              processEngineer:
                data.experimentDispatchParticipants.filter(
                  (p) => p.roleType === 3
                ) || [],
              experimenter:
                data.experimentDispatchParticipants.filter(
                  (p) => p.roleType === 5
                ) || [],
              analyst:
                data.experimentDispatchParticipants.filter(
                  (p) => p.roleType === 4
                ) || [],
            };
            // 组装流程数据
            let processData = [];
            // 提交节点
            processData.push({
              type: "primary",
              mode: "list",
              fields: [
                { label: "提交人:", value: data.createBy || "" },
                { label: "提交时间:", value: data.createTime || "" },
              ],
            });
            // 处理参与人员数据,按角色分类
            const participants = data.experimentDispatchParticipants || [];
            const analyst = participants.filter((p) => p.roleType === 4); // 化验师
            const experimenter = participants.filter((p) => p.roleType === 5); // 实验员
            // 添加确认节点
            processData.push({
              type: "success",
              mode: "card",
              groups: [
                {
                  title: "化验师",
                  members: analyst.map((item) => ({
                    name: item.nickName || "",
                    status: item.status === 2 ? "已确认" : "待确认",
                    approveTime: item.status === 2 ? item.signTime : "",
                    avatar: item.avatar || "",
                  })),
                },
                {
                  title: "实验员",
                  members: experimenter.map((item) => ({
                    name: item.nickName || "",
                    status: item.status === 2 ? "已确认" : "待确认",
                    approveTime: item.status === 2 ? item.signTime : "",
                    avatar: item.avatar || "",
                  })),
                },
              ],
            });
            this.form.processData = processData;
          }
        })
        .catch((err) => {
          console.error("获取详情失败:", err);
          this.$message.error("获取详情失败");
        });
    },
    memberList(type) {
      switch (type) {
        case 3: // 工艺工程师
          return this.members.processEngineer;
        case 5: // 实验员
          return this.members.experimenter;
        case 4: // 化验师
          return this.members.analyst;
        default:
          break;
          return [];
      }
    },
    handleClose() {
      this.$emit("update:visible", false);
      this.form.approvalComment = "";
      this.$emit("close", false);
      this.$emit("update:data", {}); // 触发事件通知父组件更新data
      this.signatureDialogVisible = false;
      this.imgSrc = '';
    },
    handleApprove() {
      if (!this.form.approvalComment) {
        this.$message.warning("请输入审批意见");
        return;
      }
      this.$emit("approve", {
        ...this.form,
        status: "approved",
      // 组装签名数据
      const params = {
        dispatchId: this.data.id, // 传递当前调度id
        confirmSign: this.imgSrc, // 签名图片
      };
      sign(params).then(res => {
        if (res && res.code === 200) {
          this.$message.success('签字成功');
          this.handleClose();
        } else {
          this.$message.error(res.msg || '签字失败');
        }
      }).catch(() => {
        this.$message.error('签字失败');
      });
    },
    handleReject() {
      if (!this.form.approvalComment) {
        this.$message.warning("请输入审批意见");
        return;
      }
      this.$emit("reject", {
        ...this.form,
        status: "rejected",
      });
    },
    memberList(item) {
      return item === 1 ? 2 : item === 2 ? 3 : 1;
    },
    openSignature() {
      this.signatureDialogVisible = true;
    },
    handleSignatureConfirm(imageData) {
      console.log("imageData imageData", imageData);
      this.signatureDialogVisible = false;
      this.imgSrc = imageData;
      // 这里处理签名确认后的逻辑
      // this.$confirm('确认该实验调度吗?', '提示', {
      //   confirmButtonText: '确定',
      //   cancelButtonText: '取消',
      //   type: 'warning'
      // }).then(() => {
      //   // 这里可以将签名图片数据(imageData)连同其他数据一起提交到后端
      //   this.$message.success('确认成功');
      //   this.signatureDialogVisible = false;
      //   this.getTableData();
      // }).catch(() => {
      //   this.signatureDialogVisible = false;
      // });
      // 模拟上传签名图片,实际应调用上传接口,成功后回显图片链接
      // TODO: 替换为实际上传接口
      // uploadSignature(imageData).then(url => { this.imgSrc = url })
      this.imgSrc = 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'; // 默认图片链接
    },
  },
};
@@ -488,6 +602,7 @@
}
.header-title:first-child {
  margin-top: 0;
  .header-title-left {
    margin-top: 0;
  }
laboratory/src/views/dataManagement/dispatching/list.vue
@@ -1,10 +1,10 @@
<template>
  <div class="list">
    <TableCustom :queryForm="form" :tableData="tableData" :total="total">
    <TableCustom :queryForm="form" :tableData="tableData" :total="total" @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange">
      <template #search>
        <el-form :model="form" labelWidth="auto" inline>
          <el-form-item label="所属项目课题方案:">
            <el-input v-model="form.planName" placeholder="请输入"></el-input>
            <el-input v-model="form.projectName" placeholder="请输入"></el-input>
          </el-form-item>
          <el-form-item label="实验编号">
            <el-input
@@ -20,19 +20,21 @@
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd"
              @change="handleDateChange"
            ></el-date-picker>
          </el-form-item>
          <el-form-item label="状态">
          <el-form-item label="状态" >
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option label="待确认" value="pending"></el-option>
              <el-option label="已确认" value="confirmed"></el-option>
              <el-option label="已取消" value="cancelled"></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 label="">
            <el-button type="default" @click="resetForm">重置</el-button>
            <el-button type="primary" @click="handleSearch">查询</el-button>
            <el-button type="primary" @click="handleSearch" style="margin-left: 10px;">查询</el-button>
          </el-form-item>
        </el-form>
      </template>
@@ -44,9 +46,10 @@
              :class="{ active: currentType === 'list' }"
              @click="handleTypeChange('list')"
            >
              实验调度列表
              实验与调度列表
            </div>
            <div
              v-if="userRole === '3'"
              class="drafts"
              :class="{ active: currentType === 'draft' }"
              @click="handleTypeChange('draft')"
@@ -54,32 +57,49 @@
              草稿箱
            </div>
          </div>
          <el-button @click="handleAddPlan" class="el-icon-plus" type="primary">
            新增实验调度</el-button
          <el-button
            v-if="userRole === '3'"
            @click="handleAddPlan"
            class="el-icon-plus"
            type="primary"
          >
            新增实验调度
          </el-button>
        </div>
      </template>
      <template #table>
        <el-table-column
          prop="experimentCode"
          prop="projectName"
          label="所属项目课题方案"
        ></el-table-column>
        <el-table-column
          prop="experimentName"
          prop="experimentCode"
          label="实验编号"
        ></el-table-column>
        <el-table-column prop="startTime" label="实验名称"></el-table-column>
        <el-table-column prop="endTime" label="通知时间"></el-table-column>
        <el-table-column
          prop="participants"
          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="createTime"
          prop="experimentEndTime"
          label="实验结束时间"
        ></el-table-column>
        <el-table-column prop="people" label="参加人员"></el-table-column>
        <el-table-column prop="status" label="状态">
        <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) }}
@@ -88,164 +108,131 @@
        </el-table-column>
        <el-table-column label="操作" width="200">
          <template slot-scope="scope">
            <el-button
              v-if="scope.row.status === 'pending'"
              type="text"
              @click="handleConfirm(scope.row)"
              >确认</el-button
            >
            <el-button type="text" @click="handleDelete(scope.row)"
              >删除</el-button
            >
            <el-button type="text" @click="handleDetail(scope.row)"
              >详情</el-button
            >
            <!-- 工艺工程师(3) -->
            <template v-if="userRole == '3'">
              <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
              <el-button
                v-if="scope.row.status === 1"
                type="text"
                @click="handleDelete(scope.row)"
              >删除</el-button>
            </template>
            <!-- 化验师(4)和实验员(5) -->
            <template v-if="userRole == '4' || userRole == '5'">
              <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
              <el-button
                v-if="scope.row.status === 1"
                type="text"
                @click="handleConfirm(scope.row)"
              >确认</el-button>
            </template>
            <!-- 超级管理员(1)和审批人(2) -->
            <template v-if="userRole =='1' || userRole == '2'">
              <el-button type="text" @click="handleDetail(scope.row)">详情</el-button>
            </template>
          </template>
        </el-table-column>
      </template>
    </TableCustom>
    <SignatureCanvas
      :visible="signatureDialogVisible"
      @confirm="handleSignatureConfirm"
    />
    <edit-dispatch
      :visible.sync="approvalDialogVisible"
      :type="approvalDialogType"
      :data="currentApprovalData"
      @close="approvalDialogVisible = false"
      @update:data="handleUpdateData"
    />
    <ShowDelConfirm
      :title="changeStatusTitle"
      :tip="changeStatusTip"
      :show="changeStatus"
      @close="changeStatus = false"
      @confirm="handleChangeStatusConfirm"
    />
  </div>
</template>
<script>
import SignatureCanvas from "@/components/SignatureCanvas.vue";
import EditDispatch from "./editDispatch.vue";
import { getList } from './service'
import ShowDelConfirm from "@/components/showDelConfirm/index.vue";
import { getDispatchList, deleteById } from "./service";
export default {
  name: "dispatchingList",
  components: {
    SignatureCanvas,
    EditDispatch,
    ShowDelConfirm
  },
  data() {
    return {
      currentType: "list", // 当前显示类型:list-列表,draft-草稿箱
      userRole: JSON.parse(sessionStorage.getItem('userInfo'))?.roleType || '', // 用户角色
      form: {
        experimentName: "",
        projectName: "",
        experimentCode: "",
        createTime: [],
        startTime: "",
        endTime: "",
        status: "",
        pageNum: 1,
        pageSize: 10
      },
      tableData: [],
      total: 0,
      // 模拟数据
      mockListData: [
        {
          experimentCode: "EXP-2024-001",
          experimentName: "材料力学性能测试实验",
          startTime: "2024-03-20 09:00",
          endTime: "2024-03-20 17:00",
          participants: "张三、李四、王五",
          createTime: "2024-03-15",
          status: "pending",
          planName: "新材料研发项目",
          planCode: "PLAN-2024-001",
          stage: "实验阶段",
          testDate: "2024-03-20",
          testName: "材料力学性能测试",
          testCode: "TEST-2024-001",
          testTime: "2024-03-20 09:00",
          groupTableData: [
            {
              groupName: "对照组",
              remark: "标准材料组"
            },
            {
              groupName: "实验组",
              remark: "新材料组"
            }
          ],
          taskTableData: [
            {
              taskName: "材料准备",
              leader: "张三",
              startTime: "2024-03-20 09:00"
            },
            {
              taskName: "性能测试",
              leader: "李四",
              startTime: "2024-03-20 10:00"
            }
          ]
        },
        {
          experimentCode: "EXP-2024-002",
          experimentName: "化学合成实验",
          startTime: "2024-03-21 10:00",
          endTime: "2024-03-21 16:00",
          participants: "赵六、钱七、孙八",
          createTime: "2024-03-16",
          status: "confirmed",
        },
        {
          experimentCode: "EXP-2024-003",
          experimentName: "生物培养实验",
          startTime: "2024-03-22 08:00",
          endTime: "2024-03-22 18:00",
          participants: "周九、吴十、郑十一",
          createTime: "2024-03-17",
          status: "cancelled",
        },
      ],
      mockDraftData: [
        {
          experimentCode: "EXP-2024-004",
          experimentName: "物理光学实验(草稿)",
          startTime: "2024-03-23 09:00",
          endTime: "2024-03-23 17:00",
          participants: "王十二、李十三",
          createTime: "2024-03-18",
          status: "draft",
        },
      ],
      signatureDialogVisible: false,
      currentRow: null,
      approvalDialogVisible: false,
      approvalDialogType: "view",
      currentApprovalData: null,
      // 确认弹窗相关数据
      changeStatus: false,
      changeStatusTitle: "",
      changeStatusTip: "",
      currentOperationRow: null, // 当前操作的行数据
    };
  },
  created() {
    this.getTableData();
  },
  methods: {
    handleDateChange(val) {
      if (val) {
        this.form.startTime = val[0];
        this.form.endTime = val[1];
      } else {
        this.form.startTime = "";
        this.form.endTime = "";
      }
    },
    resetForm() {
      this.form = {
        experimentName: "",
        projectName: "",
        experimentCode: "",
        createTime: [],
        startTime: "",
        endTime: "",
        status: "",
        pageNum: 1,
        pageSize: 10
      };
      this.getTableData();
    },
    handleSearch() {
      // 实现查询逻辑
      console.log("查询条件:", this.form);
      this.form.pageNum = 1;
      this.getTableData();
    },
    getStatusType(status) {
      const statusMap = {
        pending: "warning",
        confirmed: "success",
        cancelled: "danger",
        draft: "info",
        "-1": "info",
        "1": "warning",
        "2": "success",
        "3": "info"
      };
      return statusMap[status] || "info";
    },
    getStatusText(status) {
      const statusMap = {
        pending: "待确认",
        confirmed: "已确认",
        cancelled: "已取消",
        draft: "草稿",
        "-1": "草稿箱",
        "1": "待确认",
        "2": "已确认",
        "3": "已封存"
      };
      return statusMap[status] || "未知";
    },
@@ -255,42 +242,15 @@
      });
    },
    handleConfirm(row) {
      // this.currentRow = row;
      // this.signatureDialogVisible = true;
      this.currentApprovalData = row;
      this.approvalDialogType = "approve";
      this.approvalDialogVisible = true;
    },
    handleSignatureConfirm(imageData) {
      console.log("imageData imageData", imageData);
      this.signatureDialogVisible = false;
      // 这里处理签名确认后的逻辑
      // this.$confirm('确认该实验调度吗?', '提示', {
      //   confirmButtonText: '确定',
      //   cancelButtonText: '取消',
      //   type: 'warning'
      // }).then(() => {
      //   // 这里可以将签名图片数据(imageData)连同其他数据一起提交到后端
      //   this.$message.success('确认成功');
      //   this.signatureDialogVisible = false;
      //   this.getTableData();
      // }).catch(() => {
      //   this.signatureDialogVisible = false;
      // });
    },
    handleDelete(row) {
      this.$confirm("确定要删除该实验调度吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$message.success("删除成功");
          this.getTableData();
        })
        .catch(() => {});
      this.currentOperationRow = row;
      this.changeStatusTitle = "确认要删除该实验调度吗?";
      this.changeStatusTip = "删除后信息无法找回";
      this.changeStatus = true;
    },
    handleDetail(row) {
      this.currentApprovalData = row;
@@ -299,18 +259,50 @@
    },
    handleTypeChange(type) {
      this.currentType = type;
      this.form.status = type === 'draft' ? '-1' : '';
      this.form.pageNum = 1;
      this.getTableData();
    },
    getTableData() {
      // 根据currentType请求不同的数据
      if (this.currentType === "list") {
        this.tableData = this.mockListData;
        this.total = this.mockListData.length;
      } else {
        this.tableData = this.mockDraftData;
        this.total = this.mockDraftData.length;
      }
      const params = {
        ...this.form,
        status: this.currentType === 'draft' ? '-1' : this.form.status
      };
      getDispatchList(params).then(res => {
        console.log('111111111111',res)
        if (res.code==200) {
          this.tableData = res.data.records || [];
          this.total = res.data.total || 0;
        }
      });
    },
    // 处理页码改变
    handleCurrentChange(val) {
      this.form.pageNum = val;
      this.getTableData();
    },
    // 处理每页条数改变
    handleSizeChange(val) {
      this.form.pageSize = val;
      this.form.pageNum = 1;
      this.getTableData();
    },
    handleChangeStatusConfirm() {
      // 处理删除逻辑
      deleteById({
        id: this.currentOperationRow.id
      }).then(() => {
        this.$message.success("删除成功");
        this.changeStatus = false;
        this.getTableData();
      }).catch(error => {
        this.$message.error("删除失败");
      });
    },
    handleUpdateData() {
      this.currentApprovalData = null;
      this.getTableData();
    }
  },
};
</script>
laboratory/src/views/dataManagement/dispatching/service.js
@@ -1,6 +1,40 @@
import axios from '@/utils/request';
// 列表
export const getList = (data) => {
  return axios.post('/t-experiment-dispatch/api/t-experiment-dispatch/pageList', { ...data })
// 添加项目课题方案
export function addDispatch(data) {
  return axios.post('/api/t-experiment-dispatch/add', { ...data })
}
//修改方案
export function updateDispatch(data) {
  return axios.post('/api/t-experiment-dispatch/update', { ...data })
}
//查询方案列表
export function getDispatchList(data) {
  return axios.post('/api/t-experiment-dispatch/pageList', { ...data })
}
//上下架
// export function upAndDown(data) {
//   return axios.post('/api/t-project-proposal/upAndDown', { ...data })
// }
//获取项目课题方案列表(下拉框
export function getProposalList(data) {
  return axios.get('/open/t-project-proposal/list', {params:data })
}
//删除
export function deleteById(data) {
  return axios.delete('/open/t-experiment-dispatch/deleteById', { params:data })
}
//批量删除
export function deleteByIds(data) {
  return axios.delete('/open/t-experiment-dispatch/deleteByIds', { params:data })
}
//根据id查询方案详情
export function getDetailById(data) {
  return axios.get('/open/t-experiment-dispatch/getDetailById', {params:data })
}
// 签名
export function sign(data) {
  return axios.post('/api/t-experiment-dispatch/sign', { ...data })
}
laboratory/src/views/reportLibrary/feasibilityStudy/add.vue
@@ -12,12 +12,12 @@
                </div>
            </div>
            <Table :height="null" :queryForm="queryForm" :total="0">
            <Table :height="null" :data="tableData" :queryForm="queryForm" :total="0">
                <template>
                    <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="teamName" label="项目组名称" />
                    <el-table-column prop="personCharge" label="项目负责人" />
                    <el-table-column prop="staffName" label="项目组成员" />
                    <el-table-column prop="createTime" label="创建时间" />
                </template>
            </Table>
            <el-form ref="form" :model="form" :rules="rules" inline label-position="top" style="margin-top: 38px">
@@ -27,9 +27,9 @@
                        <div>报告编号</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <el-form-item prop="reportCode" style="margin-top: 38px">
                    <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
@@ -37,9 +37,9 @@
                        <div>报告名称</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <el-form-item prop="reportName" style="margin-top: 38px">
                    <el-input v-model="form.reportName" style="width: 100%;" placeholder="请输入报告编号" />
                </el-form-item>
                <div class="header-title" style="width: 100%;">
                    <div class="header-title-left">
@@ -47,35 +47,40 @@
                        <div>报告正文</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                    <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" />
                </form-item>
                <el-form-item prop="reportText" style="margin-top: 38px">
                    <ai-editor v-model="form.reportText" 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" />
                        <div>附件</div>
                        <div class="noRequire">附件</div>
                    </div>
                </div>
                <form-item prop="name" style="margin-top: 38px">
                <el-form-item prop="name" style="margin-top: 38px">
                    <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList">
                        <el-button size="small" type="primary">点击上传</el-button>
                    </el-upload>
                </form-item>
                </el-form-item>
                <div class="end-btn" style="margin-top: 38px">
                    <el-button type="primary">发送</el-button>
                    <el-button type="default">存草稿</el-button>
                    <el-button type="primary" @click="submit">发送</el-button>
                    <el-button type="default" @clice="save">存草稿</el-button>
                </div>
            </el-form>
        </Card>
        <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
    </div>
</template>
<script>
import { Card } from 'element-ui';
import AiEditor from '@/components/AiEditor'
import chooseProject from '@/components/chooseProject'
export default {
    components: { AiEditor },
    components: {
        AiEditor,
        chooseProject
    },
    data() {
        return {
            form: {
@@ -89,6 +94,7 @@
                approver: "",
                approveTime: ""
            },
            tableData: [],
            fileList: [], // 附件列表
            showChoose: false,
            radio1: 1,
@@ -99,7 +105,24 @@
            }
        }
    }
    },
    methods: {
        //获取选择项目组数据
        getProjectData(data) {
            console.log('4458454', data);
            this.tableData = [data]
            this.$forceUpdate()
            console.log('dsadasdsad', this.tableData);
            this.showChoose = false
        },
        submit(){
        },
        save(){
        },
    },
}
</script>
@@ -138,6 +161,13 @@
            }
        }
        .noRequire:before {
            content: unset;
            // color: #f56c6c;
            // margin-right: 4px;
        }
        span {
            flex-shrink: 0;
            font-weight: bold;
@@ -159,12 +189,12 @@
    }
}
.end-btn{
.end-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    button{
    button {
        width: 180px;
        height: 36px;
        // background: #409EFF; 
laboratory/src/views/reportLibrary/feasibilityStudy/components/approval/index.vue
@@ -12,8 +12,8 @@
                                <div>所属项目组</div>
                            </div>
                        </div>
                        <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange"
                            @sizeChange="handleSizeChange">
                        <Table :height="null" :total="0" @handleCurrentChange="handleCurrentChange"
                            @handleSizeChange="handleSizeChange">
                            <template>
                                <el-table-column prop="name" label="项目组名称" />
                                <el-table-column prop="age" label="项目负责人" />
@@ -183,6 +183,15 @@
                status: "rejected",
            });
        },
        handleCurrentChange(page) {
            this.form.pageNum = page
            this.getList()
        },
        handleSizeChange(size) {
            this.form.pageSize = size
            this.getList()
        },
    },
};
</script>
laboratory/src/views/reportLibrary/feasibilityStudy/index.vue
@@ -10,18 +10,18 @@
                <p>2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题。</p>
            </div>
        </el-card>
        <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange"
            @sizeChange="handleSizeChange">
        <TableCustom :tableData="tableData" :total="total" @handleCurrentChange="handleCurrentChanges"
            @handleSizeChange="handleSizeChanges">
            <template #search>
                <el-form :model="form" label-width="auto" inline>
                    <el-form-item label="所属项目组:">
                        <el-input v-model="form.name" placeholder="请输入"></el-input>
                        <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>
                        <el-input v-model="form.reportName" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="报告编号:">
                        <el-input v-model="form.name" placeholder="请输入"></el-input>
                        <el-input v-model="form.reportCode" placeholder="请输入"></el-input>
                    </el-form-item>
                    <el-form-item label="创建日期:">
                        <el-date-picker v-model="form.date" type="daterange" range-separator="至"
@@ -54,19 +54,19 @@
            </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="teamName" label="所属项目组" />
                <el-table-column prop="reportCode" label="报告编号" />
                <el-table-column prop="reportName" label="报告名称" />
                <el-table-column prop="createBy" label="创建人" />
                <el-table-column prop="createTime" label="创建时间" />
                <el-table-column prop="status" label="状态">
                    <template #default="{ row }">
                        <el-tag v-if="row.status == 1" type="success">待审核</el-tag>
                        <el-tag v-else-if="row.status == 0" type="success">已通过</el-tag>
                        <el-tag v-else type="danger">已驳回</el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="操作">
                <el-table-column prop="options" label="操作">
                    <template #default="{ row }">
                        <el-button type="text">审核</el-button>
                        <el-button type="text">详情</el-button>
@@ -84,6 +84,7 @@
<script>
import Approval from './components/approval'
import { getDataList } from './service'
export default {
    name: 'ProjectList',
@@ -101,13 +102,27 @@
            showApproval: false,
            changeStatusTitle: '',
            changeStatusTip: '',
            queryForm: {
            tableData:[],
            form: {
                pageSize: 10,
                pageNum: 1
                pageNum: 1,
                teamName:'',
                status:'',
                startTime:'',
                reportType:1,
                reportName:'',
                reportCode:'',
                endTime:'',
                date:''
            },
            total: 0
        }
    },
    mounted() {
        this.getList()
    },
    methods: {
        handleAddProject() {
            this.$router.push('/reportLibrary/add')
@@ -136,15 +151,20 @@
            this.changeStatusTip = ''
            this.getList()
        },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
        handleCurrentChanges(page) {
            this.form.pageNum = page
            this.getList()
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
        handleSizeChanges(size) {
            this.form.pageSize = size
            this.getList()
        },
        getList() {
            getDataList(this.form).then(res => {
                console.log('sdasdasdqweqw',res);
                this.tableData = res.records || []
                this.total = res.total || 0
            })
        }
    }
laboratory/src/views/reportLibrary/feasibilityStudy/service.js
New file
@@ -0,0 +1,6 @@
import axios from '@/utils/request';
// 添加项目课题方案
export function getDataList(data) {
  return axios.post('/api/t-feasibility-study-report/pageList', { ...data })
}