style(ui): 统一弹窗分组白卡样式并改造相关弹窗布局
- 新增全局弹窗灰底背景色,提升视觉一致性 - 新增通用分组白卡组件 section-card,标题融入卡头,支持额外插槽 - 统一 Avue 弹窗表单及分组为白卡样式 - 调整 common-route.vue 弹窗,使用 section-card 分组包裹查询条件与常用地址 - 改造 loading-manage.vue 弹窗所有分区,采用 section-card 统一风格 - 全局样式调整弹窗内容区表单项间距及两列表单布局工具类 - 在 main.js 全局注册 section-card 组件,便于项目统一复用
This commit is contained in:
17
.workbuddy/memory/2026-08-06.md
Normal file
17
.workbuddy/memory/2026-08-06.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 2026-08-06
|
||||
|
||||
## 复盘 src/views/business/project-apply.vue 弹窗 UI 规范
|
||||
- 主弹窗为**自定义 el-dialog + el-form**(非 Avue option 驱动),width 1440px、top 4vh、append-to-body、destroy-on-close。
|
||||
- 分区标题复用全局 `.dialog-section-title`(4px 主色竖条 + 8px 间距);页面将其改造为「白卡头 + 下方白内容卡」拼合方案(radius 6px + 淡阴影 0 1px 2px rgba(0,0,0,.04))。
|
||||
- 表单:label-position="right" / label-width="auto";两列 grid(`column-gap: 72px`);表单项 margin-bottom 16px;label min-width 160px。
|
||||
- 备注类 textarea 整行展示 + 200 字上限 + show-word-limit;金额/天数有非负与范围校验。
|
||||
- 底部按钮:非变更弹窗=取消/提交(右对齐);变更弹窗=提交/保存/关闭(左对齐)。
|
||||
- **与设计规范(AGENTS.md)对照**:基本符合 4.8 弹窗表单规范;但本页 scoped 用 `white-space: normal` 覆盖了全局 `.el-dialog .el-form-item__label { white-space: nowrap }`,允许长标签换行(与全局「label 不换行」取向不同);两列 grid 统一 min-width 160px,未严格「按列分别计算 label 宽度」。
|
||||
|
||||
## 将 project-apply 弹窗标准推广为「全项目通用标准」
|
||||
用户要求把 project-apply 弹窗视觉(灰底 + 分组白卡 + 标题在卡内)复制到其他页面。落地方式(已执行):
|
||||
- 新增可复用组件 `src/components/section-card/main.vue`:白卡 + 标题在卡头(4px 主色竖条 + 8px 间距),支持 `title` prop 与 `#title`/`#extra` slot;已在 `src/main.js` 全局注册为 `<section-card>`。
|
||||
- 在 `src/styles/element-ui.scss` 末尾新增全局标准:① `.el-dialog__body` 统一灰底 `#f5f6fa`(影响全项目所有弹窗);② `.el-dialog .avue-form` 自动包白卡(Avue 默认增删改弹窗无需改 option 即统一);③ `.el-dialog .avue-form__group` 分组白卡(option.group 渲染为标题在卡内);④ 弹窗内 `.el-form-item` 默认 16px 间距;⑤ `.section-card` 全局样式;⑥ `.form-grid-2` 两列栅格工具类(column-gap 72px)。
|
||||
- 应用落地:business 模块自定义弹窗——`common-route.vue` 的「选择常用地址」弹窗用 section-card 包成「查询条件/常用地址」两组;`loading-manage.vue` 主弹窗 6 个分区全部改用 `<section-card>`;`common-cargo.vue` 导入弹窗经全局 `.el-dialog .avue-form` 规则自动获得白卡。`project-apply.vue` 本身作为参照未改(其 scoped 样式已符合,全局灰底与其一致)。
|
||||
- 验证:`vite build` 失败为仓库既有问题(`waybill-import-dialog.vue` 引入的 `xlsx` 依赖缺失),与本次改动无关;改用 `@vue/compiler-sfc` 编译三个改动 .vue(均 OK)+ sass 编译 `element-ui.scss`(OK)。
|
||||
- 注意:其他模块的**自定义弹窗**需按同样方式用 `<section-card>` 包裹各组(灰底已由全局规则自动生效);如需继续推进其余模块可照此模式批量处理。
|
||||
28
src/components/section-card/main.vue
Normal file
28
src/components/section-card/main.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="section-card">
|
||||
<div v-if="title || $slots.title || $slots.extra" class="section-card__header">
|
||||
<span class="section-card__bar" />
|
||||
<span class="section-card__title">
|
||||
<slot name="title">{{ title }}</slot>
|
||||
</span>
|
||||
<span class="section-card__extra">
|
||||
<slot name="extra" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="section-card__body">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SectionCard',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -39,6 +39,8 @@ import codeSetting from './views/tool/codesetting.vue';
|
||||
import formSetting from './views/tool/formsetting.vue';
|
||||
import tenantPackage from './views/system/tenantpackage.vue';
|
||||
import tenantDatasource from './views/system/tenantdatasource.vue';
|
||||
// 通用弹窗分组白卡(灰底弹窗内使用,标题在卡内)
|
||||
import sectionCard from './components/section-card/main.vue';
|
||||
|
||||
window.$crudCommon = crudCommon;
|
||||
debug();
|
||||
@@ -61,6 +63,7 @@ app.component('codeSetting', codeSetting);
|
||||
app.component('formSetting', formSetting);
|
||||
app.component('tenantPackage', tenantPackage);
|
||||
app.component('tenantDatasource', tenantDatasource);
|
||||
app.component('sectionCard', sectionCard);
|
||||
app.config.globalProperties.$app = app;
|
||||
app.config.globalProperties.$dayjs = dayjs;
|
||||
app.config.globalProperties.website = website;
|
||||
|
||||
@@ -207,6 +207,101 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// 弹窗标准(与 business/project-apply 弹窗视觉一致)
|
||||
// 灰底弹窗体 + 分组白卡(标题融入卡头,4px 主色竖条 + 8px 间距)
|
||||
// =====================================================================
|
||||
|
||||
// 1) 所有弹窗内容区统一灰底
|
||||
.el-dialog__body {
|
||||
background-color: #f5f6fa;
|
||||
}
|
||||
|
||||
// 2) Avue 默认弹窗表单自动包成白卡,无需逐页改 option 即统一标准
|
||||
.el-dialog .avue-form {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
// 3) Avue 弹窗内分组(option.group)渲染为白卡,标题在卡内
|
||||
.el-dialog .avue-form__group {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 16px;
|
||||
overflow: hidden;
|
||||
|
||||
.avue-group__header {
|
||||
border-bottom: none;
|
||||
padding: 14px 16px 4px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.avue-group__item {
|
||||
padding: 14px 16px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 4) 弹窗内表单项默认上下间距 16px(覆盖默认 18px / 22px)
|
||||
.el-dialog .el-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
// 5) 通用分组白卡组件(<section-card>):标题融入卡头
|
||||
.section-card {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 16px;
|
||||
overflow: hidden;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 14px 16px 4px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
flex: none;
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&__title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__extra {
|
||||
margin-left: auto;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 14px 16px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 6) 弹窗内两列表单栅格工具类(与 project-apply 一致)
|
||||
.form-grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
column-gap: 72px;
|
||||
row-gap: 0;
|
||||
}
|
||||
|
||||
.avue-crud__dialog .avue-dialog__footer > .el-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
class="common-route-page__address-dialog"
|
||||
@opened="loadAddressList"
|
||||
>
|
||||
<section-card title="查询条件">
|
||||
<div class="common-route-page__address-search">
|
||||
<el-form :model="addressQuery" label-position="right" label-width="86px">
|
||||
<el-row :gutter="16">
|
||||
@@ -196,7 +197,9 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<section-card title="常用地址">
|
||||
<el-table
|
||||
border
|
||||
:data="addressData"
|
||||
@@ -233,6 +236,7 @@
|
||||
@current-change="handleAddressCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="addressDialogVisible = false">关闭</el-button>
|
||||
|
||||
@@ -358,7 +358,7 @@
|
||||
label-width="auto"
|
||||
class="loading-manage-dialog__form"
|
||||
>
|
||||
<div class="dialog-section-title">配载基本信息</div>
|
||||
<section-card title="配载基本信息">
|
||||
<div class="loading-manage-dialog__grid">
|
||||
<el-form-item label="配载单号">
|
||||
<el-input v-model="dialogForm.loadingNo" disabled placeholder="系统自动生成" />
|
||||
@@ -449,11 +449,12 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title loading-manage-dialog__title-action">
|
||||
<span>筛选待配载运单</span>
|
||||
<section-card title="筛选待配载运单">
|
||||
<template #extra>
|
||||
<el-link v-if="!dialogReadonly" type="primary" @click="loadCandidateWaybills">筛选</el-link>
|
||||
</div>
|
||||
</template>
|
||||
<div class="loading-manage-dialog__candidate-search" v-if="candidateSearchVisible">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
@@ -733,8 +734,9 @@
|
||||
@current-change="handleCandidateCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">待配载列表</div>
|
||||
<section-card title="待配载列表">
|
||||
<el-table
|
||||
:data="selectedWaybillRows"
|
||||
border
|
||||
@@ -769,8 +771,9 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">路线信息</div>
|
||||
<section-card title="路线信息">
|
||||
<div class="loading-manage-dialog__route-list" v-if="routeNodes.length">
|
||||
<div
|
||||
v-for="(node, index) in routeNodes"
|
||||
@@ -790,8 +793,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="添加待配载运单后自动生成路线" :image-size="72" />
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">货物信息</div>
|
||||
<section-card title="货物信息">
|
||||
<el-table :data="cargoRows" border class="loading-manage-dialog__cargo-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" fixed="left" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="150" />
|
||||
@@ -807,8 +811,9 @@
|
||||
<el-table-column prop="equipmentCode" label="设备编码" min-width="130" />
|
||||
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</section-card>
|
||||
|
||||
<div class="dialog-section-title">任务信息</div>
|
||||
<section-card title="任务信息">
|
||||
<div class="loading-manage-dialog__carrier-tabs">
|
||||
<el-segmented
|
||||
v-model="dialogForm.carrierType"
|
||||
@@ -913,6 +918,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</section-card>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@@ -1882,10 +1888,8 @@ export default {
|
||||
}
|
||||
|
||||
.loading-manage-dialog__candidate-search {
|
||||
padding: 12px 12px 4px;
|
||||
padding: 4px 0;
|
||||
margin-bottom: 8px;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.loading-manage-dialog__candidate-actions,
|
||||
|
||||
Reference in New Issue
Block a user