445 lines
12 KiB
Vue
445 lines
12 KiB
Vue
<template>
|
||
<div class="table-showcase">
|
||
<section class="intro">
|
||
<p class="eyebrow">组件展示 · Table</p>
|
||
<h1>表格组件设计指南</h1>
|
||
<p class="subtitle">
|
||
基于配置驱动的列表查询组件,通过简单的配置即可快速构建包含查询表单和数据表格的完整页面,支持丰富的表单类型和表格功能。
|
||
</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-content">
|
||
<ComTable
|
||
:size="`large`"
|
||
:show-action="true"
|
||
:show-toolbar="true"
|
||
:load-data="loadData"
|
||
@action="handleAction"
|
||
:form-columns="formColumns"
|
||
:table-columns="tableColumns"
|
||
:action-columns="actionColumns"
|
||
:show-more-action="true"
|
||
:more-action-count="2"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<!-- 工具栏插槽 -->
|
||
<template #toolbar>
|
||
<ComButton type="primary" icon="Plus" @click="handleAdd"
|
||
>新增</ComButton
|
||
>
|
||
<ComButton
|
||
type="danger"
|
||
icon="Delete"
|
||
:disabled="!multipleSelection.length"
|
||
@click="handleBatchDelete"
|
||
>
|
||
批量删除
|
||
</ComButton>
|
||
</template>
|
||
|
||
<!-- 状态列自定义渲染 -->
|
||
<template #status="{ row }">
|
||
<el-tag :type="row.status === '1' ? 'success' : 'danger'">
|
||
{{ row.status === '1' ? '启用' : '禁用' }}
|
||
</el-tag>
|
||
</template>
|
||
</ComTable>
|
||
</div>
|
||
</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>
|
||
<div class="config-demo">
|
||
<div class="config-section">
|
||
<h4>表单配置(formColumns)</h4>
|
||
<pre class="code-block">{{ formConfigExample }}</pre>
|
||
</div>
|
||
<div class="config-section">
|
||
<h4>表格配置(tableColumns)</h4>
|
||
<pre class="code-block">{{ tableConfigExample }}</pre>
|
||
</div>
|
||
<div class="config-section">
|
||
<h4>搜索字段示例(本次查询参数)</h4>
|
||
<p class="config-tip">
|
||
在上方查询表单中输入条件并点击「搜索」后,这里会实时展示本次请求携带的查询字段名及其对应的值。
|
||
</p>
|
||
<pre class="code-block">{{ searchParamsDisplay }}</pre>
|
||
</div>
|
||
</div>
|
||
</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>表单和表格组件采用职责分离设计,可独立使用,也可组合使用。</li>
|
||
<li>通过配置驱动的方式定义表单字段和表格列,减少重复代码。</li>
|
||
<li>表单组件已二次封装,提供统一的接口和样式,便于维护和扩展。</li>
|
||
<li>支持插槽自定义渲染,满足复杂场景的定制化需求。</li>
|
||
<li>表格支持分页、选择、操作列等常用功能,开箱即用。</li>
|
||
<li>数据加载通过 loadData 函数统一处理,便于对接后端接口。</li>
|
||
</ul>
|
||
</el-card>
|
||
</section>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup name="ShowTable">
|
||
import { ref, computed } from 'vue'
|
||
import ComTable from '@/components/ComTable/index.vue'
|
||
import ComButton from '@/components/ComButton/index.vue'
|
||
import { formColumns, tableColumns, actionColumns } from './config'
|
||
|
||
const multipleSelection = ref([])
|
||
|
||
// 配置示例代码(与当前 config 保持一致,只展示核心字段)
|
||
const formConfigExample = `[
|
||
{
|
||
type: 'input', // 文本输入
|
||
prop: 'queryTableName', // 查询字段名
|
||
placeholder: '请输入表格名称',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
type: 'select', // 下拉选择
|
||
prop: 'queryStatus',
|
||
placeholder: '请选择状态',
|
||
options: [
|
||
{ label: '启用', value: '1' },
|
||
{ label: '禁用', value: '0' },
|
||
],
|
||
},
|
||
{
|
||
type: 'cascader', // 级联选择
|
||
prop: 'queryClass',
|
||
placeholder: '请选择班级',
|
||
options: [/* 班级层级数据 */],
|
||
},
|
||
{
|
||
type: 'date', // 日期区间
|
||
prop: 'queryDateRange',
|
||
dateType: 'daterange',
|
||
paramsList: ['queryStartDate', 'queryEndDate'],
|
||
valueFormat: 'YYYY-MM-DD',
|
||
startPlaceholder: '开始日期',
|
||
endPlaceholder: '结束日期',
|
||
},
|
||
{
|
||
type: 'date', // 月份区间
|
||
prop: 'queryMonthRange',
|
||
dateType: 'monthrange',
|
||
paramsList: ['queryStartMonth', 'queryEndMonth'],
|
||
valueFormat: 'YYYY-MM',
|
||
},
|
||
{
|
||
type: 'date', // 单选年份
|
||
prop: 'queryYear',
|
||
dateType: 'year',
|
||
valueFormat: 'YYYY',
|
||
},
|
||
]`
|
||
|
||
const tableConfigExample = `[
|
||
{
|
||
prop: 'tableName', // 字段名
|
||
label: '表格名称', // 列标题
|
||
width: 180,
|
||
align: 'left',
|
||
showOverflowTooltip: true,
|
||
},
|
||
{
|
||
prop: 'status',
|
||
label: '状态',
|
||
width: 100,
|
||
slot: 'status', // 使用插槽自定义单元格
|
||
},
|
||
]`
|
||
|
||
// 当前查询参数展示(演示用)
|
||
const lastQueryParams = ref({})
|
||
const searchParamsDisplay = computed(() => {
|
||
const data = lastQueryParams.value || {}
|
||
const keys = Object.keys(data || {})
|
||
if (!keys.length) {
|
||
return '// 暂未触发查询,先在上方表单中输入条件并点击“搜索”\n'
|
||
}
|
||
return JSON.stringify(data, null, 2)
|
||
})
|
||
|
||
// 模拟数据加载函数
|
||
const loadData = async (params) => {
|
||
console.log('加载数据,参数:', params)
|
||
// 记录本次查询参数,供下方“搜索字段”展示
|
||
lastQueryParams.value = params || {}
|
||
|
||
// 模拟 API 请求
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
const mockData = {
|
||
rows: [
|
||
{
|
||
id: 1,
|
||
tableName: '用户表',
|
||
status: '1',
|
||
createTime: '2024-01-01 10:00:00',
|
||
remark: '用户信息表,存储系统用户的基本信息',
|
||
},
|
||
{
|
||
id: 2,
|
||
tableName: '角色表',
|
||
status: '1',
|
||
createTime: '2024-01-02 10:00:00',
|
||
remark: '角色信息表,存储系统角色和权限信息',
|
||
},
|
||
{
|
||
id: 3,
|
||
tableName: '菜单表',
|
||
status: '0',
|
||
createTime: '2024-01-03 10:00:00',
|
||
remark: '菜单信息表,存储系统菜单和路由信息',
|
||
},
|
||
{
|
||
id: 4,
|
||
tableName: '部门表',
|
||
status: '1',
|
||
createTime: '2024-01-04 10:00:00',
|
||
remark: '部门信息表,存储组织架构信息',
|
||
},
|
||
{
|
||
id: 5,
|
||
tableName: '字典表',
|
||
status: '1',
|
||
createTime: '2024-01-05 10:00:00',
|
||
remark: '字典信息表,存储系统字典数据',
|
||
},
|
||
],
|
||
total: 5,
|
||
}
|
||
resolve(mockData)
|
||
}, 500)
|
||
})
|
||
}
|
||
|
||
// 选择变化
|
||
const handleSelectionChange = (selection) => {
|
||
multipleSelection.value = selection
|
||
console.log('选择变化:', selection)
|
||
}
|
||
|
||
// 操作按钮处理
|
||
const handleAction = (action, row, index) => {
|
||
console.log('操作:', action, row, index)
|
||
}
|
||
|
||
// 新增
|
||
const handleAdd = () => {
|
||
console.log('新增')
|
||
}
|
||
|
||
// 编辑
|
||
const handleEdit = (row) => {
|
||
console.log('编辑', row)
|
||
}
|
||
|
||
// 删除
|
||
const handleDelete = (row) => {
|
||
console.log('删除', row)
|
||
}
|
||
|
||
// 批量删除
|
||
const handleBatchDelete = () => {
|
||
console.log('批量删除', multipleSelection.value)
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.table-showcase {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 32px;
|
||
padding: 18px;
|
||
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: 24px;
|
||
}
|
||
|
||
.demo-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.guide-card :deep(.el-card__body) {
|
||
padding: 20px 28px 28px;
|
||
}
|
||
|
||
.config-demo {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
.config-section h4 {
|
||
margin: 0 0 12px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1f2a56;
|
||
}
|
||
|
||
.code-block {
|
||
background: #f8f9fa;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
color: #2c3e50;
|
||
overflow-x: auto;
|
||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||
border: 1px solid #e9ecef;
|
||
}
|
||
|
||
.config-tip {
|
||
margin: 0 0 8px;
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
|
||
/* 覆盖组件内部样式 */
|
||
.demo-content :deep(.search-form-card) {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.demo-content :deep(.search-form-card .el-card__body) {
|
||
padding: 18px 20px 0;
|
||
}
|
||
|
||
.demo-content :deep(.data-table-card) {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
@media (max-width: 1024px) {
|
||
.table-showcase {
|
||
padding: 24px 24px 36px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 600px) {
|
||
.intro h1 {
|
||
font-size: 26px;
|
||
}
|
||
|
||
.subtitle {
|
||
font-size: 15px;
|
||
}
|
||
|
||
.config-demo {
|
||
gap: 16px;
|
||
}
|
||
|
||
.code-block {
|
||
font-size: 12px;
|
||
padding: 12px;
|
||
}
|
||
}
|
||
</style>
|