<template>
|
<Card>
|
<el-form
|
ref="form"
|
:model="form"
|
:rules="rules"
|
inline
|
label-position="top"
|
>
|
<div style="padding-left: 25px">
|
<el-form-item prop="originalCode" label="原始检验记录编号">
|
<el-input v-model="form.originalCode" placeholder="请输入" disabled />
|
</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>
|
<div style="padding-left: 25px">
|
<el-form-item prop="termName" label="检测项名字">
|
<el-input v-model="form.termName" placeholder="请输入" disabled />
|
</el-form-item>
|
<el-form-item prop="termCode" label="检测项编号">
|
<el-input v-model="form.termCode" placeholder="请输入" disabled />
|
</el-form-item>
|
<el-form-item prop="termMethod" label="检测方法名字">
|
<el-input v-model="form.termMethod" placeholder="请输入" disabled />
|
</el-form-item>
|
<el-form-item prop="termMethodCode" label="检测方法编号">
|
<el-input v-model="form.termMethodCode" placeholder="请输入" disabled />
|
</el-form-item>
|
</div>
|
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>一 、检测标准</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="standardEditor"
|
:value="editorContents.termStandard"
|
height="200px"
|
style="margin: 20px 0;"
|
placeholder="请输入检测标准..."
|
:readOnly="isDetail"
|
/>
|
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>二 、检测仪器</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="instrumentEditor"
|
:value="editorContents.termInstrument"
|
height="200px"
|
style="margin: 20px 0;"
|
placeholder="请输入检测仪器..."
|
:readOnly="isDetail"
|
/>
|
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>三 、检测试剂</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="reagentEditor"
|
:value="editorContents.termReagent"
|
height="200px"
|
style="margin: 20px 0;"
|
placeholder="请输入检测试剂..."
|
:readOnly="isDetail"
|
/>
|
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>四 、检测步骤</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="stepsEditor"
|
:value="editorContents.termStep"
|
height="200px"
|
style="margin: 20px 0;"
|
placeholder="请输入检测步骤..."
|
:readOnly="isDetail"
|
/>
|
|
<div class="header-title" style="margin-bottom: 38px">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>五 、检测数据及参照</div>
|
</div>
|
<el-button v-if="!isDetail" 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="sampleCode" label="检测样编号"></el-table-column>
|
<el-table-column prop="testData" label="检测数据"></el-table-column>
|
<el-table-column prop="createTime" label="检测时间" width="180"></el-table-column>
|
<el-table-column label="检测图片" width="200">
|
<template slot-scope="scope">
|
<div class="image-preview" v-if="scope.row.photos && scope.row.photos.length">
|
<el-image
|
v-for="(photo, index) in scope.row.photos"
|
:key="index"
|
:src="photo.url"
|
:preview-src-list="getPhotoUrls(scope.row.photos)"
|
fit="cover"
|
class="preview-image"
|
>
|
<div slot="error" class="image-slot">
|
<i class="el-icon-picture-outline"></i>
|
</div>
|
</el-image>
|
</div>
|
<span v-else>无图片</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="检测图谱" width="200">
|
<template slot-scope="scope">
|
<div v-if="scope.row.spectrums && scope.row.spectrums.length">
|
<el-link
|
v-for="(spectrum, index) in scope.row.spectrums"
|
:key="index"
|
type="primary"
|
:href="spectrum.url"
|
target="_blank"
|
class="spectrum-link"
|
>
|
{{ spectrum.name }}
|
</el-link>
|
</div>
|
<span v-else>无图谱</span>
|
</template>
|
</el-table-column>
|
|
<el-table-column v-if="!isDetail" label="操作" width="150">
|
<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">
|
<img src="@/assets/public/headercard.png" />
|
<div>六 、检测结果运算</div>
|
</div>
|
</div>
|
<AiEditor
|
ref="resultCalculationEditor"
|
:value="editorContents.termResult"
|
height="200px"
|
style="margin: 20px 0;"
|
placeholder="请输入检测结果运算..."
|
:readOnly="isDetail"
|
/>
|
<Table :data="taskTableData" :total="0" :height="null" class="rwuTable">
|
<el-table-column type="index" label="序号" width="80"></el-table-column>
|
<el-table-column prop="sampleCode" label="检测样编号"></el-table-column>
|
<el-table-column prop="testData" label="检测数据"></el-table-column>
|
<el-table-column label="检测结果" >
|
<template slot-scope="scope">
|
<el-input v-model="scope.row.resultText" placeholder="请输入检测结果" :disabled="isDetail"></el-input>
|
</template>
|
</el-table-column>
|
</Table>
|
|
<div class="add-project-footer" v-if="!isDetail">
|
<el-button type="primary" class="save-btn" @click="handleSubmit(false)">填写完毕</el-button>
|
<el-button @click="handleSaveDraft">存草稿</el-button>
|
</div>
|
</el-form>
|
<!-- 添加检测数据弹窗 -->
|
<add-dialog
|
ref="addDialog"
|
:visible.sync="dialogVisible"
|
:is-edit="isEdit"
|
@success="handleTaskSubmit"
|
/>
|
</Card>
|
</template>
|
|
<script>
|
import AddDialog from './components/addDialog.vue'
|
import AiEditor from '@/components/AiEditor'
|
import moment from 'moment'
|
import { getDetail, update } from './service'
|
|
export default {
|
name: "AddProject",
|
components: {
|
AddDialog,
|
AiEditor
|
},
|
data() {
|
return {
|
dialogVisible: false,
|
isEdit: false,
|
currentEditIndex: -1,
|
isDetail: this.$route.query.type === 'detail',
|
form: {
|
id: '',
|
originalCode: '',
|
termName: '',
|
termCode: '',
|
termMethod: '',
|
termMethodCode: '',
|
status: 1,
|
termStandard: '',
|
termInstrument: '',
|
termReagent: '',
|
termStep: '',
|
termResult: ''
|
},
|
editorContents: {
|
termStandard: '',
|
termInstrument: '',
|
termReagent: '',
|
termStep: '',
|
termResult: ''
|
},
|
rules: {
|
termName: [{ required: true, message: "请输入检测项名字", trigger: "blur" }],
|
termCode: [{ required: true, message: "请输入检测项编号", trigger: "blur" }],
|
experimentName: [{ required: true, message: "请输入检测方法名字", trigger: "blur" }],
|
experimentCode: [{ required: true, message: "请输入检测方法编号", trigger: "blur" }]
|
},
|
taskTableData: []
|
};
|
},
|
methods: {
|
// 获取详情
|
getDetail() {
|
const id = this.$route.query.id;
|
if (id) {
|
getDetail({ id }).then(res => {
|
if (res) {
|
const data = res;
|
// 设置表单数据
|
this.form = {
|
...data,
|
termCode: data.testMethodConfirmSheetTerm.termCode || '',
|
termName: data.testMethodConfirmSheetTerm.termName || '',
|
termMethod: data.testMethodConfirmSheetTerm.termMethod || '',
|
termMethodCode: data.testMethodConfirmSheetTerm.termMethodCode || '',
|
|
termStandard: data.termStandard || '',
|
termInstrument: data.termInstrument || '',
|
termReagent: data.termReagent || '',
|
termStep: data.termStep || '',
|
termResult: data.termResult || ''
|
};
|
// 设置编辑器内容
|
this.editorContents = {
|
termStandard: data.termStandard || '',
|
termInstrument: data.termInstrument || '',
|
termReagent: data.termReagent || '',
|
termStep: data.termStep || '',
|
termResult: data.termResult || ''
|
};
|
// 设置检测数据表格
|
if (data.testMethodConfirmSheetOriginalDataList && data.testMethodConfirmSheetOriginalDataList.length > 0) {
|
this.taskTableData = data.testMethodConfirmSheetOriginalDataList.map(item => ({
|
sampleCode: item.dataCode || '',
|
testData: item.dataTitle || '',
|
resultText: item.resultText || '',
|
photos: item.dataPictures ? item.dataPictures.split(',').map(url => ({ url })) : [],
|
spectrums: item.dataFiles ? JSON.parse(item.dataFiles) : [],
|
createTime: item.createTime || moment().format('YYYY-MM-DD HH:mm:ss')
|
}));
|
}
|
}
|
}).catch(err => {
|
console.error('获取详情失败:', err);
|
this.$message.error('获取详情失败');
|
});
|
}
|
},
|
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 = {
|
dataCode: row.sampleCode,
|
dataTitle: row.testData,
|
dataType: [],
|
dataFiles: '',
|
dataPictures: '',
|
photos: [],
|
spectrums: []
|
};
|
|
if (row.photos && row.photos.length > 0) {
|
editData.dataType.push('1');
|
editData.dataPictures = row.photos;
|
}
|
if (row.spectrums && row.spectrums.length > 0) {
|
editData.dataType.push('2');
|
editData.dataFiles = row.spectrums;
|
}
|
|
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 newData = {
|
sampleCode: formData.dataCode,
|
testData: formData.dataTitle,
|
resultText: this.isEdit && this.currentEditIndex > -1 ? this.taskTableData[this.currentEditIndex].resultText : '',
|
photos: formData.dataPictures ? JSON.parse(formData.dataPictures) : [],
|
spectrums: formData.dataFiles ? JSON.parse(formData.dataFiles) : [],
|
createTime: this.isEdit ? this.taskTableData[this.currentEditIndex].createTime : moment().format('YYYY-MM-DD HH:mm:ss')
|
};
|
|
if (this.isEdit && this.currentEditIndex > -1) {
|
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);
|
},
|
// 获取所有编辑器的内容
|
getAllEditorContent() {
|
return {
|
termStandard: this.$refs.standardEditor.getContent(),
|
termInstrument: this.$refs.instrumentEditor.getContent(),
|
termReagent: this.$refs.reagentEditor.getContent(),
|
termStep: this.$refs.stepsEditor.getContent(),
|
termResult: this.$refs.resultCalculationEditor.getContent()
|
}
|
},
|
// 验证所有编辑器内容
|
validateEditors() {
|
const editors = {
|
termStandard: this.$refs.standardEditor.getContent(),
|
termInstrument: this.$refs.instrumentEditor.getContent(),
|
termReagent: this.$refs.reagentEditor.getContent(),
|
termStep: this.$refs.stepsEditor.getContent(),
|
termResult: this.$refs.resultCalculationEditor.getContent()
|
};
|
|
// 判断内容是否为空(排除<p></p>)
|
const isEmptyContent = (content) => {
|
return !content || content === '<p></p>' || content.trim() === '<p></p>';
|
};
|
|
const emptyFields = [];
|
if (isEmptyContent(editors.termStandard)) emptyFields.push('检测标准');
|
if (isEmptyContent(editors.termInstrument)) emptyFields.push('检测仪器');
|
if (isEmptyContent(editors.termReagent)) emptyFields.push('检测试剂');
|
if (isEmptyContent(editors.termStep)) emptyFields.push('检测步骤');
|
if (isEmptyContent(editors.termResult)) emptyFields.push('检测结果运算');
|
|
if (emptyFields.length > 0) {
|
this.$message.warning(`请填写${emptyFields.join('、')}`);
|
return false;
|
}
|
return true;
|
},
|
|
// 获取编辑器对应的标签名
|
getEditorLabel(key) {
|
const labels = {
|
termStandard: '检测标准',
|
termInstrument: '检测仪器',
|
termReagent: '检测试剂',
|
termStep: '检测步骤',
|
termResult: '检测结果运算'
|
};
|
return labels[key] || '';
|
},
|
|
// 验证表格数据
|
validateTableData() {
|
if (!this.taskTableData || this.taskTableData.length === 0) {
|
this.$message.error('请至少添加一条检测数据');
|
return false;
|
}
|
return true;
|
},
|
|
// 提交表单
|
async handleSubmit(isDraft) {
|
try {
|
// 如果不是草稿,需要验证所有必填项
|
if (!isDraft) {
|
// 验证编辑器内容
|
if (!this.validateEditors()) {
|
return;
|
}
|
|
// 验证表格数据
|
if (!this.validateTableData()) {
|
return;
|
}
|
}
|
|
// 获取所有编辑器内容
|
const editorContents = {
|
termStandard: this.$refs.standardEditor.getContent(),
|
termInstrument: this.$refs.instrumentEditor.getContent(),
|
termReagent: this.$refs.reagentEditor.getContent(),
|
termStep: this.$refs.stepsEditor.getContent(),
|
termResult: this.$refs.resultCalculationEditor.getContent()
|
};
|
|
// 构建提交数据
|
const submitData = {
|
id: this.form.id,
|
status: isDraft ? -1 : 2,
|
...editorContents,
|
testMethodConfirmSheetOriginalDataList: this.taskTableData.map(item => ({
|
dataCode: item.sampleCode,
|
dataTitle: item.testData,
|
dataType: item.photos && item.spectrums ? '1,2' :
|
item.photos ? '1' :
|
item.spectrums ? '2' : '',
|
dataFiles: JSON.stringify(item.spectrums || []),
|
dataPictures: (item.photos || []).map(photo => photo.url).join(','),
|
originalId: this.form.id,
|
resultText: item.resultText || ''
|
}))
|
};
|
|
console.log('提交数据:', submitData);
|
|
// 调用更新接口
|
const res = await update(submitData);
|
if (res.code === 200) {
|
// 根据 isDraft 显示不同的成功提示
|
if (isDraft) {
|
this.$message.success('保存草稿成功');
|
} else {
|
this.$message.success('填写完毕');
|
}
|
// 返回上一页
|
this.$router.back();
|
} else {
|
this.$message.error(res.msg || '提交失败');
|
}
|
} catch (error) {
|
console.error('提交失败:', error);
|
this.$message.error('提交失败');
|
}
|
},
|
|
// 存草稿
|
handleSaveDraft() {
|
this.handleSubmit(true);
|
}
|
},
|
created() {
|
this.getDetail();
|
}
|
};
|
</script>
|
|
<style scoped lang="less">
|
.ai-editor-container{
|
margin-left: 40px;
|
width: 85%;
|
}
|
.el-form--inline .el-form-item {
|
margin-right: 83px;
|
}
|
|
.header-title {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 13px;
|
margin-top: 38px;
|
margin-bottom: 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>
|