This commit is contained in:
吴红兵
2026-03-07 01:34:48 +08:00
parent adc511cfdc
commit 94c3473958
1211 changed files with 599405 additions and 322105 deletions

View File

@@ -4,17 +4,17 @@
### 1. 入参 `BasicTableProps`
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `createdIsNeed` | `boolean` | **true** | 是否在 `onMounted` 时自动请求列表 |
| `isPage` | `boolean` | true | 是否分页 |
| `queryForm` | `any` | `{}` | 查询条件,会合并到请求参数 |
| `pageList` | `(...arg: any) => Promise<any>` | - | **必填**,分页接口方法 |
| `props` | `object` | `{ item: 'records', totalCount: 'total' }` | 列表/总数的数据路径 |
| `validate` | `Function` | - | 请求前校验,不通过则不请求 |
| `onLoaded` | `Function` | - | 请求成功、写入 `dataList` 后的回调 |
| `onCascaded` | `Function` | - | 级联回调 |
| `pagination` | `Pagination` | 见源码 | 分页配置 |
| 属性 | 类型 | 默认值 | 说明 |
| --------------- | ------------------------------- | ------------------------------------------ | ---------------------------------- |
| `createdIsNeed` | `boolean` | **true** | 是否在 `onMounted` 时自动请求列表 |
| `isPage` | `boolean` | true | 是否分页 |
| `queryForm` | `any` | `{}` | 查询条件,会合并到请求参数 |
| `pageList` | `(...arg: any) => Promise<any>` | - | **必填**,分页接口方法 |
| `props` | `object` | `{ item: 'records', totalCount: 'total' }` | 列表/总数的数据路径 |
| `validate` | `Function` | - | 请求前校验,不通过则不请求 |
| `onLoaded` | `Function` | - | 请求成功、写入 `dataList` 后的回调 |
| `onCascaded` | `Function` | - | 级联回调 |
| `pagination` | `Pagination` | 见源码 | 分页配置 |
### 2. 内部逻辑
@@ -27,12 +27,12 @@
```ts
{
getDataList, // (refresh?: any) => void默认重置到第 1 页再请求getDataList(false) 不重置页码
currentChangeHandle, // 页码变化时调用
sizeChangeHandle, // 每页条数变化时调用
sortChangeHandle, // 排序变化时调用(若表格支持 sortable="custom"
tableStyle, // { cellStyle, headerCellStyle }
downBlobFile // 下载文件
getDataList, // (refresh?: any) => void默认重置到第 1 页再请求getDataList(false) 不重置页码
currentChangeHandle, // 页码变化时调用
sizeChangeHandle, // 每页条数变化时调用
sortChangeHandle, // 排序变化时调用(若表格支持 sortable="custom"
tableStyle, // { cellStyle, headerCellStyle }
downBlobFile; // 下载文件
}
```
@@ -43,17 +43,17 @@
### 1. 定义 state 并传入 useTable
```ts
import { BasicTableProps, useTable } from '/@/hooks/table'
import { BasicTableProps, useTable } from '/@/hooks/table';
const search = reactive({ deptCode: '', realName: '', teacherNo: '' })
const search = reactive({ deptCode: '', realName: '', teacherNo: '' });
const state = reactive<BasicTableProps>({
queryForm: search, // 与 search-form 的 :model 同一对象
pageList: fetchList, // 或自定义方法合并额外参数
// createdIsNeed 不写则默认为 true首屏自动请求
})
queryForm: search, // 与 search-form 的 :model 同一对象
pageList: fetchList, // 或自定义方法合并额外参数
// createdIsNeed 不写则默认为 true首屏自动请求
});
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
```
- **state 由调用方定义并传入**,不要在解构时期望 `useTable` 返回 `state`(源码未返回)。
@@ -78,18 +78,18 @@ const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTa
## 三、professionaltitlerelation/index.vue 检查结果
| 检查项 | 状态 | 说明 |
|--------|------|------|
| queryForm 使用 search | ✅ | 与 search-form 的 model 一致 |
| pageList 返回结构 | ✅ | 返回 `{ data: { records, total } }`,与默认 props 一致 |
| createdIsNeed | ✅ | 未配置即默认 true首屏由 useTable 自动请求 |
| onMounted 不重复请求 | ✅ | 仅 `loadDictData()`,未再调 getDataList |
| 表格绑定 state.dataList / state.loading | ✅ | 正确 |
| 分页绑定 state.pagination + currentChangeHandle/sizeChangeHandle | ✅ | 正确 |
| 查询 handleFilter → getDataList() | ✅ | 正确 |
| 重置 resetQuery → 清空 search + getDataList() | ✅ | 正确 |
| 删除/审核后 getDataList() | ✅ | 正确 |
| tableStyle 用于 el-table | ✅ | 正确 |
| 检查项 | 状态 | 说明 |
| ---------------------------------------------------------------- | ---- | ------------------------------------------------------ |
| queryForm 使用 search | ✅ | 与 search-form 的 model 一致 |
| pageList 返回结构 | ✅ | 返回 `{ data: { records, total } }`,与默认 props 一致 |
| createdIsNeed | ✅ | 未配置即默认 true首屏由 useTable 自动请求 |
| onMounted 不重复请求 | ✅ | 仅 `loadDictData()`,未再调 getDataList |
| 表格绑定 state.dataList / state.loading | ✅ | 正确 |
| 分页绑定 state.pagination + currentChangeHandle/sizeChangeHandle | ✅ | 正确 |
| 查询 handleFilter → getDataList() | ✅ | 正确 |
| 重置 resetQuery → 清空 search + getDataList() | ✅ | 正确 |
| 删除/审核后 getDataList() | ✅ | 正确 |
| tableStyle 用于 el-table | ✅ | 正确 |
**结论**:当前 `professionaltitlerelation/index.vue` 对 hooks/table 的使用符合上述规范,无需修改。

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
`useTableColumnControl` 是一个用于统一管理表格列显示/隐藏和排序功能的 Vue 3 Composition API Hook。它封装了列配置的加载、保存、同步等逻辑让开发者只需几行代码即可实现完整的表格列控制功能。
### 主要功能
- ✅ 列显示/隐藏控制
- ✅ 列排序管理
- ✅ 配置自动保存到本地存储
@@ -17,13 +18,15 @@
## 二、安装和引入
### 文件位置
```
src/hooks/tableColumn.ts
```
### 引入方式
```typescript
import { useTableColumnControl, type TableColumn } from '/@/hooks/tableColumn'
import { useTableColumnControl, type TableColumn } from '/@/hooks/tableColumn';
```
---
@@ -43,102 +46,96 @@ import { useTableColumnControl, type TableColumn } from '/@/hooks/tableColumn'
### 2. 定义表格列配置
```typescript
import { User, Calendar, Phone } from '@element-plus/icons-vue'
import { User, Calendar, Phone } from '@element-plus/icons-vue';
const tableColumns = [
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{ prop: 'phone', label: '电话', icon: Phone }
]
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{ prop: 'phone', label: '电话', icon: Phone },
];
```
### 3. 使用 Hook
```typescript
const {
visibleColumns,
visibleColumnsSorted,
checkColumnVisible,
handleColumnChange,
handleColumnOrderChange
} = useTableColumnControl(tableColumns)
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
```
### 4. 在模板中使用
```vue
<template>
<div class="modern-page-container">
<div class="page-wrapper">
<!-- 搜索表单卡片 -->
<el-card v-show="showSearch" class="search-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Search /></el-icon>
筛选条件
</span>
</div>
</template>
<el-form class="search-form">
<!-- 搜索表单项 -->
</el-form>
</el-card>
<div class="modern-page-container">
<div class="page-wrapper">
<!-- 搜索表单卡片 -->
<el-card v-show="showSearch" class="search-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Search /></el-icon>
筛选条件
</span>
</div>
</template>
<el-form class="search-form">
<!-- 搜索表单项 -->
</el-form>
</el-card>
<!-- 内容卡片 -->
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Document /></el-icon>
数据列表
</span>
<div class="header-actions">
<!-- TableColumnControl 组件 -->
<TableColumnControl
:columns="tableColumns"
v-model="visibleColumns"
@change="handleColumnChange"
@order-change="handleColumnOrderChange"
/>
</div>
</div>
</template>
<!-- 内容卡片 -->
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Document /></el-icon>
数据列表
</span>
<div class="header-actions">
<!-- TableColumnControl 组件 -->
<TableColumnControl
:columns="tableColumns"
v-model="visibleColumns"
@change="handleColumnChange"
@order-change="handleColumnOrderChange"
/>
</div>
</div>
</template>
<!-- 表格 -->
<el-table :data="dataList" stripe class="modern-table">
<el-table-column type="index" label="序号" width="70">
<template #default="{ $index }">
{{ $index + 1 + ((pagination?.current || 1) - 1) * (pagination?.size || 10) }}
</template>
</el-table-column>
<!-- 动态渲染列 -->
<template v-for="col in visibleColumnsSorted" :key="col.prop">
<el-table-column
v-if="checkColumnVisible(col.prop || '')"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
>
<template #header>
<el-icon v-if="col.icon">
<component :is="col.icon" />
</el-icon>
<span style="margin-left: 4px">{{ col.label }}</span>
</template>
</el-table-column>
</template>
</el-table>
<!-- 表格 -->
<el-table :data="dataList" stripe class="modern-table">
<el-table-column type="index" label="序号" width="70">
<template #default="{ $index }">
{{ $index + 1 + ((pagination?.current || 1) - 1) * (pagination?.size || 10) }}
</template>
</el-table-column>
<!-- 分页 -->
<div class="pagination-wrapper">
<pagination v-bind="pagination" />
</div>
</el-card>
</div>
</div>
<!-- 动态渲染列 -->
<template v-for="col in visibleColumnsSorted" :key="col.prop">
<el-table-column
v-if="checkColumnVisible(col.prop || '')"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
>
<template #header>
<el-icon v-if="col.icon">
<component :is="col.icon" />
</el-icon>
<span style="margin-left: 4px">{{ col.label }}</span>
</template>
</el-table-column>
</template>
</el-table>
<!-- 分页 -->
<div class="pagination-wrapper">
<pagination v-bind="pagination" />
</div>
</el-card>
</div>
</div>
</template>
```
@@ -148,86 +145,80 @@ const {
```vue
<template>
<div>
<right-toolbar>
<TableColumnControl
ref="columnControlRef"
:columns="tableColumns"
v-model="visibleColumns"
trigger-type="default"
trigger-circle
@change="handleColumnChange"
@order-change="handleColumnOrderChange"
>
<template #trigger>
<el-tooltip content="列设置" placement="top">
<el-button circle>
<el-icon><Menu /></el-icon>
</el-button>
</el-tooltip>
</template>
</TableColumnControl>
</right-toolbar>
<div>
<right-toolbar>
<TableColumnControl
ref="columnControlRef"
:columns="tableColumns"
v-model="visibleColumns"
trigger-type="default"
trigger-circle
@change="handleColumnChange"
@order-change="handleColumnOrderChange"
>
<template #trigger>
<el-tooltip content="列设置" placement="top">
<el-button circle>
<el-icon><Menu /></el-icon>
</el-button>
</el-tooltip>
</template>
</TableColumnControl>
</right-toolbar>
<el-table :data="state.dataList" stripe>
<el-table-column type="index" label="序号" width="70">
<template #default="{ $index }">
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
</template>
</el-table-column>
<el-table :data="state.dataList" stripe>
<el-table-column type="index" label="序号" width="70">
<template #default="{ $index }">
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
</template>
</el-table-column>
<template v-for="col in visibleColumnsSorted" :key="col.prop">
<el-table-column
v-if="checkColumnVisible(col.prop || '')"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
show-overflow-tooltip
>
<template #header>
<el-icon v-if="col.icon">
<component :is="col.icon" />
</el-icon>
<span style="margin-left: 4px">{{ col.label }}</span>
</template>
</el-table-column>
</template>
<template v-for="col in visibleColumnsSorted" :key="col.prop">
<el-table-column
v-if="checkColumnVisible(col.prop || '')"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
show-overflow-tooltip
>
<template #header>
<el-icon v-if="col.icon">
<component :is="col.icon" />
</el-icon>
<span style="margin-left: 4px">{{ col.label }}</span>
</template>
</el-table-column>
</template>
<el-table-column label="操作" width="180" fixed="right">
<!-- 操作列内容 -->
</el-table-column>
</el-table>
</div>
<el-table-column label="操作" width="180" fixed="right">
<!-- 操作列内容 -->
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useTableColumnControl } from '/@/hooks/tableColumn'
import { User, Calendar, Phone, Menu } from '@element-plus/icons-vue'
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
import { ref } from 'vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import { User, Calendar, Phone, Menu } from '@element-plus/icons-vue';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
// 定义表格列
const tableColumns = [
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{ prop: 'phone', label: '电话', icon: Phone }
]
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{ prop: 'phone', label: '电话', icon: Phone },
];
// 使用 Hook
const {
visibleColumns,
visibleColumnsSorted,
checkColumnVisible,
handleColumnChange,
handleColumnOrderChange
} = useTableColumnControl(tableColumns)
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
const columnControlRef = ref()
const columnControlRef = ref();
const state = ref({
dataList: [],
pagination: { current: 1, size: 10 }
})
dataList: [],
pagination: { current: 1, size: 10 },
});
</script>
```
@@ -239,37 +230,37 @@ const state = ref({
```typescript
interface TableColumn {
prop?: string // 列属性名
label?: string // 列标题
icon?: any // 列图标组件
width?: number | string // 列宽度
minWidth?: number | string // 最小宽度
showOverflowTooltip?: boolean // 是否显示溢出提示
align?: 'left' | 'center' | 'right' // 对齐方式
alwaysShow?: boolean // 是否始终显示(不参与列控制)
fixed?: boolean | 'left' | 'right' // 是否固定列
[key: string]: any // 其他自定义属性
prop?: string; // 列属性名
label?: string; // 列标题
icon?: any; // 列图标组件
width?: number | string; // 列宽度
minWidth?: number | string; // 最小宽度
showOverflowTooltip?: boolean; // 是否显示溢出提示
align?: 'left' | 'center' | 'right'; // 对齐方式
alwaysShow?: boolean; // 是否始终显示(不参与列控制)
fixed?: boolean | 'left' | 'right'; // 是否固定列
[key: string]: any; // 其他自定义属性
}
```
### Hook 返回值
| 属性/方法 | 类型 | 说明 |
|----------|------|------|
| `visibleColumns` | `Ref<string[]>` | 当前可见的列 key 数组 |
| `columnOrder` | `Ref<string[]>` | 列排序顺序数组 |
| `visibleColumnsSorted` | `ComputedRef<TableColumn[]>` | 排序后的可见列配置数组 |
| `checkColumnVisible` | `(prop: string) => boolean` | 检查列是否可见 |
| `handleColumnChange` | `(value: string[]) => void` | 处理列显示变化 |
| `handleColumnOrderChange` | `(order: string[]) => void` | 处理列排序变化 |
| `loadSavedConfig` | `() => void` | 手动加载保存的配置 |
| 属性/方法 | 类型 | 说明 |
| ------------------------- | ---------------------------- | ---------------------- |
| `visibleColumns` | `Ref<string[]>` | 当前可见的列 key 数组 |
| `columnOrder` | `Ref<string[]>` | 列排序顺序数组 |
| `visibleColumnsSorted` | `ComputedRef<TableColumn[]>` | 排序后的可见列配置数组 |
| `checkColumnVisible` | `(prop: string) => boolean` | 检查列是否可见 |
| `handleColumnChange` | `(value: string[]) => void` | 处理列显示变化 |
| `handleColumnOrderChange` | `(order: string[]) => void` | 处理列排序变化 |
| `loadSavedConfig` | `() => void` | 手动加载保存的配置 |
### Hook 选项参数
```typescript
interface Options {
autoLoad?: boolean // 是否自动加载配置,默认 true
storageKey?: string // 自定义存储 key默认使用路由路径
autoLoad?: boolean; // 是否自动加载配置,默认 true
storageKey?: string; // 自定义存储 key默认使用路由路径
}
```
@@ -282,15 +273,12 @@ interface Options {
如果不想使用默认的路由路径作为存储 key可以自定义
```typescript
const {
visibleColumns,
visibleColumnsSorted,
checkColumnVisible,
handleColumnChange,
handleColumnOrderChange
} = useTableColumnControl(tableColumns, {
storageKey: 'custom-table-columns-key'
})
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(
tableColumns,
{
storageKey: 'custom-table-columns-key',
}
);
```
### 2. 禁用自动加载
@@ -298,21 +286,15 @@ const {
如果需要在特定时机手动加载配置:
```typescript
const {
visibleColumns,
visibleColumnsSorted,
checkColumnVisible,
handleColumnChange,
handleColumnOrderChange,
loadSavedConfig
} = useTableColumnControl(tableColumns, {
autoLoad: false
})
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange, loadSavedConfig } =
useTableColumnControl(tableColumns, {
autoLoad: false,
});
// 在需要的时候手动加载
onMounted(() => {
loadSavedConfig()
})
loadSavedConfig();
});
```
### 3. 固定列和始终显示的列
@@ -321,15 +303,15 @@ onMounted(() => {
```typescript
const tableColumns = [
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{
prop: 'action',
label: '操作',
alwaysShow: true, // 始终显示
fixed: 'right' // 固定在右侧
}
]
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
{
prop: 'action',
label: '操作',
alwaysShow: true, // 始终显示
fixed: 'right', // 固定在右侧
},
];
```
### 4. 特殊列模板
@@ -338,23 +320,19 @@ const tableColumns = [
```vue
<template v-for="col in visibleColumnsSorted" :key="col.prop">
<el-table-column
v-if="checkColumnVisible(col.prop || '')"
:prop="col.prop"
:label="col.label"
>
<!-- 状态列特殊模板 -->
<template v-if="col.prop === 'status'" #default="scope">
<el-tag :type="scope.row.status === '1' ? 'success' : 'warning'">
{{ scope.row.status }}
</el-tag>
</template>
<!-- 其他列默认显示 -->
<template v-else #default="scope">
{{ scope.row[col.prop] }}
</template>
</el-table-column>
<el-table-column v-if="checkColumnVisible(col.prop || '')" :prop="col.prop" :label="col.label">
<!-- 状态列特殊模板 -->
<template v-if="col.prop === 'status'" #default="scope">
<el-tag :type="scope.row.status === '1' ? 'success' : 'warning'">
{{ scope.row.status }}
</el-tag>
</template>
<!-- 其他列默认显示 -->
<template v-else #default="scope">
{{ scope.row[col.prop] }}
</template>
</el-table-column>
</template>
```
@@ -369,15 +347,12 @@ const tableColumns = [
```typescript
// ✅ 正确
const tableColumns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' }
]
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
];
// ❌ 错误:两个列都没有 prop
const tableColumns = [
{ label: '姓名' },
{ label: '年龄' }
]
const tableColumns = [{ label: '姓名' }, { label: '年龄' }];
```
### 2. 响应式更新
@@ -386,12 +361,12 @@ const tableColumns = [
```typescript
const tableColumns = ref([
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' }
])
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
]);
// 动态添加列
tableColumns.value.push({ prop: 'phone', label: '电话' })
tableColumns.value.push({ prop: 'phone', label: '电话' });
```
### 3. 配置存储位置
@@ -405,12 +380,15 @@ tableColumns.value.push({ prop: 'phone', label: '电话' })
Hook 默认在组件挂载时自动加载配置。如果需要在数据加载后重新加载:
```typescript
const { loadSavedConfig } = useTableColumnControl(tableColumns)
const { loadSavedConfig } = useTableColumnControl(tableColumns);
watch(() => someData.value, () => {
// 数据变化后重新加载配置
loadSavedConfig()
})
watch(
() => someData.value,
() => {
// 数据变化后重新加载配置
loadSavedConfig();
}
);
```
---
@@ -424,23 +402,23 @@ watch(() => someData.value, () => {
```typescript
// 扩展 Hook
function useTableColumnControlWithWidth(tableColumns: TableColumn[]) {
const baseHook = useTableColumnControl(tableColumns)
const columnWidths = ref<Record<string, number>>({})
const baseHook = useTableColumnControl(tableColumns);
const columnWidths = ref<Record<string, number>>({});
const handleColumnWidthChange = (prop: string, width: number) => {
columnWidths.value[prop] = width
// 保存到本地存储
const storageKey = getStorageKey()
const config = getTableConfigFromLocal(storageKey) || {}
config.columnWidths = columnWidths.value
saveTableConfigToLocal(storageKey, config)
}
const handleColumnWidthChange = (prop: string, width: number) => {
columnWidths.value[prop] = width;
// 保存到本地存储
const storageKey = getStorageKey();
const config = getTableConfigFromLocal(storageKey) || {};
config.columnWidths = columnWidths.value;
saveTableConfigToLocal(storageKey, config);
};
return {
...baseHook,
columnWidths,
handleColumnWidthChange
}
return {
...baseHook,
columnWidths,
handleColumnWidthChange,
};
}
```
@@ -450,24 +428,24 @@ function useTableColumnControlWithWidth(tableColumns: TableColumn[]) {
```typescript
function useTableColumnControlWithFixed(tableColumns: TableColumn[]) {
const baseHook = useTableColumnControl(tableColumns)
const fixedColumns = ref<string[]>([])
const baseHook = useTableColumnControl(tableColumns);
const fixedColumns = ref<string[]>([]);
const toggleColumnFixed = (prop: string) => {
const index = fixedColumns.value.indexOf(prop)
if (index > -1) {
fixedColumns.value.splice(index, 1)
} else {
fixedColumns.value.push(prop)
}
// 保存配置
}
const toggleColumnFixed = (prop: string) => {
const index = fixedColumns.value.indexOf(prop);
if (index > -1) {
fixedColumns.value.splice(index, 1);
} else {
fixedColumns.value.push(prop);
}
// 保存配置
};
return {
...baseHook,
fixedColumns,
toggleColumnFixed
}
return {
...baseHook,
fixedColumns,
toggleColumnFixed,
};
}
```
@@ -476,22 +454,17 @@ function useTableColumnControlWithFixed(tableColumns: TableColumn[]) {
如果需要按分组管理列:
```typescript
function useTableColumnControlWithGroup(
tableColumns: TableColumn[],
groups: Record<string, string[]>
) {
const baseHook = useTableColumnControl(tableColumns)
const getColumnsByGroup = (groupName: string) => {
return tableColumns.filter(col =>
groups[groupName]?.includes(col.prop || '')
)
}
function useTableColumnControlWithGroup(tableColumns: TableColumn[], groups: Record<string, string[]>) {
const baseHook = useTableColumnControl(tableColumns);
return {
...baseHook,
getColumnsByGroup
}
const getColumnsByGroup = (groupName: string) => {
return tableColumns.filter((col) => groups[groupName]?.includes(col.prop || ''));
};
return {
...baseHook,
getColumnsByGroup,
};
}
```
@@ -501,13 +474,13 @@ function useTableColumnControlWithGroup(
```typescript
function useTableColumnControlWithCustomStorage(
tableColumns: TableColumn[],
storageAdapter: {
get: (key: string) => Promise<any>
set: (key: string, value: any) => Promise<void>
}
tableColumns: TableColumn[],
storageAdapter: {
get: (key: string) => Promise<any>;
set: (key: string, value: any) => Promise<void>;
}
) {
// 实现自定义存储逻辑
// 实现自定义存储逻辑
}
```
@@ -518,6 +491,7 @@ function useTableColumnControlWithCustomStorage(
### Q1: 为什么配置没有保存?
**A:** 检查以下几点:
1. 确保 `handleColumnChange``handleColumnOrderChange` 已正确绑定到组件
2. 检查浏览器控制台是否有错误
3. 确认 API 调用是否成功(检查网络请求)
@@ -538,11 +512,11 @@ function useTableColumnControlWithCustomStorage(
```typescript
// 清除本地存储
localStorage.removeItem('user-table-configs-all')
localStorage.removeItem('user-table-configs-all');
// 或通过 API 删除
import { deleteUserTableConfig } from '/@/api/admin/usertable'
deleteUserTableConfig(storageKey)
import { deleteUserTableConfig } from '/@/api/admin/usertable';
deleteUserTableConfig(storageKey);
```
### Q4: 如何在多个页面共享列配置?
@@ -551,8 +525,8 @@ deleteUserTableConfig(storageKey)
```typescript
const { visibleColumns } = useTableColumnControl(tableColumns, {
storageKey: 'shared-table-columns'
})
storageKey: 'shared-table-columns',
});
```
---
@@ -565,12 +539,12 @@ const { visibleColumns } = useTableColumnControl(tableColumns, {
```typescript
// src/views/xxx/columns.ts
import { User, Calendar } from '@element-plus/icons-vue'
import { User, Calendar } from '@element-plus/icons-vue';
export const tableColumns = [
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar }
]
{ prop: 'name', label: '姓名', icon: User },
{ prop: 'age', label: '年龄', icon: Calendar },
];
```
### 2. 类型定义
@@ -578,11 +552,9 @@ export const tableColumns = [
为列配置添加类型约束:
```typescript
import type { TableColumn } from '/@/hooks/tableColumn'
import type { TableColumn } from '/@/hooks/tableColumn';
const tableColumns: TableColumn[] = [
{ prop: 'name', label: '姓名', icon: User }
]
const tableColumns: TableColumn[] = [{ prop: 'name', label: '姓名', icon: User }];
```
### 3. 统一命名
@@ -600,25 +572,25 @@ const tableColumns: TableColumn[] = [
### 从旧实现迁移到 Hook
**旧代码(~90 行):**
```typescript
const visibleColumns = ref<string[]>([])
const columnOrder = ref<string[]>([])
const loadSavedConfig = () => { /* ... */ }
const handleColumnChange = () => { /* ... */ }
const visibleColumns = ref<string[]>([]);
const columnOrder = ref<string[]>([]);
const loadSavedConfig = () => {
/* ... */
};
const handleColumnChange = () => {
/* ... */
};
// ... 更多代码
```
**新代码(~5 行):**
```typescript
import { useTableColumnControl } from '/@/hooks/tableColumn'
const {
visibleColumns,
visibleColumnsSorted,
checkColumnVisible,
handleColumnChange,
handleColumnOrderChange
} = useTableColumnControl(tableColumns)
```typescript
import { useTableColumnControl } from '/@/hooks/tableColumn';
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
```
### 迁移步骤
@@ -633,6 +605,7 @@ const {
## 十二、更新日志
### v1.0.0 (2024-01-XX)
- ✅ 初始版本发布
- ✅ 支持列显示/隐藏控制
- ✅ 支持列排序管理
@@ -653,6 +626,7 @@ const {
## 十四、贡献指南
如果发现 bug 或有改进建议,请:
1. 提交 Issue 描述问题
2. 提交 Pull Request 提供修复方案
3. 更新本文档说明变更
@@ -660,4 +634,3 @@ const {
---
**最后更新2024-01-XX**

View File

@@ -16,83 +16,77 @@
```vue
<template>
<!-- 搜索表单 -->
<search-form
v-show="showSearch"
:model="search"
ref="searchFormRef"
@keyup-enter="handleFilter(search)"
>
<!-- 表单项 -->
</search-form>
<!-- 搜索表单 -->
<search-form v-show="showSearch" :model="search" ref="searchFormRef" @keyup-enter="handleFilter(search)">
<!-- 表单项 -->
</search-form>
<!-- 表格 -->
<el-table :data="tableData" v-loading="tableLoading">
<!-- 表格列 -->
</el-table>
<!-- 表格 -->
<el-table :data="tableData" v-loading="tableLoading">
<!-- 表格列 -->
</el-table>
<!-- 分页 -->
<pagination
:current="page.currentPage"
:size="page.pageSize"
:total="page.total"
@currentChange="currentChange"
@sizeChange="handleSizeChange"
/>
<!-- 分页 -->
<pagination :current="page.currentPage" :size="page.pageSize" :total="page.total" @currentChange="currentChange" @sizeChange="handleSizeChange" />
</template>
<script setup lang="ts">
const search = reactive({
deptCode: '',
realName: '',
teacherNo: '',
// ... 其他字段
})
deptCode: '',
realName: '',
teacherNo: '',
// ... 其他字段
});
const tableData = ref([])
const tableLoading = ref(false)
const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
const params = ref<any>({})
currentPage: 1,
pageSize: 10,
total: 0,
});
const params = ref<any>({});
// 手动实现数据加载
const getList = (page: any) => {
tableLoading.value = true
fetchList(Object.assign({
current: page.currentPage,
size: page.pageSize
}, params.value)).then((response: any) => {
tableData.value = response.data.record.records
page.total = response.data.record.total
tableLoading.value = false
})
}
tableLoading.value = true;
fetchList(
Object.assign(
{
current: page.currentPage,
size: page.pageSize,
},
params.value
)
).then((response: any) => {
tableData.value = response.data.record.records;
page.total = response.data.record.total;
tableLoading.value = false;
});
};
// 手动实现分页
const currentChange = (val: number) => {
page.currentPage = val
getList(page)
}
page.currentPage = val;
getList(page);
};
const handleSizeChange = (val: number) => {
page.pageSize = val
page.currentPage = 1
getList(page)
}
page.pageSize = val;
page.currentPage = 1;
getList(page);
};
// 查询
const handleFilter = (param: any) => {
params.value = { ...param }
page.currentPage = 1
getList(page)
}
params.value = { ...param };
page.currentPage = 1;
getList(page);
};
onMounted(() => {
getList(page)
})
getList(page);
});
</script>
```
@@ -100,130 +94,114 @@ onMounted(() => {
```vue
<template>
<!-- 搜索表单 - 保持不变 -->
<search-form
v-show="showSearch"
:model="search"
ref="searchFormRef"
@keyup-enter="handleFilter(search)"
>
<!-- 表单项 -->
</search-form>
<!-- 搜索表单 - 保持不变 -->
<search-form v-show="showSearch" :model="search" ref="searchFormRef" @keyup-enter="handleFilter(search)">
<!-- 表单项 -->
</search-form>
<!-- 表格 - 使用 state.dataList state.loading -->
<el-table
:data="state.dataList"
v-loading="state.loading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<!-- 表格列 -->
</el-table>
<!-- 表格 - 使用 state.dataList state.loading -->
<el-table :data="state.dataList" v-loading="state.loading" :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle">
<!-- 表格列 -->
</el-table>
<!-- 分页 - 使用 state.pagination -->
<pagination
:current="state.pagination.current"
:size="state.pagination.size"
:total="state.pagination.total"
@currentChange="currentChangeHandle"
@sizeChange="sizeChangeHandle"
/>
<!-- 分页 - 使用 state.pagination -->
<pagination
:current="state.pagination.current"
:size="state.pagination.size"
:total="state.pagination.total"
@currentChange="currentChangeHandle"
@sizeChange="sizeChangeHandle"
/>
</template>
<script setup lang="ts">
import { BasicTableProps, useTable } from '/@/hooks/table'
import { fetchList } from '/@/api/professional/teacherbase'
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList } from '/@/api/professional/teacherbase';
// 搜索表单数据 - 保持不变
const search = reactive({
deptCode: '',
realName: '',
teacherNo: '',
// ... 其他字段
})
deptCode: '',
realName: '',
teacherNo: '',
// ... 其他字段
});
// 额外参数(如 flag 等)
const params = ref<any>({})
const params = ref<any>({});
// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
// 将 search 对象作为 queryForm
queryForm: search,
// 自定义 pageList 方法,合并额外参数
pageList: async (queryParams: any) => {
// 合并 search 和 params 中的额外参数
return await fetchList({
...queryParams,
...params.value
})
},
// 数据属性映射(根据后端返回结构调整)
props: {
item: 'record.records', // 数据列表路径
totalCount: 'record.total' // 总数字段路径
},
// 数据加载完成后的回调
onLoaded: async (state) => {
// 数据转换逻辑
state.dataList = convertDictData(state.dataList)
// 其他处理逻辑(如 auditAll
// ...
}
})
// 将 search 对象作为 queryForm
queryForm: search,
// 自定义 pageList 方法,合并额外参数
pageList: async (queryParams: any) => {
// 合并 search 和 params 中的额外参数
return await fetchList({
...queryParams,
...params.value,
});
},
// 数据属性映射(根据后端返回结构调整)
props: {
item: 'record.records', // 数据列表路径
totalCount: 'record.total', // 总数字段路径
},
// 数据加载完成后的回调
onLoaded: async (state) => {
// 数据转换逻辑
state.dataList = convertDictData(state.dataList);
// 其他处理逻辑(如 auditAll
// ...
},
});
// 使用 useTable Hook
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
tableStyle,
state
} = useTable(state)
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, state } = useTable(state);
// 查询方法 - 简化
const handleFilter = (param: any) => {
// 更新额外参数
params.value = { ...param }
// 调用 getDataList 刷新数据(会自动跳转到第一页)
getDataList()
}
// 更新额外参数
params.value = { ...param };
// 调用 getDataList 刷新数据(会自动跳转到第一页)
getDataList();
};
// 重置查询
const resetQuery = () => {
searchFormRef.value?.formRef?.resetFields()
// 重置 search 对象
Object.keys(search).forEach(key => {
search[key] = ''
})
params.value = {}
getDataList()
}
searchFormRef.value?.formRef?.resetFields();
// 重置 search 对象
Object.keys(search).forEach((key) => {
search[key] = '';
});
params.value = {};
getDataList();
};
// 其他需要刷新表格的地方
const handelQuickSeach = (val: any) => {
params.value.flag = val
getDataList() // 使用 getDataList 替代 getList(page)
}
params.value.flag = val;
getDataList(); // 使用 getDataList 替代 getList(page)
};
const updateInoutFlag = (row: any, val: any) => {
const updateParams = {"teacherNo": row.teacherNo, "inoutFlag": val}
messageBox.confirm('确认操作?').then(() => {
updateInout(updateParams).then((res: any) => {
message.success("修改成功")
getDataList(false) // 刷新但保持当前页
})
})
}
const updateParams = { teacherNo: row.teacherNo, inoutFlag: val };
messageBox.confirm('确认操作?').then(() => {
updateInout(updateParams).then((res: any) => {
message.success('修改成功');
getDataList(false); // 刷新但保持当前页
});
});
};
// 数据转换函数(保持不变)
const convertDictData = (records: any[]) => {
// ... 转换逻辑
return records
}
// ... 转换逻辑
return records;
};
</script>
```
@@ -232,20 +210,20 @@ const convertDictData = (records: any[]) => {
### 1. 导入 useTable
```typescript
import { BasicTableProps, useTable } from '/@/hooks/table'
import { BasicTableProps, useTable } from '/@/hooks/table';
```
### 2. 配置 state
```typescript
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search, // 将 search 对象作为 queryForm
pageList: fetchList, // 或自定义方法
props: {
item: 'record.records',
totalCount: 'record.total'
}
})
queryForm: search, // 将 search 对象作为 queryForm
pageList: fetchList, // 或自定义方法
props: {
item: 'record.records',
totalCount: 'record.total',
},
});
```
### 3. 处理额外参数
@@ -255,49 +233,49 @@ const state: BasicTableProps = reactive<BasicTableProps>({
#### 方式一:自定义 pageList 方法(推荐)
```typescript
const params = ref<any>({})
const params = ref<any>({});
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search,
pageList: async (queryParams: any) => {
// 合并额外参数
return await fetchList({
...queryParams,
...params.value // 合并额外参数
})
}
})
queryForm: search,
pageList: async (queryParams: any) => {
// 合并额外参数
return await fetchList({
...queryParams,
...params.value, // 合并额外参数
});
},
});
```
#### 方式二:在 onLoaded 中处理
```typescript
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search,
pageList: fetchList,
onLoaded: async (state) => {
// 可以在这里处理数据转换等逻辑
}
})
queryForm: search,
pageList: fetchList,
onLoaded: async (state) => {
// 可以在这里处理数据转换等逻辑
},
});
```
### 4. 替换数据引用
| 原代码 | 改造后 |
|--------|--------|
| `tableData` | `state.dataList` |
| `tableLoading` | `state.loading` |
| 原代码 | 改造后 |
| ------------------ | -------------------------- |
| `tableData` | `state.dataList` |
| `tableLoading` | `state.loading` |
| `page.currentPage` | `state.pagination.current` |
| `page.pageSize` | `state.pagination.size` |
| `page.total` | `state.pagination.total` |
| `page.pageSize` | `state.pagination.size` |
| `page.total` | `state.pagination.total` |
### 5. 替换方法调用
| 原代码 | 改造后 |
|--------|--------|
| `getList(page)` | `getDataList()``getDataList(false)` |
| `currentChange(val)` | `currentChangeHandle(val)` |
| `handleSizeChange(val)` | `sizeChangeHandle(val)` |
| 原代码 | 改造后 |
| ----------------------- | --------------------------------------- |
| `getList(page)` | `getDataList()``getDataList(false)` |
| `currentChange(val)` | `currentChangeHandle(val)` |
| `handleSizeChange(val)` | `sizeChangeHandle(val)` |
### 6. 处理数据转换
@@ -305,114 +283,108 @@ const state: BasicTableProps = reactive<BasicTableProps>({
```typescript
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search,
pageList: fetchList,
onLoaded: async (state) => {
// 字典数据转换
state.dataList = convertDictData(state.dataList)
// 处理 auditAll 等逻辑
// 注意:需要在 API 响应中获取,或通过其他方式处理
}
})
queryForm: search,
pageList: fetchList,
onLoaded: async (state) => {
// 字典数据转换
state.dataList = convertDictData(state.dataList);
// 处理 auditAll 等逻辑
// 注意:需要在 API 响应中获取,或通过其他方式处理
},
});
```
## 完整改造示例(针对当前页面)
```typescript
// 1. 导入 useTable
import { BasicTableProps, useTable } from '/@/hooks/table'
import { BasicTableProps, useTable } from '/@/hooks/table';
// 2. 搜索表单数据(保持不变)
const search = reactive({
deptCode: '',
secDeptCode: '',
tied: '',
realName: '',
teacherNo: '',
retireDate: '',
pfTitleId: '',
stationDutyLevelId: '',
politicsStatus: '',
teacherCate: '',
inoutFlag: ''
})
deptCode: '',
secDeptCode: '',
tied: '',
realName: '',
teacherNo: '',
retireDate: '',
pfTitleId: '',
stationDutyLevelId: '',
politicsStatus: '',
teacherCate: '',
inoutFlag: '',
});
// 3. 额外参数(用于 flag 等)
const params = ref<any>({})
const params = ref<any>({});
// 4. 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search, // 将 search 作为 queryForm
// 自定义 pageList合并额外参数
pageList: async (queryParams: any) => {
// 合并 search 和 params
const mergedParams = {
...queryParams,
...params.value,
tied: search.tied // 如果需要特殊处理
}
return await fetchList(mergedParams)
},
// 数据属性映射
props: {
item: 'record.records',
totalCount: 'record.total'
},
// 数据加载完成回调
onLoaded: async (state) => {
// 字典数据转换
state.dataList = convertDictData(state.dataList)
// 注意auditAll 需要从 API 响应中获取
// 如果 API 返回在 response.data.auditAll需要特殊处理
}
})
queryForm: search, // 将 search 作为 queryForm
// 自定义 pageList合并额外参数
pageList: async (queryParams: any) => {
// 合并 search 和 params
const mergedParams = {
...queryParams,
...params.value,
tied: search.tied, // 如果需要特殊处理
};
return await fetchList(mergedParams);
},
// 数据属性映射
props: {
item: 'record.records',
totalCount: 'record.total',
},
// 数据加载完成回调
onLoaded: async (state) => {
// 字典数据转换
state.dataList = convertDictData(state.dataList);
// 注意auditAll 需要从 API 响应中获取
// 如果 API 返回在 response.data.auditAll需要特殊处理
},
});
// 5. 使用 useTable
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
tableStyle,
state
} = useTable(state)
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, state } = useTable(state);
// 6. 查询方法(简化)
const handleFilter = (param: any) => {
params.value = { ...param }
getDataList() // 自动跳转到第一页
}
params.value = { ...param };
getDataList(); // 自动跳转到第一页
};
// 7. 重置查询
const resetQuery = () => {
searchFormRef.value?.formRef?.resetFields()
Object.keys(search).forEach(key => {
search[key] = ''
})
params.value = {}
getDataList()
}
searchFormRef.value?.formRef?.resetFields();
Object.keys(search).forEach((key) => {
search[key] = '';
});
params.value = {};
getDataList();
};
// 8. 快速查询
const handelQuickSeach = (val: any) => {
params.value.flag = val
getDataList()
}
params.value.flag = val;
getDataList();
};
// 9. 其他需要刷新的地方
const updateInoutFlag = (row: any, val: any) => {
const updateParams = {"teacherNo": row.teacherNo, "inoutFlag": val}
messageBox.confirm('确认操作?').then(() => {
updateInout(updateParams).then((res: any) => {
message.success("修改成功")
getDataList(false) // 保持当前页
})
})
}
const updateParams = { teacherNo: row.teacherNo, inoutFlag: val };
messageBox.confirm('确认操作?').then(() => {
updateInout(updateParams).then((res: any) => {
message.success('修改成功');
getDataList(false); // 保持当前页
});
});
};
```
## 注意事项
@@ -434,12 +406,12 @@ props: {
```typescript
pageList: async (queryParams: any) => {
return await fetchList({
...queryParams,
...params.value, // 额外参数
// 或其他特殊参数
})
}
return await fetchList({
...queryParams,
...params.value, // 额外参数
// 或其他特殊参数
});
};
```
### 3. 数据转换
@@ -448,8 +420,8 @@ pageList: async (queryParams: any) => {
```typescript
onLoaded: async (state) => {
state.dataList = convertDictData(state.dataList)
}
state.dataList = convertDictData(state.dataList);
};
```
### 4. 特殊响应字段
@@ -458,20 +430,20 @@ onLoaded: async (state) => {
```typescript
pageList: async (queryParams: any) => {
const response = await fetchList({
...queryParams,
...params.value
})
// 处理特殊字段
if (response.data.auditAll == '0') {
auditAll.value = false
} else {
auditAll.value = true
}
return response
}
const response = await fetchList({
...queryParams,
...params.value,
});
// 处理特殊字段
if (response.data.auditAll == '0') {
auditAll.value = false;
} else {
auditAll.value = true;
}
return response;
};
```
### 5. 初始化数据加载
@@ -480,17 +452,17 @@ pageList: async (queryParams: any) => {
```typescript
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search,
pageList: fetchList,
createdIsNeed: false // 禁用自动加载
})
queryForm: search,
pageList: fetchList,
createdIsNeed: false, // 禁用自动加载
});
// 手动调用
onMounted(() => {
init()
loadSearchDictData()
getDataList() // 手动加载
})
init();
loadSearchDictData();
getDataList(); // 手动加载
});
```
## 优势总结
@@ -513,4 +485,3 @@ onMounted(() => {
4. 使用 `currentChangeHandle``sizeChangeHandle` 替代手动分页方法
如果有额外参数或特殊处理,使用自定义 `pageList` 方法或 `onLoaded` 回调即可。

View File

@@ -6,7 +6,7 @@
**所有按钮统一使用默认尺寸**,不需要设置 `size` 属性。
- 高度32pxElement Plus默认
- 高度32pxElement Plus 默认)
- 适用于所有场景:页面操作区域、表格操作列、对话框底部等
```vue
@@ -16,21 +16,22 @@
## 二、颜色
| 操作类型 | type | plain | 颜色 | 使用场景 |
|---------|------|-------|------|---------|
| 主要操作 | `primary` | - | 蓝色实心 | 新增、保存、提交 |
| 查询 | `primary` | - | 蓝色实心 | 查询 |
| 重置 | - | - | 灰色 | 重置 |
| 导出操作 | `warning` | ✓ | 橙色边框 | 导出、下载 |
| 导入操作 | `primary` | ✓ | 蓝色边框 | 导入、上传 |
| 设置操作 | `primary` | ✓ | 蓝色边框 | 设置、配置 |
| 同步操作 | `primary` | ✓ | 蓝色边框 | 同步、连接 |
| 状态锁定 | - | - | 灰色 | 状态锁定、解锁 |
| 危险操作 | `danger` | - | 红色实心 | 删除、清空 |
| 操作类型 | type | plain | 颜色 | 使用场景 |
| -------- | --------- | ----- | -------- | ---------------- |
| 主要操作 | `primary` | - | 蓝色实心 | 新增、保存、提交 |
| 查询 | `primary` | - | 蓝色实心 | 查询 |
| 重置 | - | - | 灰色 | 重置 |
| 导出操作 | `warning` | ✓ | 橙色边框 | 导出、下载 |
| 导入操作 | `primary` | ✓ | 蓝色边框 | 导入、上传 |
| 设置操作 | `primary` | ✓ | 蓝色边框 | 设置、配置 |
| 同步操作 | `primary` | ✓ | 蓝色边框 | 同步、连接 |
| 状态锁定 | - | - | 灰色 | 状态锁定、解锁 |
| 危险操作 | `danger` | - | 红色实心 | 删除、清空 |
## 三、样式
### 1. 实心按钮(默认)
- **使用场景**:新增、保存、删除等主要操作
- **代码**`type="primary"``type="danger"`
@@ -39,7 +40,8 @@
<el-button type="danger" icon="Delete"> </el-button>
```
### 2. Plain按钮边框样式
### 2. Plain 按钮(边框样式)
- **使用场景**:重置、导出、导入、设置、同步等次要操作
- **代码**`type="primary" plain``type="warning" plain`
@@ -52,6 +54,7 @@
```
### 3. 设置按钮
- **使用场景**:设置、配置等操作
- **代码**`type="primary" plain`
@@ -60,6 +63,7 @@
```
### 4. 同步按钮
- **使用场景**:同步、连接等操作
- **代码**`type="primary" plain`
@@ -68,6 +72,7 @@
```
### 5. 默认按钮(灰色)
- **使用场景**:状态锁定、解锁等中性操作
- **代码**:不设置 `type` 属性
@@ -76,6 +81,7 @@
```
### 6. 表格操作列按钮link
- **使用场景**:表格操作列,使用 `link` 属性
- **代码**`link` 属性,配合 `type` 使用
- **说明**:表格内的操作按钮统一使用 `link` 样式,节省空间
@@ -93,25 +99,25 @@
### 常用图标映射
| 操作类型 | 图标名称 |
|---------|---------|
| 查询 | `Search` |
| 重置 | `Refresh` |
| 新增/添加 | `FolderAdd` |
| 导出/下载 | `Download` |
| 导入/上传 | `UploadFilled` |
| 编辑/修改 | `EditPen` |
| 删除 | `Delete` |
| 批量删除 | `DocumentDelete` |
| 通过 | `CircleCheck` |
| 驳回 | `CircleClose` |
| 查看图片 | `Picture` |
| 详情/其他 | `Document` |
| 设置/配置 | `Setting` |
| 锁定/解锁 | `Lock` |
| 用户相关 | `User` |
| 调动/转换 | `Switch` |
| 同步/连接 | `Connection` |
| 操作类型 | 图标名称 |
| --------- | ---------------- |
| 查询 | `Search` |
| 重置 | `Refresh` |
| 新增/添加 | `FolderAdd` |
| 导出/下载 | `Download` |
| 导入/上传 | `UploadFilled` |
| 编辑/修改 | `EditPen` |
| 删除 | `Delete` |
| 批量删除 | `DocumentDelete` |
| 通过 | `CircleCheck` |
| 驳回 | `CircleClose` |
| 查看图片 | `Picture` |
| 详情/其他 | `Document` |
| 设置/配置 | `Setting` |
| 锁定/解锁 | `Lock` |
| 用户相关 | `User` |
| 调动/转换 | `Switch` |
| 同步/连接 | `Connection` |
### 使用示例
@@ -126,7 +132,7 @@
## 五、间距
按钮之间使用 `class="ml10"` 保持10px的左边距确保按钮组视觉统一。
按钮之间使用 `class="ml10"` 保持 10px 的左边距,确保按钮组视觉统一。
```vue
<el-button type="primary" icon="FolderAdd"> </el-button>
@@ -229,15 +235,15 @@
## 七、快速参考
| 要素 | 规范 |
|------|------|
| **尺寸** | 统一使用默认尺寸,不设置 `size` 属性 |
| **颜色** | 主要操作用蓝色实心,次要操作用蓝色/橙色边框,危险操作用红色 |
| 要素 | 规范 |
| -------- | --------------------------------------------------------------- |
| **尺寸** | 统一使用默认尺寸,不设置 `size` 属性 |
| **颜色** | 主要操作用蓝色实心,次要操作用蓝色/橙色边框,危险操作用红色 |
| **样式** | 主要操作用实心,次要操作用 `plain`**表格操作列必须用 `link`** |
| **图标** | 所有按钮必须配合图标,使用 PascalCase 格式 |
| **间距** | 按钮之间使用 `class="ml10"` 保持10px间距 |
| **图标** | 所有按钮必须配合图标,使用 PascalCase 格式 |
| **间距** | 按钮之间使用 `class="ml10"` 保持 10px 间距 |
---
**维护者:** 前端开发团队
**最后更新:** 2024年
**最后更新:** 2024

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long