| | |
| | | <template> |
| | | <div class="production-cell-record"> |
| | | <!-- 页面头部 --> |
| | | <div class="page-header"> |
| | | <div class="header-left"> |
| | | <el-button icon="el-icon-arrow-left" @click="$router.go(-1)">返回</el-button> |
| | | <h2>生产细胞库菌种详情</h2> |
| | | </div> |
| | | <div class="header-actions"> |
| | | <el-button type="primary" plain icon="el-icon-edit" @click="handleEdit">编辑</el-button> |
| | | <el-button type="primary" plain icon="el-icon-printer" @click="handlePrint">打印</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="record-page"> |
| | | <!-- 基本信息展示区域 --> |
| | | <el-card class="header-box"> |
| | | <div class="header-content"> |
| | | <!-- 第一行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ detail.strainCode }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">鉴定方法:</span> |
| | | <span class="value">{{ detail.appraisalMethod }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">保藏位置:</span> |
| | | <span class="value">{{ detail.saveLocation }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 菌种信息卡片 --> |
| | | <el-card class="strain-card" v-loading="loading"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">菌种信息</span> |
| | | <div class="status-tag"> |
| | | <el-tag :type="getStatusType(strainData.status)">{{ strainData.status }}</el-tag> |
| | | <!-- 第二行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种名称:</span> |
| | | <span class="value">{{ detail.strainName }}</span> |
| | | </div> |
| | | <div class="info-item flex-column full-width"> |
| | | <span class="label">特性描述:</span> |
| | | <span class="value">{{ detail.features }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="strain-info"> |
| | | <div class="info-item"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ strainData.strainNo }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种名称:</span> |
| | | <span class="value">{{ strainData.strainName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种来源:</span> |
| | | <span class="value">{{ strainData.source }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">生产批次:</span> |
| | | <span class="value">{{ strainData.batchNo }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">保存方法:</span> |
| | | <span class="value">{{ strainData.preservationMethod }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">保存位置:</span> |
| | | <span class="value">{{ strainData.storageLocation }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">当前库存:</span> |
| | | <span class="value">{{ strainData.inventory }} 份</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">状态:</span> |
| | | <span class="value">{{ strainData.status }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">更新时间:</span> |
| | | <span class="value">{{ strainData.updateTime }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">制备日期:</span> |
| | | <span class="value">{{ strainData.preparationDate }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">有效期至:</span> |
| | | <span class="value">{{ strainData.expiryDate }}</span> |
| | | </div> |
| | | <div class="info-item full-width"> |
| | | <span class="label">特征描述:</span> |
| | | <div class="value description">{{ strainData.description }}</div> |
| | | </div> |
| | | |
| | | <div class="info-item full-width" v-if="strainData.certificateUrl"> |
| | | <span class="label">质量证书:</span> |
| | | <div class="value"> |
| | | <el-button type="text" @click="handleViewCertificate">查看证书</el-button> |
| | | <el-button type="text" @click="handleDownloadCertificate">下载证书</el-button> |
| | | |
| | | <!-- 第三行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种来源:</span> |
| | | <span class="value">{{ detail.strainSource }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">菌种保存方法:</span> |
| | | <span class="value">{{ detail.saveMethod }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 使用记录 --> |
| | | <el-card class="record-card" v-loading="loadingRecords"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">使用记录</span> |
| | | <el-button type="text" @click="handleAddUsage">新增使用记录</el-button> |
| | | </div> |
| | | |
| | | <el-table |
| | | :data="usageRecords" |
| | | style="width: 100%" |
| | | :empty-text="usageRecords.length ? '' : '暂无使用记录'" |
| | | > |
| | | <el-table-column prop="date" label="使用日期" width="120"></el-table-column> |
| | | <el-table-column prop="amount" label="使用数量" width="100"></el-table-column> |
| | | <el-table-column prop="operator" label="操作人" width="120"></el-table-column> |
| | | <el-table-column prop="project" label="项目名称"></el-table-column> |
| | | <el-table-column prop="batchNo" label="生产批次" width="150"></el-table-column> |
| | | <el-table-column prop="purpose" label="使用目的"></el-table-column> |
| | | <el-table-column label="操作" width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" size="small" @click="handleViewUsageDetail(scope.row)">查看</el-button> |
| | | <el-button type="text" size="small" @click="handleEditUsage(scope.row)">编辑</el-button> |
| | | <!-- 出入库记录表格 --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="recordList" |
| | | :total="total" |
| | | @currentChange="handlePageChange" |
| | | > |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'table' }" |
| | | @click="handleTypeChange('table')" |
| | | > |
| | | 原始细胞保藏出/入库登记表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'timeline' }" |
| | | @click="handleTypeChange('timeline')" |
| | | > |
| | | 原始细胞保藏出/入库时间轴 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button |
| | | v-if="roleType == 4" |
| | | @click="handleAddRecord" |
| | | class="el-icon-plus" |
| | | type="primary" |
| | | >新增出入库记录</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table v-if="currentType === 'table'"> |
| | | <el-table-column prop="type" label="出库/入库"> |
| | | <template #default="{ row }"> |
| | | <span> |
| | | {{ row.type === 1 ? "出库" : "入库" }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container" v-if="usageRecords.length"> |
| | | <el-pagination |
| | | background |
| | | layout="prev, pager, next" |
| | | :total="usageTotalCount" |
| | | :current-page.sync="usageCurrentPage" |
| | | :page-size="usagePageSize" |
| | | @current-change="handleUsagePageChange"> |
| | | </el-pagination> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 测试记录 --> |
| | | <el-card class="record-card" v-loading="loadingTests"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">测试记录</span> |
| | | <el-button type="text" @click="handleAddTest">新增测试记录</el-button> |
| | | </div> |
| | | |
| | | <el-table |
| | | :data="testRecords" |
| | | style="width: 100%" |
| | | :empty-text="testRecords.length ? '' : '暂无测试记录'" |
| | | > |
| | | <el-table-column prop="date" label="测试日期" width="120"></el-table-column> |
| | | <el-table-column prop="type" label="测试类型" width="150"></el-table-column> |
| | | <el-table-column prop="operator" label="操作人" width="120"></el-table-column> |
| | | <el-table-column prop="result" label="测试结果"> |
| | | <template slot-scope="scope"> |
| | | <el-tag :type="scope.row.result === '合格' ? 'success' : scope.row.result === '不合格' ? 'danger' : 'info'"> |
| | | {{ scope.row.result }} |
| | | <el-table-column prop="boundTime" label="操作时间" /> |
| | | <el-table-column prop="handleSignature" label="操作人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.handleSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.handleSignature" |
| | | :preview-src-list="[row.handleSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="preserveSignature" label="菌种保藏人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.preserveSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.preserveSignature" |
| | | :preview-src-list="[row.preserveSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.preserveSignature ? 'success' : 'warning'"> |
| | | {{ row.preserveSignature ? "已确认" : "待确认" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="备注"></el-table-column> |
| | | <el-table-column label="操作" width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" size="small" @click="handleViewTestDetail(scope.row)">查看</el-button> |
| | | <el-button type="text" size="small" @click="handleEditTest(scope.row)">编辑</el-button> |
| | | <el-table-column label="操作" width="180"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | v-if="!row.preserveSignature && roleType == 3" |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleConfirm(row)" |
| | | >确认</el-button |
| | | > |
| | | <el-button |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleView(row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container" v-if="testRecords.length"> |
| | | <el-pagination |
| | | background |
| | | layout="prev, pager, next" |
| | | :total="testTotalCount" |
| | | :current-page.sync="testCurrentPage" |
| | | :page-size="testPageSize" |
| | | @current-change="handleTestPageChange"> |
| | | </el-pagination> |
| | | </div> |
| | | </el-card> |
| | | </template> |
| | | <template #tableCustom v-if="currentType === 'timeline'"> |
| | | <record-timeline :list="timelineList" /> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <!-- 证书预览对话框 --> |
| | | <el-dialog |
| | | title="证书预览" |
| | | :visible.sync="certificateDialogVisible" |
| | | width="70%"> |
| | | <div v-if="strainData.certificateUrl" class="certificate-preview"> |
| | | <iframe v-if="strainData.certificateUrl.endsWith('.pdf')" :src="strainData.certificateUrl" width="100%" height="500"></iframe> |
| | | <img v-else :src="strainData.certificateUrl" style="max-width: 100%; max-height: 500px;" /> |
| | | </div> |
| | | </el-dialog> |
| | | <!-- 详情弹窗 --> |
| | | <record-detail-dialog |
| | | :visible.sync="dialogVisible" |
| | | :record-data="currentRecord" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | <!-- 新增出入库记录弹窗 --> |
| | | <add-record-dialog |
| | | :visible.sync="addDialogVisible" |
| | | @confirm="handleAddRecordConfirm" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import RecordDetailDialog from "../strain-library-manage/components/RecordDetailDialog.vue"; |
| | | import AddRecordDialog from "../strain-library-manage/components/AddRecordDialog.vue"; |
| | | import RecordTimeline from "../strain-library-manage/components/RecordTimeline.vue"; |
| | | import { |
| | | timeList, |
| | | getDetail, |
| | | addWarehousing, |
| | | getDetailById, |
| | | confirmWarehousing, |
| | | } from "./service"; |
| | | |
| | | export default { |
| | | name: 'ProductionCellLibraryRecord', |
| | | name: "StrainRecord", |
| | | components: { |
| | | RecordDetailDialog, |
| | | AddRecordDialog, |
| | | RecordTimeline, |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | loadingRecords: false, |
| | | loadingTests: false, |
| | | strainId: '', |
| | | strainData: { |
| | | id: '', |
| | | strainNo: '', |
| | | strainName: '', |
| | | source: '', |
| | | batchNo: '', |
| | | preservationMethod: '', |
| | | storageLocation: '', |
| | | inventory: 0, |
| | | status: '', |
| | | description: '', |
| | | preparationDate: '', |
| | | expiryDate: '', |
| | | updateTime: '', |
| | | certificateUrl: '' |
| | | currentType: "table", |
| | | detail: {}, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | certificateDialogVisible: false, |
| | | |
| | | // 使用记录分页数据 |
| | | usageRecords: [], |
| | | usageCurrentPage: 1, |
| | | usagePageSize: 10, |
| | | usageTotalCount: 0, |
| | | |
| | | // 测试记录分页数据 |
| | | testRecords: [], |
| | | testCurrentPage: 1, |
| | | testPageSize: 10, |
| | | testTotalCount: 0 |
| | | } |
| | | recordList: [], |
| | | timelineList: [], |
| | | dialogVisible: false, |
| | | currentRecord: {}, |
| | | addDialogVisible: false, |
| | | dialogType: "detail", |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | created() { |
| | | this.strainId = this.$route.params.id; |
| | | this.fetchStrainData(); |
| | | this.fetchUsageRecords(); |
| | | this.fetchTestRecords(); |
| | | activated() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | |
| | | // 获取路由参数中的菌种信息 |
| | | const strainId = this.$route.query.id; |
| | | this.queryForm.id = strainId; |
| | | if (strainId) { |
| | | this.getStrainDetail(strainId); |
| | | this.getRecordList(); |
| | | } |
| | | }, |
| | | methods: { |
| | | // 获取菌种详情 |
| | | fetchStrainData() { |
| | | this.loading = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.strainData = { |
| | | id: this.strainId, |
| | | strainNo: 'PCLS-2023-001', |
| | | strainName: '枯草芽孢杆菌生产株', |
| | | source: '主细胞库', |
| | | batchNo: 'P20230515-001', |
| | | preservationMethod: '冻干保存', |
| | | storageLocation: 'A区-A-102-冷藏柜', |
| | | inventory: 12, |
| | | status: '正常', |
| | | description: '本菌种为工业生产级别枯草芽孢杆菌生产株,由主细胞库转入,经过严格筛选和稳定性测试。该菌株具有高产蛋白酶能力,发酵条件适应性强,适合大规模工业化生产。产品稳定性好,批次间差异小,可用于洗涤用酶制剂、食品加工酶制剂等多种产品的生产。', |
| | | preparationDate: '2023-05-10', |
| | | expiryDate: '2024-05-10', |
| | | updateTime: '2023-05-15 14:30:22', |
| | | certificateUrl: '/api/strain-library/certificates/sample.pdf' |
| | | }; |
| | | |
| | | this.loading = false; |
| | | }, 500); |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteWarehousing({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.getRecordList(); |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 获取使用记录 |
| | | fetchUsageRecords() { |
| | | this.loadingRecords = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.usageRecords = [ |
| | | { |
| | | id: '1', |
| | | date: '2023-06-05', |
| | | amount: 2, |
| | | operator: '张工', |
| | | project: '酶制剂研发项目', |
| | | batchNo: 'E20230605-001', |
| | | purpose: '小试生产' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-07-12', |
| | | amount: 3, |
| | | operator: '李工', |
| | | project: '蛋白酶产品项目', |
| | | batchNo: 'E20230712-002', |
| | | purpose: '中试生产' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-08-18', |
| | | amount: 5, |
| | | operator: '王工', |
| | | project: '工业酶制剂生产', |
| | | batchNo: 'E20230818-003', |
| | | purpose: '规模化生产' |
| | | } |
| | | ]; |
| | | |
| | | this.usageTotalCount = 3; |
| | | this.loadingRecords = false; |
| | | }, 600); |
| | | getStrainDetail(id) { |
| | | // 这里应该调用接口获取菌种详情 |
| | | getDetail({ id }).then((res) => { |
| | | this.detail = res; |
| | | }); |
| | | }, |
| | | |
| | | // 获取测试记录 |
| | | fetchTestRecords() { |
| | | this.loadingTests = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.testRecords = [ |
| | | { |
| | | id: '1', |
| | | date: '2023-05-15', |
| | | type: '活力测定', |
| | | operator: '刘工', |
| | | result: '合格', |
| | | remark: '酶活性达标,符合生产要求' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-05-15', |
| | | type: '纯度检测', |
| | | operator: '张工', |
| | | result: '合格', |
| | | remark: '纯度>98%,无杂菌污染' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-05-16', |
| | | type: '稳定性测试', |
| | | operator: '李工', |
| | | result: '合格', |
| | | remark: '常温保存7天活力下降小于5%' |
| | | } |
| | | ]; |
| | | |
| | | this.testTotalCount = 3; |
| | | this.loadingTests = false; |
| | | }, 700); |
| | | getRecordList() { |
| | | // 这里应该调用接口获取出入库记录 |
| | | timeList(this.queryForm).then((res) => { |
| | | this.timelineList = res.data; |
| | | }); |
| | | getDetailById({ id: this.$route.query.id }).then((res) => { |
| | | this.recordList = res.warehousingList.records; |
| | | this.total = res.warehousingList.total; |
| | | }); |
| | | }, |
| | | |
| | | // 状态标签类型 |
| | | getStatusType(status) { |
| | | switch(status) { |
| | | case '正常': |
| | | return 'success'; |
| | | case '缺货': |
| | | return 'warning'; |
| | | case '异常': |
| | | return 'danger'; |
| | | case '已停用': |
| | | return 'info'; |
| | | default: |
| | | return 'info'; |
| | | } |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | |
| | | // 编辑菌种 |
| | | handleEdit() { |
| | | this.$router.push(`/strain-library/production-cell-library/edit/${this.strainId}`); |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | |
| | | // 打印菌种信息 |
| | | handlePrint() { |
| | | window.print(); |
| | | handlePageChange(page) { |
| | | this.queryForm.pageNum = page; |
| | | // 这里应该调用接口获取对应页码的数据 |
| | | }, |
| | | |
| | | // 查看证书 |
| | | handleViewCertificate() { |
| | | this.certificateDialogVisible = true; |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | }, |
| | | |
| | | // 下载证书 |
| | | handleDownloadCertificate() { |
| | | // 实际项目中应处理文件下载逻辑 |
| | | window.open(this.strainData.certificateUrl, '_blank'); |
| | | handleAddRecord() { |
| | | this.addDialogVisible = true; |
| | | }, |
| | | |
| | | // 新增使用记录 |
| | | handleAddUsage() { |
| | | this.$message.info('功能开发中:新增使用记录'); |
| | | // 实际项目中应跳转到新增使用记录页面或打开对话框 |
| | | handleDialogClose() { |
| | | this.currentRecord = {}; |
| | | this.dialogVisible = false; |
| | | }, |
| | | |
| | | // 查看使用记录详情 |
| | | handleViewUsageDetail(row) { |
| | | this.$message.info(`查看使用记录: ${row.id}`); |
| | | // 实际项目中应跳转到使用记录详情页面或打开对话框 |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.currentRecord.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | console.log(res); |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.dialogVisible = false; |
| | | // 刷新列表 |
| | | this.getRecordList(); |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 编辑使用记录 |
| | | handleEditUsage(row) { |
| | | this.$message.info(`编辑使用记录: ${row.id}`); |
| | | // 实际项目中应跳转到编辑使用记录页面或打开对话框 |
| | | handleAddRecordConfirm(record) { |
| | | addWarehousing({ ...record, trainLibraryId: this.$route.query.id }).then( |
| | | (res) => { |
| | | this.$message.success("操作成功"); |
| | | this.getRecordList(); |
| | | } |
| | | ); |
| | | }, |
| | | |
| | | // 使用记录分页切换 |
| | | handleUsagePageChange(page) { |
| | | this.usageCurrentPage = page; |
| | | this.fetchUsageRecords(); |
| | | goBack() { |
| | | this.$router.go(-1); |
| | | }, |
| | | |
| | | // 新增测试记录 |
| | | handleAddTest() { |
| | | this.$message.info('功能开发中:新增测试记录'); |
| | | // 实际项目中应跳转到新增测试记录页面或打开对话框 |
| | | }, |
| | | |
| | | // 查看测试记录详情 |
| | | handleViewTestDetail(row) { |
| | | this.$message.info(`查看测试记录: ${row.id}`); |
| | | // 实际项目中应跳转到测试记录详情页面或打开对话框 |
| | | }, |
| | | |
| | | // 编辑测试记录 |
| | | handleEditTest(row) { |
| | | this.$message.info(`编辑测试记录: ${row.id}`); |
| | | // 实际项目中应跳转到编辑测试记录页面或打开对话框 |
| | | }, |
| | | |
| | | // 测试记录分页切换 |
| | | handleTestPageChange(page) { |
| | | this.testCurrentPage = page; |
| | | this.fetchTestRecords(); |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .production-cell-record { |
| | | padding: 20px; |
| | | <style lang="less" scoped> |
| | | .record-page { |
| | | min-height: 100vh; |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | |
| | | .header-left { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | h2 { |
| | | margin: 0 0 0 12px; |
| | | font-size: 22px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .header-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | } |
| | | } |
| | | |
| | | .strain-card { |
| | | margin-bottom: 24px; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .strain-info { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | |
| | | .info-item { |
| | | width: 33.33%; |
| | | margin-bottom: 16px; |
| | | |
| | | &.full-width { |
| | | width: 100%; |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | height: 130px; |
| | | overflow: hidden; |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .label { |
| | | font-weight: 500; |
| | | color: #606266; |
| | | } |
| | | |
| | | .value { |
| | | color: #303133; |
| | | |
| | | &.description { |
| | | white-space: pre-line; |
| | | line-height: 1.6; |
| | | padding: 8px 0; |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 6px; |
| | | |
| | | &.left-column { |
| | | width: 33%; |
| | | min-width: 200px; |
| | | } |
| | | |
| | | &.flex-column { |
| | | flex: 1; |
| | | min-width: 150px; |
| | | } |
| | | |
| | | &.full-width { |
| | | flex: 1; |
| | | min-width: 300px; |
| | | } |
| | | |
| | | .label { |
| | | color: #606266; |
| | | margin-right: 8px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value { |
| | | flex: 1; |
| | | color: #303133; |
| | | word-break: break-all; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 1; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-card { |
| | | margin-bottom: 24px; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | } |
| | | |
| | | .certificate-preview { |
| | | |
| | | .flex { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | min-height: 500px; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | @media print { |
| | | .page-header, .header-actions, .record-card { |
| | | display: none; |
| | | |
| | | .tableTitle { |
| | | 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; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .strain-card { |
| | | border: none; |
| | | box-shadow: none; |
| | | |
| | | .card-header { |
| | | background-color: #fff !important; |
| | | border-bottom: 1px solid #ddd; |
| | | |
| | | .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: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .timeline-container { |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .timeline-card { |
| | | margin-bottom: 10px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | h4 { |
| | | margin: 0 0 10px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-btn { |
| | | margin-right: 12px; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |