This commit is contained in:
zlwu committed 2026-07-01 16:37:33 +08:00
1 parent 28f233c922
commit 038a60b09e
478 files changed
+67530 -51951

No files matched your search

@@ -0,0 +1,118 @@
<!-- 附件 ZIP 导出进度弹窗 -->
<!-- eslint-disable vue/no-v-model-argument -->
<template>
<el-dialog
v-model="dialogVisible"
title="正在导出附件"
width="480px"
append-to-body
modal-class="protocol-dialog-mask"
:close-on-click-modal="false"
:show-close="!running"
@close="handleDialogClose"
>
<div class="attachment-zip-progress">
<el-progress :percentage="displayPercent" :stroke-width="8" :status="progressStatus" />
<p class="attachment-zip-progress__phase">{{ phaseLabel }}</p>
<p v-if="progress.currentFile" class="attachment-zip-progress__file">
{{ progress.currentFile }}
</p>
<p v-if="progress.contextHint" class="attachment-zip-progress__hint">
{{ progress.contextHint }}
</p>
</div>
<template #footer>
<el-button v-if="running" class="btn-ghost" @click="emit('cancel')">
<el-icon><Close /></el-icon>取消
</el-button>
<el-button v-else class="btn-main" type="primary" @click="dialogVisible = false">
<el-icon><Check /></el-icon>关闭
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Close, Check } from '@element-plus/icons-vue'
import type { AttachmentZipExportProgress } from '@/utils/qc-work-order-attachment-export'
defineOptions({ name: 'AttachmentZipProgressDialog' })
const props = withDefaults(
defineProps<{
visible: boolean
progress: AttachmentZipExportProgress
running?: boolean
}>(),
{
running: false
}
)
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'cancel'): void
}>()
const dialogVisible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
})
const displayPercent = computed(() => Math.min(100, Math.max(0, props.progress.percent || 0)))
const progressStatus = computed(() => {
if (props.progress.phase === 'done') return 'success'
if (props.progress.phase === 'cancelled') return 'warning'
return undefined
})
const phaseLabel = computed(() => {
const { phase, currentIndex, totalFiles } = props.progress
if (phase === 'preparing') return '正在加载工单附件清单…'
if (phase === 'downloading') {
const total = totalFiles ? `(${currentIndex || 0}/${totalFiles})` : ''
return `正在下载附件${total}`
}
if (phase === 'zipping') return '正在生成压缩包…'
if (phase === 'done') return '导出完成'
if (phase === 'cancelled') return '已取消导出'
return '处理中…'
})
function handleDialogClose() {
if (props.running) {
emit('cancel')
}
}
</script>
<style scoped lang="scss">
.attachment-zip-progress {
display: flex;
flex-direction: column;
gap: 10px;
padding: 4px 0 8px;
}
.attachment-zip-progress__phase {
margin: 0;
font-size: 14px;
font-weight: 600;
color: var(--mint-text, #0f172a);
}
.attachment-zip-progress__file {
margin: 0;
font-size: 13px;
color: var(--mint-text-secondary, #334155);
word-break: break-all;
}
.attachment-zip-progress__hint {
margin: 0;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
}
</style>
@@ -10,7 +10,7 @@
:type="protocolStatusTagType(String(detail?.protocolStatus || ''))"
size="small"
>
{{ protocolStatusLabel(String(detail?.protocolStatus || '')) }}
{{ protocolStatusDisplayLabel(String(detail?.protocolStatus || ''), String(detail?.voidType || '')) }}
</el-tag>
</dd>
</div>
@@ -192,7 +192,7 @@
payModeLabel,
payStatusLabel as protocolPayStatusLabel,
payStatusTagType as protocolPayStatusTagType,
protocolStatusLabel,
protocolStatusLabel, protocolStatusDisplayLabel,
protocolStatusTagType
} from '@/utils/protocol-payment-labels'
import { formatMoneyDisplay } from '@/utils/money-format'
@@ -194,7 +194,11 @@
</el-table-column>
<el-table-column label="附件" min-width="320">
<template #default="{ row, $index }">
<div class="paper-att-cards">
<div
class="paper-att-cards paper-att-list"
:class="{ 'is-dragover': isPaperRowDragover($index) }"
v-bind="paperRowDropHandlers($index)"
>
<div
v-for="(att, attIdx) in row.attachments"
:key="attIdx"
@@ -405,6 +409,7 @@
VideoPlay
} from '@element-plus/icons-vue'
import { fetchUploadAttachment } from '@/api/business'
import { useIndexedAttachmentDropZone } from '@/composables/useAttachmentDropZone'
import { fetchCellProductList } from '@/api/cell-product'
import { fetchMaterialList, type MaterialOption } from '@/api/material'
import type { OutboundReleaseCellRow } from '@/api/outbound-release-review'
@@ -886,6 +891,15 @@
}
}
const { isDragover: isPaperRowDragover, handlersFor: paperRowDropHandlers } =
useIndexedAttachmentDropZone({
onFiles: (index, files) => {
for (const file of files) {
void handlePaperAttachmentChange(index, { raw: file })
}
}
})
defineExpose({
loading,
loadFromApiData,
@@ -724,21 +724,22 @@
.view-kv-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px 24px;
}
.view-kv {
margin: 0;
display: grid;
grid-template-columns: 92px 1fr;
gap: 8px 12px;
align-items: start;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
font-size: 13px;
}
.view-kv dt {
margin: 0;
font-size: 12px;
color: var(--mint-text-muted);
font-weight: 500;
}
@@ -5,7 +5,7 @@
v-model:visible="innerVisible"
title="生产任务详情"
width="960px"
:grid-columns="3"
:grid-columns="4"
:icon="Operation"
:meta="viewDetail?.taskNo || ''"
:sections="viewSections"
@@ -11,7 +11,11 @@
/>
</el-form-item>
<el-form-item :label="attachmentLabel" class="form-col-span-2">
<div class="attachment-upload">
<div
class="attachment-upload"
:class="{ 'is-dragover': isAttachDragover }"
v-bind="attachDropHandlers"
>
<div class="attachment-list">
<el-upload
:auto-upload="false"
@@ -70,7 +74,9 @@
</div>
</div>
</div>
<p class="upload-hint">支持图片、视频、文档等。</p>
<p class="upload-hint">
支持拖拽或点击上传图片、视频、PDF、Word、Excel等文件,单文件不超过 20MB
</p>
</div>
</el-form-item>
</div>
@@ -81,6 +87,7 @@
import { Plus, Document, Delete, Download, Loading, VideoPlay } from '@element-plus/icons-vue'
import { fetchUploadAttachment } from '@/api/business'
import { downloadAttachmentFile } from '@/utils/download-attachment'
import { useAttachmentDropZone } from '@/composables/useAttachmentDropZone'
import type { FinanceAttachmentItem } from './finance-attachments'
const props = withDefaults(
@@ -193,6 +200,15 @@
emit('update:attachments', remaining)
}
}
const { isDragover: isAttachDragover, dropZoneHandlers: attachDropHandlers } =
useAttachmentDropZone({
onFiles: (files) => {
for (const file of files) {
void handleAttachmentChange({ raw: file })
}
}
})
</script>
<style scoped lang="scss">
@@ -5,7 +5,7 @@
<dl class="view-kv-grid view-kv-grid--4">
<div class="view-kv">
<dt>协议状态</dt>
<dd>{{ protocolStatusLabel(String(detail?.protocolStatus || '')) }}</dd>
<dd>{{ protocolStatusDisplayLabel(String(detail?.protocolStatus || ''), String(detail?.voidType || '')) }}</dd>
</div>
<div class="view-kv">
<dt>缴费方式</dt>
@@ -112,6 +112,7 @@
payStatusLabel,
payStatusTagType,
protocolStatusLabel,
protocolStatusDisplayLabel,
loadTransferTypeDict,
transferTypeLabel
} from '@/utils/protocol-payment-labels'
@@ -5,7 +5,7 @@
v-model:visible="innerVisible"
title="质检任务详情"
width="960px"
:grid-columns="3"
:grid-columns="4"
:icon="Tickets"
:meta="viewDetail?.taskNo || ''"
:sections="viewSections"
@@ -14,6 +14,14 @@
compact
modal-class="qc-task-view-dialog-mask"
>
<template v-if="viewSampleSpecial.isSpecial" #prepend>
<SampleCodeWithSpecialDisplay
:sample-code="viewSampleCode"
:is-special="viewSampleSpecial.isSpecial"
:special-remark="viewSampleSpecial.specialRemark"
monospace
/>
</template>
<template #reception-extra>
<div class="view-reception-attachments">
<div class="view-kv view-kv-span-2">
@@ -94,6 +102,7 @@
import { Tickets } from '@element-plus/icons-vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
import SampleCodeWithSpecialDisplay from '@/components/business/sample-code-with-special-display/index.vue'
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { fetchQcTaskDetail, type QcTask, type QcTaskDetail } from '@/api/qc-task'
import {
@@ -114,7 +123,6 @@
workOrderStatusLabel,
qcTaskConclusionLabel
} from '@/utils/qc-labels'
import { formatMoneyDisplay } from '@/utils/money-format'
import { loadQcInspectionBatches, type QcInspectionBatch } from '@/utils/qc-inspection-batch'
import {
qcAttachmentFilesFromCommaUrls,
@@ -293,6 +301,23 @@
return qcAttachmentFilesFromCommaUrls(String(d.thirdPartyAttachments || ''))
})
const viewSampleSpecial = computed(() => {
const d = viewDetail.value
if (!d) return { isSpecial: false, specialRemark: '' }
const r = (d.reception || {}) as Record<string, unknown>
return {
isSpecial: !!(d.isSpecial || r.isSpecial),
specialRemark: String(d.specialRemark || r.specialRemark || '').trim()
}
})
const viewSampleCode = computed(() => {
const d = viewDetail.value
if (!d) return ''
const r = (d.reception || {}) as Record<string, unknown>
return String(r.sampleCode || d.sampleCode || '').trim()
})
function formatMetric(v: unknown) {
if (v === null || v === undefined || v === '') return '—'
return String(v)
@@ -410,13 +435,7 @@
{ label: '项目名称', value: d.itemName || '—' },
{ label: '项目编码', value: d.itemCode || '—' },
...(d.taskType === 'dsfjc'
? [
{ label: '第三方公司', value: d.companyName || '—' },
{
label: '检测费用(元)',
value: d.feeAmount != null ? `¥${formatMoneyDisplay(d.feeAmount)}` : '—'
}
]
? [{ label: '第三方公司', value: d.companyName || '—' }]
: [])
]
}
@@ -511,14 +530,15 @@
margin-top: 4px;
.view-kv {
display: grid;
grid-template-columns: 96px 1fr;
gap: 8px 12px;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
font-size: 13px;
align-items: start;
dt {
margin: 0;
font-size: 12px;
color: var(--mint-text-muted, #334155);
font-weight: 500;
}
@@ -0,0 +1,72 @@
<!-- 样本编码 + 特殊样本警示(列表场景:编码与说明均为红色加粗) -->
<template>
<span
class="sample-code-with-special"
:class="[
`sample-code-with-special--${layout}`,
{ 'sample-code-with-special--danger': isSpecial },
{ 'sample-code-with-special--mono': monospace }
]"
>
<span v-if="showCode" class="sample-code-with-special__code">{{ displayCode }}</span>
<SpecialSampleDisplay
v-if="isSpecial"
:is-special="isSpecial"
:special-remark="specialRemark"
:layout="layout"
/>
</span>
</template>
<script setup lang="ts">
import SpecialSampleDisplay from '@/components/business/special-sample-display/index.vue'
defineOptions({ name: 'SampleCodeWithSpecialDisplay' })
const props = withDefaults(
defineProps<{
sampleCode?: string
isSpecial?: boolean
specialRemark?: string
layout?: 'inline' | 'block'
fallback?: string
showCode?: boolean
monospace?: boolean
}>(),
{
sampleCode: '',
isSpecial: false,
specialRemark: '',
layout: 'inline',
fallback: '—',
showCode: true,
monospace: false
}
)
const displayCode = computed(() => {
const code = String(props.sampleCode || '').trim()
return code || props.fallback
})
</script>
<style scoped lang="scss">
.sample-code-with-special {
&.sample-code-with-special--inline {
display: inline;
}
&.sample-code-with-special--block {
display: block;
}
}
.sample-code-with-special--mono .sample-code-with-special__code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.sample-code-with-special--danger .sample-code-with-special__code {
color: var(--el-color-danger);
font-weight: 700;
}
</style>
@@ -6,7 +6,7 @@
>
<div v-if="showSectionLabel" class="sample-card__section-label">质检信息</div>
<div class="sample-qc-grouped-panel">
<section class="sample-qc-grouped-panel__block">
<section v-if="showGateSection" class="sample-qc-grouped-panel__block">
<h4 class="sample-qc-grouped-panel__subtitle">{{ gateSectionLabel }}</h4>
<SampleQcInfoCards
embedded
@@ -42,7 +42,11 @@
}}</span>
</div>
</div>
<SampleQcInfoCards embedded :qc-info="item" :hide-sample-context="hideSampleContext" />
<SampleQcInfoCards
embedded
:qc-info="item"
:hide-sample-context="hideSampleContext"
/>
</article>
</div>
</section>
@@ -66,12 +70,15 @@
hideSampleContext?: boolean
/** 协议/捐赠样本卡内展示外层「质检信息」标题 */
showSectionLabel?: boolean
/** 是否展示样本接收质检(入库门禁)区块 */
showGateSection?: boolean
gateSectionLabel?: string
processSectionLabel?: string
}>(),
{
processQcInfoList: () => [],
showSectionLabel: true,
showGateSection: true,
gateSectionLabel: '样本接收质检(入库门禁)',
processSectionLabel: '生产过程质检'
}
@@ -5,7 +5,7 @@
<h4 v-if="qcTitle" class="detail-section-title">{{ qcTitle }}</h4>
<div v-if="!qcReception" class="sample-reception-dual-readonly__empty">{{ qcEmptyHint }}</div>
<template v-else>
<div class="readonly-grid form-grid-2">
<div class="readonly-grid form-grid-4">
<div class="readonly-item">
<span class="label">接收时间</span>{{ formatDisplayOrDash(qcReception.receptionTime) }}
</div>
@@ -129,7 +129,7 @@
showProduction: true,
qcTitle: '质检接收信息',
productionTitle: '生产接收信息',
productionGridCols: 2,
productionGridCols: 4,
qcEmptyHint: '暂未接收',
productionEmptyHint: '生产尚未登记'
}
@@ -198,19 +198,30 @@
}
.readonly-item {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
font-size: 14px;
line-height: 1.5;
.label {
display: inline-block;
min-width: 72px;
margin-right: 0;
display: block;
min-width: 0;
margin: 0;
font-size: 12px;
font-weight: 500;
color: var(--mint-text-muted, #64748b);
&::after {
content: ': ';
content: none;
}
}
> .el-tag {
width: fit-content;
max-width: 100%;
}
}
.check-items-readonly {
@@ -0,0 +1,131 @@
<!-- 入库样本 · 特殊标记与特殊说明编辑 -->
<template>
<el-dialog
v-model="dialogVisible"
title="调整特殊样本"
width="560px"
class="dialog-form-layout"
align-center
append-to-body
modal-class="protocol-dialog-mask"
destroy-on-close
:close-on-click-modal="false"
@close="handleClose"
>
<el-form label-position="top" class="biz-dialog-form">
<div class="form-grid-2">
<el-form-item label="样本编码" class="form-col-span-2">
<span class="sample-special-mark-dialog__code">{{ sampleCode || '—' }}</span>
</el-form-item>
<el-form-item class="form-col-span-2">
<el-checkbox v-model="form.isSpecial">特殊样本</el-checkbox>
</el-form-item>
<el-form-item label="特殊说明" class="form-col-span-2">
<el-input
v-model="form.specialRemark"
type="textarea"
:rows="3"
maxlength="256"
show-word-limit
placeholder="如小三阳、HBV 携带等"
/>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="handleClose">
<el-icon><Close /></el-icon>取消
</el-button>
<el-button class="btn-main" type="primary" :loading="submitting" @click="handleSubmit">
<el-icon><Check /></el-icon>保存
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import { Check, Close } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { fetchUpdateInboundSampleSpecialMark } from '@/api/inbound-sample'
import type { InboundSampleSpecialMarkTarget } from '@/utils/inbound-sample-special-mark'
defineOptions({ name: 'SampleSpecialMarkDialog' })
const props = defineProps<{
visible: boolean
target: InboundSampleSpecialMarkTarget | null
}>()
const emit = defineEmits<{
'update:visible': [visible: boolean]
success: []
}>()
const dialogVisible = ref(false)
const submitting = ref(false)
const sampleCode = ref('')
const form = reactive({
isSpecial: false,
specialRemark: ''
})
watch(
() => props.visible,
(visible) => {
dialogVisible.value = visible
if (visible) syncFromTarget()
},
{ immediate: true }
)
watch(dialogVisible, (visible) => {
emit('update:visible', visible)
})
function syncFromTarget() {
const target = props.target
sampleCode.value = target?.sampleCode || ''
form.isSpecial = !!target?.isSpecial
form.specialRemark = target?.specialRemark || ''
}
function handleClose() {
dialogVisible.value = false
}
async function handleSubmit() {
const target = props.target
if (!target?.protocolSampleId) {
ElMessage.warning('缺少样本信息,无法保存')
return
}
if (form.isSpecial && !String(form.specialRemark || '').trim()) {
ElMessage.warning('特殊样本须填写特殊说明')
return
}
submitting.value = true
try {
await fetchUpdateInboundSampleSpecialMark({
receptionSource: target.receptionSource,
protocolSampleId: target.protocolSampleId,
isSpecial: form.isSpecial,
specialRemark: String(form.specialRemark || '').trim()
})
ElMessage.success('特殊样本已更新')
emit('success')
handleClose()
} finally {
submitting.value = false
}
}
</script>
<style scoped lang="scss">
.sample-special-mark-dialog__code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 14px;
font-weight: 600;
color: #1e293b;
}
</style>
@@ -35,8 +35,15 @@
<el-table-column label="样本类型" min-width="120" show-overflow-tooltip>
<template #default="{ row }">{{ sampleTypeName(row.sampleTypeId) }}</template>
</el-table-column>
<el-table-column label="样本编码" min-width="140" show-overflow-tooltip>
<template #default="{ row }">{{ row.sampleCode || '—' }}</template>
<el-table-column label="样本编码" min-width="180" show-overflow-tooltip>
<template #default="{ row }">
<SampleCodeWithSpecialDisplay
:sample-code="row.sampleCode"
:is-special="!!row.isSpecial"
:special-remark="row.specialRemark"
monospace
/>
</template>
</el-table-column>
<el-table-column
v-if="showPrice"
@@ -73,6 +80,12 @@
<span v-else>—</span>
</template>
</el-table-column>
<el-table-column label="特殊说明" min-width="140" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.isSpecial">{{ row.specialRemark || '—' }}</span>
<span v-else>—</span>
</template>
</el-table-column>
<el-table-column label="运输类型" min-width="100" show-overflow-tooltip>
<template #default="{ row }">
{{
@@ -220,6 +233,22 @@
<el-option label="已作废" value="yzf" />
</el-select>
</el-form-item>
<el-form-item class="form-col-span-2">
<el-checkbox v-model="sampleDraft.isSpecial" @change="onSpecialSampleToggle">
特殊样本
</el-checkbox>
</el-form-item>
<el-form-item label="特殊说明" class="form-col-span-2">
<el-input
v-model="sampleDraft.specialRemark"
type="textarea"
:rows="2"
:disabled="!sampleDraft.isSpecial"
maxlength="256"
show-word-limit
placeholder="如小三阳、HBV 携带等"
/>
</el-form-item>
</div>
</el-form>
<template #footer>
@@ -361,6 +390,7 @@
<script setup lang="ts">
import { Plus, Edit, Delete, Close, Check } from '@element-plus/icons-vue'
import AmountInput from '@/components/common/amount-input/index.vue'
import SampleCodeWithSpecialDisplay from '@/components/business/sample-code-with-special-display/index.vue'
import {
sampleStatusLabel,
sampleStatusTagType,
@@ -471,6 +501,8 @@
return {
...raw,
sampleStatus,
isSpecial: !!raw.isSpecial,
specialRemark: String(raw.specialRemark || '').trim(),
_rowKey: raw.id || raw._rowKey || `new-${++sampleRowSeq}`,
transport: {
...createEmptyTransport(),
@@ -708,6 +740,12 @@
ElMessage.success(`已为 ${selectedSamples.value.length} 个样本应用运输信息`)
}
function onSpecialSampleToggle(checked: boolean | string | number) {
if (!checked) {
sampleDraft.specialRemark = ''
}
}
async function openAddSampleDialog() {
sampleDialogMode.value = 'add'
sampleDialogIndex.value = -1
@@ -723,7 +761,9 @@
price: props.showPrice ? null : undefined,
originalPrice: props.showPrice ? null : undefined,
storageYears: null,
sampleStatus: 'ycj'
sampleStatus: 'ycj',
isSpecial: false,
specialRemark: ''
},
props.samples.length
)
@@ -778,6 +818,13 @@
ElMessage.warning('请选择样本编码')
return
}
if (sampleDraft.isSpecial && !String(sampleDraft.specialRemark || '').trim()) {
ElMessage.warning('特殊样本须填写特殊说明')
return
}
if (!sampleDraft.isSpecial) {
sampleDraft.specialRemark = ''
}
ensureSampleOriginalPrice(sampleDraft)
const next = [...props.samples]
const normalized = normalizeSampleRow(
@@ -0,0 +1,48 @@
<!-- 特殊样本警示展示(红色加粗) -->
<template>
<span v-if="isSpecial" class="special-sample-display" :class="`special-sample-display--${layout}`">
<span class="special-sample-mark">【特殊样本】</span>
<span v-if="displayRemark" class="special-sample-remark">{{ displayRemark }}</span>
</span>
</template>
<script setup lang="ts">
defineOptions({ name: 'SpecialSampleDisplay' })
const props = withDefaults(
defineProps<{
isSpecial?: boolean
specialRemark?: string
layout?: 'inline' | 'block'
}>(),
{
isSpecial: false,
specialRemark: '',
layout: 'inline'
}
)
const displayRemark = computed(() => String(props.specialRemark || '').trim())
</script>
<style scoped lang="scss">
.special-sample-display {
&.special-sample-display--inline {
display: inline;
}
&.special-sample-display--block {
display: block;
}
}
.special-sample-mark,
.special-sample-remark {
color: var(--el-color-danger);
font-weight: 700;
}
.special-sample-remark {
margin-left: 4px;
}
</style>
@@ -21,10 +21,17 @@
</div>
<div class="view-hero-main">
<h2>{{ title }}</h2>
<p v-if="heroMeta" class="view-hero-meta">{{ heroMeta }}</p>
<p v-if="heroMeta && !$slots['hero-meta']" class="view-hero-meta">{{ heroMeta }}</p>
<div v-if="$slots['hero-meta']" class="view-hero-meta">
<slot name="hero-meta" />
</div>
</div>
</div>
<div v-if="$slots.prepend" class="view-prepend">
<slot name="prepend" />
</div>
<!-- sections -->
<div
v-for="(section, si) in sections"
@@ -298,6 +305,12 @@
align-items: center;
}
.view-prepend {
padding: 12px 22px;
background: #fff5f5;
border-bottom: 1px solid #fecaca;
}
.view-hero-icon {
width: 72px;
height: 72px;
@@ -385,14 +398,16 @@
}
.view-kv {
display: grid;
grid-template-columns: 96px 1fr;
gap: 8px 12px;
min-width: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
font-size: 13px;
align-items: start;
dt {
margin: 0;
font-size: 12px;
color: var(--mint-text-muted, #334155);
font-weight: 500;
}
@@ -401,6 +416,11 @@
margin: 0;
color: #1e293b;
word-break: break-word;
> .el-tag {
width: fit-content;
max-width: 100%;
}
}
}
@@ -488,11 +508,6 @@
.view-kv-grid--cols-4 {
grid-template-columns: 1fr;
}
.view-kv {
grid-template-columns: 1fr;
gap: 4px;
}
}
.system-view-dialog--compact {
@@ -539,7 +554,10 @@
.view-kv {
font-size: 12px;
grid-template-columns: 84px 1fr;
dt {
font-size: 11px;
}
}
.view-field-label {