feat(frontend): 视觉规范 v4 全站落地与实测修复
token 补齐与 EP 形体基准、全站版式工具类(.page-head/.card 系/.filter-bar/.ys-pill 等)、布局与登录页、工作台 Bento 与图表主题、打印稿纸、全部业务页统一到全局类;StatusTag 改 pill、AppPagination 加 background。 浏览器实测修复:表格行高收到 1.5;月结生命周期条圆点按阶段着色并加操作提示;工作台空态垂直居中;状态/结果列宽按胶囊内容给足(96/108/120),消除 Element Plus 省略号伪『小点』。设计稿反向同步圆点着色与流程条提示。
This commit is contained in:
1 parent
1f65913002
commit
8e8bcaa5fb
16 files changed
+415
-132
No files matched your search
@@ -589,6 +589,12 @@ span.cell-num {
|
||||
|
||||
.el-table .cell {
|
||||
padding: 0 16px;
|
||||
/*
|
||||
* Element Plus 默认给单元格 23px 行高(≈1.77 倍),加上 12px 上下内距,
|
||||
* 单行数据行会到 51px —— 一屏少看两行,也与设计稿的「12px 内距 + 13px 字」
|
||||
* 不符。收到 1.5(中文正文常用行高)后单行约 45px;多行单元格仍按内容撑开。
|
||||
*/
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.el-table__body tr:hover > td.el-table__cell {
|
||||
|
||||
@@ -25,19 +25,19 @@ import {
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
/**
|
||||
* 鑿滃崟鍥炬爣娉ㄥ唽琛ㄣ??
|
||||
* 菜单图标注册表。
|
||||
*
|
||||
* **璺敱鍙啓璇箟 key锛坢eta.icon锛夛紝涓嶇洿鎺ュ紩鐢ㄥ浘鏍囩粍浠?**锛氳矾鐢辫〃淇濇寔杞婚噺鍙?
|
||||
* 搴忓垪鍖栵紝鍥炬爣瀹炵幇鎹㈠簱鎴栨崲椋庢牸鏃跺彧鏀规湰鏂囦欢锛岃矾鐢变笌鑿滃崟缁勪欢涓嶅姩銆?
|
||||
* **路由只写语义 key(meta.icon),不直接引用图标组件**:路由表保持轻量、
|
||||
* 序列化,图标实现换库或换风格时只改本文件,路由与菜单组件不动。
|
||||
*
|
||||
* 鍏峰悕瀵煎叆锛堜笉鐢? `import * as`锛変互淇濊瘉鎽囨爲 鈥斺?? 鏁村寘寮曞叆浼氭妸 200+ 鍥炬爣鎵撹繘
|
||||
* 浜х墿銆傛敞鍐岃〃閲屽浣欑殑鍥炬爣鍚屾牱浼氳鎽囨帀锛屼絾浼氳銆岀敤浜嗗摢浜涖?嶉毦浠ユ牳瀵癸紝鏁?
|
||||
* 鍙繚鐣欏疄闄呯敤鍒扮殑銆?
|
||||
* 具名导入(不用 `import * as`)以保证摇树 —— 整包引入会把 200+ 图标打进
|
||||
* 产物。注册表里多余的图标同样会被摇掉,但会让「用了哪些」难以核对,
|
||||
* 只保留实际用到的。
|
||||
*
|
||||
* **鍏ㄩ儴鍙栫嚎鎬э紙outline锛夊浘鏍囷紝涓嶇敤 *-filled 鍙樹綋**锛氫晶鏍忓悓涓?灞傜骇娣风敤瀹炲績涓?
|
||||
* 绾挎?у浘鏍囦細璁╄彍鍗曠湅鐫?涓嶆槸涓?濂楄瑷?锛堣璁$ǹ 搂04 鐨勫浘鏍囨棌鍗? 16px 绾挎?э級銆?
|
||||
* 棣栭〉鐢? House锛堢嚎鎬ф埧灞嬶級鑰岄潪 HomeFilled锛屼汉鍛樼鐞嗙敤 Postcard锛堜汉鍛樻。妗堝崱锛?
|
||||
* 鑰岄潪 UserFilled 鈥斺?? 鐢ㄦ埛绠$悊宸插崰 User锛屼汉鍛樻敼鐢ㄦ。妗堝崱浠ュ厤涓や釜銆屼汉銆嶆挒褰€??
|
||||
* **全部取线性(outline)图标,不用 *-filled 变体**:侧栏同一层级混用实心与
|
||||
* 线性图标会让菜单看着不是一套语汇(设计稿 §04 的图标族:16px 线性)。
|
||||
* 首页用 House(线性房屋)而非 HomeFilled,人员管理用 Postcard(人员档案卡)
|
||||
* 而非 UserFilled —— 用户管理已占 User,人员改用档案卡以免两个「人」撞形。
|
||||
*/
|
||||
const ICONS = {
|
||||
home: House,
|
||||
@@ -63,10 +63,10 @@ const ICONS = {
|
||||
'report-payment': PieChart,
|
||||
} satisfies Record<string, Component>
|
||||
|
||||
/** 鑿滃崟鍥炬爣鐨勮涔? key锛堣矾鐢? meta.icon 鐨勫彇鍊艰寖鍥达級銆? */
|
||||
/** 菜单图标的语义 key(路由 meta.icon 的取值范围)。 */
|
||||
export type MenuIconName = keyof typeof ICONS
|
||||
|
||||
/** 鎸夎涔? key 鍙栧浘鏍囷紱鏈厤缃椂杩斿洖 undefined锛堣彍鍗曢」鍙樉绀烘枃瀛楋級銆? */
|
||||
/** 按语义 key 取图标;未配置时返回 undefined(菜单项只显示文字)。 */
|
||||
export function menuIcon(name?: string): Component | undefined {
|
||||
return name ? (ICONS[name as MenuIconName] ?? undefined) : undefined
|
||||
}
|
||||
@@ -460,7 +460,7 @@ onMounted(() => {
|
||||
<span class="cell-num">{{ row.salary_standard ?? '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<StatusTag :value="row.status" active-text="在职" inactive-text="离职" />
|
||||
</template>
|
||||
|
||||
@@ -283,7 +283,7 @@ onMounted(() => {
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<StatusTag :value="row.status" />
|
||||
</template>
|
||||
|
||||
@@ -692,7 +692,7 @@ onMounted(() => {
|
||||
<el-table-column prop="business_date" label="业务日期" min-width="110">
|
||||
<template #default="{ row }">{{ row.business_date ?? '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="108" align="center">
|
||||
<template #default="{ row }">
|
||||
<!-- 状态列统一用 pill:颜色之外必有文字,色觉差异不影响判读 -->
|
||||
<span :class="statusPillClass(row.status)">
|
||||
|
||||
@@ -348,7 +348,7 @@ onMounted(() => {
|
||||
<span class="cell-num">{{ row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="以物抵顶" width="110" align="center">
|
||||
<el-table-column label="以物抵顶" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<!-- 以物抵顶影响折算比例,属需要一眼看见的分支,用 pill 而非普通文字 -->
|
||||
<span v-if="row.is_barter === 1" class="ys-pill ys-pill--wait">以物抵顶</span>
|
||||
@@ -361,7 +361,7 @@ onMounted(() => {
|
||||
<span v-else class="cell-muted">未指定批次</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="核算状态" width="100" align="center">
|
||||
<el-table-column label="核算状态" width="108" align="center">
|
||||
<template #default="{ row }">
|
||||
<!-- 已核算=已确认(靛绿)、未核算=待处理(琥珀);已核算行禁改禁删 -->
|
||||
<span
|
||||
|
||||
@@ -158,7 +158,7 @@ async function submitRecalc(): Promise<void> {
|
||||
<span class="cell-num">{{ row.payable_amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="版本" width="100">
|
||||
<el-table-column label="版本" width="108">
|
||||
<template #default="{ row }">
|
||||
<span class="cell-code">v{{ row.calc_version }}</span>
|
||||
<!-- 历史版本用中性 pill:被替代不是异常,只是不再是生效版本 -->
|
||||
|
||||
@@ -411,6 +411,8 @@ function formatTime(value: string): string {
|
||||
|
||||
.bento-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px 18px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, var(--ys-paper), #fcfcfe);
|
||||
@@ -511,10 +513,19 @@ function formatTime(value: string): string {
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
/*
|
||||
* 空态在卡片剩余高度里居中:待办/预警是 2×2 的卡,只有一行提示时
|
||||
* 内容全挤在顶部、下方留一大片空白,看起来像没加载完。
|
||||
*/
|
||||
.b-empty-mini {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--ys-ink-3);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart {
|
||||
|
||||
@@ -45,10 +45,10 @@ function resetFilters(): void {
|
||||
* 复用 search() 意味着**不新增任何后端请求口径**。
|
||||
*/
|
||||
const FLOW_STEPS = [
|
||||
{ value: 1, label: '草稿' },
|
||||
{ value: 2, label: '待审批' },
|
||||
{ value: 3, label: '已审定(锁定)' },
|
||||
{ value: 4, label: '已驳回' },
|
||||
{ value: 1, label: '草稿', tone: 'draft' },
|
||||
{ value: 2, label: '待审批', tone: 'wait' },
|
||||
{ value: 3, label: '已审定(锁定)', tone: 'lock' },
|
||||
{ value: 4, label: '已驳回', tone: 'reject' },
|
||||
] as const
|
||||
|
||||
/** 点当前段再点一次即取消筛选(idle 态),避免「点了没反应」的死角 */
|
||||
@@ -149,8 +149,10 @@ async function handleSubmit(row: Settlement): Promise<void> {
|
||||
:class="{ 'flow-step__item--cur': filters.status === step.value }"
|
||||
@click="pickStatus(step.value)"
|
||||
>
|
||||
<span class="flow-step__dot"></span>{{ step.label }}
|
||||
<span class="flow-step__dot" :class="`flow-step__dot--${step.tone}`"></span>
|
||||
{{ step.label }}
|
||||
</button>
|
||||
<span class="flow-step__hint">点状态只看该阶段,再点一次取消</span>
|
||||
</div>
|
||||
|
||||
<!-- 生成行:文案保留「生成月结快照」,对应真实动作(生成的是快照批次) -->
|
||||
@@ -328,6 +330,7 @@ async function handleSubmit(row: Settlement): Promise<void> {
|
||||
.flow-step {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
@@ -350,6 +353,14 @@ async function handleSubmit(row: Settlement): Promise<void> {
|
||||
border-color 150ms var(--ys-ease);
|
||||
}
|
||||
|
||||
/* 未选中时四段必须读起来仍是「一条流程」:给右侧挂一行说明,
|
||||
高度与分段齐平,避免出现四颗孤立小按钮的观感 */
|
||||
.flow-step__hint {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.flow-step__item:first-child {
|
||||
border-radius: var(--ys-radius-sm) 0 0 var(--ys-radius-sm);
|
||||
}
|
||||
@@ -378,6 +389,19 @@ async function handleSubmit(row: Settlement): Promise<void> {
|
||||
background: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
/* 圆点按阶段着色:未选中时也能看出四段各自代表什么(颜色之外仍有文字) */
|
||||
.flow-step__dot--wait {
|
||||
background: var(--ys-warn);
|
||||
}
|
||||
|
||||
.flow-step__dot--lock {
|
||||
background: var(--ys-indigo);
|
||||
}
|
||||
|
||||
.flow-step__dot--reject {
|
||||
background: var(--ys-danger);
|
||||
}
|
||||
|
||||
.flow-step__item--cur {
|
||||
font-weight: 500;
|
||||
color: var(--ys-indigo);
|
||||
|
||||
@@ -276,7 +276,7 @@ onMounted(() => {
|
||||
<el-table-column label="排序" width="70" align="right">
|
||||
<template #default="{ row }"><span class="cell-num">{{ row.sort_order }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<StatusTag :value="row.status" />
|
||||
</template>
|
||||
|
||||
@@ -265,7 +265,7 @@ watch(activeTab, (tab) => {
|
||||
<el-table-column prop="module" label="模块" width="100" />
|
||||
<el-table-column prop="action" label="操作" width="90" />
|
||||
<el-table-column prop="summary" label="摘要" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="结果" width="80" align="center">
|
||||
<el-table-column label="结果" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip
|
||||
:content="row.error_message ?? ''"
|
||||
@@ -368,7 +368,7 @@ watch(activeTab, (tab) => {
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户名" min-width="130" />
|
||||
<el-table-column label="结果" width="80" align="center">
|
||||
<el-table-column label="结果" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<StatusTag
|
||||
:value="row.success"
|
||||
|
||||
@@ -245,7 +245,7 @@ onMounted(load)
|
||||
<el-table-column label="排序" width="80" align="right">
|
||||
<template #default="{ row }"><span class="cell-num">{{ row.sort_order }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<StatusTag :value="row.status" />
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,10 @@ import { handledError } from '@/utils/error'
|
||||
* 公司信息设置(2026-10-15 补充需求:公司名称、logo)。
|
||||
*
|
||||
* 签名元素是右侧「登录页实景预览」:品牌名与 logo 改动即时反映在一张
|
||||
* 缩比登录卡上 —— 所见即所得,避免「保存后去登录页核对」的往返。
|
||||
* **1:1 等比**的登录卡上 —— 所见即所得,避免「保存后去登录页核对」的往返。
|
||||
* 预览按登录页的真实版式复刻(品牌区 / 欢迎回来 / 三项输入 / 登录按钮 /
|
||||
* 版权行),控件尺寸与登录页一致,logo 展示位也按登录页的 ≤56×36 约束。
|
||||
*
|
||||
* logo 校验(png/jpg ≤2MB)与后端三重校验同口径,前端先拦一道。
|
||||
*
|
||||
* 进入页面即加载当前设置(设置页即所见即所得,无需手动刷新)。
|
||||
@@ -99,79 +102,131 @@ const previewName = computed(() => form.company_name.trim() || '衍水集团')
|
||||
</div>
|
||||
|
||||
<div class="settings-grid">
|
||||
<div class="card settings-card">
|
||||
<!-- 卡片标题刻意不写「公司信息」:页面标题已经说明了,再重复一遍只是噪音 -->
|
||||
<div class="card-head">
|
||||
<span class="card-title">基础信息</span>
|
||||
<!-- 左列:基础信息(表单)+ 生效范围(这份设置会出现在哪里) -->
|
||||
<div class="settings-col">
|
||||
<div class="card">
|
||||
<!-- 卡片标题刻意不写「公司信息」:页面标题已经说明了,再重复一遍只是噪音 -->
|
||||
<div class="card-head">
|
||||
<span class="card-title">基础信息</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="92px"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="公司名称" prop="company_name">
|
||||
<!-- 控件与说明并排:说明靠行尾对齐,宽屏下整行铺满卡片而非缩在左上角 -->
|
||||
<div class="field-control">
|
||||
<el-input
|
||||
v-model="form.company_name"
|
||||
class="field-control__main"
|
||||
maxlength="64"
|
||||
placeholder="展示在登录页与导出页眉"
|
||||
clearable
|
||||
/>
|
||||
<p class="field-control__note">最多 64 个字符;保存后对所有在线用户立即生效。</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="logo">
|
||||
<div class="field-control">
|
||||
<el-upload
|
||||
class="logo-uploader"
|
||||
:show-file-list="false"
|
||||
:http-request="handleUpload"
|
||||
:before-upload="beforeUpload"
|
||||
accept="image/png,image/jpeg"
|
||||
>
|
||||
<div v-loading="uploading" class="logo-box" title="点击上传 png / jpg(≤2MB)">
|
||||
<img v-if="logoUrl" :src="logoUrl" alt="公司 logo" />
|
||||
<span v-else class="logo-plus">+</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
<p class="field-control__note">
|
||||
png / jpg,不超过 2MB;仅展示于登录页品牌位,按 ≤56×36 显示。
|
||||
</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
保存按钮移进 card-foot:表单项里的按钮会跟着 label 列缩进、并对齐到输入框左缘,
|
||||
作为整张表单的收尾动作用卡片底栏右对齐更符合阅读顺序。
|
||||
按钮在 form 之外仍安全:handleSubmit 走 formRef 校验,且 el-button 默认 type="button",
|
||||
不会触发浏览器原生提交。
|
||||
-->
|
||||
<div class="card-foot">
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="88px"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="公司名称" prop="company_name">
|
||||
<el-input
|
||||
v-model="form.company_name"
|
||||
maxlength="64"
|
||||
placeholder="展示在登录页与导出页眉"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="logo">
|
||||
<div class="logo-field">
|
||||
<el-upload
|
||||
class="logo-uploader"
|
||||
:show-file-list="false"
|
||||
:http-request="handleUpload"
|
||||
:before-upload="beforeUpload"
|
||||
accept="image/png,image/jpeg"
|
||||
>
|
||||
<div v-loading="uploading" class="logo-box" title="点击上传 png / jpg(≤2MB)">
|
||||
<img v-if="logoUrl" :src="logoUrl" alt="公司 logo" />
|
||||
<span v-else class="logo-plus">+</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
<p class="logo-hint">png / jpg,不超过 2MB;<br />展示于登录页品牌位与导出页眉。</p>
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<span class="card-title">生效范围</span>
|
||||
<span class="preview-note">保存后对所有人生效</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="scope-list">
|
||||
<div class="scope-item">
|
||||
<dt>公司名称</dt>
|
||||
<dd>登录页品牌位与版权行 · Excel 导出页眉 · 打印稿页眉</dd>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
保存按钮移进 card-foot:表单项里的按钮会跟着 label 列缩进、并对齐到输入框左缘,
|
||||
作为整张表单的收尾动作用卡片底栏右对齐更符合阅读顺序。
|
||||
按钮在 form 之外仍安全:handleSubmit 走 formRef 校验,且 el-button 默认 type="button",
|
||||
不会触发浏览器原生提交。
|
||||
-->
|
||||
<div class="card-foot">
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">保存</el-button>
|
||||
<div class="scope-item">
|
||||
<dt>logo</dt>
|
||||
<dd>登录页品牌位(≤56×36)</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 签名元素:登录页实景预览(缩比登录卡,品牌名/logo 即时反映) -->
|
||||
<!-- 签名元素:登录页实景预览(1:1 等比登录卡,非 iframe 截图) -->
|
||||
<div class="card preview-card">
|
||||
<div class="card-head">
|
||||
<span class="card-title">登录页预览</span>
|
||||
<span class="preview-note">保存后对所有人生效</span>
|
||||
<span class="preview-note">1:1 等比</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="login-mock">
|
||||
<div class="mock-brand">
|
||||
<img v-if="logoUrl" :src="logoUrl" alt="" class="mock-logo" />
|
||||
<div class="mock-name">{{ previewName }}</div>
|
||||
<p class="mock-slogan">把每一笔回款,算成一份踏实。</p>
|
||||
<span class="mock-waterline"></span>
|
||||
<div class="login-stage" aria-hidden="true">
|
||||
<div class="mock-card">
|
||||
<div class="mock-brand">
|
||||
<img v-if="logoUrl" :src="logoUrl" alt="" class="mock-logo" />
|
||||
<div class="mock-name">{{ previewName }}</div>
|
||||
<p class="mock-slogan">把每一笔回款,算成一份踏实。</p>
|
||||
<span class="mock-waterline"></span>
|
||||
</div>
|
||||
|
||||
<div class="mock-head">
|
||||
<div class="mock-title">欢迎回来</div>
|
||||
<div class="mock-hint">请输入账号密码进入系统</div>
|
||||
</div>
|
||||
|
||||
<div class="mock-field">
|
||||
<span class="mock-label">用户名</span>
|
||||
<span class="mock-box"></span>
|
||||
</div>
|
||||
<div class="mock-field">
|
||||
<span class="mock-label">密码</span>
|
||||
<span class="mock-box"></span>
|
||||
</div>
|
||||
<div class="mock-field">
|
||||
<span class="mock-label">验证码</span>
|
||||
<span class="mock-captcha-row">
|
||||
<span class="mock-box"></span>
|
||||
<span class="mock-captcha"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mock-submit">登 录</div>
|
||||
</div>
|
||||
<div class="mock-field"></div>
|
||||
<div class="mock-field"></div>
|
||||
<div class="mock-submit">登 录</div>
|
||||
<div class="mock-foot">© {{ previewName }} · 内部系统</div>
|
||||
</div>
|
||||
<p class="preview-caption">登录页品牌位实景(示意,非交互)</p>
|
||||
<p class="preview-caption">登录页品牌位实景(示意,非交互)——显示的是当前编辑值</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -181,11 +236,18 @@ const previewName = computed(() => form.company_name.trim() || '衍水集团')
|
||||
<style scoped>
|
||||
.settings-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(360px, 460px) minmax(300px, 380px);
|
||||
grid-template-columns: minmax(0, 1fr) 480px;
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.settings-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 说明文字不再用 float:right 顶到卡片头右侧 —— .card-head 已是 flex +
|
||||
* space-between,第二个子元素自然落在右端,float 反而会破坏行内布局。
|
||||
@@ -195,10 +257,37 @@ const previewName = computed(() => form.company_name.trim() || '衍水集团')
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.logo-field {
|
||||
/*
|
||||
* 控件行:主控件在左、说明在右,两者共享一行高度。
|
||||
* 说明用 flex-grow 撑满剩余宽度并右对齐 —— 宽屏下整行铺到卡片右缘,
|
||||
* 不会出现「输入框缩在左上角、右侧留一整块空白」的观感;
|
||||
* 窄屏放不下时自动换行,说明退回左对齐。
|
||||
*/
|
||||
.field-control {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 14px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.field-control__main {
|
||||
flex: 0 1 420px;
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
.field-control__note {
|
||||
flex: 1 1 240px;
|
||||
min-width: 240px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
color: var(--ys-ink-3);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.logo-uploader {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.logo-box {
|
||||
@@ -232,22 +321,76 @@ const previewName = computed(() => form.company_name.trim() || '衍水集团')
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.logo-hint {
|
||||
margin: 4px 0 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
/* ── 生效范围:定义列表(项名 / 取值) ── */
|
||||
.scope-list {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.scope-item {
|
||||
display: grid;
|
||||
grid-template-columns: 92px minmax(0, 1fr);
|
||||
column-gap: 20px;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.scope-item + .scope-item {
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid var(--ys-line-soft);
|
||||
}
|
||||
|
||||
.scope-item dt {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--ys-ink-2);
|
||||
}
|
||||
|
||||
.scope-item dd {
|
||||
margin: 0;
|
||||
font-size: 12.5px;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
/* ── 登录页实景预览:按登录卡视觉 0.8 缩比重建(非 iframe 截图) ── */
|
||||
.login-mock {
|
||||
padding: 22px 26px 24px;
|
||||
/* ── 登录页实景预览:按登录页真实版式 1:1 复刻 ── */
|
||||
.login-stage {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 24px 0 20px;
|
||||
overflow: hidden;
|
||||
background-color: #f2f4f8;
|
||||
/* 点阵网格:与登录页同一套秩序感 */
|
||||
background-image: radial-gradient(rgba(28, 35, 51, 0.07) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
border-radius: var(--ys-radius-sm);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* 顶部天光:登录页的落点光源,等比搬过来 */
|
||||
.login-stage::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -180px;
|
||||
left: 50%;
|
||||
width: 860px;
|
||||
height: 460px;
|
||||
transform: translateX(-50%);
|
||||
pointer-events: none;
|
||||
background: radial-gradient(closest-side, rgba(46, 75, 168, 0.08), rgba(46, 75, 168, 0));
|
||||
}
|
||||
|
||||
.mock-card {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
padding: 30px 36px 32px;
|
||||
background: linear-gradient(180deg, #ffffff, #fcfcfe);
|
||||
border: 1px solid var(--ys-line);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(28, 35, 51, 0.09);
|
||||
border-radius: 14px;
|
||||
box-shadow:
|
||||
0 2px 4px rgba(28, 35, 51, 0.04),
|
||||
0 10px 26px rgba(28, 35, 51, 0.08);
|
||||
0 16px 40px rgba(28, 35, 51, 0.1);
|
||||
}
|
||||
|
||||
.mock-brand {
|
||||
@@ -256,62 +399,136 @@ const previewName = computed(() => form.company_name.trim() || '衍水集团')
|
||||
|
||||
.mock-logo {
|
||||
display: block;
|
||||
max-width: 64px;
|
||||
max-height: 40px;
|
||||
margin: 0 auto 8px;
|
||||
max-width: 56px;
|
||||
max-height: 36px;
|
||||
margin: 0 auto 10px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.mock-name {
|
||||
font-family: var(--ys-font-brand);
|
||||
font-size: 14px;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.34em;
|
||||
color: var(--ys-ink);
|
||||
}
|
||||
|
||||
.mock-slogan {
|
||||
margin: 6px 0 0;
|
||||
font-size: 11px;
|
||||
margin: 8px 0 0;
|
||||
font-size: 12.5px;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.mock-waterline {
|
||||
display: block;
|
||||
width: 34px;
|
||||
width: 40px;
|
||||
height: 2px;
|
||||
margin: 10px auto 0;
|
||||
margin: 14px auto 0;
|
||||
border-radius: 1px;
|
||||
background: linear-gradient(90deg, var(--ys-indigo), rgba(46, 75, 168, 0));
|
||||
}
|
||||
|
||||
.mock-head {
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.mock-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--ys-ink);
|
||||
}
|
||||
|
||||
.mock-hint {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.mock-field {
|
||||
height: 32px;
|
||||
margin-top: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.mock-field + .mock-field {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.mock-label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: var(--ys-ink-2);
|
||||
}
|
||||
|
||||
.mock-box {
|
||||
display: block;
|
||||
height: 38px;
|
||||
background: #f4f5f8;
|
||||
border: 1px solid rgba(28, 35, 51, 0.07);
|
||||
border-radius: 6px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.mock-captcha-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.mock-captcha-row .mock-box {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 验证码位:留空壳 + 斜纹质感,不伪造字符,避免与真实验证码混淆 */
|
||||
.mock-captcha {
|
||||
flex: 0 0 104px;
|
||||
height: 38px;
|
||||
background-color: #f1f3f8;
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
rgba(28, 35, 51, 0.07) 0 1px,
|
||||
transparent 1px 7px
|
||||
);
|
||||
border: 1px solid var(--ys-line);
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.mock-submit {
|
||||
height: 32px;
|
||||
margin-top: 14px;
|
||||
font-size: 12px;
|
||||
line-height: 32px;
|
||||
height: 38px;
|
||||
margin-top: 20px;
|
||||
font-size: 13px;
|
||||
line-height: 38px;
|
||||
letter-spacing: 0.4em;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background: var(--ys-indigo);
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(180deg, var(--ys-indigo-hi), var(--ys-indigo));
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.mock-foot {
|
||||
margin-top: 16px;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
.preview-caption {
|
||||
margin: 10px 0 0;
|
||||
margin: 12px 0 0;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
color: var(--ys-ink-3);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
/*
|
||||
* 宽屏(≥1600px)说明文字靠右缘对齐,与左侧输入框形成「两端锚点」,
|
||||
* 整行铺满卡片而不是缩在左上角;1600px 以下说明跟着输入框走,
|
||||
* 放不下时整体换行到控件下方。
|
||||
*/
|
||||
@media (min-width: 1600px) {
|
||||
.field-control__note {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.settings-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ onMounted(() => {
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="状态" width="96" align="center">
|
||||
<template #default="{ row }">
|
||||
<!-- 状态统一交给 StatusTag(内部已是 ys-pill),页面不再自造标签形态 -->
|
||||
<StatusTag :value="row.status" />
|
||||
|
||||
Reference in new issue
Block a user