From a749b62894ec0dcda3bb055371bc75db75f17ce1 Mon Sep 17 00:00:00 2001 From: 13404089107 <puwei@sinata.cn> Date: 星期一, 12 五月 2025 17:46:57 +0800 Subject: [PATCH] Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory --- laboratory/src/views/dataManagement/dispatching/addDispatch.vue | 675 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 618 insertions(+), 57 deletions(-) diff --git a/laboratory/src/views/dataManagement/dispatching/addDispatch.vue b/laboratory/src/views/dataManagement/dispatching/addDispatch.vue index ca50dab..8923947 100644 --- a/laboratory/src/views/dataManagement/dispatching/addDispatch.vue +++ b/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; } -- Gitblit v1.7.1