company_components_web/src/views/showComponents/showDialog/index.vue

441 lines
14 KiB
Vue
Raw Normal View History

2026-02-02 15:41:05 +08:00
<template>
<div class="dialog-showcase">
<!-- 介绍区 -->
<section class="intro">
<p class="eyebrow">组件展示 · Dialog</p>
<h1>弹框组件设计指南</h1>
<p class="subtitle">
基于 Element Plus 弹框能力的二次封装支持外层 +
内层嵌套弹框统一的视觉样式和交互行为
适合在复杂业务中复用避免每个页面重复堆样式与逻辑
</p>
</section>
<!-- 基础示例外层弹框 -->
<section class="card-full">
<el-card shadow="hover" class="demo-card">
<template #header>
<div class="card-header">
<h3>基础弹框</h3>
<span>最常见的确认 / 信息展示场景</span>
</div>
</template>
<p class="card-description">
点击下方按钮打开基础弹框外层弹框默认居中吸附带有统一的头部样式阴影和内容区域滚动处理
</p>
<div class="demo-actions">
<ComButton type="primary" size="large" @click="openBaseDialog">
打开基础弹框
</ComButton>
</div>
<ComDialog
:dialog-config="baseDialog"
@closeDialogOuter="handleCloseBaseOuter"
@closeDialogInner="handleCloseBaseInner"
>
<template #outerContent>
<div class="dialog-content">
<h4 class="dialog-title">创建任务</h4>
<p class="dialog-subtitle">
在这里展示业务表单或提示文案内容区域已处理最大高度和滚动保证在小屏幕下也能完整展示
</p>
<el-form label-width="80px" class="dialog-form">
<el-form-item label="任务名称">
<el-input
v-model="baseForm.name"
placeholder="请输入任务名称"
/>
</el-form-item>
<el-form-item label="优先级">
<el-select v-model="baseForm.level" placeholder="请选择">
<el-option label="普通" value="normal" />
<el-option label="重要" value="important" />
<el-option label="紧急" value="urgent" />
</el-select>
</el-form-item>
<el-form-item label="备注说明">
<el-input
v-model="baseForm.remark"
type="textarea"
:rows="3"
placeholder="可选填写,补充说明信息"
/>
</el-form-item>
</el-form>
<div class="dialog-footer">
<ComButton plain @click="closeBaseDialog">取消</ComButton>
<ComButton type="primary" @click="submitBaseDialog">
确认提交
</ComButton>
</div>
</div>
</template>
</ComDialog>
</el-card>
</section>
<!-- 内外层嵌套弹框示例 -->
<section class="card-full">
<el-card shadow="hover" class="demo-card">
<template #header>
<div class="card-header">
<h3>内外层嵌套弹框</h3>
<span>适用于详情 + 深层操作的复杂流程</span>
</div>
</template>
<p class="card-description">
外层弹框承载主流程如详情编辑表单当需要处理更深入的步骤如高级设置二次确认
可以在外层内部再打开内层弹框保持上下文不丢失
</p>
<div class="demo-actions">
<ComButton type="primary" @click="openNestedOuter"> 打开嵌套弹框 </ComButton>
</div>
<ComDialog
:dialog-config="nestedDialog"
@closeDialogOuter="handleCloseNestedOuter"
@closeDialogInner="handleCloseNestedInner"
>
<!-- 外层弹框内容 -->
<template #outerContent>
<div class="dialog-content">
<h4 class="dialog-title">用户详情</h4>
<p class="dialog-subtitle">
外层用于展示主要信息和基础操作点击高级设置将打开内层弹框避免页面跳转打断当前上下文
</p>
<el-descriptions :column="2" border class="dialog-descriptions">
<el-descriptions-item label="用户名">
bns_admin
</el-descriptions-item>
<el-descriptions-item label="角色">
超级管理员
</el-descriptions-item>
<el-descriptions-item label="部门"> 技术中心 </el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag type="success">启用</el-tag>
</el-descriptions-item>
</el-descriptions>
<div class="dialog-footer">
<ComButton plain @click="closeNestedOuter">关闭</ComButton>
<ComButton type="primary" @click="openNestedInner">
打开高级设置
</ComButton>
</div>
</div>
</template>
<!-- 内层弹框内容 -->
<template #innerContent>
<div class="dialog-content">
<h4 class="dialog-title">高级设置</h4>
<p class="dialog-subtitle">
内层弹框通常体量较小用于配置少量但影响较大的选项例如权限范围敏感操作确认等
</p>
<el-form label-width="90px" class="dialog-form">
<el-form-item label="数据权限">
<el-select
v-model="nestedForm.scope"
placeholder="请选择数据范围"
>
<el-option label="仅本人" value="self" />
<el-option label="本部门" value="dept" />
<el-option label="本部门及下级" value="dept_child" />
<el-option label="全部数据" value="all" />
</el-select>
</el-form-item>
<el-form-item label="登录保护">
<el-switch v-model="nestedForm.mfa" />
</el-form-item>
</el-form>
<div class="dialog-footer">
<ComButton plain @click="closeNestedInner">取消</ComButton>
<ComButton type="primary" @click="submitNestedInner">
保存设置
</ComButton>
</div>
</div>
</template>
</ComDialog>
</el-card>
</section>
<!-- 使用建议 -->
<section class="card-full guide-card">
<el-card shadow="never">
<template #header>
<div class="card-header">
<h3>使用建议</h3>
<span>保持一致的交互体验与视觉规范</span>
</div>
</template>
<ul class="guide-list">
<li>尽量保证系统中所有弹框都通过 `ComDialog` 使用统一头部样式与位置</li>
<li>外层弹框承担主要流程内层弹框仅在确有必要时使用避免过深的弹框嵌套</li>
<li>
推荐使用 `dialogConfig`
对象集中管理弹框状态与标题避免在多个变量间来回切换
</li>
<li>
关闭弹框时结合 `closeDialogOuter / closeDialogInner`
事件重置表单清理临时状态
</li>
</ul>
</el-card>
</section>
</div>
</template>
<script setup name="ShowDialog">
import { reactive } from 'vue'
import ComDialog from '@/components/ComDialog/index.vue'
import ComButton from '@/components/ComButton/index.vue'
// 基础弹框配置
const baseDialog = reactive({
outerVisible: false,
outerTitle: '基础弹框示例',
outerWidth: '720px',
minHeight: '320px',
maxHeight: '70vh',
// 以下字段用于兼容组件的内层结构(本示例未使用)
innerVisible: false,
})
const baseForm = reactive({
name: '',
level: 'normal',
remark: '',
})
const openBaseDialog = () => {
baseDialog.outerVisible = true
}
const closeBaseDialog = () => {
baseDialog.outerVisible = false
}
const submitBaseDialog = () => {
// 此处可替换为实际提交逻辑
console.log('提交基础弹框表单:', { ...baseForm })
baseDialog.outerVisible = false
}
const handleCloseBaseOuter = () => {
baseDialog.outerVisible = false
}
const handleCloseBaseInner = () => {
baseDialog.innerVisible = false
}
// 内外层嵌套弹框配置
const nestedDialog = reactive({
outerVisible: false,
outerTitle: '外层弹框 · 用户详情',
outerWidth: '760px',
minHeight: '360px',
maxHeight: '75vh',
innerVisible: false,
innerTitle: '内层弹框 · 高级设置',
innerWidth: '520px',
innerMinHeight: '260px',
innerMaxHeight: '60vh',
})
const nestedForm = reactive({
scope: 'dept_child',
mfa: true,
})
const openNestedOuter = () => {
nestedDialog.outerVisible = true
}
const closeNestedOuter = () => {
nestedDialog.outerVisible = false
nestedDialog.innerVisible = false
}
const openNestedInner = () => {
nestedDialog.innerVisible = true
}
const closeNestedInner = () => {
nestedDialog.innerVisible = false
}
const submitNestedInner = () => {
console.log('保存高级设置:', { ...nestedForm })
nestedDialog.innerVisible = false
}
const handleCloseNestedOuter = () => {
closeNestedOuter()
}
const handleCloseNestedInner = () => {
closeNestedInner()
}
</script>
<style scoped>
.dialog-showcase {
display: flex;
flex-direction: column;
gap: 32px;
padding: 32px 40px 48px;
background: linear-gradient(160deg, #f6f8ff 0%, #ffffff 55%, #f9fbff 100%);
min-height: 100%;
}
.intro {
max-width: 720px;
text-align: left;
}
.eyebrow {
font-size: 14px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #5c6aff;
margin-bottom: 12px;
font-weight: 600;
}
.intro h1 {
font-size: 32px;
font-weight: 700;
margin: 0 0 12px;
color: #1f2a56;
}
.subtitle {
font-size: 16px;
line-height: 1.7;
color: #4c5a7a;
margin: 0;
}
.card-full {
width: 100%;
}
.demo-card {
border-radius: 18px;
overflow: hidden;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
}
.card-header h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #1f2a56;
}
.card-header span {
font-size: 14px;
color: #8792b0;
}
.card-description {
font-size: 14px;
line-height: 1.6;
color: #4c5a7a;
margin-bottom: 20px;
}
.demo-actions {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-bottom: 8px;
}
.dialog-content {
display: flex;
flex-direction: column;
gap: 16px;
}
.dialog-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #111827;
}
.dialog-subtitle {
margin: 0;
font-size: 13px;
line-height: 1.6;
color: #6b7280;
}
.dialog-form {
margin-top: 4px;
}
.dialog-descriptions {
margin-top: 8px;
}
.dialog-footer {
margin-top: 12px;
display: flex;
justify-content: flex-end;
gap: 12px;
}
.guide-card :deep(.el-card__body) {
padding: 20px 28px 28px;
}
.guide-list {
margin: 0;
padding-left: 18px;
display: grid;
gap: 10px;
color: #4c5a7a;
font-size: 14px;
line-height: 1.6;
}
.guide-list li {
list-style: disc;
}
@media (max-width: 1024px) {
.dialog-showcase {
padding: 24px 24px 36px;
}
}
@media (max-width: 600px) {
.intro h1 {
font-size: 26px;
}
.subtitle {
font-size: 15px;
}
}
</style>