fix(pc): 弹窗遮罩改毛玻璃并清掉 9 处提示折行

遮罩底色被 Naive 写死在 css-render 里(Modal / Drawer 主题没有 mask token,
themeOverrides 改不到),只能上 CSS;加 backdrop-filter 后遮罩后面的页面糊掉、
弹层本体仍是纯白,NModal / NDrawer / useDialog 共用 .n-modal-mask 一条规则覆盖。

折行的根因是格子宽度写死(半宽 264px / span 8 192px / 定宽 160px),与窗口宽度无关:
能压短的压短;「文件名预览」那处是 .n-form-item-blank 属于 flex 行、把提示挤成 3 行,
改成包一层块级容器;材料预览失败的占位在 108px 小格里曾折 3 行且被裁掉。

约定写进 frontend-pc/AGENTS.md 第 11 条与 code-css skill;实测与刻意不改的清单见
docs/交接摘要.md 的 §一·四十二。
This commit is contained in:
2026-10-14 15:34:40 +08:00
parent e94e76ba0f
commit 623e6393d5
11 changed files with 328 additions and 15 deletions
+29
View File
@@ -36,6 +36,10 @@
--xt-text: #1f2229;
--xt-text-2: #667085;
--xt-text-3: #98a2b3;
/* 弹窗遮罩:比 Naive 原生的 .4/.3 浅一档,模糊才透得出来(见下方「弹窗遮罩」) */
--xt-mask-bg: rgb(16 24 40 / 26%);
--xt-mask-blur: 8px;
}
* {
@@ -117,6 +121,31 @@ body {
border-bottom-color: var(--xt-card-border-weak);
}
/* ── 弹窗遮罩(毛玻璃) ─────────────────────────────── */
/**
* 三种弹层的遮罩层都变毛玻璃:`NModal`、`NDrawer`、以及 `useDialog()` 的提示框。
* **弹层本体保持纯白**,只处理背后那一层。
*
* ⚠️ 为什么只能用 CSS、改不到 `App.vue` 的 themeOverrides:Naive 把遮罩色**写死在
* css-render 里**(`modal/src/styles/index.cssr.mjs` 的 `modal-mask` = `rgba(0,0,0,.4)`、
* `drawer/src/styles/index.cssr.mjs` 的 `drawer-mask` = `rgba(0,0,0,.3)`),
* Modal / Drawer 的主题里**没有 mask token** —— 主题变量改不到它。
* ⚠️ 为什么用双类名:理由同上一条(css-render 运行时注入 <head>,先后顺序不保证),
* 与 `.n-card.n-card` 是同一招。
* ⚠️ `DialogEnvironment` 里 `useDialog()` 走的是 `NModal`(`dialog/src/DialogEnvironment.mjs`),
* 所以它和普通弹窗共用 `.n-modal-mask`,一条规则全覆盖。
* ⚠️ `.n-drawer-mask--invisible`(`show-mask="transparent"`)必须排除在外:它是
* "看不见的遮罩",被这条规则染上颜色就变成"看得见的挡板"。仓里目前没人用这个属性,
* 这个排除是给以后用的。`.n-modal-mask` 没有对应的隐藏变体。
*/
.n-modal-mask.n-modal-mask,
.n-drawer-mask.n-drawer-mask:not(.n-drawer-mask--invisible) {
background-color: var(--xt-mask-bg);
backdrop-filter: blur(var(--xt-mask-blur)) saturate(130%);
-webkit-backdrop-filter: blur(var(--xt-mask-blur)) saturate(130%);
}
/* ── 列表页卡片 ─────────────────────────────────────── */
/**
+1 -1
View File
@@ -137,7 +137,7 @@ onMounted(loadNormal)
<NSpin v-if="loading" :size="16" />
<img v-else-if="src" :src="src" class="fp__img" alt="材料预览" />
<div v-else class="fp__fail">
预览取不到<br>(链接过期或已删除)
预览取不到<br>(链接已过期)
</div>
</div>
<div class="fp__name" :title="fileName">{{ fileName }}</div>
+1 -1
View File
@@ -247,7 +247,7 @@ defineExpose({ add, edit })
<NSelect v-model:value="form.templateCode" :options="templateOptions" />
<template #feedback>
<span class="rf__hint">
复制它的权限码与菜单;建好后在右侧授权矩阵里增删。新角色至少要有一项权限与一个菜单
复制它的权限码与菜单。新角色至少要有一项权限与一个菜单
</span>
</template>
</NFormItem>
+19 -2
View File
@@ -365,8 +365,16 @@ defineExpose({ add, edit })
</div>
<NFormItem label="文件名预览">
<span class="task-form__preview-note">以「张同学 / 361029200912100015 / 身份证」为例</span>
<code class="task-form__preview">{{ namingPreview }}</code>
<!--
⚠️ 必须包一层块级容器:`.n-form-item-blank` 是 **flex 行**(form-item 是 grid、
blank 区是 flex),直接放两个子元素会被排成同一行、各自被压缩 ——
实测这行提示被挤到 191px、折成 3 行("样例"根本读不出是一句话)。
包成块级容器后 note 独占一行(容器 603px,需要 312px)。
-->
<div class="task-form__preview-box">
<span class="task-form__preview-note">以「张同学 / 361029200912100015 / 身份证」为例</span>
<code class="task-form__preview">{{ namingPreview }}</code>
</div>
</NFormItem>
</NForm>
@@ -415,6 +423,15 @@ defineExpose({ add, edit })
color: #8a8a8a;
}
/**
* 样例提示 + 文件名预览:**必须整体占满 blank 区**。
* `.n-form-item-blank` 是 flex 行,不包这一层的话两个子元素会被并排压缩
* (实测提示被挤到 191px、折成 3 行)。
*/
&__preview-box {
width: 100%;
}
&__preview-note {
display: block;
margin-bottom: 4px;
@@ -619,7 +619,7 @@ defineExpose({ open })
<NInput v-model:value="extraForm.key" placeholder="extra_xxx" :maxlength="46" clearable />
<template #feedback>
<span class="fd__hint fd__hint--inline">
只能用小写字母、数字、下划线;改动后导出列名会跟着变
只能用小写字母、数字、下划线;导出列名跟着变
</span>
</template>
</NFormItemGi>
@@ -573,8 +573,7 @@ defineExpose({ open })
<NDynamicTags v-model:value="form.aliases" :max="6" />
<template #feedback>
<span class="mat-form__hint">
输入后回车,如:身份证正面、身份证人像面。
用于从历史文件名里认出这是哪一项材料 —— 别名不全,该认出来的就认不出来
输入后回车,如:身份证正面、身份证人像面。用于从历史文件名认出材料,别名不全就认不出来
</span>
</template>
</NFormItemGi>
@@ -622,7 +621,7 @@ defineExpose({ open })
<NFormItemGi :span="8" label="压缩档位" path="compressProfile">
<NSelect v-model:value="form.compressProfile" :options="profileOptions" />
<template #feedback>
<span class="mat-form__hint">档位决定分辨率与清晰度,一般不用改</span>
<span class="mat-form__hint">影响清晰度,一般不用改</span>
</template>
</NFormItemGi>
+1 -1
View File
@@ -280,7 +280,7 @@ defineExpose({ open })
:disabled="readonly"
/>
<div class="org-drawer__fallback">
留空表示不比对,填了才与名册比
留空 = 不比对
</div>
</div>
</div>
+2 -2
View File
@@ -328,7 +328,7 @@ defineExpose({ add, edit })
<NFormItem label="登录账号" path="username">
<NInput v-model:value="form.username" :disabled="isEdit" placeholder="如 zhangsan" clearable />
<template v-if="isEdit" #feedback>
<span class="uf__hint">登录名不可修改:改了会让历史记录与导出包里的账号对不上</span>
<span class="uf__hint">不可修改:会让历史记录与导出包对不上</span>
</template>
</NFormItem>
@@ -340,7 +340,7 @@ defineExpose({ add, edit })
<NInput v-model:value="form.phone" placeholder="11 位手机号" :maxlength="11" clearable />
<template #feedback>
<span class="uf__hint">
{{ isEdit ? '列表只返回脱敏值,这里必须重填一次(加密存储)' : '加密存储,列表只显示脱敏值' }}
{{ isEdit ? '必须重填一次(列表只给脱敏值)' : '加密存储,列表只显示脱敏值' }}
</span>
</template>
</NFormItem>