fix: improve knowledge review scope controls

This commit is contained in:
key
2026-08-04 09:50:50 +08:00
parent ca205a9d13
commit 2807dd0746
+350 -20
View File
@@ -892,7 +892,7 @@
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="资料">{{ selectedQualityAsset.sourceName }}</el-descriptions-item>
<el-descriptions-item label="状态">{{ lifecycleLabel(selectedQualityAsset.lifecycleStatus) }}</el-descriptions-item>
<el-descriptions-item label="来源">{{ selectedQualityAsset.sourceAuthority }}</el-descriptions-item>
<el-descriptions-item label="来源">{{ sourceAuthorityLabel(selectedQualityAsset.sourceAuthority) }}</el-descriptions-item>
<el-descriptions-item label="版本">{{ selectedQualityAsset.sourceVersion }}</el-descriptions-item>
<el-descriptions-item label="语义分析">
{{ semanticStatusLabel(selectedQualityAsset.semanticAnalysisStatus) }}
@@ -907,7 +907,7 @@
v-if="reviewPackage"
:type="reviewPackage.riskLevel === 'LOW' ? 'success' : reviewPackage.riskLevel === 'MEDIUM' ? 'warning' : 'danger'"
>
{{ reviewPackage.riskLevel }} 风险
{{ riskLevelLabel(reviewPackage.riskLevel) }}风险
</el-tag>
</div>
<div v-if="reviewPackage" class="review-assistant-grid">
@@ -920,7 +920,9 @@
<el-table-column label="版本" width="86"
><template #default="{ row }">v{{ row.versionNo }}</template></el-table-column
>
<el-table-column prop="versionStatus" label="状态" width="130" />
<el-table-column label="状态" width="130">
<template #default="{ row }">{{ versionStatusLabel(row.versionStatus) }}</template>
</el-table-column>
<el-table-column label="指针" width="150">
<template #default="{ row }">
<el-tag v-if="row.published" size="small" type="success">生效版</el-tag>
@@ -995,9 +997,9 @@
<div v-loading="qualityDetailLoading" class="quality-issue-list">
<h3>检测结果</h3>
<div v-for="issue in qualityIssues" :key="issue.id" class="quality-issue">
<el-tag :type="issue.gateType === 'HARD' ? 'danger' : 'warning'" size="small">{{ issue.reasonCode }}</el-tag>
<span>{{ issueEvidence(issue.evidenceJson) }}</span>
<small>{{ issue.recommendedAction }}</small>
<el-tag :type="issue.gateType === 'HARD' ? 'danger' : 'warning'" size="small">{{ qualityReasonLabel(issue.reasonCode) }}</el-tag>
<span>{{ qualityIssueDescription(issue) }}</span>
<small>{{ qualityIssueAction(issue) }}</small>
</div>
<el-empty v-if="!qualityDetailLoading && !qualityIssues.length" :image-size="56" description="未发现质量问题" />
</div>
@@ -1089,13 +1091,70 @@
<el-input v-model="qualityReviewForm.sourceVersion" />
</el-form-item>
<el-form-item label="适用岗位">
<el-input v-model="qualityReviewForm.applicableRole" placeholder="例如:生活顾问" />
<div class="quality-scope-field">
<el-segmented
v-model="qualityScopeModes.applicableRole"
:options="scopeModeOptions"
size="small"
@change="changeQualityScope('applicableRole', $event)"
/>
<el-select
v-if="qualityScopeModes.applicableRole === 'SPECIFIED'"
v-model="qualityReviewForm.applicableRole"
filterable
allow-create
clearable
default-first-option
:loading="qualityScopeOptionsLoading"
placeholder="请选择岗位;无匹配项可输入后回车"
>
<el-option v-for="item in qualityScopeOptions.applicableRole" :key="item" :label="qualityScopeOptionLabel(item)" :value="item" />
</el-select>
</div>
</el-form-item>
<el-form-item label="适用区域">
<el-input v-model="qualityReviewForm.applicableRegion" placeholder="例如:南京" />
<div class="quality-scope-field">
<el-segmented
v-model="qualityScopeModes.applicableRegion"
:options="scopeModeOptions"
size="small"
@change="changeQualityScope('applicableRegion', $event)"
/>
<el-select
v-if="qualityScopeModes.applicableRegion === 'SPECIFIED'"
v-model="qualityReviewForm.applicableRegion"
filterable
allow-create
clearable
default-first-option
:loading="qualityScopeOptionsLoading"
placeholder="请选择区域;无匹配项可输入后回车"
>
<el-option v-for="item in qualityScopeOptions.applicableRegion" :key="item" :label="qualityScopeOptionLabel(item)" :value="item" />
</el-select>
</div>
</el-form-item>
<el-form-item label="适用项目">
<el-input v-model="qualityReviewForm.applicableProject" placeholder="例如:江北项目" />
<div class="quality-scope-field">
<el-segmented
v-model="qualityScopeModes.applicableProject"
:options="scopeModeOptions"
size="small"
@change="changeQualityScope('applicableProject', $event)"
/>
<el-select
v-if="qualityScopeModes.applicableProject === 'SPECIFIED'"
v-model="qualityReviewForm.applicableProject"
filterable
allow-create
clearable
default-first-option
:loading="qualityScopeOptionsLoading"
placeholder="请选择项目;无匹配项可输入后回车"
>
<el-option v-for="item in qualityScopeOptions.applicableProject" :key="item" :label="qualityScopeOptionLabel(item)" :value="item" />
</el-select>
</div>
</el-form-item>
<el-form-item label="生效日期">
<el-date-picker v-model="qualityReviewForm.effectiveFrom" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" />
@@ -1117,10 +1176,20 @@
<el-form-item label="审核意见">
<el-input v-model="qualityReviewForm.reason" type="textarea" :rows="3" maxlength="1000" show-word-limit />
</el-form-item>
<el-form-item v-if="openSoftQualityIssues.length" label="确认已人工核对以下软提示">
<el-form-item v-if="openSoftQualityIssues.length" label="人工核对确认(需逐项勾选)">
<el-alert
class="quality-acknowledgement-tip"
title="请先对照上方检测结果核查原文;勾选表示已确认该提示不影响本次发布,系统不会自动修改资料。"
type="warning"
:closable="false"
show-icon
/>
<el-checkbox-group v-model="qualityReviewForm.acceptedReasonCodes" class="reason-checks">
<el-checkbox v-for="issue in openSoftQualityIssues" :key="issue.id" :value="issue.reasonCode">
{{ issue.reasonCode }}
<span class="reason-check-content">
<strong>已核对:{{ qualityReasonLabel(issue.reasonCode) }}</strong>
<small>{{ qualityAcknowledgementText(issue.reasonCode) }}</small>
</span>
</el-checkbox>
</el-checkbox-group>
</el-form-item>
@@ -1232,6 +1301,7 @@
import { CircleCheck, Document, Files, Operation, Plus, Refresh, Search, Upload, WarningFilled } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { getOrgSnapshot, type OrgSnapshotResponse } from '@/api/aihr/mobile-admin';
import {
addGoldenSample,
approveKnowledgeGlossary,
@@ -1437,7 +1507,10 @@ const sampleReviewForm = ref({
result: 'CONFIRMED' as NonNullable<RuleReviewSample['reviewResult']>,
note: ''
});
const openSoftQualityIssues = computed(() => qualityIssues.value.filter((issue) => issue.status === 'OPEN' && issue.gateType === 'SOFT'));
const openSoftQualityIssues = computed(() => {
const openIssues = qualityIssues.value.filter((issue) => issue.status === 'OPEN' && issue.gateType === 'SOFT');
return Array.from(new Map(openIssues.map((issue) => [issue.reasonCode, issue])).values());
});
const hasVersionConflict = computed(() => qualityIssues.value.some((issue) => issue.reasonCode === 'VERSION_CONFLICT'));
const unresolvedQualityConflicts = computed(() =>
qualityConflicts.value.filter((conflict) => conflict.status === 'PENDING_REVIEW' || conflict.status === 'CONFIRMED')
@@ -1446,6 +1519,23 @@ const semanticAnalysisComplete = computed(() => ['COMPLETE', 'NOT_REQUIRED'].inc
const privacyDerivativeReady = computed(() => ['CLEAN', 'REDACTED'].includes(qualityPrivacyPreview.value?.privacyStatus || ''));
const selectedQualityAsset = ref<QualityAsset | null>(null);
const qualityDialogVisible = ref(false);
type QualityScopeField = 'applicableRole' | 'applicableRegion' | 'applicableProject';
type QualityScopeMode = 'ALL' | 'SPECIFIED';
const scopeModeOptions = [
{ label: '全部', value: 'ALL' },
{ label: '指定', value: 'SPECIFIED' }
];
const qualityScopeModes = ref<Record<QualityScopeField, QualityScopeMode>>({
applicableRole: 'ALL',
applicableRegion: 'ALL',
applicableProject: 'ALL'
});
const qualityScopeOptionsLoading = ref(false);
const qualityScopeOptions = ref<Record<QualityScopeField, string[]>>({
applicableRole: [],
applicableRegion: [],
applicableProject: []
});
const qualityReviewForm = ref<QualityReviewRequest>({
reason: '',
usageType: 'REFERENCE_ONLY',
@@ -1543,6 +1633,96 @@ const usageOptions = [
{ label: '仅供参考', value: 'REFERENCE_ONLY' }
];
const qualityReasonLabels: Record<string, string> = {
PARSE_EMPTY: '未解析到正文',
PARSE_FAILED: '内容解析异常',
PAGE_COUNT_MISMATCH: '页数不一致',
SOURCE_UNAVAILABLE: '来源文件不可用',
SOURCE_UNKNOWN: '来源权威不明确',
SOURCE_EVIDENCE_INSUFFICIENT: '来源依据不足',
SOURCE_VERSION_MISSING: '来源版本缺失',
PII_REDACTED: '已执行个人信息脱敏',
PII_DETECTED: '检测到未脱敏个人信息',
SECRET_DETECTED: '检测到疑似密钥',
CROSS_TENANT_REFERENCE: '检测到跨租户引用',
PROMPT_INJECTION_SUSPECTED: '检测到疑似提示词注入',
POLICY_EXPIRED: '资料已超过有效期',
SYNTHETIC_UNDECLARED: '合成内容未声明',
SYNTHETIC_UNVERIFIED: '合成内容待核验',
EXACT_DUPLICATE: '完全重复资料',
OCR_LOW_CONFIDENCE: '图片文字识别可信度低',
ASR_LOW_CONFIDENCE: '语音识别可信度低',
HEADER_FOOTER_NOISE: '页眉页脚噪声',
PAGINATION_NOISE: '页码噪声',
CHUNK_CONTEXT_BROKEN: '片段上下文不完整',
DOMAIN_IRRELEVANT: '业务相关性较低',
CONTEXT_INCOMPLETE: '案例要素不完整',
NEAR_DUPLICATE: '高度相似资料',
SEMANTIC_DUPLICATE: '语义重复资料',
SEMANTIC_ANALYSIS_DEGRADED: '语义分析已降级',
SEMANTIC_ANALYSIS_FAILED: '语义分析失败',
VERSION_CONFLICT: '资料版本冲突',
EXPERT_CONFLICT: '专家观点冲突',
DOWNSTREAM_ANSWER_DISPUTED: '引用回答存在争议',
HUMAN_REVIEW_REQUIRED: '需要人工审核'
};
const qualityReasonDescriptions: Record<string, string> = {
PARSE_EMPTY: '系统没有从文件中提取到可审核的正文。',
PARSE_FAILED: '解析结果存在异常字符或内容损坏。',
PAGE_COUNT_MISMATCH: '文件声明的页数与实际解析页数不一致。',
SOURCE_UNAVAILABLE: '原始文件当前无法读取或验证。',
SOURCE_UNKNOWN: '尚未确认资料的发布主体或权威级别。',
SOURCE_EVIDENCE_INSUFFICIENT: '资料明确缺少事实来源或支撑依据。',
SOURCE_VERSION_MISSING: '尚未填写可追溯的资料版本。',
PII_REDACTED: '系统已对识别到的个人信息进行脱敏处理。',
PII_DETECTED: '正文仍包含可能识别到个人的信息。',
SECRET_DETECTED: '正文包含疑似账号、口令或访问密钥。',
CROSS_TENANT_REFERENCE: '资料引用了其他租户的数据。',
PROMPT_INJECTION_SUSPECTED: '正文包含可能影响模型行为的指令性内容。',
POLICY_EXPIRED: '资料已不在标注的有效期内。',
SYNTHETIC_UNDECLARED: '系统发现合成内容,但资料没有如实声明。',
SYNTHETIC_UNVERIFIED: '合成内容尚未由业务人员核实。',
EXACT_DUPLICATE: '检测到内容完全相同的历史资料,不会自动合并。',
OCR_LOW_CONFIDENCE: '图片文字识别结果的可信度不足。',
ASR_LOW_CONFIDENCE: '语音转写结果的可信度不足。',
HEADER_FOOTER_NOISE: '多页重复出现短文本,可能是页眉或页脚。',
PAGINATION_NOISE: '正文中检测到独立的页码行。',
CHUNK_CONTEXT_BROKEN: '部分切片过短或依赖前后文,单独引用时可能失真。',
DOMAIN_IRRELEVANT: '没有检测到已配置的物业服务或企业学习领域内容。',
CONTEXT_INCOMPLETE: '案例的场景、事实、行动、依据或结果信息不完整。',
NEAR_DUPLICATE: '检测到内容高度相似的历史资料。',
SEMANTIC_DUPLICATE: '检测到表达不同但含义接近的历史资料。',
SEMANTIC_ANALYSIS_DEGRADED: '当前仅完成降级分析,重复判断能力有限。',
SEMANTIC_ANALYSIS_FAILED: '语义重复分析没有成功完成。',
VERSION_CONFLICT: '同名资料已有已发布版本,且本次内容发生变化。',
EXPERT_CONFLICT: '资料中的结论与已记录的专家结论存在冲突。',
DOWNSTREAM_ANSWER_DISPUTED: '使用该资料生成的回答曾被标记为有争议。',
HUMAN_REVIEW_REQUIRED: '上传、提取和生成的内容在人工批准前均不视为可信。'
};
const qualityAcknowledgements: Record<string, string> = {
PAGINATION_NOISE: '已确认页码不属于正文,不影响内容含义。',
HEADER_FOOTER_NOISE: '已确认重复页眉页脚不影响正文理解。',
HUMAN_REVIEW_REQUIRED: '已人工阅读资料,并确认内容可进入生产检索。',
EXACT_DUPLICATE: '已对照重复资料,确认保留当前版本且不自动合并。',
NEAR_DUPLICATE: '已对照相似资料,确认两份资料的保留方式。',
SEMANTIC_DUPLICATE: '已对照语义相近资料,确认不会造成错误召回。',
SOURCE_UNKNOWN: '已核实并补充正确的来源权威级别。',
SOURCE_EVIDENCE_INSUFFICIENT: '已核查缺失依据,并确认当前发布结论可追溯。',
SOURCE_VERSION_MISSING: '已补充并核对可追溯的来源版本。',
SYNTHETIC_UNVERIFIED: '已人工核实合成内容与正式业务事实一致。',
OCR_LOW_CONFIDENCE: '已对照原图复核识别文字。',
ASR_LOW_CONFIDENCE: '已回听原音频复核转写内容。',
CHUNK_CONTEXT_BROKEN: '已抽查相关片段,确认单独引用不会改变原意。',
DOMAIN_IRRELEVANT: '已确认资料属于本次知识库的业务范围。',
CONTEXT_INCOMPLETE: '已确认缺失要素不影响该资料的预期用途。',
SEMANTIC_ANALYSIS_DEGRADED: '已人工扩大重复资料核查范围并确认可发布。',
VERSION_CONFLICT: '已确认新旧版本关系和适用范围。',
EXPERT_CONFLICT: '已完成业务裁决并确认采用的权威结论。',
DOWNSTREAM_ANSWER_DISPUTED: '已复核争议回答及引用原文,确认本资料可继续使用。'
};
const seedOverview: ProcessingOverview = {
metrics: [
{ key: 'total', label: '资料总量', value: '3.2 GB', note: '已接入 1,286 个文件', type: 'danger' },
@@ -2623,15 +2803,23 @@ async function openQualityReview(asset: QualityAsset) {
acceptedReasonCodes: [],
supersedesAssetId: undefined
};
qualityScopeModes.value = {
applicableRole: asset.applicableRole?.trim() ? 'SPECIFIED' : 'ALL',
applicableRegion: asset.applicableRegion?.trim() ? 'SPECIFIED' : 'ALL',
applicableProject: asset.applicableProject?.trim() ? 'SPECIFIED' : 'ALL'
};
buildQualityScopeOptions(asset, [], undefined);
qualityScopeOptionsLoading.value = true;
try {
const [issues, privacyPreview, conflicts, published, versions, impact, review] = await Promise.all([
const [issues, privacyPreview, conflicts, published, versions, impact, review, orgSnapshot] = await Promise.all([
listQualityIssues(asset.id),
getQualityPrivacyPreview(asset.id),
listQualityConflicts(asset.id),
listQualityAssets('PUBLISHED', 200),
listAssetVersions(asset.id),
getDeletionImpact(asset.id),
asset.lifecycleStatus === 'REVIEW_PENDING' ? getAssetReviewPackage(asset.id) : Promise.resolve({ data: null })
asset.lifecycleStatus === 'REVIEW_PENDING' ? getAssetReviewPackage(asset.id) : Promise.resolve({ data: null }),
getOrgSnapshot({ status: 'active', pageNum: 1, pageSize: 500 }).catch(() => undefined)
]);
if (selectedQualityAsset.value?.id !== asset.id) return;
qualityIssues.value = issues.data || [];
@@ -2641,6 +2829,7 @@ async function openQualityReview(asset: QualityAsset) {
assetVersions.value = versions.data || [];
deletionImpact.value = impact.data || null;
reviewPackage.value = review.data || null;
buildQualityScopeOptions(asset, published.data || [], orgSnapshot?.data);
} catch {
if (selectedQualityAsset.value?.id !== asset.id) return;
qualityIssues.value = [];
@@ -2652,10 +2841,37 @@ async function openQualityReview(asset: QualityAsset) {
deletionImpact.value = null;
ElMessage.error('质量原因加载失败');
} finally {
if (selectedQualityAsset.value?.id === asset.id) qualityDetailLoading.value = false;
if (selectedQualityAsset.value?.id === asset.id) {
qualityScopeOptionsLoading.value = false;
qualityDetailLoading.value = false;
}
}
}
function changeQualityScope(field: QualityScopeField, mode: string | number | boolean | undefined) {
if (mode === 'ALL') qualityReviewForm.value[field] = '';
}
function buildQualityScopeOptions(asset: QualityAsset, history: QualityAsset[], snapshot?: OrgSnapshotResponse) {
const assets = [...qualityAssets.value, ...history, asset];
const distinct = (values: Array<string | undefined>) =>
Array.from(new Set(values.map((value) => value?.trim()).filter((value): value is string => Boolean(value)))).sort((left, right) =>
left.localeCompare(right, 'zh-CN')
);
qualityScopeOptions.value = {
applicableRole: distinct([...assets.map((item) => item.applicableRole), ...(snapshot?.rows.map((item) => item.positionName) || [])]),
applicableRegion: distinct(assets.map((item) => item.applicableRegion)),
applicableProject: distinct([
...assets.map((item) => item.applicableProject),
...(snapshot?.projects.map((item) => item.projectName || item.projectCode) || [])
])
};
}
function qualityScopeOptionLabel(value: string) {
return ({ employee: '员工' } as Record<string, string>)[value.toLowerCase()] || value;
}
async function reviewConflict(conflict: QualityConflict, decision: 'CONFIRMED' | 'FALSE_POSITIVE' | 'RESOLVED') {
const labels = {
CONFIRMED: '说明为何判定为真实冲突',
@@ -2688,6 +2904,13 @@ async function publishAsset() {
ElMessage.warning('请填写来源权威级别、来源版本和审核意见');
return;
}
const missingScope = (Object.keys(qualityScopeModes.value) as QualityScopeField[]).find(
(field) => qualityScopeModes.value[field] === 'SPECIFIED' && !form[field]?.trim()
);
if (missingScope) {
ElMessage.warning(`请选择${{ applicableRole: '适用岗位', applicableRegion: '适用区域', applicableProject: '适用项目' }[missingScope]}`);
return;
}
const openReasons = openSoftQualityIssues.value.map((item) => item.reasonCode);
if (openReasons.some((reason) => !form.acceptedReasonCodes.includes(reason))) {
ElMessage.warning('请逐项确认所有软质量提示');
@@ -2699,7 +2922,13 @@ async function publishAsset() {
}
qualityPublishing.value = true;
try {
await publishQualityAsset(asset.id, { ...form, reason: form.reason.trim() });
await publishQualityAsset(asset.id, {
...form,
reason: form.reason.trim(),
applicableRole: form.applicableRole?.trim() || undefined,
applicableRegion: form.applicableRegion?.trim() || undefined,
applicableProject: form.applicableProject?.trim() || undefined
});
ElMessage.success('已批准并发布到生产检索');
qualityDialogVisible.value = false;
await Promise.all([loadQualityAssets(), loadOverview(), loadIndexHealth(), loadQualityMonitoring()]);
@@ -2817,14 +3046,67 @@ function usageLabel(usage: string) {
return usageOptions.find((item) => item.value === usage)?.label || usage;
}
function issueEvidence(value: string) {
function sourceAuthorityLabel(value: string) {
const labels: Record<string, string> = {
FORMAL_POLICY: '正式制度',
COMPANY_POLICY: '公司正式制度',
APPROVED_SOP: '已批准 SOP',
REGULATION: '法规',
EMPLOYEE_SUBMISSION: '员工经验投稿',
UNKNOWN: '来源待确认'
};
if (!value) return '未填写';
return labels[value] || (/^[A-Z0-9_]+$/.test(value) ? '其他来源(待确认)' : value);
}
function riskLevelLabel(value: string) {
return ({ LOW: '低', MEDIUM: '中', HIGH: '高', CRITICAL: '关键' } as Record<string, string>)[value] || '未知';
}
function versionStatusLabel(value: string) {
return (
(
{
REVIEW_PENDING: '待审核',
QUARANTINED: '已隔离',
APPROVED: '已批准',
PUBLISHED: '已发布',
DEPRECATED: '已撤回'
} as Record<string, string>
)[value] || '未知状态'
);
}
function qualityReasonLabel(reasonCode: string) {
return qualityReasonLabels[reasonCode] || '其他质量提示';
}
function qualityIssueSummary(value: string) {
try {
return JSON.parse(value || '{}').summary || '已命中质量规则';
return String(JSON.parse(value || '{}').summary || '');
} catch {
return '已命中质量规则';
return '';
}
}
function qualityIssueDescription(issue: QualityIssue) {
const summary = qualityIssueSummary(issue.evidenceJson);
const count = summary.match(/(?:Detected|covers)\s+(\d+)/i)?.[1];
if (issue.reasonCode === 'PAGINATION_NOISE' && count) return `正文中检测到 ${count} 行独立页码。`;
if (issue.reasonCode === 'CHUNK_CONTEXT_BROKEN' && count) return `检测到 ${count} 个过短或依赖前后文的片段。`;
if (issue.reasonCode === 'CONTEXT_INCOMPLETE' && count) return `案例目前覆盖 5 类必要要素中的 ${count} 类。`;
return qualityReasonDescriptions[issue.reasonCode] || '系统命中了一项需要人工核对的质量规则。';
}
function qualityIssueAction(issue: QualityIssue) {
if (issue.gateType === 'HARD') return '请修订原资料并重新上传,解决后才能发布。';
return qualityAcknowledgements[issue.reasonCode] || '请对照原资料人工核查,确认不影响发布后再勾选接受。';
}
function qualityAcknowledgementText(reasonCode: string) {
return qualityAcknowledgements[reasonCode] || '已对照原资料完成核查,并确认该提示不影响本次发布。';
}
function formatLag(seconds: number) {
if (seconds < 60) return `${seconds} 秒`;
if (seconds < 3600) return `${Math.floor(seconds / 60)} 分钟`;
@@ -4003,10 +4285,54 @@ async function requestAssetPurge(asset: QualityAsset) {
gap: 0 16px;
}
.quality-scope-field {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 10px;
width: 100%;
.el-segmented {
justify-self: start;
width: max-content;
}
}
.quality-acknowledgement-tip {
margin-bottom: 10px;
}
.reason-checks {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px 12px;
gap: 8px 12px;
width: 100%;
.el-checkbox {
align-items: flex-start;
height: auto;
min-height: 62px;
margin-right: 0;
padding: 10px 12px;
border: 1px solid #e4e7ed;
border-radius: 6px;
white-space: normal;
}
}
.reason-check-content {
display: grid;
gap: 4px;
line-height: 1.45;
strong {
color: #303846;
}
small {
color: #667085;
white-space: normal;
}
}
@media (max-width: 1500px) {
@@ -4057,6 +4383,10 @@ async function requestAssetPurge(asset: QualityAsset) {
grid-template-columns: 1fr;
}
.quality-scope-field {
grid-template-columns: 1fr;
}
.quality-metrics {
grid-template-columns: 1fr 1fr;
}