| | |
| | | <template> |
| | | <Card class="confirm-detail-page"> |
| | | <el-card class="top-card"> |
| | | <!-- 顶部信息卡片 - 优化排版 --> |
| | | <el-card class="top-card" shadow="never"> |
| | | <el-row :gutter="24" class="top-info-row"> |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"><span class="label">菌种来源:</span>{{ detail.strainSource }}</div> |
| | | <div class="info-item"><span class="label">鉴别菌株编号:</span>{{ detail.identifyingStrainCode }}</div> |
| | | <div class="info-item"><span class="label">鉴别菌株名称:</span>{{ detail.identifyingStrainName }}</div> |
| | | <el-col :span="24" class="info-col source-col"> |
| | | <div class="info-item source-item"> |
| | | <span class="label">菌种来源:</span> |
| | | <el-tooltip |
| | | :content="detail.strainSource || '暂无数据'" |
| | | placement="top" |
| | | :disabled="!detail.strainSource || detail.strainSource.length < 30" |
| | | popper-class="source-tooltip" |
| | | effect="dark" |
| | | > |
| | | <span class="source-text">{{ detail.strainSource || '暂无数据' }}</span> |
| | | </el-tooltip> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"><span class="label">验证实验编号:</span>{{ detail.validationExperimentCode }}</div> |
| | | <div class="info-item"><span class="label">实验时间:</span>{{ detail.experimentTime | formatDate }}</div> |
| | | <div class="info-item"></div> |
| | | <div class="info-item"> |
| | | <span class="label">鉴别菌株编号:</span> |
| | | <span class="value">{{ detail.identifyingStrainCode || '-' }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">鉴别菌株名称:</span> |
| | | <span class="value">{{ detail.identifyingStrainName || '-' }}</span> |
| | | </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"> |
| | | |
| | | <el-col :span="8" class="info-col"> |
| | | <div class="info-item"> |
| | | <span class="label">验证实验编号:</span> |
| | | <span class="value">{{ detail.validationExperimentCode || '-' }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">实验时间:</span> |
| | | <span class="value">{{ detail.experimentTime | formatDate }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">签字时间:</span> |
| | | <span class="value">{{ detail.handleTime || '-' }}</span> |
| | | </div> |
| | | </el-col> |
| | | |
| | | <el-col :span="8" class="info-col sign-col"> |
| | | <div class="sign-wrapper"> |
| | | <div class="sign-label-text">菌种实验员签字</div> |
| | | <div class="signature-area"> |
| | | <el-image style="width: 120px;" v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)" :preview-src-list="[getFullUrl(detail.handleSignature)]" alt="签字" /> |
| | | <el-image |
| | | v-if="detail.handleSignature" |
| | | :src="getFullUrl(detail.handleSignature)" |
| | | :preview-src-list="[getFullUrl(detail.handleSignature)]" |
| | | alt="签字" |
| | | fit="contain" |
| | | /> |
| | | <span v-else class="waiting-text">暂无签名</span> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | <div class="section-card" style="margin-top: 24px;"> |
| | | |
| | | <!-- 实验结论 & 用途 --> |
| | | <div class="section-card"> |
| | | <el-form ref="form" label-width="100px" :model="detail" :rules="rules" label-position="top"> |
| | | <el-form-item label="实验结论" prop="result"> |
| | | <el-input type="textarea" v-model="detail.result" :rows="3" placeholder="请输入" /> |
| | | </el-form-item> |
| | | <el-form-item label="批准菌株用途" prop="purpose"> |
| | | <el-checkbox-group v-model="detail.purpose"> |
| | | <el-checkbox :label="1">传代</el-checkbox> |
| | | <el-checkbox :label="2">菌种保藏</el-checkbox> |
| | | <el-checkbox :label="3">废弃</el-checkbox> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="14"> |
| | | <el-form-item label="实验结论" prop="result"> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="detail.result" |
| | | :rows="3" |
| | | placeholder="请输入实验结论" |
| | | maxlength="500" |
| | | show-word-limit |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | <el-form-item label="批准菌株用途" prop="purpose"> |
| | | <el-checkbox-group v-model="detail.purpose"> |
| | | <el-checkbox :label="1">传代</el-checkbox> |
| | | <el-checkbox :label="2">菌种保藏</el-checkbox> |
| | | <el-checkbox :label="3">废弃</el-checkbox> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </div> |
| | | <el-button type="primary" @click="handleAdd" 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="conditions" label="菌种培养工艺条件" /> |
| | | <el-table-column prop="record" label="菌种培养工艺实况记录" /> |
| | | <el-table-column prop="workmanship" label="菌种培养标准工艺" /> |
| | | <el-table-column label="操作" width="120"> |
| | | <!-- 表格区域 --> |
| | | <div class="table-section"> |
| | | <div class="table-header"> |
| | | <span class="table-title">菌种培养工艺</span> |
| | | <el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增</el-button> |
| | | </div> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | style="width: 100%" |
| | | :row-class-name="getRowClassName" |
| | | stripe |
| | | > |
| | | <el-table-column prop="conditions" label="菌种培养工艺条件" min-width="180" /> |
| | | <el-table-column prop="record" label="菌种培养工艺实况记录" min-width="200" /> |
| | | <el-table-column prop="workmanship" label="菌种培养标准工艺" min-width="200" /> |
| | | <el-table-column label="操作" width="160" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleEdits(row)">详情</el-button> |
| | | <el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" size="small" @click="handleDetail(row)">详情</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> |
| | | <el-button type="primary" size="medium" @click="handleSave">保存</el-button> |
| | | <el-button size="medium" @click="handleDraft">存稿</el-button> |
| | | </div> |
| | | <!-- <DetailConditionDialog |
| | | :visible.sync="detailDialogVisible" |
| | | :value="detailDialogValue" |
| | | /> --> |
| | | |
| | | <!-- 弹窗 --> |
| | | <EditConditionDialog |
| | | :visible.sync="dialogVisible" |
| | | :isEdit="dialogIsEdit" |
| | | :isFixed="dialogIsFixed" |
| | | :value="dialogValue" |
| | | @ok="handleDialogOk" |
| | | /> |
| | | <DetailConditionDialog |
| | | :visible.sync="detailDialogVisible" |
| | | :value="detailDialogValue" |
| | | /> |
| | | </Card> |
| | | </template> |
| | | |
| | | <script> |
| | | import EditConditionDialog from './EditConditionDialog.vue' |
| | | import DetailConditionDialog from './DetailConditionDialog.vue' |
| | | import { detail,confirm } from './service' |
| | | import {detail, confirm, saveDraft} from './service' |
| | | import moment from 'moment' |
| | | import {getFullUrl} from '@/utils/utils' |
| | | import { getFullUrl } from '@/utils/utils' |
| | | |
| | | export default { |
| | | name: 'ConfirmDetail', |
| | | components: { EditConditionDialog, DetailConditionDialog }, |
| | |
| | | identifyingStrainName: '', |
| | | validationExperimentCode: '', |
| | | experimentTime: '', |
| | | handleSignature: '', // 签名图片url |
| | | result:'', |
| | | handleSignature: '', |
| | | result: '', |
| | | purpose: [] |
| | | }, |
| | | activeTab: 'conditions', |
| | | rules: { |
| | | result: [ |
| | | { required: true, message: '请输入实验结论', trigger: 'blur' } |
| | |
| | | { conditions: '发酵时间', record: '', workmanship: '' }, |
| | | { conditions: '检测数据及结果', record: '', workmanship: '' } |
| | | ], |
| | | tableData: [ |
| | | { conditions: '平板培养基', record: '', workmanship: '' }, |
| | | { conditions: '培养温度', record: '', workmanship: '' }, |
| | | { conditions: '培养时间', record: '', workmanship: '' }, |
| | | { conditions: '摇瓶培养基', record: '', workmanship: '' }, |
| | | { conditions: '接种量', record: '', workmanship: '' }, |
| | | { conditions: '培养时间', record: '', workmanship: '' }, |
| | | { conditions: '发酵时间', record: '', workmanship: '' }, |
| | | { conditions: '检测数据及结果', record: '', workmanship: '' } |
| | | ], |
| | | tableData: [], |
| | | dialogVisible: false, |
| | | dialogIsEdit: false, |
| | | dialogIsFixed: false, |
| | | dialogValue: {}, |
| | | dialogIndex: null, |
| | | detailDialogVisible: false, |
| | | detailDialogValue: {} |
| | | detailDialogValue: {}, |
| | | |
| | | cacheForm: null, |
| | | cacheFormtableData: null, |
| | | isFirstLoad: true, |
| | | isLoading: false, |
| | | } |
| | | }, |
| | | filters: { |
| | |
| | | return '' |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.getDetail() |
| | | // ========== 只使用 activated ========== |
| | | activated() { |
| | | console.log('activated, isFirstLoad:', this.isFirstLoad) |
| | | |
| | | // 1. 首次加载 - 初始化数据并请求 |
| | | if (this.isFirstLoad) { |
| | | this.isFirstLoad = false |
| | | // 初始化表格数据(显示默认行) |
| | | this.tableData = this.initialTableData.map(item => ({ ...item })) |
| | | |
| | | if (this.$route.query.id) { |
| | | this.getDetail() |
| | | } |
| | | return |
| | | } |
| | | |
| | | // 2. 从缓存恢复数据(非首次加载) |
| | | if (this.cacheForm) { |
| | | this.detail = JSON.parse(JSON.stringify(this.cacheForm)) |
| | | this.tableData = JSON.parse(JSON.stringify(this.cacheFormtableData)) |
| | | this.restorePurpose() |
| | | } |
| | | |
| | | // 3. 如果路由参数变化,重新加载数据 |
| | | if (this.$route.query.id && this.detail.id && this.$route.query.id !== String(this.detail.id)) { |
| | | this.getDetail() |
| | | } |
| | | }, |
| | | deactivated() { |
| | | // 缓存当前数据 |
| | | this.cacheForm = JSON.parse(JSON.stringify(this.detail)) |
| | | this.cacheFormtableData = JSON.parse(JSON.stringify(this.tableData)) |
| | | console.log('deactivated - 数据已缓存') |
| | | }, |
| | | // ========== 移除 mounted,或保留仅用于调试 ========== |
| | | mounted() { |
| | | // 不做任何初始化,所有逻辑都在 activated 中 |
| | | console.log('mounted - 仅用于调试,无初始化逻辑') |
| | | }, |
| | | // ========== 方法 ========== |
| | | methods: { |
| | | getFullUrl(url) { |
| | | if (url) { |
| | |
| | | } |
| | | return '' |
| | | }, |
| | | getDetail() { |
| | | detail({id: this.$route.query.id}).then(res => { |
| | | this.detail = { |
| | | ...res, |
| | | handleSignature: res.handleSignature || '', // 处理签名为空的情况 |
| | | purpose: res.purpose || [] // 处理 purpose 为空的情况 |
| | | } |
| | | }) |
| | | |
| | | restorePurpose() { |
| | | if (!this.detail.purpose) { |
| | | this.detail.purpose = [] |
| | | return |
| | | } |
| | | |
| | | let purposeArray = [] |
| | | if (typeof this.detail.purpose === 'string') { |
| | | purposeArray = this.detail.purpose.split(',').map(item => Number(item.trim())).filter(num => !isNaN(num)) |
| | | } else if (Array.isArray(this.detail.purpose)) { |
| | | purposeArray = this.detail.purpose |
| | | } |
| | | this.detail.purpose = purposeArray |
| | | }, |
| | | |
| | | getDetail() { |
| | | if (this.isLoading) { |
| | | console.log('正在加载中,跳过重复请求') |
| | | return |
| | | } |
| | | |
| | | const id = this.$route.query.id |
| | | if (!id) { |
| | | console.warn('缺少 id 参数') |
| | | return |
| | | } |
| | | |
| | | this.isLoading = true |
| | | console.log('开始请求详情数据, id:', id) |
| | | |
| | | detail({ id }) |
| | | .then(res => { |
| | | console.log('详情数据返回:', res) |
| | | |
| | | const data = res.data || res |
| | | |
| | | // 处理 purpose |
| | | let purposeArray = [] |
| | | if (data.purpose) { |
| | | if (typeof data.purpose === 'string') { |
| | | purposeArray = data.purpose.split(',').map(item => Number(item.trim())).filter(num => !isNaN(num)) |
| | | } else if (Array.isArray(data.purpose)) { |
| | | purposeArray = data.purpose |
| | | } |
| | | } |
| | | |
| | | // 处理 tableData |
| | | const tableList = data.list && data.list.length > 0 ? data.list : this.initialTableData.map(item => ({ ...item })) |
| | | |
| | | // 更新数据 |
| | | this.detail = { |
| | | ...data, |
| | | handleSignature: data.handleSignature || '', |
| | | purpose: purposeArray |
| | | } |
| | | this.tableData = tableList |
| | | |
| | | // 更新缓存 |
| | | this.cacheForm = JSON.parse(JSON.stringify(this.detail)) |
| | | this.cacheFormtableData = JSON.parse(JSON.stringify(this.tableData)) |
| | | }) |
| | | .catch(err => { |
| | | console.error('获取详情失败:', err) |
| | | this.$message.error('加载数据失败,请重试') |
| | | |
| | | // 加载失败时使用初始数据 |
| | | this.tableData = this.initialTableData.map(item => ({ ...item })) |
| | | }) |
| | | .finally(() => { |
| | | this.isLoading = false |
| | | }) |
| | | }, |
| | | |
| | | handleAdd() { |
| | | this.dialogVisible = true |
| | | this.dialogIsEdit = false |
| | | this.dialogIsFixed = false |
| | | this.dialogValue = {} |
| | | this.dialogIndex = null |
| | | }, |
| | | |
| | | handleEdit(row) { |
| | | const idx = this.tableData.indexOf(row) |
| | | this.dialogVisible = true |
| | |
| | | this.dialogValue = { ...row } |
| | | this.dialogIndex = idx |
| | | }, |
| | | handleEdits(row) { |
| | | const idx = this.tableData.indexOf(row) |
| | | this.dialogVisible = true |
| | | this.dialogIsEdit = true |
| | | this.dialogIsFixed = idx < this.initialTableData?.length |
| | | this.dialogValue = { ...row,isDetail:true } |
| | | this.dialogIndex = idx |
| | | }, |
| | | |
| | | handleDetail(row) { |
| | | this.detailDialogVisible = true |
| | | this.detailDialogValue = { ...row } |
| | | }, |
| | | |
| | | handleSave() { |
| | | this.$refs.form.validate((valid) => { |
| | | if (valid) { |
| | | this.detail.list = this.tableData || [] |
| | | this.detail.purpose = this.detail.purpose.join(',') |
| | | confirm({...this.detail}).then(res => { |
| | | const payload = { |
| | | ...this.detail, |
| | | list: this.tableData || [], |
| | | purpose: (this.detail.purpose || []).join(','), |
| | | isDraft: 0 |
| | | } |
| | | confirm(payload).then(res => { |
| | | if (res.code == 200) { |
| | | this.$message.success('保存成功'); |
| | | this.$router.back() |
| | | this.$message.success('保存成功') |
| | | this.cacheForm = null |
| | | this.cacheFormtableData = null |
| | | this.$closeCurrentView('/strain/validation/primitive-cell') |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | this.$message.error(res.msg || '保存失败') |
| | | } |
| | | }) |
| | | } else { |
| | | this.$message.error('请填写必填项'); |
| | | return false; |
| | | this.$message.error('请填写必填项') |
| | | return false |
| | | } |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | handleDraft() { |
| | | // 存稿逻辑 |
| | | this.$refs.form.validate((valid) => { |
| | | if (valid) { |
| | | const payload = { |
| | | ...this.detail, |
| | | list: this.tableData || [], |
| | | purpose: (this.detail.purpose || []).join(',') |
| | | } |
| | | |
| | | saveDraft(payload).then(res => { |
| | | if (res.code == 200) { |
| | | this.$message.success('存稿成功') |
| | | this.cacheForm = null |
| | | this.cacheFormtableData = null |
| | | this.$closeCurrentView('/strain/validation/primitive-cell') |
| | | } else { |
| | | this.$message.error(res.msg || '存稿失败') |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | handleAdd() { |
| | | this.dialogVisible = true |
| | | this.dialogIsEdit = false |
| | | this.dialogIsFixed = false |
| | | this.dialogValue = {} |
| | | this.dialogIndex = null |
| | | }, |
| | | |
| | | handleDialogOk(val) { |
| | | if (this.dialogIsEdit && this.dialogIndex !== null) { |
| | | this.$set(this.tableData, this.dialogIndex, val) |
| | |
| | | this.tableData.push(val) |
| | | } |
| | | }, |
| | | |
| | | getRowClassName({ rowIndex }) { |
| | | return rowIndex < this.initialTableData?.length ? 'fixed-row' : ''; |
| | | return rowIndex < this.initialTableData?.length ? 'fixed-row' : '' |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .confirm-detail-page { |
| | | padding: 20px; |
| | | background: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | // ========== 顶部卡片 ========== |
| | | .top-card { |
| | | margin-bottom: 0; |
| | | background: rgba(239, 239, 239, 1); |
| | | border-radius: 16px; |
| | | margin-bottom: 20px; |
| | | background: #e3e3e3; |
| | | border-radius: 12px; |
| | | border: none; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); |
| | | |
| | | /deep/ .el-card__body { |
| | | padding: 20px 24px; |
| | | } |
| | | } |
| | | |
| | | .top-info-row { |
| | | display: flex; |
| | | align-items: stretch; |
| | | } |
| | | |
| | | .info-col { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | justify-content: center; |
| | | padding: 2px 0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | font-size: 15px; |
| | | line-height: 45px; |
| | | align-items: center; |
| | | font-size: 14px; |
| | | line-height: 38px; |
| | | padding: 1px 0; |
| | | |
| | | .label { |
| | | color: #8c8f9c; |
| | | font-weight: 500; |
| | | flex-shrink: 0; |
| | | min-width: 110px; |
| | | } |
| | | |
| | | .value { |
| | | color: #303133; |
| | | font-weight: 400; |
| | | } |
| | | } |
| | | |
| | | .label { |
| | | color: #666; |
| | | font-weight: 500; |
| | | flex-shrink: 0; |
| | | // ========== 菌种来源 ========== |
| | | .source-item { |
| | | width: 500px; |
| | | |
| | | .source-text { |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | color: #303133; |
| | | cursor: pointer; |
| | | padding: 0 4px; |
| | | font-weight: 400; |
| | | transition: color 0.2s; |
| | | |
| | | &:hover { |
| | | color: #409eff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ========== 签名区域 ========== |
| | | .sign-col { |
| | | align-items: center; |
| | | text-align: center; |
| | | } |
| | | |
| | | .sign-label { |
| | | justify-content: center; |
| | | } |
| | | |
| | | .signature-item { |
| | | justify-content: center; |
| | | .sign-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | gap: 6px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .sign-label-text { |
| | | font-size: 14px; |
| | | color: #8c8f9c; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .signature-area { |
| | | min-height: 80px; |
| | | min-width: 120px; |
| | | background: #f5f7fa; |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | width: 130px; |
| | | height: 66px; |
| | | background: #fafbfc; |
| | | border: 1.5px dashed #d9dce6; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-top: 8px; |
| | | } |
| | | overflow: hidden; |
| | | transition: border-color 0.2s; |
| | | |
| | | .signature-area img { |
| | | max-width: 100%; |
| | | max-height: 100%; |
| | | display: block; |
| | | &:hover { |
| | | border-color: #409eff; |
| | | } |
| | | |
| | | .el-image { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | |
| | | .waiting-text { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | color: #b0b3bf; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .sign-time { |
| | | justify-content: center; |
| | | text-align: center; |
| | | color: #666; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | // ========== 实验结论卡片 ========== |
| | | .section-card { |
| | | margin-bottom: 0; |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px 24px; |
| | | margin-bottom: 16px; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); |
| | | |
| | | /deep/ .el-form-item { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | /deep/ .el-form-item__label { |
| | | font-weight: 500; |
| | | color: #303133; |
| | | } |
| | | |
| | | /deep/ .el-checkbox-group { |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | /deep/ .el-checkbox { |
| | | margin-right: 24px; |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ========== 表格区域 ========== |
| | | .table-section { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 16px 20px 20px; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .table-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 14px; |
| | | |
| | | .table-title { |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | position: relative; |
| | | padding-left: 12px; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 3px; |
| | | height: 16px; |
| | | background: #409eff; |
| | | border-radius: 2px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /deep/ .el-table { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | |
| | | th.el-table__cell { |
| | | background-color: #f5f7fa; |
| | | color: #303133; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .fixed-row { |
| | | background-color: #f0f9ff !important; |
| | | } |
| | | } |
| | | |
| | | // ========== 底部按钮 ========== |
| | | .footer-btns { |
| | | display: flex; |
| | | justify-content: center; |
| | | padding: 24px; |
| | | padding-bottom: 0; |
| | | gap: 24px; |
| | | padding: 8px 0 4px; |
| | | gap: 20px; |
| | | |
| | | .el-button { |
| | | width: 150px; |
| | | width: 140px; |
| | | border-radius: 8px; |
| | | font-weight: 500; |
| | | letter-spacing: 1px; |
| | | } |
| | | } |
| | | |
| | | ::v-deep(.fixed-row) { |
| | | background-color: rgb(228, 248, 250) !important; |
| | | // ========== Tooltip ========== |
| | | /deep/ .source-tooltip { |
| | | max-width: 320px !important; |
| | | min-width: 120px !important; |
| | | word-break: break-word; |
| | | line-height: 1.7; |
| | | padding: 10px 16px; |
| | | font-size: 13px; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @media (max-width: 900px) { |
| | | .info-col { |
| | | height: auto; |
| | | // ========== 响应式 ========== |
| | | @media (max-width: 992px) { |
| | | .confirm-detail-page { |
| | | padding: 12px; |
| | | |
| | | .top-info-row { |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .info-col { |
| | | width: 100% !important; |
| | | flex: none !important; |
| | | } |
| | | |
| | | .sign-col { |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .sign-wrapper { |
| | | flex-direction: row; |
| | | gap: 16px; |
| | | align-items: center; |
| | | } |
| | | |
| | | .signature-area { |
| | | width: 100px; |
| | | height: 56px; |
| | | } |
| | | |
| | | .section-card /deep/ .el-col { |
| | | width: 100% !important; |
| | | flex: none !important; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | |
| | | @media (max-width: 576px) { |
| | | .confirm-detail-page { |
| | | padding: 8px; |
| | | |
| | | .top-card /deep/ .el-card__body { |
| | | padding: 14px 16px; |
| | | } |
| | | |
| | | .section-card { |
| | | padding: 14px 16px; |
| | | } |
| | | |
| | | .table-section { |
| | | padding: 12px 14px 16px; |
| | | } |
| | | |
| | | .footer-btns { |
| | | flex-direction: column; |
| | | align-items: center; |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | width: 100%; |
| | | max-width: 180px; |
| | | } |
| | | } |
| | | |
| | | .info-item { |
| | | font-size: 13px; |
| | | line-height: 34px; |
| | | |
| | | .label { |
| | | min-width: 90px; |
| | | font-size: 13px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |