<template>
|
<Card>
|
<el-form
|
ref="form"
|
:model="form"
|
:rules="rules"
|
inline
|
label-position="top"
|
>
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>一 、所属实验调度</div>
|
</div>
|
<el-button
|
type="primary"
|
class="el-icon-plus"
|
@click="handleSelectScheduling"
|
>选择实验调度</el-button
|
>
|
</div>
|
|
<Table
|
:data="[selectedScheduling].filter(Boolean)"
|
:total="0"
|
:height="null"
|
class="rwuTable"
|
>
|
<el-table-column
|
prop="planName"
|
label="所属项目课题方案"
|
min-width="180"
|
></el-table-column>
|
<el-table-column
|
prop="planCode"
|
label="实验编号"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="experimentName"
|
label="实验名称"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="noticeTime"
|
label="通知时间"
|
min-width="150"
|
></el-table-column>
|
<el-table-column
|
prop="startTime"
|
label="实验开始时间"
|
min-width="150"
|
></el-table-column>
|
<el-table-column
|
prop="endTime"
|
label="实验结束时间"
|
min-width="150"
|
></el-table-column>
|
<el-table-column
|
prop="participants"
|
label="参加人员"
|
min-width="180"
|
></el-table-column>
|
<el-table-column
|
prop="status"
|
label="状态"
|
min-width="100"
|
></el-table-column>
|
</Table>
|
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>一 、实验结果</div>
|
</div>
|
</div>
|
<Table
|
:data="experimentResultData"
|
:total="0"
|
:height="null"
|
class="rwuTable"
|
>
|
<el-table-column
|
prop="planName"
|
label="所属项目课题方案"
|
min-width="180"
|
></el-table-column>
|
<el-table-column
|
prop="experimentCode"
|
label="实验编号"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="experimentName"
|
label="实验名称"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="experimentDate"
|
label="实验日期"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="experimenter"
|
label="实验员"
|
min-width="100"
|
></el-table-column>
|
<el-table-column
|
prop="createTime"
|
label="创建日期"
|
min-width="150"
|
></el-table-column>
|
<el-table-column
|
prop="creator"
|
label="创建人"
|
min-width="100"
|
></el-table-column>
|
<el-table-column
|
prop="status"
|
label="当前状态"
|
min-width="120"
|
></el-table-column>
|
<el-table-column label="操作" min-width="100" fixed="right">
|
<template slot-scope="scope">
|
<el-button type="text" @click="handleViewDetail(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>
|
<Table
|
:data="inspectionResultData"
|
:total="0"
|
:height="null"
|
class="rwuTable"
|
>
|
<el-table-column
|
prop="planName"
|
label="所属项目课题方案"
|
min-width="180"
|
></el-table-column>
|
<el-table-column
|
prop="experimentCode"
|
label="所属实验编号"
|
min-width="120"
|
></el-table-column>
|
<el-table-column
|
prop="createTime"
|
label="创建时间"
|
min-width="150"
|
></el-table-column>
|
<el-table-column
|
prop="creator"
|
label="创建人"
|
min-width="100"
|
></el-table-column>
|
<el-table-column
|
prop="status"
|
label="状态"
|
min-width="100"
|
></el-table-column>
|
<el-table-column label="操作" min-width="100" fixed="right">
|
<template slot-scope="scope">
|
<el-button
|
type="text"
|
@click="handleViewInspectionDetail(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>
|
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>四 、化验师工作评定</div>
|
</div>
|
</div>
|
|
<div class="evaluate-card">
|
<div class="evaluate-card-people">
|
<div
|
v-for="technician in labTechnicians"
|
:key="technician.id"
|
class="evaluate-card-people-item"
|
:class="{ 'active-people': selectedLabTechnician?.id === technician.id }"
|
@click="handleSelectLabTechnician(technician)"
|
>
|
{{ technician.name }}
|
</div>
|
</div>
|
<div class="evaluate-card-cotent">
|
<template v-if="selectedLabTechnician">
|
<template v-if="selectedLabTechnician.data">
|
<EvaluateTable
|
class="evaluate-table"
|
:isReadonly="true"
|
:type="1"
|
:viewJson="JSON.stringify(selectedLabTechnician.data)"
|
/>
|
</template>
|
<template v-else>
|
<div class="no-data">暂未评定</div>
|
<div class="to-evaluate" @click="handleEvaluate('labTechnician')">去评价</div>
|
</template>
|
</template>
|
</div>
|
</div>
|
|
<div class="header-title">
|
<div class="header-title-left">
|
<img src="@/assets/public/headercard.png" />
|
<div>五 、实验员工作评定</div>
|
</div>
|
</div>
|
|
<div class="evaluate-card">
|
<div class="evaluate-card-people">
|
<div
|
v-for="experimenter in experimenters"
|
:key="experimenter.id"
|
class="evaluate-card-people-item"
|
:class="{ 'active-people': selectedExperimenter?.id === experimenter.id }"
|
@click="handleSelectExperimenter(experimenter)"
|
>
|
{{ experimenter.name }}
|
</div>
|
</div>
|
<div class="evaluate-card-cotent">
|
<template v-if="selectedExperimenter">
|
<template v-if="selectedExperimenter.data">
|
<EvaluateTable
|
ref="experimenterEvaluateTable"
|
class="evaluate-table"
|
:isReadonly="true"
|
:viewJson="JSON.stringify(selectedExperimenter.data)"
|
/>
|
</template>
|
<template v-else>
|
<div class="no-data">暂未评定</div>
|
<div class="to-evaluate" @click="handleEvaluate('experimenter')">去评价</div>
|
</template>
|
</template>
|
</div>
|
</div>
|
|
<div class="add-project-footer">
|
<el-button type="primary" class="save-btn">发送</el-button>
|
<el-button>存草稿</el-button>
|
</div>
|
</el-form>
|
<!-- 选择实验调度弹窗 -->
|
<experimental-scheduling
|
:show.sync="schedulingDialogVisible"
|
@select="handleSchedulingSelect"
|
/>
|
<!-- 评价弹窗 -->
|
<evaluation-dialog
|
:modelValue="evaluationDialogVisible"
|
:type="currentEvaluationType"
|
@update:modelValue="updateEvaluationDialogVisible"
|
@submit="handleEvaluationSubmit"
|
/>
|
<!-- 检验结果详情弹窗 -->
|
<checkout-result
|
:visible.sync="checkoutResultVisible"
|
:data="currentCheckoutResult"
|
/>
|
<!-- 新增组件弹窗 -->
|
<add-component-dialog
|
v-if="showNewDialog"
|
:visible.sync="showNewDialog"
|
@confirm="handleAddComponent"
|
/>
|
</Card>
|
</template>
|
|
<script>
|
import ExperimentalScheduling from "./components/experimental-scheduling.vue";
|
import moment from "moment";
|
import EvaluationDialog from "./components/evaluation-dialog.vue";
|
import CheckoutResult from "./components/checkout-result.vue";
|
import AddComponentDialog from "@/components/AddComponentDialog";
|
|
export default {
|
name: "AddProject",
|
components: {
|
ExperimentalScheduling,
|
EvaluationDialog,
|
CheckoutResult,
|
AddComponentDialog
|
},
|
data() {
|
return {
|
showNewDialog: true,
|
dialogVisible: false,
|
schedulingDialogVisible: false,
|
isEdit: false,
|
currentEditIndex: -1,
|
selectedScheduling: null,
|
form: {
|
recordNo: "",
|
testItemName: "",
|
testItemNo: "",
|
testMethodName: "",
|
testMethodNo: "",
|
},
|
rules: {
|
recordNo: [
|
{
|
required: true,
|
message: "请输入原始检验记录编号",
|
trigger: "blur",
|
},
|
],
|
testItemName: [
|
{ required: true, message: "请输入检测项名字", trigger: "blur" },
|
],
|
testItemNo: [
|
{ required: true, message: "请输入检测项编号", trigger: "blur" },
|
],
|
testMethodName: [
|
{ required: true, message: "请输入检测方法名字", trigger: "blur" },
|
],
|
testMethodNo: [
|
{ required: true, message: "请输入检测方法编号", trigger: "blur" },
|
],
|
},
|
taskTableData: [],
|
experimentResultData: [
|
{
|
planName: "名称名称名称",
|
experimentCode: "3814763",
|
experimentName: "名称名称22",
|
experimentDate: "2024-05-28",
|
experimenter: "刘大大",
|
createTime: "2025-1-2 16:27:17",
|
creator: "周乐心",
|
status: "实验员已提交",
|
},
|
],
|
inspectionResultData: [
|
{
|
planName: "名称名称名称",
|
experimentCode: "31423764",
|
createTime: "",
|
creator: "",
|
status: "已提交",
|
},
|
{
|
planName: "名称名称名称",
|
experimentCode: "31423764",
|
createTime: "",
|
creator: "",
|
status: "已提交",
|
},
|
],
|
// 化验师数据
|
labTechnicians: [
|
{
|
id: 1,
|
name: '张三',
|
role: '化验师',
|
data: null // 评定数据,null 表示未评定
|
},
|
{
|
id: 2,
|
name: '李四',
|
role: '化验师',
|
data: null
|
}
|
],
|
selectedLabTechnician: null,
|
|
// 实验员数据
|
experimenters: [
|
{
|
id: 1,
|
name: '王五',
|
role: '实验员',
|
data: null
|
},
|
{
|
id: 2,
|
name: '赵六',
|
role: '实验员',
|
data: null
|
}
|
],
|
selectedExperimenter: null,
|
|
// 弹窗控制
|
evaluationDialogVisible: false,
|
currentEvaluationType: '',
|
checkoutResultVisible: false,
|
currentCheckoutResult: null
|
};
|
},
|
watch: {
|
selectedLabTechnician: {
|
handler(newVal) {
|
console.log("selectedLabTechnician", newVal);
|
},
|
},
|
},
|
created() {
|
// 默认选中第一个人员
|
this.selectedLabTechnician = this.labTechnicians[0];
|
this.selectedExperimenter = this.experimenters[0];
|
},
|
methods: {
|
handleSelectScheduling() {
|
this.schedulingDialogVisible = true;
|
},
|
handleSchedulingSelect(selectedData) {
|
if (selectedData && selectedData.length > 0) {
|
this.selectedScheduling = selectedData[0];
|
this.$message.success("选择成功");
|
}
|
},
|
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);
|
},
|
handleViewDetail(row) {
|
console.log("查看详情", row);
|
},
|
handleViewInspectionDetail(row) {
|
this.currentCheckoutResult = row;
|
this.checkoutResultVisible = true;
|
},
|
// 选择化验师
|
handleSelectLabTechnician(technician) {
|
this.selectedLabTechnician = technician;
|
},
|
// 选择实验员
|
handleSelectExperimenter(experimenter) {
|
this.selectedExperimenter = experimenter;
|
},
|
// 去评价
|
handleEvaluate(type) {
|
this.currentEvaluationType = type;
|
this.evaluationDialogVisible = true;
|
},
|
// 处理评价提交
|
handleEvaluationSubmit(evaluationData) {
|
const { type, activeIndex } = evaluationData;
|
|
if (type === 'labTechnician') {
|
// 更新化验师列表中的数据
|
const labTechnician = this.labTechnicians.find(item => item.id === this.selectedLabTechnician.id);
|
if (labTechnician) {
|
labTechnician.data = activeIndex;
|
// 更新当前选中的化验师数据
|
this.selectedLabTechnician = { ...labTechnician };
|
}
|
} else if (type === 'experimenter') {
|
// 更新实验员列表中的数据
|
const experimenter = this.experimenters.find(item => item.id === this.selectedExperimenter.id);
|
if (experimenter) {
|
experimenter.data = activeIndex;
|
// 更新当前选中的实验员数据
|
this.selectedExperimenter = { ...experimenter };
|
}
|
}
|
|
// 这里可以添加数据持久化的逻辑,比如调用API保存到后端
|
// this.saveEvaluationData(type, activeIndex);
|
|
this.$message.success('评价提交成功');
|
this.evaluationDialogVisible = false;
|
},
|
// 更新弹窗显示状态
|
updateEvaluationDialogVisible(value) {
|
this.evaluationDialogVisible = value;
|
}
|
},
|
};
|
</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;
|
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;
|
}
|
}
|
|
.evaluate-card {
|
width: calc(95% - 40px);
|
background: #eff8fa;
|
padding: 30px;
|
margin-left: 29px;
|
|
.evaluate-card-people {
|
display: flex;
|
align-items: center;
|
gap: 16px;
|
|
.evaluate-card-people-item {
|
width: 125px;
|
background: #ffffff;
|
border-radius: 6px;
|
padding: 10px 5px;
|
font-family: PingFangSC, PingFang SC;
|
font-weight: 400;
|
font-size: 16px;
|
color: #333333;
|
line-height: 22px;
|
text-align: center;
|
}
|
|
.active-people {
|
background: #ebffff;
|
border-radius: 6px;
|
border: 1px solid #049c9a;
|
color: rgba(4, 156, 154, 1);
|
}
|
}
|
.evaluate-card-cotent {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
.no-data {
|
font-family: PingFangSC, PingFang SC;
|
font-weight: 500;
|
font-size: 20px;
|
color: #909399;
|
line-height: 28px;
|
margin-top: 58px;
|
margin-bottom: 30px;
|
}
|
.to-evaluate {
|
width: 65px;
|
background: #049c9a;
|
border-radius: 4px;
|
font-family: SourceHanSansCN, SourceHanSansCN;
|
font-weight: 400;
|
font-size: 14px;
|
color: #ffffff;
|
line-height: 32px;
|
text-align: center;
|
margin-bottom: 12px;
|
}
|
.evaluate-table{
|
width: 100%;
|
margin-top: 29px;
|
}
|
}
|
}
|
</style>
|