13404089107
2025-05-12 a749b62894ec0dcda3bb055371bc75db75f17ce1
laboratory/src/views/dataManagement/dispatching/addDispatch.vue
@@ -15,14 +15,52 @@
          </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>
@@ -33,14 +71,20 @@
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验日期">
            <el-input v-model="form.name" placeholder="请输入" />
          <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="description" label="实验名称">
            <el-input v-model="form.description" placeholder="请输入" />
          <el-form-item prop="experimentName" label="实验名称">
            <el-input v-model="form.experimentName" placeholder="请输入" />
          </el-form-item>
          <el-form-item prop="description" label="实验编号">
            <el-input v-model="form.description" placeholder="请输入" />
          <el-form-item prop="experimentCode" label="实验编号">
            <el-input v-model="form.experimentCode" placeholder="请输入" disabled/>
          </el-form-item>
        </div>
@@ -72,8 +116,18 @@
          </div>
        </div>
        <div style="padding-left: 25px">
          <el-form-item prop="name" label="试验时间">
            <el-input v-model="form.name" placeholder="请输入" />
          <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">
@@ -82,32 +136,32 @@
          <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 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 ? 'member-name-box' : 'flex1'"
                :class="item == 3 ? 'member-name-box' : 'flex1'"
              >
                <div
                  :class="
                    item == 1 || item == 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">
                <div class="member-change-btn">修改</div>
                <div class="member-change-btn" @click="editUserList(item)" v-if="item == 4 || item == 5">修改</div>
              </div>
            </div>
          </div>
@@ -129,7 +183,7 @@
        >
          <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="personCharge" label="负责人"></el-table-column>
          <el-table-column prop="startTime" label="开始时间"></el-table-column>
          <el-table-column label="操作" width="200">
            <template slot-scope="scope">
@@ -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;
  }