| | |
| | | component: () => import("../views/strain-library/validation/primitive-cell/add.vue") |
| | | }, |
| | | { |
| | | path: 'confirm-detail', |
| | | name: 'ConfirmDetail', |
| | | meta: { |
| | | title: '确认原始细胞库资料', |
| | | hide: true |
| | | }, |
| | | component: () => import("../views/strain-library/validation/primitive-cell/confirm-detail.vue") |
| | | }, |
| | | { |
| | | path: 'chief-cell', |
| | | name: 'ChiefCell', |
| | | meta: { |
New file |
| | |
| | | <template> |
| | | <el-dialog :visible.sync="visible" title="新增培养皿观察记录" width="80%" @close="handleClose"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" label-position="top"> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="分离菌落编号" prop="colonyNo" required> |
| | | <el-input v-model="form.colonyNo" placeholder="请输入分离菌落编号" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="形状强壮度排名" prop="rank" required> |
| | | <el-input v-model="form.rank" placeholder="请输入形状强壮度排名" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <el-table :data="tableData" border style="width: 100%; margin-bottom: 16px;"> |
| | | <el-table-column prop="index" label="记录次数" width="90"> |
| | | <template #default="{ row }"> |
| | | 第{{ row.index }}次 |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="desc" label="形态记录"> |
| | | <template #default="{ row }"> |
| | | <el-input v-model="row.desc" placeholder="请输入形态记录" style="width: 100%;" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="images" label="拍照上传" width="120"> |
| | | <template #default="{ row }"> |
| | | <el-upload |
| | | :file-list="row.images" |
| | | list-type="picture-card" |
| | | :on-preview="file => handlePreview(row, file)" |
| | | :on-remove="(file, fileList) => handleRemove(row, file, fileList)" |
| | | :on-success="(res, file, fileList) => handleUpload(row, file, fileList)" |
| | | :before-upload="beforeUpload" |
| | | action="#" |
| | | :limit="5" |
| | | class="mini-upload" |
| | | > |
| | | <i class="el-icon-plus"></i> |
| | | </el-upload> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="time" label="记录时间" width="160"> |
| | | <template #default="{ row }"> |
| | | {{ row.time }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div style="text-align: center;"> |
| | | <el-button type="primary" @click="handleOk">保存</el-button> |
| | | </div> |
| | | <el-dialog :visible.sync="previewVisible" width="400px"> |
| | | <img :src="previewImg" alt="图片预览" style="width: 100%;" /> |
| | | </el-dialog> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'SlantRecordDialog', |
| | | props: { |
| | | visible: Boolean, |
| | | value: { |
| | | type: Object, |
| | | default: () => ({ colonyNo: '', rank: '', records: [] }) |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | colonyNo: '', |
| | | rank: '' |
| | | }, |
| | | rules: { |
| | | colonyNo: [{ required: true, message: '请输入分离菌落编号', trigger: 'blur' }], |
| | | rank: [{ required: true, message: '请输入形状强壮度排名', trigger: 'blur' }] |
| | | }, |
| | | tableData: [], |
| | | previewVisible: false, |
| | | previewImg: '' |
| | | } |
| | | }, |
| | | watch: { |
| | | value: { |
| | | immediate: true, |
| | | handler(val) { |
| | | this.form.colonyNo = val.colonyNo || '' |
| | | this.form.rank = val.rank || '' |
| | | this.tableData = (val.records && val.records.length === 10) |
| | | ? val.records.map((item, i) => ({ ...item, index: i + 1 })) |
| | | : Array.from({ length: 10 }, (_, i) => ({ index: i + 1, desc: '', images: [], time: this.getNowTime() })) |
| | | } |
| | | }, |
| | | visible(val) { |
| | | if (!val) { |
| | | this.reset() |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | getNowTime() { |
| | | const d = new Date() |
| | | return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()} ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}` |
| | | }, |
| | | reset() { |
| | | this.form.colonyNo = '' |
| | | this.form.rank = '' |
| | | this.tableData = Array.from({ length: 10 }, (_, i) => ({ index: i + 1, desc: '', images: [], time: this.getNowTime() })) |
| | | }, |
| | | handleOk() { |
| | | this.$refs.formRef.validate(valid => { |
| | | if (!valid) return |
| | | // 校验每行形态记录必填 |
| | | for (let i = 0; i < this.tableData.length; i++) { |
| | | if (!this.tableData[i].desc) { |
| | | this.$message.error(`第${i + 1}次形态记录不能为空`) |
| | | return |
| | | } |
| | | } |
| | | this.$emit('ok', { |
| | | colonyNo: this.form.colonyNo, |
| | | rank: this.form.rank, |
| | | records: this.tableData |
| | | }) |
| | | this.handleClose() |
| | | }) |
| | | }, |
| | | handleClose() { |
| | | this.$emit('update:visible', false) |
| | | }, |
| | | beforeUpload(file) { |
| | | // 这里只做本地预览 |
| | | return new Promise(resolve => { |
| | | const reader = new FileReader() |
| | | reader.onload = e => { |
| | | resolve() |
| | | } |
| | | reader.readAsDataURL(file) |
| | | }) |
| | | }, |
| | | handleUpload(row, file, fileList) { |
| | | // 这里只做本地预览 |
| | | row.images = fileList.map(f => ({ ...f, url: f.url || URL.createObjectURL(f.raw) })) |
| | | }, |
| | | handleRemove(row, file, fileList) { |
| | | row.images = fileList |
| | | }, |
| | | handlePreview(row, file) { |
| | | this.previewImg = file.url |
| | | this.previewVisible = true |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | ::v-deep(.el-upload--picture-card) { |
| | | width: 40px !important; |
| | | height: 40px !important; |
| | | line-height: 40px !important; |
| | | } |
| | | ::v-deep(.mini-upload .el-upload-list--picture-card .el-upload-list__item) { |
| | | width: 40px !important; |
| | | height: 40px !important; |
| | | } |
| | | ::v-deep(.mini-upload .el-upload-list--picture-card .el-upload-list__item-thumbnail) { |
| | | width: 40px !important; |
| | | height: 40px !important; |
| | | object-fit: cover; |
| | | } |
| | | ::v-deep(.mini-upload .el-upload-list--picture-card .el-upload-list__item-preview), |
| | | ::v-deep(.mini-upload .el-upload-list--picture-card .el-upload-list__item-delete) { |
| | | width: 18px; |
| | | height: 18px; |
| | | font-size: 14px; |
| | | } |
| | | ::v-deep(.el-upload--picture-card) { |
| | | width: 40px !important; |
| | | height: 40px !important; |
| | | line-height: 40px !important; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | ::v-deep(.mini-upload .el-upload--picture-card i.el-icon-plus) { |
| | | font-size: 18px; /* 缩小icon */ |
| | | color: #999; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | </style> |
| | |
| | | <div>一、培养基分离记录</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | <el-button @click="showSeparationDialog = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 新增培养皿分离记录</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | <div>二、培养皿生物学形态观察记录</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | <el-button @click="showObservationDialog = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 新增观察记录</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | <div>三、接种斜面记录</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | <el-button @click="showInoculationDialog = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 新增斜面记录</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | <div>四、菌种保藏记录</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | <el-button @click="showPreserveDialog = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 新增菌种保藏记录</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | </el-table-column> |
| | | </template> |
| | | </Table> |
| | | <!-- 弹窗组件 --> |
| | | <SeparationRecordDialog |
| | | :visible.sync="showSeparationDialog" |
| | | @confirm="handleSeparationConfirm" |
| | | /> |
| | | <SlantRecordDialog |
| | | :visible.sync="showObservationDialog" |
| | | @ok="handleObservationConfirm" |
| | | /> |
| | | <InoculationSlopeRecordDialog |
| | | :visible.sync="showInoculationDialog" |
| | | @save="handleInoculationConfirm" |
| | | /> |
| | | <PreserveStrainRecordDialog |
| | | :visible.sync="showPreserveDialog" |
| | | @save="handlePreserveConfirm" |
| | | /> |
| | | <div class="end-btn"> |
| | | <el-button type="primary">发送</el-button> |
| | | <el-button type="default">存草稿</el-button> |
| | |
| | | </template> |
| | | <script> |
| | | import AiEditor from "@/components/AiEditor"; |
| | | import SeparationRecordDialog from "./separation-record-dialog.vue"; |
| | | import SlantRecordDialog from "./SlantRecordDialog.vue"; |
| | | import InoculationSlopeRecordDialog from "./inoculation-slope-record-dialog.vue"; |
| | | import PreserveStrainRecordDialog from "./preserve-strain-record-dialog.vue"; |
| | | |
| | | export default { |
| | | components: { AiEditor }, |
| | | components: { |
| | | AiEditor, |
| | | SeparationRecordDialog, |
| | | SlantRecordDialog, |
| | | InoculationSlopeRecordDialog, |
| | | PreserveStrainRecordDialog, |
| | | }, |
| | | name: "AddBreedingRecord", |
| | | data() { |
| | | return { |
| | |
| | | status: "1", |
| | | remark: "", |
| | | queryForm: {}, |
| | | showSeparationDialog: false, |
| | | showObservationDialog: false, |
| | | showInoculationDialog: false, |
| | | showPreserveDialog: false, |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleSeparationConfirm(data) { |
| | | console.log("培养皿分离记录确认", data); |
| | | }, |
| | | handleObservationConfirm(data) { |
| | | console.log("培养皿观察记录确认", data); |
| | | }, |
| | | handleInoculationConfirm(data) { |
| | | console.log("接种斜面记录确认", data); |
| | | }, |
| | | handlePreserveConfirm(data) { |
| | | console.log("菌种保藏记录确认", data); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | |
| | | <template> |
| | | <el-dialog |
| | | title="添加出入库记录" |
| | | title="新增培养皿分离记录" |
| | | :visible.sync="visible" |
| | | width="520px" |
| | | :close-on-click-modal="false" |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> |
| | | <span>菌种源保藏出/入细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore">查看全部 >></el-button> |
| | | </div> |
| | | <div class="header-content" :class="{ 'collapsed': true }"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | </div> |
| | | |
| | | <!-- 查看全部弹窗 --> |
| | | <el-dialog |
| | | title="菌种源保藏出/入细胞库登记表说明" |
| | | :visible.sync="dialogVisible" |
| | | width="50%" |
| | | class="view-all-dialog" |
| | | > |
| | | <div class="dialog-content"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-form-item label="鉴别菌株编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="鉴别菌株名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="验证实验编号:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option label="已入库" value="1"></el-option> |
| | | <el-option label="已出库" value="2"></el-option> |
| | | <el-option label="入库待确认" value="3"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item class="search-btn-box"> |
| | | <el-button type="default" @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="searchData">查询</el-button> |
| | |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')"> |
| | | 原始细胞列表</div> |
| | | 主细胞库资料列表</div> |
| | | <div class="drafts" :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')"> |
| | | 草稿箱</div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button @click="handleNewStrain" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增原始细胞</el-button> |
| | | <el-button @click="handleBatchAdd" class="el-icon-plus" type="primary">批量新增</el-button> |
| | | <el-button @click="handleNewStrain" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增主细胞</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table> |
| | | <el-table-column prop="strainNo" label="菌种编号" /> |
| | | <el-table-column prop="strainName" label="菌种名称" /> |
| | | <el-table-column prop="source" label="菌种来源" /> |
| | | <el-table-column prop="method" label="鉴定方法" /> |
| | | <el-table-column prop="certificate" label="特征描述" /> |
| | | <el-table-column prop="storage" label="菌种保存方法" /> |
| | | <el-table-column prop="amount" label="保存位置" /> |
| | | <el-table-column prop="inventory" label="库存余量" /> |
| | | <el-table-column prop="notes" label="备注" /> |
| | | <el-table-column prop="status" label="当前状态"> |
| | | <el-table-column prop="strainNo" label="菌种来源" /> |
| | | <el-table-column prop="strainNo" label="鉴别菌株编号" /> |
| | | <el-table-column prop="strainName" label="鉴别菌株名称" /> |
| | | <el-table-column prop="source" label="验证实验编号" /> |
| | | <el-table-column prop="method" label="创建人" /> |
| | | <el-table-column prop="certificate" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | </template> |
| | |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleRecord(row)">出入库记录</el-button> |
| | | <el-button type="text" @click="handleRecord(row)">删除</el-button> |
| | | <el-button type="text" @click="handleRecord(row)">确认</el-button> |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | </div> |
| | | </template> |
| | | |
New file |
| | |
| | | <template> |
| | | <el-dialog :visible.sync="visible" width="80%" @close="handleClose"> |
| | | <el-card class="top-card"> |
| | | <el-row :gutter="24" class="top-info-row"> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"> |
| | | <span class="label">菌种来源:</span>{{ detail.source }} |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">鉴别菌株编号:</span>{{ detail.strainNo }} |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">鉴别菌株名称:</span>{{ detail.strainName }} |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"> |
| | | <span class="label">验证实验编号:</span>{{ detail.verifyNo }} |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">实验时间:</span>{{ detail.experimentTime }} |
| | | </div> |
| | | <div class="info-item"></div> |
| | | </el-col> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item sign-label"> |
| | | <span class="label">菌种实验员签字</span> |
| | | </div> |
| | | <div class="info-item signature-item"> |
| | | <div class="signature-area"> |
| | | <img v-if="detail.signature" :src="detail.signature" alt="签字" /> |
| | | <span v-else class="waiting-text">暂无签名</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | <div class="section-card" style="margin-top: 24px"> |
| | | <el-form label-width="100px" label-position="top"> |
| | | <el-form-item label="实验结论"> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="detail.conclusion" |
| | | :rows="3" |
| | | placeholder="请输入" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="批准菌株用途"> |
| | | <el-checkbox-group v-model="detail.usage"> |
| | | <el-checkbox label="传代" /> |
| | | <el-checkbox label="菌种保藏" /> |
| | | <el-checkbox label="废弃" /> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <EditConditionDialog |
| | | :visible.sync="dialogVisible" |
| | | :isEdit="dialogIsEdit" |
| | | :isFixed="dialogIsFixed" |
| | | :value="dialogValue" |
| | | @ok="handleDialogOk" |
| | | /> |
| | | |
| | | <div class="section-card" style="margin-top: 12px"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | style="width: 100%" |
| | | :row-class-name="getRowClassName" |
| | | > |
| | | <el-table-column prop="condition" label="菌种培养工艺条件" /> |
| | | <el-table-column prop="record" label="菌种培养工艺实况记录" /> |
| | | <el-table-column prop="process" label="菌种培养标准工艺" /> |
| | | <el-table-column label="操作" width="120"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleEdit(row)">详情</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | import EditConditionDialog from "./EditConditionDialog.vue"; |
| | | import DetailConditionDialog from "./DetailConditionDialog.vue"; |
| | | export default { |
| | | name: "DetailConditionDialog", |
| | | components: { EditConditionDialog, DetailConditionDialog }, |
| | | props: { |
| | | visible: Boolean, |
| | | value: { |
| | | type: Object, |
| | | default: () => ({ condition: "", record: "", process: "" }), |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | detail: { |
| | | source: "内容的内容内容内容", |
| | | strainNo: "3411234", |
| | | strainName: "名称名称名称", |
| | | verifyNo: "34133214", |
| | | experimentTime: "2025-1-23 11:10:28", |
| | | signature: "", // 签名图片url |
| | | conclusion: "", |
| | | usage: [], |
| | | }, |
| | | activeTab: "condition", |
| | | initialTableData: [ |
| | | { |
| | | condition: "平板培养基", |
| | | record: "文字内容文字内容文字内容文字内容文字内容文字内容", |
| | | process: "文字内容文字内容文字内容文字内容文字内容文字内容", |
| | | }, |
| | | { condition: "培养温度", record: "", process: "" }, |
| | | { condition: "培养时间", record: "", process: "" }, |
| | | { condition: "摇瓶培养基", record: "", process: "" }, |
| | | { condition: "接种量", record: "", process: "" }, |
| | | { condition: "培养时间", record: "", process: "" }, |
| | | { condition: "发酵时间", record: "", process: "" }, |
| | | { condition: "检测数据及结果", record: "", process: "" }, |
| | | ], |
| | | tableData: [ |
| | | { |
| | | condition: "平板培养基", |
| | | record: "文字内容文字内容文字内容文字内容文字内容文字内容", |
| | | process: "文字内容文字内容文字内容文字内容文字内容文字内容", |
| | | }, |
| | | { condition: "培养温度", record: "", process: "" }, |
| | | { condition: "培养时间", record: "", process: "" }, |
| | | { condition: "摇瓶培养基", record: "", process: "" }, |
| | | { condition: "接种量", record: "", process: "" }, |
| | | { condition: "培养时间", record: "", process: "" }, |
| | | { condition: "发酵时间", record: "", process: "" }, |
| | | { condition: "检测数据及结果", record: "", process: "" }, |
| | | ], |
| | | dialogVisible: false, |
| | | dialogIsEdit: false, |
| | | dialogIsFixed: false, |
| | | dialogValue: {}, |
| | | dialogIndex: null, |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleClose() { |
| | | this.$emit("update:visible", false); |
| | | }, |
| | | handleEdit(row) { |
| | | const idx = this.tableData.indexOf(row); |
| | | this.dialogVisible = true; |
| | | this.dialogIsEdit = true; |
| | | this.dialogIsFixed = idx < this.initialTableData.length; |
| | | this.dialogValue = { ...row }; |
| | | this.dialogIndex = idx; |
| | | }, |
| | | |
| | | handleSave() { |
| | | this.dialogVisible = true; |
| | | this.dialogIsEdit = false; |
| | | this.dialogIsFixed = false; |
| | | this.dialogValue = { condition: "", record: "", process: "" }; |
| | | this.dialogIndex = null; |
| | | }, |
| | | handleDraft() { |
| | | // 存稿逻辑 |
| | | }, |
| | | handleDialogOk(val) { |
| | | if (this.dialogIsEdit && this.dialogIndex !== null) { |
| | | this.$set(this.tableData, this.dialogIndex, val); |
| | | } else { |
| | | this.tableData.push(val); |
| | | } |
| | | }, |
| | | getRowClassName({ rowIndex }) { |
| | | return rowIndex < this.initialTableData.length ? "fixed-row" : ""; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .el-dialog__body { |
| | | padding-bottom: 0; |
| | | } |
| | | .top-card { |
| | | margin-bottom: 0; |
| | | background: rgba(239, 239, 239, 1); |
| | | border-radius: 16px; |
| | | } |
| | | |
| | | .top-info-row { |
| | | align-items: stretch; |
| | | } |
| | | |
| | | .info-col { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | font-size: 15px; |
| | | height: 45px; |
| | | line-height: 45px; |
| | | } |
| | | |
| | | .label { |
| | | color: #666; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .sign-col { |
| | | align-items: center; |
| | | text-align: center; |
| | | } |
| | | |
| | | .sign-label { |
| | | justify-content: center; |
| | | } |
| | | |
| | | .signature-item { |
| | | justify-content: center; |
| | | } |
| | | |
| | | .signature-area { |
| | | min-height: 80px; |
| | | min-width: 120px; |
| | | background: #f5f7fa; |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .signature-area img { |
| | | max-width: 100%; |
| | | max-height: 100%; |
| | | display: block; |
| | | } |
| | | |
| | | .waiting-text { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .sign-time { |
| | | justify-content: center; |
| | | text-align: center; |
| | | color: #666; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .section-card { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .footer-btns { |
| | | display: flex; |
| | | justify-content: center; |
| | | padding: 24px; |
| | | padding-bottom: 0; |
| | | gap: 24px; |
| | | .el-button { |
| | | width: 150px; |
| | | } |
| | | } |
| | | |
| | | ::v-deep(.fixed-row) { |
| | | background-color: rgb(228, 248, 250) !important; |
| | | } |
| | | |
| | | @media (max-width: 900px) { |
| | | .info-col { |
| | | height: auto; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <el-dialog :visible.sync="visible" width="800px" @close="handleClose"> |
| | | <el-form label-width="120px" label-position="top"> |
| | | <el-form-item label="菌种培养工艺条件"> |
| | | <el-input v-model="form.condition" :disabled="isFixed" placeholder="请输入" /> |
| | | </el-form-item> |
| | | <el-form-item label="菌种培养工艺实况记录"> |
| | | <el-input type="textarea" v-model="form.record" :rows="7" placeholder="请输入文本内容" /> |
| | | </el-form-item> |
| | | <el-form-item label="菌种培养标准工艺"> |
| | | <el-input type="textarea" v-model="form.process" :rows="7" placeholder="请输入文本内容" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div style="text-align: center; margin-top: 24px;"> |
| | | <el-button type="primary" @click="handleOk">保存</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'EditConditionDialog', |
| | | props: { |
| | | visible: Boolean, |
| | | isEdit: Boolean, |
| | | isFixed: Boolean, // true: 固定的8个条件,false: 新增条件 |
| | | value: { |
| | | type: Object, |
| | | default: () => ({ condition: '', record: '', process: '' }) |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { condition: '', record: '', process: '' } |
| | | } |
| | | }, |
| | | watch: { |
| | | value: { |
| | | immediate: true, |
| | | handler(val) { |
| | | this.form = { ...val } |
| | | } |
| | | }, |
| | | visible(val) { |
| | | if (!val) { |
| | | this.form = { condition: '', record: '', process: '' } |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | handleOk() { |
| | | this.$emit('ok', { ...this.form }) |
| | | this.handleClose() |
| | | }, |
| | | handleClose() { |
| | | this.$emit('update:visible', false) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .el-dialog__body { |
| | | padding-bottom: 0; |
| | | } |
| | | </style> |
| | |
| | | </el-dialog> |
| | | |
| | | <!-- 签字确认组件 --> |
| | | <SignatureCanvas |
| | | <ConfirmStorageDialog |
| | | :visible.sync="signatureVisible" |
| | | @confirm="handleSignatureConfirm" |
| | | name="操作人签字" |
| | | text="是否确认提交该项原始细胞库资料信息?" |
| | | /> |
| | | </Card> |
| | | </template> |
| | | |
| | | <script> |
| | | import SignatureCanvas from '@/components/SignatureCanvas.vue' |
| | | import ConfirmStorageDialog from '@/components/confirm-storage-dialog/index.vue' |
| | | |
| | | export default { |
| | | name: 'AddprimitiveCell', |
| | | components: { |
| | | SignatureCanvas |
| | | ConfirmStorageDialog |
| | | }, |
| | | data() { |
| | | return { |
New file |
| | |
| | | <template> |
| | | <Card class="confirm-detail-page"> |
| | | <el-card class="top-card"> |
| | | <el-row :gutter="24" class="top-info-row"> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"><span class="label">菌种来源:</span>{{ detail.source }}</div> |
| | | <div class="info-item"><span class="label">鉴别菌株编号:</span>{{ detail.strainNo }}</div> |
| | | <div class="info-item"><span class="label">鉴别菌株名称:</span>{{ detail.strainName }}</div> |
| | | </el-col> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"><span class="label">验证实验编号:</span>{{ detail.verifyNo }}</div> |
| | | <div class="info-item"><span class="label">实验时间:</span>{{ detail.experimentTime }}</div> |
| | | <div class="info-item"></div> |
| | | </el-col> |
| | | <el-col :span="8" class="info-col "> |
| | | <div class="info-item sign-label"><span class="label">菌种实验员签字</span></div> |
| | | <div class="info-item signature-item"> |
| | | <div class="signature-area"> |
| | | <img v-if="detail.signature" :src="detail.signature" alt="签字" /> |
| | | <span v-else class="waiting-text">暂无签名</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | <div class="section-card" style="margin-top: 24px;"> |
| | | <el-form label-width="100px" label-position="top"> |
| | | <el-form-item label="实验结论"> |
| | | <el-input type="textarea" v-model="detail.conclusion" :rows="3" placeholder="请输入" /> |
| | | </el-form-item> |
| | | <el-form-item label="批准菌株用途"> |
| | | <el-checkbox-group v-model="detail.usage"> |
| | | <el-checkbox label="传代" /> |
| | | <el-checkbox label="菌种保藏" /> |
| | | <el-checkbox label="废弃" /> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <el-button type="primary" @click="handleSave" class="el-icon-plus"> 新增</el-button> |
| | | <EditConditionDialog |
| | | :visible.sync="dialogVisible" |
| | | :isEdit="dialogIsEdit" |
| | | :isFixed="dialogIsFixed" |
| | | :value="dialogValue" |
| | | @ok="handleDialogOk" |
| | | /> |
| | | |
| | | <div class="section-card" style="margin-top: 12px;"> |
| | | <el-table :data="tableData" border style="width: 100%;" :row-class-name="getRowClassName"> |
| | | <el-table-column prop="condition" label="菌种培养工艺条件" /> |
| | | <el-table-column prop="record" label="菌种培养工艺实况记录" /> |
| | | <el-table-column prop="process" label="菌种培养标准工艺" /> |
| | | <el-table-column label="操作" width="120"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleDetail(row)">详情2</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <div class="footer-btns"> |
| | | <el-button type="primary" @click="handleSave">保存</el-button> |
| | | <el-button @click="handleDraft">存稿</el-button> |
| | | </div> |
| | | <DetailConditionDialog |
| | | :visible.sync="detailDialogVisible" |
| | | :value="detailDialogValue" |
| | | /> |
| | | </Card> |
| | | </template> |
| | | |
| | | <script> |
| | | import EditConditionDialog from './EditConditionDialog.vue' |
| | | import DetailConditionDialog from './DetailConditionDialog.vue' |
| | | export default { |
| | | name: 'ConfirmDetail', |
| | | components: { EditConditionDialog, DetailConditionDialog }, |
| | | data() { |
| | | return { |
| | | detail: { |
| | | source: '内容的内容内容内容', |
| | | strainNo: '3411234', |
| | | strainName: '名称名称名称', |
| | | verifyNo: '34133214', |
| | | experimentTime: '2025-1-23 11:10:28', |
| | | signature: '', // 签名图片url |
| | | conclusion: '', |
| | | usage: [] |
| | | }, |
| | | activeTab: 'condition', |
| | | initialTableData: [ |
| | | { condition: '平板培养基', record: '文字内容文字内容文字内容文字内容文字内容文字内容', process: '文字内容文字内容文字内容文字内容文字内容文字内容' }, |
| | | { condition: '培养温度', record: '', process: '' }, |
| | | { condition: '培养时间', record: '', process: '' }, |
| | | { condition: '摇瓶培养基', record: '', process: '' }, |
| | | { condition: '接种量', record: '', process: '' }, |
| | | { condition: '培养时间', record: '', process: '' }, |
| | | { condition: '发酵时间', record: '', process: '' }, |
| | | { condition: '检测数据及结果', record: '', process: '' } |
| | | ], |
| | | tableData: [ |
| | | { condition: '平板培养基', record: '文字内容文字内容文字内容文字内容文字内容文字内容', process: '文字内容文字内容文字内容文字内容文字内容文字内容' }, |
| | | { condition: '培养温度', record: '', process: '' }, |
| | | { condition: '培养时间', record: '', process: '' }, |
| | | { condition: '摇瓶培养基', record: '', process: '' }, |
| | | { condition: '接种量', record: '', process: '' }, |
| | | { condition: '培养时间', record: '', process: '' }, |
| | | { condition: '发酵时间', record: '', process: '' }, |
| | | { condition: '检测数据及结果', record: '', process: '' } |
| | | ], |
| | | dialogVisible: false, |
| | | dialogIsEdit: false, |
| | | dialogIsFixed: false, |
| | | dialogValue: {}, |
| | | dialogIndex: null, |
| | | detailDialogVisible: false, |
| | | detailDialogValue: {} |
| | | } |
| | | }, |
| | | methods: { |
| | | handleEdit(row) { |
| | | const idx = this.tableData.indexOf(row) |
| | | this.dialogVisible = true |
| | | this.dialogIsEdit = true |
| | | this.dialogIsFixed = idx < this.initialTableData.length |
| | | this.dialogValue = { ...row } |
| | | this.dialogIndex = idx |
| | | }, |
| | | handleDetail(row) { |
| | | this.detailDialogVisible = true |
| | | this.detailDialogValue = { ...row } |
| | | }, |
| | | handleSave() { |
| | | this.dialogVisible = true |
| | | this.dialogIsEdit = false |
| | | this.dialogIsFixed = false |
| | | this.dialogValue = { condition: '', record: '', process: '' } |
| | | this.dialogIndex = null |
| | | }, |
| | | handleDraft() { |
| | | // 存稿逻辑 |
| | | }, |
| | | handleDialogOk(val) { |
| | | if (this.dialogIsEdit && this.dialogIndex !== null) { |
| | | this.$set(this.tableData, this.dialogIndex, val) |
| | | } else { |
| | | this.tableData.push(val) |
| | | } |
| | | }, |
| | | getRowClassName({ rowIndex }) { |
| | | return rowIndex < this.initialTableData.length ? 'fixed-row' : ''; |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .top-card { |
| | | margin-bottom: 0; |
| | | background: rgba(239, 239, 239, 1); |
| | | border-radius: 16px; |
| | | } |
| | | |
| | | .top-info-row { |
| | | align-items: stretch; |
| | | } |
| | | |
| | | .info-col { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | font-size: 15px; |
| | | height: 45px; |
| | | line-height: 45px; |
| | | } |
| | | |
| | | .label { |
| | | color: #666; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .sign-col { |
| | | align-items: center; |
| | | text-align: center; |
| | | } |
| | | |
| | | .sign-label { |
| | | justify-content: center; |
| | | } |
| | | |
| | | .signature-item { |
| | | justify-content: center; |
| | | } |
| | | |
| | | .signature-area { |
| | | min-height: 80px; |
| | | min-width: 120px; |
| | | background: #f5f7fa; |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .signature-area img { |
| | | max-width: 100%; |
| | | max-height: 100%; |
| | | display: block; |
| | | } |
| | | |
| | | .waiting-text { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .sign-time { |
| | | justify-content: center; |
| | | text-align: center; |
| | | color: #666; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .section-card { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .footer-btns { |
| | | display: flex; |
| | | justify-content: center; |
| | | padding: 24px; |
| | | padding-bottom: 0; |
| | | gap: 24px; |
| | | .el-button { |
| | | width: 150px; |
| | | } |
| | | } |
| | | |
| | | ::v-deep(.fixed-row) { |
| | | background-color: rgb(228, 248, 250) !important; |
| | | } |
| | | |
| | | @media (max-width: 900px) { |
| | | .info-col { |
| | | height: auto; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <!-- Table --> |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="鉴别菌株编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="鉴别菌株名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="验证实验编号:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item class="search-btn-box"> |
| | | <el-button type="default" @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="searchData">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <div class="list"> |
| | | <!-- Table --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="tableData" |
| | | :total="total" |
| | | @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange" |
| | | > |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="鉴别菌株编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="鉴别菌株名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="验证实验编号:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item class="search-btn-box"> |
| | | <el-button type="default" @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="searchData">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')"> |
| | | 原始细胞库验证资料</div> |
| | | <div class="drafts" :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')"> |
| | | 草稿箱</div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button @click="handleNewStrain" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增原始细胞库资料</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')" |
| | | > |
| | | 原始细胞库验证资料 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')" |
| | | > |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button |
| | | @click="handleNewStrain" |
| | | class="el-icon-plus" |
| | | type="primary" |
| | | style="margin-right: 12px" |
| | | >新增原始细胞库资料</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table> |
| | | <el-table-column prop="source" label="菌种来源" /> |
| | | <el-table-column prop="method" label="鉴别菌株编号" /> |
| | | <el-table-column prop="certificate" label="鉴别菌株名称" /> |
| | | <el-table-column prop="storage" label="验证实验编号" /> |
| | | <el-table-column prop="amount" label="创建人" /> |
| | | <el-table-column prop="inventory" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleDetail(row)">确认</el-button> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleRecord(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | </div> |
| | | <template #table> |
| | | <el-table-column prop="source" label="菌种来源" /> |
| | | <el-table-column prop="method" label="鉴别菌株编号" /> |
| | | <el-table-column prop="certificate" label="鉴别菌株名称" /> |
| | | <el-table-column prop="storage" label="验证实验编号" /> |
| | | <el-table-column prop="amount" label="创建人" /> |
| | | <el-table-column prop="inventory" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ |
| | | getStatusText(row.status) |
| | | }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | type="text" |
| | | @click="$router.push('/strain/validation/confirm-detail')" |
| | | >确认</el-button |
| | | > |
| | | <el-button type="text" @click="handleDetail(row)">详情1</el-button> |
| | | <el-button type="text" @click="handleDetail2(row)">详情2</el-button> |
| | | <el-button type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleRecord(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <PrimitiveCellDetailDialog |
| | | :visible.sync="detailVisible" |
| | | :detail="currentDetail" |
| | | /> |
| | | <DetailConditionDialog |
| | | :visible.sync="detailDialogVisible" |
| | | :value="detailDialogValue" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | |
| | | import PrimitiveCellDetailDialog from "./primitive-cell-detail-dialog.vue"; |
| | | import DetailConditionDialog from "./DetailConditionDialog.vue"; |
| | | export default { |
| | | name: 'PrimitiveCell', |
| | | components: { |
| | | name: "PrimitiveCell", |
| | | components: { |
| | | PrimitiveCellDetailDialog, |
| | | DetailConditionDialog, |
| | | }, |
| | | data() { |
| | | return { |
| | | detailDialogVisible: false, |
| | | detailDialogValue: {}, |
| | | dialogVisible: false, |
| | | currentType: "list", |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | total: 800, |
| | | tableData: [ |
| | | { |
| | | strainNo: "YX-2024001", |
| | | strainName: "大肠杆菌", |
| | | source: "实验室分离", |
| | | method: "形态学鉴定、生理生化试验", |
| | | certificate: "革兰氏阴性杆菌,可发酵葡萄糖产酸产气,IMViC试验++--", |
| | | storage: "斜面培养", |
| | | amount: "A区-01-001", |
| | | inventory: "50", |
| | | notes: "用于质粒转化", |
| | | status: "1", |
| | | }, |
| | | { |
| | | strainNo: "YX-2024002", |
| | | strainName: "枯草芽孢杆菌", |
| | | source: "菌种保藏中心", |
| | | method: "16S rDNA测序", |
| | | certificate: "革兰氏阳性芽孢杆菌,可水解淀粉,产生溶菌素", |
| | | storage: "冷冻保存", |
| | | amount: "B区-02-005", |
| | | inventory: "30", |
| | | notes: "工业发酵菌种", |
| | | status: "1", |
| | | }, |
| | | { |
| | | strainNo: "YX-2024003", |
| | | strainName: "酿酒酵母", |
| | | source: "发酵工厂", |
| | | method: "显微镜观察、生理特性", |
| | | certificate: "椭圆形单细胞真菌,可发酵葡萄糖产生乙醇", |
| | | storage: "甘油管保存", |
| | | amount: "A区-03-002", |
| | | inventory: "40", |
| | | notes: "发酵工艺优化", |
| | | status: "2", |
| | | }, |
| | | { |
| | | strainNo: "YX-2024004", |
| | | strainName: "乳酸菌", |
| | | source: "乳制品分离", |
| | | method: "生化鉴定、API条", |
| | | certificate: "革兰氏阳性球菌,产生乳酸,耐酸性强", |
| | | storage: "冷冻干燥", |
| | | amount: "C区-01-003", |
| | | inventory: "25", |
| | | notes: "益生菌研究", |
| | | status: "3", |
| | | }, |
| | | { |
| | | strainNo: "YX-2024005", |
| | | strainName: "青霉菌", |
| | | source: "环境样本", |
| | | method: "形态学特征、ITS测序", |
| | | certificate: "丝状真菌,产生蓝绿色分生孢子,可产青霉素", |
| | | storage: "斜面培养", |
| | | amount: "B区-04-001", |
| | | inventory: "35", |
| | | notes: "次级代谢产物研究", |
| | | status: "1", |
| | | }, |
| | | ], |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleDetail(row) { |
| | | this.currentDetail = row; |
| | | this.detailVisible = true; |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: 'list', |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | }, |
| | | total: 800, |
| | | tableData: [ |
| | | { |
| | | strainNo: 'YX-2024001', |
| | | strainName: '大肠杆菌', |
| | | source: '实验室分离', |
| | | method: '形态学鉴定、生理生化试验', |
| | | certificate: '革兰氏阴性杆菌,可发酵葡萄糖产酸产气,IMViC试验++--', |
| | | storage: '斜面培养', |
| | | amount: 'A区-01-001', |
| | | inventory: '50', |
| | | notes: '用于质粒转化', |
| | | status: '1' |
| | | }, |
| | | { |
| | | strainNo: 'YX-2024002', |
| | | strainName: '枯草芽孢杆菌', |
| | | source: '菌种保藏中心', |
| | | method: '16S rDNA测序', |
| | | certificate: '革兰氏阳性芽孢杆菌,可水解淀粉,产生溶菌素', |
| | | storage: '冷冻保存', |
| | | amount: 'B区-02-005', |
| | | inventory: '30', |
| | | notes: '工业发酵菌种', |
| | | status: '1' |
| | | }, |
| | | { |
| | | strainNo: 'YX-2024003', |
| | | strainName: '酿酒酵母', |
| | | source: '发酵工厂', |
| | | method: '显微镜观察、生理特性', |
| | | certificate: '椭圆形单细胞真菌,可发酵葡萄糖产生乙醇', |
| | | storage: '甘油管保存', |
| | | amount: 'A区-03-002', |
| | | inventory: '40', |
| | | notes: '发酵工艺优化', |
| | | status: '2' |
| | | }, |
| | | { |
| | | strainNo: 'YX-2024004', |
| | | strainName: '乳酸菌', |
| | | source: '乳制品分离', |
| | | method: '生化鉴定、API条', |
| | | certificate: '革兰氏阳性球菌,产生乳酸,耐酸性强', |
| | | storage: '冷冻干燥', |
| | | amount: 'C区-01-003', |
| | | inventory: '25', |
| | | notes: '益生菌研究', |
| | | status: '3' |
| | | }, |
| | | { |
| | | strainNo: 'YX-2024005', |
| | | strainName: '青霉菌', |
| | | source: '环境样本', |
| | | method: '形态学特征、ITS测序', |
| | | certificate: '丝状真菌,产生蓝绿色分生孢子,可产青霉素', |
| | | storage: '斜面培养', |
| | | amount: 'B区-04-001', |
| | | inventory: '35', |
| | | notes: '次级代谢产物研究', |
| | | status: '1' |
| | | } |
| | | ] |
| | | } |
| | | handleDetail2(row) { |
| | | this.detailDialogValue = row; |
| | | this.detailDialogVisible = true; |
| | | }, |
| | | methods: { |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }; |
| | | this.searchData(); |
| | | }, |
| | | searchData() { |
| | | // 模拟搜索逻辑 |
| | | const { strainNo, strainName, status } = this.form; |
| | | let filteredData = [...this.tableData]; |
| | | |
| | | if (strainNo) { |
| | | filteredData = filteredData.filter((item) => |
| | | item.strainNo.toLowerCase().includes(strainNo.toLowerCase()) |
| | | ); |
| | | } |
| | | if (strainName) { |
| | | filteredData = filteredData.filter((item) => |
| | | item.strainName.toLowerCase().includes(strainName.toLowerCase()) |
| | | ); |
| | | } |
| | | if (status) { |
| | | filteredData = filteredData.filter((item) => item.status === status); |
| | | } |
| | | |
| | | this.total = filteredData.length; |
| | | // 实际项目中这里应该调用API |
| | | console.log("搜索条件:", this.form); |
| | | console.log("分页信息:", this.queryForm); |
| | | }, |
| | | handleNewStrain() { |
| | | this.$router.push("/strain/validation/add-primitive-cell"); |
| | | // Implement new strain logic |
| | | }, |
| | | handleBatchAdd() { |
| | | // Implement batch add logic |
| | | }, |
| | | handleEdit(row) { |
| | | // Implement edit logic |
| | | }, |
| | | handleRecord(row) { |
| | | this.$router.push({ |
| | | path: "/strain-library/strain-library-manage/record", |
| | | query: { |
| | | id: row.strainNo, |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | } |
| | | this.searchData() |
| | | }, |
| | | searchData() { |
| | | // 模拟搜索逻辑 |
| | | const { strainNo, strainName, status } = this.form |
| | | let filteredData = [...this.tableData] |
| | | |
| | | if (strainNo) { |
| | | filteredData = filteredData.filter(item => |
| | | item.strainNo.toLowerCase().includes(strainNo.toLowerCase()) |
| | | ) |
| | | } |
| | | if (strainName) { |
| | | filteredData = filteredData.filter(item => |
| | | item.strainName.toLowerCase().includes(strainName.toLowerCase()) |
| | | ) |
| | | } |
| | | if (status) { |
| | | filteredData = filteredData.filter(item => |
| | | item.status === status |
| | | ) |
| | | } |
| | | |
| | | this.total = filteredData.length |
| | | // 实际项目中这里应该调用API |
| | | console.log('搜索条件:', this.form) |
| | | console.log('分页信息:', this.queryForm) |
| | | }, |
| | | handleNewStrain() { |
| | | this.$router.push('/strain/validation/add-primitive-cell') |
| | | // Implement new strain logic |
| | | }, |
| | | handleBatchAdd() { |
| | | // Implement batch add logic |
| | | }, |
| | | handleDetail(row) { |
| | | this.currentDetail = row; |
| | | this.detailVisible = true; |
| | | }, |
| | | handleEdit(row) { |
| | | // Implement edit logic |
| | | }, |
| | | handleRecord(row) { |
| | | this.$router.push({ |
| | | path: '/strain-library/strain-library-manage/record', |
| | | query: { |
| | | id: row.strainNo |
| | | } |
| | | }) |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | // Implement page change logic |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | // Implement size change logic |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | // Implement type change logic |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: 'success', |
| | | 2: 'info', |
| | | 3: 'warning' |
| | | } |
| | | return types[status] || 'info' |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: '已入库', |
| | | 2: '已出库', |
| | | 3: '入库待确认' |
| | | } |
| | | return texts[status] || '未知状态' |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page; |
| | | // Implement page change logic |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size; |
| | | // Implement size change logic |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | // Implement type change logic |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: "success", |
| | | 2: "info", |
| | | 3: "warning", |
| | | }; |
| | | return types[status] || "info"; |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: "已入库", |
| | | 2: "已出库", |
| | | 3: "入库待确认", |
| | | }; |
| | | return texts[status] || "未知状态"; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | padding: 20px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049C9A; |
| | | } |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049c9a; |
| | | } |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .search-form { |
| | | margin-bottom: 20px; |
| | | background: #F5F7FA; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | margin-bottom: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .tab-container { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #DCDFE6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #F5F7FA; |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #dcdfe6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #f5f7fa; |
| | | |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049C9A; |
| | | color: #049C9A; |
| | | font-weight: bold; |
| | | } |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049c9a; |
| | | color: #049c9a; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .flex { |
| | | display: flex; |
| | | align-items: center; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | } |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | |
| | | } |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .view-all-dialog { |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <el-dialog |
| | | :visible.sync="visible" |
| | | title="原始细胞库资料详情" |
| | | width="650px" |
| | | @close="handleClose" |
| | | > |
| | | <el-form label-width="120px" label-position="top" class="detail-form"> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="菌种源"> |
| | | <el-input v-model="detail.source" disabled placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="菌种编号"> |
| | | <el-input v-model="detail.strainNo" disabled placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="菌种名称"> |
| | | <el-input v-model="detail.strainName" disabled placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="验证实验编号"> |
| | | <el-input v-model="detail.verifyNo" disabled placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="实验时间"> |
| | | <el-input v-model="detail.experimentTime" disabled placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | </el-row> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="菌种实验员签字"> |
| | | <div class="signature-area"> |
| | | <img v-if="detail.signature" :src="detail.signature" alt="签字" /> |
| | | <span v-else class="waiting-text">暂无签名</span> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="签字时间"> |
| | | <el-input v-model="detail.signTime" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'PrimitiveCellDetailDialog', |
| | | props: { |
| | | visible: Boolean, |
| | | detail: { |
| | | type: Object, |
| | | default: () => ({ |
| | | source: '', |
| | | strainNo: '', |
| | | strainName: '', |
| | | verifyNo: '', |
| | | experimentTime: '', |
| | | signature: '', |
| | | signTime: '' |
| | | }) |
| | | } |
| | | }, |
| | | methods: { |
| | | handleClose() { |
| | | this.$emit('update:visible', false) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .detail-form { |
| | | margin-top: 10px; |
| | | } |
| | | .signature-area { |
| | | min-height: 120px; |
| | | min-width: 240px; |
| | | background: #f5f7fa; |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .signature-area img { |
| | | max-width: 100%; |
| | | max-height: 100%; |
| | | display: block; |
| | | } |
| | | .waiting-text { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | </style> |