优化更新
This commit is contained in:
+92
-92
@@ -1,231 +1,231 @@
|
||||
import request from "@/utils/request";
|
||||
import request from '@/utils/request'
|
||||
|
||||
export default {
|
||||
version: {
|
||||
url: `system/index/version`,
|
||||
name: "获取最新版本号",
|
||||
name: '获取最新版本号',
|
||||
get: async function () {
|
||||
return await request.get(this.url);
|
||||
return await request.get(this.url)
|
||||
},
|
||||
},
|
||||
clearcache: {
|
||||
url: `system/index/clearcache`,
|
||||
name: "清除缓存",
|
||||
name: '清除缓存',
|
||||
post: async function () {
|
||||
return await request.post(this.url);
|
||||
return await request.post(this.url)
|
||||
},
|
||||
},
|
||||
info: {
|
||||
url: `system/index/info`,
|
||||
name: "系统信息",
|
||||
name: '系统信息',
|
||||
get: function (data) {
|
||||
return request.get(this.url, data);
|
||||
return request.get(this.url, data)
|
||||
},
|
||||
},
|
||||
setting: {
|
||||
list: {
|
||||
url: `system/setting/index`,
|
||||
name: "获取配置信息",
|
||||
name: '获取配置信息',
|
||||
get: function (params) {
|
||||
return request.get(this.url, params);
|
||||
return request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
url: `system/setting/fields`,
|
||||
name: "获取配置字段",
|
||||
name: '获取配置字段',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/setting/add`,
|
||||
name: "保存配置信息",
|
||||
name: '保存配置信息',
|
||||
post: function (data) {
|
||||
return request.post(this.url, data);
|
||||
return request.post(this.url, data)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/setting/edit`,
|
||||
name: "编辑配置信息",
|
||||
name: '编辑配置信息',
|
||||
post: function (data) {
|
||||
return request.put(this.url, data);
|
||||
return request.put(this.url, data)
|
||||
},
|
||||
},
|
||||
save: {
|
||||
url: `system/setting/save`,
|
||||
name: "保存配置信息",
|
||||
name: '保存配置信息',
|
||||
post: function (data) {
|
||||
return request.put(this.url, data);
|
||||
return request.put(this.url, data)
|
||||
},
|
||||
},
|
||||
},
|
||||
dictionary: {
|
||||
category: {
|
||||
url: `system/dict/category`,
|
||||
name: "获取字典树",
|
||||
name: '获取字典树',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
editcate: {
|
||||
url: `system/dict/editcate`,
|
||||
name: "编辑字典树",
|
||||
name: '编辑字典树',
|
||||
post: async function (data = {}) {
|
||||
return await request.put(this.url, data);
|
||||
return await request.put(this.url, data)
|
||||
},
|
||||
},
|
||||
addcate: {
|
||||
url: `system/dict/addcate`,
|
||||
name: "添加字典树",
|
||||
name: '添加字典树',
|
||||
post: async function (data = {}) {
|
||||
return await request.post(this.url, data);
|
||||
return await request.post(this.url, data)
|
||||
},
|
||||
},
|
||||
delCate: {
|
||||
url: `system/dict/deletecate`,
|
||||
name: "删除字典树",
|
||||
name: '删除字典树',
|
||||
post: async function (data = {}) {
|
||||
return await request.delete(this.url, data);
|
||||
return await request.delete(this.url, data)
|
||||
},
|
||||
},
|
||||
list: {
|
||||
url: `system/dict/lists`,
|
||||
name: "字典明细",
|
||||
name: '字典明细',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
get: {
|
||||
url: `system/dict/detail`,
|
||||
name: "获取字典数据",
|
||||
name: '获取字典数据',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/dict/edit`,
|
||||
name: "编辑字典明细",
|
||||
name: '编辑字典明细',
|
||||
post: async function (data = {}) {
|
||||
return await request.put(this.url, data);
|
||||
return await request.put(this.url, data)
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/dict/add`,
|
||||
name: "添加字典明细",
|
||||
name: '添加字典明细',
|
||||
post: async function (data = {}) {
|
||||
return await request.post(this.url, data);
|
||||
return await request.post(this.url, data)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/dict/delete`,
|
||||
name: "删除字典明细",
|
||||
name: '删除字典明细',
|
||||
post: async function (data = {}) {
|
||||
return await request.delete(this.url, data);
|
||||
return await request.delete(this.url, data)
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
url: `system/dict/detail`,
|
||||
name: "字典明细",
|
||||
name: '字典明细',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
alldic: {
|
||||
url: `system/dict/all`,
|
||||
name: "全部字典",
|
||||
name: '全部字典',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
area: {
|
||||
list: {
|
||||
url: `system/area/index`,
|
||||
name: "地区列表",
|
||||
name: '地区列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, { params })
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/area/add`,
|
||||
name: "地区添加",
|
||||
name: '地区添加',
|
||||
post: async function (params) {
|
||||
return await request.post(this.url, params);
|
||||
return await request.post(this.url, params)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/area/edit`,
|
||||
name: "地区编辑",
|
||||
name: '地区编辑',
|
||||
post: async function (params) {
|
||||
return await request.put(this.url, params);
|
||||
return await request.put(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
app: {
|
||||
list: {
|
||||
url: `system/app/list`,
|
||||
name: "应用列表",
|
||||
name: '应用列表',
|
||||
get: async function () {
|
||||
return await request.get(this.url);
|
||||
return await request.get(this.url)
|
||||
},
|
||||
},
|
||||
},
|
||||
client: {
|
||||
list: {
|
||||
url: `system/client/index`,
|
||||
name: "客户端列表",
|
||||
name: '客户端列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/client/add`,
|
||||
name: "客户端添加",
|
||||
name: '客户端添加',
|
||||
post: async function (params) {
|
||||
return await request.post(this.url, params);
|
||||
return await request.post(this.url, params)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/client/edit`,
|
||||
name: "客户端编辑",
|
||||
name: '客户端编辑',
|
||||
post: async function (params) {
|
||||
return await request.put(this.url, params);
|
||||
return await request.put(this.url, params)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/client/delete`,
|
||||
name: "客户端删除",
|
||||
name: '客户端删除',
|
||||
post: async function (params) {
|
||||
return await request.delete(this.url, params);
|
||||
return await request.delete(this.url, params)
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
list: {
|
||||
url: `system/menu/index`,
|
||||
name: "客户端菜单列表",
|
||||
name: '客户端菜单列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/menu/add`,
|
||||
name: "客户端菜单添加",
|
||||
name: '客户端菜单添加',
|
||||
post: async function (params) {
|
||||
return await request.post(this.url, params);
|
||||
return await request.post(this.url, params)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/menu/edit`,
|
||||
name: "客户端菜单编辑",
|
||||
name: '客户端菜单编辑',
|
||||
post: async function (params) {
|
||||
return await request.put(this.url, params);
|
||||
return await request.put(this.url, params)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/menu/delete`,
|
||||
name: "客户端菜单删除",
|
||||
name: '客户端菜单删除',
|
||||
post: async function (params) {
|
||||
return await request.delete(this.url, params);
|
||||
return await request.delete(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -233,109 +233,109 @@ export default {
|
||||
log: {
|
||||
list: {
|
||||
url: `system/log/index`,
|
||||
name: "日志列表",
|
||||
name: '日志列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
my: {
|
||||
url: `system/log/my`,
|
||||
name: "我的日志",
|
||||
name: '我的日志',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/log/delete`,
|
||||
name: "日志删除",
|
||||
name: '日志删除',
|
||||
post: async function (params) {
|
||||
return await request.delete(this.url, params);
|
||||
return await request.delete(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
tasks: {
|
||||
list: {
|
||||
url: `system/tasks/index`,
|
||||
name: "任务列表",
|
||||
name: '任务列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/tasks/delete`,
|
||||
name: "任务删除",
|
||||
name: '任务删除',
|
||||
post: async function (params) {
|
||||
return await request.delete(this.url, params);
|
||||
return await request.delete(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
crontab: {
|
||||
list: {
|
||||
url: `system/crontab/index`,
|
||||
name: "定时任务列表",
|
||||
name: '定时任务列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
add: {
|
||||
url: `system/crontab/add`,
|
||||
name: "定时任务添加",
|
||||
name: '定时任务添加',
|
||||
post: async function (params) {
|
||||
return await request.post(this.url, params);
|
||||
return await request.post(this.url, params)
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
url: `system/crontab/edit`,
|
||||
name: "定时任务编辑",
|
||||
name: '定时任务编辑',
|
||||
post: async function (params) {
|
||||
return await request.put(this.url, params);
|
||||
return await request.put(this.url, params)
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
url: `system/crontab/delete`,
|
||||
name: "定时任务删除",
|
||||
name: '定时任务删除',
|
||||
post: async function (params) {
|
||||
return await request.delete(this.url, params);
|
||||
return await request.delete(this.url, params)
|
||||
},
|
||||
},
|
||||
log: {
|
||||
url: `system/crontab/log`,
|
||||
name: "定时任务日志",
|
||||
name: '定时任务日志',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
reload: {
|
||||
url: `system/crontab/reload`,
|
||||
name: "定时任务重载",
|
||||
name: '定时任务重载',
|
||||
post: async function (params) {
|
||||
return await request.put(this.url, params);
|
||||
return await request.put(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
modules: {
|
||||
list: {
|
||||
url: `system/modules/index`,
|
||||
name: "模块列表",
|
||||
name: '模块列表',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
update: {
|
||||
url: `system/modules/update`,
|
||||
name: "更新模块",
|
||||
name: '更新模块',
|
||||
post: async function (params) {
|
||||
return await request.post(this.url, params);
|
||||
return await request.post(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
sms: {
|
||||
count: {
|
||||
url: `system/sms/count`,
|
||||
name: "短信发送统计",
|
||||
name: '短信发送统计',
|
||||
get: async function (params) {
|
||||
return await request.get(this.url, params);
|
||||
return await request.get(this.url, params)
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
+468
-397
@@ -1,76 +1,126 @@
|
||||
<template>
|
||||
<div class="sc-table-container" ref="containerRef">
|
||||
<!-- 顶部工具操作块 -->
|
||||
<div class="sc-table-toolbar">
|
||||
<div class="sc-table-toolbar-left">
|
||||
<!-- 自定义操作按钮插槽 -->
|
||||
<slot name="toolbar-left"></slot>
|
||||
<div class="sc-table">
|
||||
<!-- 工具栏 -->
|
||||
<div v-if="showToolbar" class="sc-table-tool">
|
||||
<div class="tool-left">
|
||||
<!-- 左侧工具栏插槽 -->
|
||||
<slot name="toolLeft"></slot>
|
||||
</div>
|
||||
<div class="sc-table-toolbar-right">
|
||||
<!-- 列设置 -->
|
||||
<a-dropdown v-if="showColumnSetting" :trigger="['click']">
|
||||
<a-button size="small" type="text">
|
||||
<SettingOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<div class="sc-table-column-setting">
|
||||
<a-checkbox-group :model-value="visibleColumns" @change="handleColumnChange">
|
||||
<a-checkbox v-for="column in columns" :key="column.key || column.dataIndex"
|
||||
:value="column.key || column.dataIndex">
|
||||
{{ column.title }}
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<!-- 表格尺寸设置 -->
|
||||
<a-dropdown v-if="showSizeSetting" :trigger="['click']">
|
||||
<a-button size="small" type="text">
|
||||
<ColumnHeightOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="handleSizeChange">
|
||||
<a-menu-item key="default">
|
||||
<a-radio :checked="tableSize === 'default'">默认</a-radio>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="middle">
|
||||
<a-radio :checked="tableSize === 'middle'">中等</a-radio>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="small">
|
||||
<a-radio :checked="tableSize === 'small'">紧凑</a-radio>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<div class="tool-right">
|
||||
<!-- 右侧工具栏插槽 -->
|
||||
<slot name="toolRight"></slot>
|
||||
<!-- 刷新按钮 -->
|
||||
<a-button size="small" type="text" @click="handleRefresh">
|
||||
<ReloadOutlined />
|
||||
<a-tooltip v-if="showRefresh" title="刷新">
|
||||
<a-button shape="circle" :loading="loading" @click="handleRefresh">
|
||||
<template #icon>
|
||||
<SyncOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
<!-- 表格设置按钮 -->
|
||||
<a-tooltip v-if="showColumnSetting" title="表格设置">
|
||||
<a-popover v-model:open="tableSettingVisible" placement="bottomRight" trigger="click" :width="240">
|
||||
<template #content>
|
||||
<div class="table-setting">
|
||||
<div class="table-setting-header">
|
||||
<span>表格设置</span>
|
||||
</div>
|
||||
<div class="table-setting-body">
|
||||
<!-- 边框设置 -->
|
||||
<div class="setting-item">
|
||||
<span class="setting-label">显示边框</span>
|
||||
<a-switch v-model:checked="tableSettings.bordered" size="small" />
|
||||
</div>
|
||||
<!-- 表格大小 -->
|
||||
<div class="setting-item">
|
||||
<span class="setting-label">表格大小</span>
|
||||
<a-radio-group v-model:value="tableSettings.size" size="small"
|
||||
button-style="solid">
|
||||
<a-radio-button value="small">小</a-radio-button>
|
||||
<a-radio-button value="middle">中</a-radio-button>
|
||||
<a-radio-button value="large">大</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-button shape="circle">
|
||||
<template #icon>
|
||||
<TableOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</a-tooltip>
|
||||
|
||||
<!-- 列设置按钮 -->
|
||||
<a-tooltip v-if="showColumnSetting" title="列设置">
|
||||
<a-popover v-model:open="columnSettingVisible" placement="bottomRight" trigger="click">
|
||||
<template #content>
|
||||
<div class="column-setting">
|
||||
<div class="column-setting-header">
|
||||
<span>显示与排序</span>
|
||||
</div>
|
||||
<div class="column-setting-list">
|
||||
<div v-for="(colKey, index) in sortedColumns" :key="colKey"
|
||||
class="column-setting-item" :class="{ dragging: draggingIndex === index }"
|
||||
draggable="true" @dragstart="handleDragStart(index, $event)"
|
||||
@dragover="handleDragOver(index, $event)" @dragend="handleDragEnd"
|
||||
@drop="handleDrop(index)">
|
||||
<HolderOutlined class="drag-handle" />
|
||||
<a-checkbox :checked="visibleColumns.includes(colKey)"
|
||||
@change="(e) => toggleColumn(colKey, e.target.checked)">
|
||||
{{ getColumnTitle(colKey) }}
|
||||
</a-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-button shape="circle">
|
||||
<template #icon>
|
||||
<HolderOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间表格内容区域 -->
|
||||
<div class="sc-table-content">
|
||||
<a-table ref="tableRef" :columns="processedColumns" :data-source="dataSource" :loading="loading"
|
||||
:row-key="rowKey" :row-selection="rowSelectionConfig" :scroll="scrollConfig" :size="tableSize"
|
||||
:custom-row="handleRow" @change="handleTableChange" @row-click="handleRowClick"
|
||||
@row-dblclick="handleRowDblClick">
|
||||
<!-- 自定义列插槽 -->
|
||||
<!-- 操作列插槽 -->
|
||||
<template v-if="showActionColumn" #action="scope">
|
||||
<slot name="action" v-bind="scope"></slot>
|
||||
<!-- 表格内容 -->
|
||||
<div class="sc-table-content" ref="tableContent">
|
||||
<a-table :columns="tableColumns" :data-source="dataSource" :loading="loading" :pagination="pagination"
|
||||
:row-key="rowKey" :row-selection="rowSelection" :scroll="scroll" :bordered="tableSettings.bordered"
|
||||
:size="tableSettings.size" :show-header="showHeader" :locale="locale" @change="handleTableChange"
|
||||
@resizeColumn="handleResizeColumn">
|
||||
<!-- 自定义单元格内容 -->
|
||||
<template #bodyCell="{ text, record, index, column }">
|
||||
<!-- 序号列 -->
|
||||
<template v-if="column.dataIndex === '_index'">
|
||||
{{ getTableIndex(index) }}
|
||||
</template>
|
||||
<!-- 自定义插槽 -->
|
||||
<template v-else-if="column.slot">
|
||||
<slot :name="column.slot || column.dataIndex" :text="text" :record="record" :index="index"
|
||||
:column="column"></slot>
|
||||
</template>
|
||||
<!-- 操作列 -->
|
||||
<template v-else-if="column.dataIndex === '_action'">
|
||||
<a-space>
|
||||
<a-button v-for="(action, idx) in actions" :key="idx" type="link" size="small"
|
||||
:disabled="action.disabled" @click="handleAction(action, record, index)">
|
||||
{{ action.label }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- 展开行插槽 -->
|
||||
<template #expandedRowRender="scope">
|
||||
<slot name="expandedRowRender" v-bind="scope"></slot>
|
||||
</template>
|
||||
|
||||
<!-- 空数据提示 -->
|
||||
<template #empty>
|
||||
<a-empty :description="emptyText" />
|
||||
<!-- 空状态 -->
|
||||
<template #emptyText>
|
||||
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" :description="emptyText">
|
||||
<slot name="empty">
|
||||
<span>{{ emptyText }}</span>
|
||||
</slot>
|
||||
</a-empty>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
@@ -78,444 +128,465 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { ref, computed, watch, reactive, useTemplateRef, onMounted } from 'vue'
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import { SyncOutlined, HolderOutlined, TableOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'scTable',
|
||||
})
|
||||
|
||||
/**
|
||||
* 通用表格组件
|
||||
* 基于 Ant Design Vue Table 封装,提供增强功能和便捷使用方式
|
||||
*/
|
||||
|
||||
// 组件属性定义
|
||||
const props = defineProps({
|
||||
// 表格列配置
|
||||
// 数据源
|
||||
dataSource: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 列配置
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
|
||||
// 表格数据源
|
||||
dataSource: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
// 行的唯一标识
|
||||
rowKey: {
|
||||
type: [String, Function],
|
||||
default: 'id',
|
||||
},
|
||||
|
||||
// 加载状态
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
// 行唯一标识
|
||||
rowKey: {
|
||||
type: [String, Function],
|
||||
default: 'id',
|
||||
},
|
||||
|
||||
// 分页配置
|
||||
pagination: {
|
||||
type: Object,
|
||||
type: [Object, Boolean],
|
||||
default: () => ({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条数据`,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
pageSizeOptions: ['20', '50', '100', '200'],
|
||||
}),
|
||||
},
|
||||
|
||||
// 行选择配置
|
||||
rowSelection: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
|
||||
// 表格尺寸
|
||||
// 表格大小
|
||||
size: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: (value) => ['default', 'middle', 'small'].includes(value),
|
||||
default: 'middle', // large, middle, small
|
||||
},
|
||||
|
||||
// 滚动配置
|
||||
scroll: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
// 空数据提示文本
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: '暂无数据',
|
||||
},
|
||||
|
||||
// 是否显示操作列
|
||||
showActionColumn: {
|
||||
// 是否显示边框
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
// 操作列配置
|
||||
actionColumn: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
}),
|
||||
// 是否显示表头
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 本地化配置
|
||||
locale: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// 是否显示序号列
|
||||
showIndex: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 序号列宽度
|
||||
indexColumnWidth: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
// 序号列标题
|
||||
indexTitle: {
|
||||
type: String,
|
||||
default: '序号',
|
||||
},
|
||||
// 是否显示操作列
|
||||
showAction: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 操作列配置
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 操作列宽度
|
||||
actionColumnWidth: {
|
||||
type: Number,
|
||||
default: 200,
|
||||
},
|
||||
// 操作列标题
|
||||
actionTitle: {
|
||||
type: String,
|
||||
default: '操作',
|
||||
},
|
||||
// 是否显示工具栏
|
||||
showToolbar: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否显示刷新按钮
|
||||
showRefresh: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
// 是否显示列设置
|
||||
showColumnSetting: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
// 是否显示尺寸设置
|
||||
showSizeSetting: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
// 初始可见列
|
||||
visibleColumns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
// 空状态文字
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: '暂无数据',
|
||||
},
|
||||
})
|
||||
|
||||
// 事件定义
|
||||
const emit = defineEmits([
|
||||
'change', // 表格变化事件
|
||||
'row-click', // 行点击事件
|
||||
'row-dblclick', // 行双击事件
|
||||
'refresh', // 刷新事件
|
||||
'column-change', // 列显示变化事件
|
||||
'size-change', // 尺寸变化事件
|
||||
'page-change', // 页码变化事件
|
||||
'page-size-change', // 每页条数变化事件
|
||||
'selection-change', // 选择变化事件
|
||||
])
|
||||
|
||||
// 组件引用
|
||||
const containerRef = ref(null)
|
||||
const tableRef = ref(null)
|
||||
|
||||
// 响应式数据
|
||||
const tableSize = ref(props.size)
|
||||
const tableHeight = ref(0)
|
||||
const visibleColumns = ref(props.visibleColumns.length > 0 ? props.visibleColumns : props.columns.map((col) => col.key || col.dataIndex))
|
||||
|
||||
// 计算属性:处理后的列配置
|
||||
const processedColumns = computed(() => {
|
||||
// 过滤可见列并添加scopedSlots配置
|
||||
let result = props.columns
|
||||
.filter((column) => {
|
||||
const columnKey = column.key || column.dataIndex
|
||||
return visibleColumns.value.includes(columnKey)
|
||||
const tableContent = useTemplateRef('tableContent')
|
||||
let scroll = ref({
|
||||
scrollToFirstRowOnChange: true,
|
||||
x: 'max-content',
|
||||
y: 100,
|
||||
})
|
||||
.map((column) => {
|
||||
const columnKey = column.key || column.dataIndex
|
||||
return {
|
||||
...column,
|
||||
scopedSlots: {
|
||||
...column.scopedSlots,
|
||||
// 如果没有自定义scopedSlots,使用columnKey作为默认插槽名
|
||||
customRender: column.scopedSlots?.customRender || columnKey,
|
||||
},
|
||||
|
||||
onMounted(() => {
|
||||
let tableHeight = 100
|
||||
if (props.pagination !== false) {
|
||||
tableHeight = tableContent.value.clientHeight - 100
|
||||
} else {
|
||||
tableHeight = tableContent.value.clientHeight - 65
|
||||
}
|
||||
scroll.value.y = tableHeight
|
||||
})
|
||||
|
||||
// 添加操作列
|
||||
if (props.showActionColumn) {
|
||||
result.push({
|
||||
...props.actionColumn,
|
||||
key: 'action',
|
||||
scopedSlots: {
|
||||
...props.actionColumn.scopedSlots,
|
||||
customRender: 'action',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
// 计算属性:行选择配置
|
||||
const rowSelectionConfig = computed(() => {
|
||||
if (!props.rowSelection) return null
|
||||
|
||||
return {
|
||||
...props.rowSelection,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
emit('selection-change', selectedRowKeys, selectedRows)
|
||||
if (props.rowSelection.onChange) {
|
||||
props.rowSelection.onChange(selectedRowKeys, selectedRows)
|
||||
// 根据表格宽度优化横向滚动配置
|
||||
watch(
|
||||
[() => props.columns, () => props.showIndex, () => props.showAction, tableContent],
|
||||
() => {
|
||||
// 如果列有固定宽度且总宽度较大,使用max-content
|
||||
// 否则使用true让表格自适应
|
||||
const hasFixedColumns = props.columns.some((col) => col.width)
|
||||
if (hasFixedColumns || props.showIndex || props.showAction) {
|
||||
scroll.value.x = 'max-content'
|
||||
} else {
|
||||
scroll.value.x = true
|
||||
}
|
||||
},
|
||||
}
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
// 表格设置状态
|
||||
const tableSettings = reactive({
|
||||
bordered: props.bordered,
|
||||
size: props.size,
|
||||
})
|
||||
|
||||
// 计算属性:滚动配置
|
||||
const scrollConfig = computed(() => {
|
||||
return {
|
||||
y: tableHeight.value,
|
||||
...props.scroll,
|
||||
}
|
||||
// 监听props变化
|
||||
watch(
|
||||
() => props.bordered,
|
||||
(val) => {
|
||||
tableSettings.bordered = val
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.size,
|
||||
(val) => {
|
||||
tableSettings.size = val
|
||||
},
|
||||
)
|
||||
|
||||
const emit = defineEmits(['refresh', 'change', 'resizeColumn', 'action', 'select', 'selectAll', 'selectNone'])
|
||||
|
||||
// 列设置相关
|
||||
const columnSettingVisible = ref(false)
|
||||
const tableSettingVisible = ref(false)
|
||||
const visibleColumns = ref([])
|
||||
const sortedColumns = ref([]) // 排序后的列key数组
|
||||
const draggingIndex = ref(-1) // 当前拖拽的索引
|
||||
|
||||
// 所有列(包含序号和操作列)
|
||||
const allColumns = computed(() => {
|
||||
return props.columns.filter((col) => col.dataIndex && col.dataIndex !== '_index' && col.dataIndex !== '_action')
|
||||
})
|
||||
|
||||
/**
|
||||
* 计算表格高度
|
||||
* 容器高度 - 顶部工具区高度 - 底部分页区高度 - 边距
|
||||
*/
|
||||
const calculateTableHeight = () => {
|
||||
if (!containerRef.value) return 0
|
||||
|
||||
const containerHeight = containerRef.value.offsetHeight
|
||||
const toolbarHeight = 60 // 顶部工具区固定高度
|
||||
const paginationHeight = props.pagination ? 56 : 0 // 分页器高度
|
||||
const margin = 16 // 边距
|
||||
|
||||
return containerHeight - toolbarHeight - paginationHeight - margin
|
||||
// 获取列标题
|
||||
const getColumnTitle = (colKey) => {
|
||||
const col = allColumns.value.find((c) => (c.dataIndex || c.key) === colKey)
|
||||
return col ? col.title : colKey
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整表格高度
|
||||
*/
|
||||
const adjustTableHeight = () => {
|
||||
nextTick(() => {
|
||||
tableHeight.value = calculateTableHeight()
|
||||
})
|
||||
// 初始化可见列和排序
|
||||
watch(
|
||||
() => props.columns,
|
||||
(newColumns) => {
|
||||
const columnKeys = newColumns.filter((col) => col.dataIndex && col.dataIndex !== '_index' && col.dataIndex !== '_action').map((col) => col.dataIndex || col.key)
|
||||
|
||||
// 如果是首次初始化,使用原始顺序
|
||||
if (sortedColumns.value.length === 0) {
|
||||
sortedColumns.value = [...columnKeys]
|
||||
} else {
|
||||
// 保留已存在的顺序,添加新列
|
||||
const existingKeys = sortedColumns.value.filter((key) => columnKeys.includes(key))
|
||||
const newKeys = columnKeys.filter((key) => !existingKeys.includes(key))
|
||||
sortedColumns.value = [...existingKeys, ...newKeys]
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口大小变化监听
|
||||
*/
|
||||
const handleResize = () => {
|
||||
adjustTableHeight()
|
||||
}
|
||||
visibleColumns.value = [...sortedColumns.value]
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
/**
|
||||
* 列设置变化处理
|
||||
* @param {Array} checkedValues - 选中的列key数组
|
||||
*/
|
||||
const handleColumnChange = (checkedValues) => {
|
||||
visibleColumns.value = checkedValues
|
||||
emit('column-change', checkedValues)
|
||||
// 切换列的显示状态
|
||||
const toggleColumn = (colKey, checked) => {
|
||||
if (checked) {
|
||||
if (!visibleColumns.value.includes(colKey)) {
|
||||
visibleColumns.value.push(colKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格尺寸变化处理
|
||||
* @param {Object} menuItem - 菜单项
|
||||
*/
|
||||
const handleSizeChange = ({ key }) => {
|
||||
tableSize.value = key
|
||||
emit('size-change', key)
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格变化处理
|
||||
* @param {Object} pagination - 分页信息
|
||||
* @param {Object} filters - 筛选信息
|
||||
* @param {Object} sorter - 排序信息
|
||||
* @param {Object} extra - 额外信息
|
||||
*/
|
||||
const handleTableChange = (pagination, filters, sorter, extra) => {
|
||||
emit('change', pagination, filters, sorter, extra)
|
||||
}
|
||||
|
||||
/**
|
||||
* 行点击处理
|
||||
* @param {Object} record - 行数据
|
||||
* @param {Event} event - 事件对象
|
||||
*/
|
||||
const handleRowClick = (record, event) => {
|
||||
emit('row-click', record, event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 行双击处理
|
||||
* @param {Object} record - 行数据
|
||||
* @param {Event} event - 事件对象
|
||||
*/
|
||||
const handleRowDblClick = (record, event) => {
|
||||
emit('row-dblclick', record, event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 行配置处理
|
||||
* @param {Object} record - 行数据
|
||||
* @returns {Object} - 行配置
|
||||
*/
|
||||
const handleRow = (record) => {
|
||||
return {
|
||||
onClick: (event) => handleRowClick(record, event),
|
||||
onDblclick: (event) => handleRowDblClick(record, event),
|
||||
} else {
|
||||
visibleColumns.value = visibleColumns.value.filter((key) => key !== colKey)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新表格数据
|
||||
*/
|
||||
// 拖拽开始
|
||||
const handleDragStart = (index, event) => {
|
||||
draggingIndex.value = index
|
||||
event.dataTransfer.effectAllowed = 'move'
|
||||
event.dataTransfer.setData('text/plain', index.toString())
|
||||
}
|
||||
|
||||
// 拖拽经过
|
||||
const handleDragOver = (index, event) => {
|
||||
event.preventDefault()
|
||||
event.dataTransfer.dropEffect = 'move'
|
||||
}
|
||||
|
||||
// 拖拽结束
|
||||
const handleDragEnd = () => {
|
||||
draggingIndex.value = -1
|
||||
}
|
||||
|
||||
// 拖拽放置
|
||||
const handleDrop = (dropIndex) => {
|
||||
if (draggingIndex.value === dropIndex) return
|
||||
|
||||
const draggedKey = sortedColumns.value[draggingIndex.value]
|
||||
const newColumns = [...sortedColumns.value]
|
||||
|
||||
// 移除被拖拽的项
|
||||
newColumns.splice(draggingIndex.value, 1)
|
||||
|
||||
// 插入到新位置
|
||||
newColumns.splice(dropIndex, 0, draggedKey)
|
||||
|
||||
sortedColumns.value = newColumns
|
||||
draggingIndex.value = -1
|
||||
}
|
||||
|
||||
// 处理刷新
|
||||
const handleRefresh = () => {
|
||||
emit('refresh')
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置表格状态
|
||||
*/
|
||||
const resetTable = () => {
|
||||
visibleColumns.value = props.columns.map((col) => col.key || col.dataIndex)
|
||||
tableSize.value = props.size
|
||||
adjustTableHeight()
|
||||
// 处理表格变化(分页、排序、筛选)
|
||||
const handleTableChange = (pagination, filters, sorter, extra) => {
|
||||
emit('change', { pagination, filters, sorter, extra })
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件挂载时执行
|
||||
*/
|
||||
onMounted(() => {
|
||||
// 初始计算表格高度
|
||||
adjustTableHeight()
|
||||
// 处理列宽调整
|
||||
const handleResizeColumn = (width, column) => {
|
||||
emit('resizeColumn', { width, column })
|
||||
}
|
||||
|
||||
// 添加窗口大小变化监听
|
||||
window.addEventListener('resize', handleResize)
|
||||
// 获取表格序号
|
||||
const getTableIndex = (index) => {
|
||||
const { current = 1, pageSize = 10 } = props.pagination || {}
|
||||
return (current - 1) * pageSize + index + 1
|
||||
}
|
||||
|
||||
// 使用 ResizeObserver 监听容器大小变化(更精确)
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
const observer = new ResizeObserver(handleResize)
|
||||
observer.observe(containerRef.value)
|
||||
// 处理操作按钮点击
|
||||
const handleAction = (action, record, index) => {
|
||||
if (action.onClick) {
|
||||
action.onClick(record, index)
|
||||
}
|
||||
emit('action', { action, record, index })
|
||||
}
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
observer.disconnect()
|
||||
// 表格列配置
|
||||
const tableColumns = computed(() => {
|
||||
let columns = []
|
||||
|
||||
// 添加序号列
|
||||
if (props.showIndex) {
|
||||
columns.push({
|
||||
title: props.indexTitle,
|
||||
dataIndex: '_index',
|
||||
key: '_index',
|
||||
width: props.indexColumnWidth,
|
||||
align: 'center',
|
||||
fixed: 'left',
|
||||
})
|
||||
}
|
||||
|
||||
// 添加数据列(按排序顺序)
|
||||
sortedColumns.value.forEach((colKey) => {
|
||||
// 过滤掉未显示的列
|
||||
if (!visibleColumns.value.includes(colKey)) {
|
||||
return
|
||||
}
|
||||
|
||||
const col = props.columns.find((c) => (c.dataIndex || c.key) === colKey)
|
||||
if (col) {
|
||||
columns.push({
|
||||
...col,
|
||||
customRender: col.slot ? undefined : col.customRender,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 组件卸载时执行
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
// 移除窗口大小变化监听
|
||||
window.removeEventListener('resize', handleResize)
|
||||
// 添加操作列
|
||||
if (props.showAction) {
|
||||
columns.push({
|
||||
title: props.actionTitle,
|
||||
dataIndex: '_action',
|
||||
key: '_action',
|
||||
width: props.actionColumnWidth,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
})
|
||||
}
|
||||
|
||||
return columns
|
||||
})
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
refresh: handleRefresh,
|
||||
reset: resetTable,
|
||||
adjustHeight: adjustTableHeight,
|
||||
getVisibleColumns: () => visibleColumns.value,
|
||||
setVisibleColumns: (columns) => {
|
||||
visibleColumns.value = columns
|
||||
emit('column-change', columns)
|
||||
},
|
||||
getTableIndex,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.sc-table-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.sc-table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sc-table-toolbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
|
||||
&-tool {
|
||||
height: 56px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
padding: 0 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sc-table-toolbar-left {
|
||||
.tool-left,
|
||||
.tool-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.sc-table-toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sc-table-content {
|
||||
&-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-table) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-table-container) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-table-body) {
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-pagination) {
|
||||
flex-shrink: 0;
|
||||
margin-top: 16px;
|
||||
padding: 0 4px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-table-wrapper) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-spin-nested-loading) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sc-table-content :deep(.ant-spin-container) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.column-setting {
|
||||
min-width: 200px;
|
||||
|
||||
.sc-table-column-setting {
|
||||
padding: 12px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sc-table-column-setting :deep(.ant-checkbox) {
|
||||
display: block;
|
||||
&-header {
|
||||
padding: 8px 0;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 4px;
|
||||
cursor: move;
|
||||
transition: all 0.2s;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
opacity: 0.5;
|
||||
background: #e6f7ff;
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
margin-right: 8px;
|
||||
color: #999;
|
||||
cursor: grab;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-checkbox-wrapper) {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-setting {
|
||||
min-width: 200px;
|
||||
|
||||
&-header {
|
||||
padding: 8px 0;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&-body {
|
||||
.setting-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px dashed #f0f0f0;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="system-area">
|
||||
<sc-table ref="tableRef" :columns="columns" :data-source="dataSource" :loading="loading"
|
||||
:pagination="pagination" @refresh="loadData" @change="handleTableChange"
|
||||
@selection-change="handleSelectionChange" :show-action-column="true"
|
||||
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: handleSelectionChange }">
|
||||
:pagination="pagination" @refresh="loadData" @change="handleTableChange" :row-selection="rowSelection"
|
||||
:show-action="true" :actions="actions" :show-index="true" :show-striped="true">
|
||||
<!-- 工具栏左侧 -->
|
||||
<template #toolbar-left>
|
||||
<template #toolLeft>
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
@@ -31,16 +30,6 @@
|
||||
<template #level="{ text }">
|
||||
<a-tag color="blue">{{ getLevelText(text) }}</a-tag>
|
||||
</template>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<template #action="{ record }">
|
||||
<a-button size="small" type="link" @click="handleEdit(record)">
|
||||
{{ $t('common.edit') }}
|
||||
</a-button>
|
||||
<a-button size="small" type="link" danger @click="handleDelete(record)">
|
||||
{{ $t('common.delete') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</sc-table>
|
||||
|
||||
<!-- 添加/编辑弹窗 -->
|
||||
@@ -50,9 +39,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import { EnvironmentOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import systemApi from '@/api/system'
|
||||
import ScTable from '@/components/scTable/index.vue'
|
||||
@@ -71,15 +60,7 @@ const dataSource = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
})
|
||||
const pagination = reactive(false)
|
||||
|
||||
// 选中的行
|
||||
const selectedRowKeys = ref([])
|
||||
@@ -89,8 +70,25 @@ const modalVisible = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const currentData = ref({})
|
||||
|
||||
// 行操作配置
|
||||
const rowActions = ref([])
|
||||
// 行选择配置
|
||||
const rowSelection = computed(() => ({
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
onChange: (selectedKeys) => {
|
||||
selectedRowKeys.value = selectedKeys
|
||||
},
|
||||
}))
|
||||
|
||||
// 操作列配置
|
||||
const actions = computed(() => [
|
||||
{
|
||||
label: t('common.edit'),
|
||||
onClick: handleEdit,
|
||||
},
|
||||
{
|
||||
label: t('common.delete'),
|
||||
onClick: handleDelete,
|
||||
},
|
||||
])
|
||||
|
||||
// 添加
|
||||
const handleAdd = () => {
|
||||
@@ -112,14 +110,6 @@ const getLevelText = (level) => {
|
||||
|
||||
// 列配置
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 80,
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: t('common.areaName'),
|
||||
dataIndex: 'title',
|
||||
@@ -165,11 +155,10 @@ const loadData = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
is_tree: 1,
|
||||
}
|
||||
const res = await systemApi.area.list.get(params)
|
||||
if (res.code === 200 || res.code === 1) {
|
||||
if (res.code === 1) {
|
||||
dataSource.value = res.data.list || res.data || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
@@ -182,17 +171,12 @@ const loadData = async () => {
|
||||
}
|
||||
|
||||
// 表格变化处理
|
||||
const handleTableChange = (params) => {
|
||||
if (params.current) pagination.current = params.current
|
||||
if (params.pageSize) pagination.pageSize = params.pageSize
|
||||
const handleTableChange = ({ pagination: newPagination }) => {
|
||||
if (newPagination.current) pagination.current = newPagination.current
|
||||
if (newPagination.pageSize) pagination.pageSize = newPagination.pageSize
|
||||
loadData()
|
||||
}
|
||||
|
||||
// 行选择变化处理
|
||||
const handleSelectionChange = (selectedKeys) => {
|
||||
selectedRowKeys.value = selectedKeys
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record) => {
|
||||
isEdit.value = true
|
||||
@@ -225,21 +209,6 @@ const handleDelete = (record) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化行操作配置(必须在 handleEdit 和 handleDelete 定义之后)
|
||||
rowActions.value = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: t('common.edit'),
|
||||
handler: handleEdit,
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: t('common.delete'),
|
||||
danger: true,
|
||||
handler: handleDelete,
|
||||
},
|
||||
]
|
||||
|
||||
// 批量删除
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
|
||||
Reference in New Issue
Block a user