| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | title="原始细胞库详情" |
| | | :visible.sync="visible" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | custom-class="strain-detail-dialog" |
| | | append-to-body |
| | | @close="$emit('update:visible', false)" |
| | | title="原始细胞库详情" |
| | | :visible.sync="visible" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | custom-class="strain-detail-dialog" |
| | | @close="$emit('update:visible', false)" |
| | | @opened="fetchDetail" |
| | | > |
| | | <div class="strain-info"> |
| | | <!-- 第一行信息 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ detail.strainNo }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">鉴定方法:</span> |
| | | <span class="value">{{ detail.method }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">保存位置:</span> |
| | | <span class="value">{{ detail.amount }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 第二行信息 --> |
| | | <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.certificate }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 第三行信息 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种来源:</span> |
| | | <span class="value">{{ detail.source }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">菌种保存方法:</span> |
| | | <span class="value">{{ detail.storage }}</span> |
| | | </div> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">出入库状态:</span> |
| | | <span class="value">{{ detail.operator }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="strain-info"> |
| | | <!-- 第一行信息 --> |
| | | <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> |
| | | |
| | | <div class="record-table"> |
| | | <div class="table-title">原始细胞库出/入库记录</div> |
| | | <el-table :data="detail.records" style="width: 100%"> |
| | | <el-table-column prop="type" label="出库/入库" /> |
| | | <el-table-column prop="operateTime" label="操作时间" /> |
| | | <el-table-column prop="operator" label="操作人姓名" /> |
| | | <el-table-column prop="reviewer" label="签核确认人姓名" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.status === '已确认' ? 'success' : 'warning'"> |
| | | {{ row.status }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleView(row)">详情</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pagination"> |
| | | <el-pagination |
| | | :current-page.sync="currentPage" |
| | | :page-size="10" |
| | | layout="total, prev, pager, next" |
| | | :total="total" |
| | | @current-change="handlePageChange" |
| | | /> |
| | | </div> |
| | | <!-- 第二行信息 --> |
| | | <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 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 class="info-item flex-column"> |
| | | <span class="label">出入库状态:</span> |
| | | <span class="value">{{ |
| | | { |
| | | 1: "已出库", |
| | | 2: "出库待确认", |
| | | 3: "已入库", |
| | | 4: "入库待确认", |
| | | }[detail.status] || "" |
| | | }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="record-table"> |
| | | <div class="table-title">原始细胞库出/入库记录</div> |
| | | <el-table :data="detail.records" style="width: 100%"> |
| | | <el-table-column label="出库/入库"> |
| | | <template #default="{ row }"> |
| | | {{ { 1: "出库", 2: "入库" }[row.type] || "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="boundTime" label="操作时间" /> |
| | | <el-table-column prop="handleName" label="操作人姓名" /> |
| | | <el-table-column prop="preserveName" label="签核确认人姓名" /> |
| | | <el-table-column label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.confirmTime ? 'success' : 'warning'"> |
| | | {{ row.confirmTime ? "已确认" : "待确认" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-button v-if="!row.confirmTime && roleType == 3" style="margin-right: 10px" type="text" @click="handleConfirm(row)">确认</el-button> |
| | | <el-button |
| | | type="text" |
| | | @click="handleView(row)" |
| | | >详情</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pagination"> |
| | | <el-pagination |
| | | :current-page.sync="currentPage" |
| | | :page-size="10" |
| | | layout="total, prev, pager, next" |
| | | :total="total" |
| | | @current-change="handlePageChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | <RecordDetailDialog |
| | | :visible="visibleRecordDetailDialog" |
| | | :recordData="recordData" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getDetailById,confirmWarehousing } from "../service"; |
| | | import RecordDetailDialog from "./RecordDetailDialog.vue"; |
| | | export default { |
| | | name: 'StrainDetail', |
| | | props: { |
| | | visible: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | detail: { |
| | | type: Object, |
| | | default: () => ({}) |
| | | } |
| | | components: { RecordDetailDialog }, |
| | | name: "StrainDetail", |
| | | props: { |
| | | visible: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | data() { |
| | | return { |
| | | currentPage: 1, |
| | | total: 0 |
| | | } |
| | | detail: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | methods: { |
| | | handleView(row) { |
| | | console.log('View record:', row) |
| | | }, |
| | | handlePageChange(page) { |
| | | this.currentPage = page |
| | | this.$emit('page-change', page) |
| | | }, |
| | | data() { |
| | | return { |
| | | visibleRecordDetailDialog: false, |
| | | recordData: {}, |
| | | currentPage: 1, |
| | | total: 0, |
| | | dialogType: "", |
| | | query: { |
| | | endTime: "", |
| | | id: "", |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | startTime: "", |
| | | roleType: "", |
| | | }, |
| | | }; |
| | | }, |
| | | |
| | | methods: { |
| | | handleDialogClose() { |
| | | this.recordData = {}; |
| | | this.visibleRecordDetailDialog = false; |
| | | }, |
| | | fetchDetail() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | this.query.id = this.detail.id; |
| | | getDetailById(this.query).then((res) => { |
| | | this.detail.records = res.warehousingList?.records || []; |
| | | this.total = res.warehousingList?.total || 0; |
| | | this.currentPage = res.warehousingList?.current || 1; |
| | | this.$forceUpdate(); |
| | | }); |
| | | }, |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.recordData = row; |
| | | this.visibleRecordDetailDialog = true; |
| | | |
| | | }, |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.recordData.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.visibleRecordDetailDialog = false; |
| | | // 刷新列表 |
| | | this.fetchDetail(); |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.recordData = row; |
| | | this.visibleRecordDetailDialog = true; |
| | | }, |
| | | handlePageChange(page) { |
| | | this.currentPage = page; |
| | | this.$emit("page-change", page); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .strain-detail-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; |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | } |
| | | } |
| | | |
| | | .strain-info { |
| | | background: #F5F7FA; |
| | | border-radius: 4px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | border-radius: 4px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 16px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 8px; |
| | | |
| | | &.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; |
| | | } |
| | | } |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 16px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 8px; |
| | | |
| | | &.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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-table { |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid #049C9A; |
| | | } |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid #049c9a; |
| | | } |
| | | |
| | | .pagination { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | .pagination { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |