<template>
|
<Card>
|
<el-form
|
ref="form"
|
:model="form"
|
:rules="rules"
|
inline
|
label-position="top"
|
>
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>所属实验调度</div>
|
</div>
|
<el-button
|
type="primary"
|
class="el-icon-plus"
|
@click="handleAddTask"
|
v-if="pageType !== 'view'"
|
>选择实验调度</el-button
|
>
|
</div>
|
|
<Table :data="taskTableData" :total="0" :height="null" class="rwuTable">
|
<el-table-column
|
prop="projectName"
|
label="所属项目课题方案"
|
width="200"
|
></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>
|
</Table>
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>本次检验结果总表</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="totalResultEditor"
|
:value="editorContents.totalResult"
|
height="200px"
|
style="margin: 20px 0"
|
placeholder="请输入本次检验结果总表..."
|
:readOnly="pageType === 'view'"
|
/>
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<span>本次检验结果</span>
|
</div>
|
</div>
|
<AiEditor
|
ref="resultEditor"
|
:value="editorContents.result"
|
height="200px"
|
style="margin: 20px 0"
|
placeholder="请输入本次检验结果..."
|
:readOnly="pageType === 'view'"
|
/>
|
|
<div class="add-project-footer" v-if="pageType !== 'view'">
|
<el-button type="primary" class="save-btn" @click="handleSave"
|
>提交</el-button
|
>
|
<el-button @click="handleSaveDraft">存草稿</el-button>
|
</div>
|
</el-form>
|
<!-- 添加检测数据弹窗 -->
|
<!-- <add-dialog
|
ref="addDialog"
|
:visible.sync="dialogVisible"
|
@success="handleTaskSubmit"
|
/> -->
|
<experimentalScheduling
|
:show="dialogVisible"
|
@close="handleSchedulingClose"
|
@submit="handleSchedulingSubmit"
|
/>
|
</Card>
|
</template>
|
|
<script>
|
import AddDialog from "./components/addDialog.vue";
|
import moment from "moment";
|
import experimentalScheduling from "../sampleManage/components/experimental-scheduling.vue";
|
import AiEditor from "@/components/AiEditor";
|
import { getDetail, add, update } from "./service";
|
import { mapState } from "vuex";
|
|
export default {
|
name: "AddProject",
|
components: {
|
AddDialog,
|
experimentalScheduling,
|
AiEditor,
|
},
|
data() {
|
return {
|
dialogVisible: false,
|
isEdit: false,
|
currentEditIndex: -1,
|
pageType: "add", // 页面类型:add-新增,edit-编辑,view-详情
|
form: {
|
id: "",
|
dispatchId: "", // 实验调度id
|
testReason: "", // 检验说明
|
testResult: "", // 检验结果
|
status: 1, // 状态:1=待提交
|
},
|
editorContents: {
|
totalResult: "",
|
result: "",
|
},
|
rules: {
|
dispatchId: [
|
{ required: true, message: "请选择实验调度", trigger: "change" },
|
],
|
},
|
taskTableData: [],
|
// 状态映射表
|
statusTypeMap: {
|
"-1": "info",
|
1: "warning",
|
2: "success",
|
3: "info",
|
},
|
statusTextMap: {
|
"-1": "草稿箱",
|
1: "待确认",
|
2: "已确认",
|
3: "已封存",
|
},
|
};
|
},
|
created() {
|
// 从路由参数中获取id和type
|
const { id, type } = this.$route.query;
|
if (id) {
|
this.pageType = type || "view";
|
this.getDetail(id);
|
}
|
},
|
computed: {
|
...mapState(["tagList", "isFold"]),
|
},
|
methods: {
|
handleAddTask() {
|
this.isEdit = false;
|
this.currentEditIndex = -1;
|
this.dialogVisible = true;
|
},
|
handleEditTask(row) {
|
this.isEdit = true;
|
this.currentEditIndex = this.taskTableData.findIndex(
|
(item) => item === row
|
);
|
|
const editData = {
|
sampleCode: row.sampleCode,
|
testData: row.testData,
|
testTypes: [],
|
photos: [],
|
spectrums: [],
|
};
|
|
if (row.photos && row.photos.length > 0) {
|
editData.testTypes.push("photo");
|
editData.photos = row.photos.map((photo) => ({
|
name: photo.name,
|
url: photo.url,
|
raw: null,
|
}));
|
}
|
if (row.spectrums && row.spectrums.length > 0) {
|
editData.testTypes.push("spectrum");
|
editData.spectrums = row.spectrums.map((spectrum) => ({
|
name: spectrum.name,
|
url: spectrum.url,
|
raw: null,
|
}));
|
}
|
|
this.$nextTick(() => {
|
this.dialogVisible = true;
|
this.$refs.addDialog.setFormData(editData);
|
});
|
},
|
handleDeleteTask(row) {
|
this.$confirm("确认删除该检测数据吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
const index = this.taskTableData.findIndex((item) => item === row);
|
if (index > -1) {
|
const item = this.taskTableData[index];
|
if (item.photos) {
|
item.photos.forEach((photo) => {
|
if (photo.url.startsWith("blob:")) {
|
URL.revokeObjectURL(photo.url);
|
}
|
});
|
}
|
if (item.spectrums) {
|
item.spectrums.forEach((spectrum) => {
|
if (spectrum.url.startsWith("blob:")) {
|
URL.revokeObjectURL(spectrum.url);
|
}
|
});
|
}
|
|
this.taskTableData.splice(index, 1);
|
this.$message.success("删除成功");
|
}
|
})
|
.catch(() => {});
|
},
|
handleTaskSubmit(formData) {
|
const photos = formData.photos.map((file) => ({
|
name: file.name,
|
url: file.url || URL.createObjectURL(file.raw),
|
}));
|
|
const spectrums = formData.spectrums.map((file) => ({
|
name: file.name,
|
url: file.url || URL.createObjectURL(file.raw),
|
}));
|
|
const newData = {
|
sampleCode: formData.sampleCode,
|
testData: formData.testData,
|
testResult: "",
|
photos,
|
spectrums,
|
createTime: this.isEdit
|
? this.taskTableData[this.currentEditIndex].createTime
|
: moment().format("YYYY-MM-DD HH:mm:ss"),
|
};
|
|
if (this.isEdit && this.currentEditIndex > -1) {
|
const oldData = this.taskTableData[this.currentEditIndex];
|
if (oldData.photos) {
|
oldData.photos.forEach((photo) => {
|
if (
|
photo.url.startsWith("blob:") &&
|
!photos.find((p) => p.url === photo.url)
|
) {
|
URL.revokeObjectURL(photo.url);
|
}
|
});
|
}
|
if (oldData.spectrums) {
|
oldData.spectrums.forEach((spectrum) => {
|
if (
|
spectrum.url.startsWith("blob:") &&
|
!spectrums.find((s) => s.url === spectrum.url)
|
) {
|
URL.revokeObjectURL(spectrum.url);
|
}
|
});
|
}
|
|
this.taskTableData.splice(this.currentEditIndex, 1, newData);
|
this.$message.success("更新成功");
|
} else {
|
this.taskTableData.push(newData);
|
this.$message.success("添加成功");
|
}
|
|
this.dialogVisible = false;
|
this.isEdit = false;
|
this.currentEditIndex = -1;
|
},
|
getPhotoUrls(photos) {
|
return photos.map((photo) => photo.url);
|
},
|
handleSchedulingClose() {
|
this.dialogVisible = false;
|
},
|
handleSchedulingSubmit(data) {
|
this.taskTableData = data || [];
|
},
|
getStatusType(status) {
|
return this.statusTypeMap[status] || "info";
|
},
|
getStatusText(status) {
|
return this.statusTextMap[status] || "未知状态";
|
},
|
// 获取所有编辑器的内容
|
getAllEditorContent() {
|
return {
|
totalResult: this.$refs.totalResultEditor.getContent(),
|
result: this.$refs.resultEditor.getContent(),
|
};
|
},
|
// 统一处理方法
|
handleSubmit(type) {
|
// 如果是存草稿,不进行校验
|
if (type === "draft") {
|
this.submitData(type);
|
return;
|
}
|
|
this.$refs.form.validate((valid) => {
|
if (valid) {
|
// 获取所有编辑器内容
|
const editorContents = this.getAllEditorContent();
|
|
// 检查编辑器内容是否为空
|
const emptyFields = [];
|
|
// 判断内容是否为空(排除<p></p>)
|
const isEmptyContent = (content) => {
|
return (
|
!content || content === "<p></p>" || content.trim() === "<p></p>"
|
);
|
};
|
|
// 检查实验调度是否选择
|
if (!this.taskTableData || this.taskTableData.length === 0) {
|
this.$message.warning("请选择实验调度");
|
return false;
|
}
|
|
// 检查检验结果总表是否填写
|
if (isEmptyContent(editorContents.totalResult)) {
|
this.$message.warning("请填写本次检验结果总表");
|
return false;
|
}
|
|
this.submitData(type);
|
} else {
|
this.$message.warning("请填写必填项");
|
return false;
|
}
|
});
|
},
|
|
// 提交数据
|
async submitData(type) {
|
try {
|
// 获取所有编辑器内容
|
const editorContents = this.getAllEditorContent();
|
|
// 构建提交数据
|
const submitData = {
|
...this.form,
|
dispatchId: this.taskTableData[0]?.id || "",
|
testReason: editorContents.totalResult,
|
testResult: editorContents.result,
|
status: type === "draft" ? -1 : 1, // 草稿箱:-1, 待提交:1
|
};
|
|
// 如果是编辑模式,添加id
|
if (this.pageType === "edit") {
|
submitData.id = this.form.id;
|
}
|
|
|
// 调用接口
|
const request = this.pageType === "edit" ? update : add;
|
const res = await request(submitData);
|
|
if (res.code === 200) {
|
const successMsg =
|
type === "draft"
|
? "草稿保存成功"
|
: this.pageType === "edit"
|
? "更新成功"
|
: "保存成功";
|
this.$message.success(successMsg);
|
this.$router.back();
|
this.$store.commit(
|
"SET_TAGLIST",
|
this.tagList.filter((item) => item.path !== this.$route.path)
|
);
|
} else {
|
const errorMsg =
|
type === "draft"
|
? "草稿保存失败"
|
: this.pageType === "edit"
|
? "更新失败"
|
: "保存失败";
|
this.$message.error(res.msg || errorMsg);
|
}
|
} catch (error) {
|
console.error("保存失败:", error);
|
const errorMsg =
|
type === "draft"
|
? "草稿保存失败"
|
: this.pageType === "edit"
|
? "更新失败"
|
: "保存失败";
|
this.$message.error(errorMsg);
|
}
|
},
|
|
// 获取详情数据
|
async getDetail(id) {
|
try {
|
const res = await getDetail({ id });
|
if (res) {
|
const data = res;
|
// 设置表单数据
|
this.form = {
|
id: data.id,
|
dispatchId: data.dispatchId,
|
testReason: data.testReason,
|
testResult: data.testResult,
|
status: data.status,
|
};
|
// 设置编辑器内容
|
this.editorContents = {
|
totalResult: data.testReason || "",
|
result: data.testResult || "",
|
};
|
// 设置实验调度数据
|
if (data.experimentDispatch) {
|
this.taskTableData = [data.experimentDispatch];
|
}
|
}
|
} catch (error) {
|
console.error("获取详情失败:", error);
|
this.$message.error("获取详情失败,请重试");
|
}
|
},
|
|
// 保存
|
handleSave() {
|
this.handleSubmit("save");
|
},
|
// 保存草稿
|
handleSaveDraft() {
|
this.handleSubmit("draft");
|
},
|
},
|
};
|
</script>
|
|
<style scoped lang="less">
|
.el-form--inline .el-form-item {
|
margin-right: 83px;
|
}
|
|
.header-title {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 13px;
|
margin-top: 38px;
|
|
.header-title-left {
|
display: flex;
|
align-items: center;
|
gap: 13px;
|
|
img {
|
width: 12px;
|
height: 19px;
|
}
|
|
span {
|
flex-shrink: 0;
|
font-weight: bold;
|
font-size: 18px;
|
color: #222222;
|
line-height: 27px;
|
font-family: "Source Han Sans CN Bold Bold";
|
}
|
div {
|
flex-shrink: 0;
|
font-weight: bold;
|
font-size: 18px;
|
color: #222222;
|
line-height: 27px;
|
font-family: "Source Han Sans CN Bold Bold";
|
|
&:before {
|
content: "*";
|
color: #f56c6c;
|
margin-right: 4px;
|
}
|
}
|
}
|
}
|
|
.rwuTable {
|
width: 85%;
|
padding-left: 40px;
|
}
|
|
.add-project-footer {
|
margin-top: 43px;
|
|
button {
|
width: 220px;
|
}
|
|
.save-btn {
|
margin-right: 20px;
|
}
|
}
|
|
.image-preview {
|
display: flex;
|
gap: 8px;
|
flex-wrap: wrap;
|
|
.preview-image {
|
width: 50px;
|
height: 50px;
|
border-radius: 4px;
|
cursor: pointer;
|
}
|
|
.image-slot {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
width: 100%;
|
height: 100%;
|
background: #f5f7fa;
|
color: #909399;
|
}
|
}
|
|
.spectrum-link {
|
display: block;
|
margin-bottom: 5px;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
</style>
|