From 0608f0febbc62b0d48309519964eedbd1c791178 Mon Sep 17 00:00:00 2001 From: molong Date: Fri, 23 Jan 2026 22:05:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/api/auth.js | 69 +++----- src/api/system.js | 138 ++++++---------- src/boot.js | 5 + src/hooks/useTable.js | 239 ++++++++++++++++++++++++++++ src/layouts/components/tags.vue | 223 ++++++++++++++++++++------ src/layouts/index.vue | 7 +- src/pages/auth/department/index.vue | 151 +++++------------- src/pages/auth/role/index.vue | 170 +++++--------------- src/pages/auth/user/index.vue | 140 +++++----------- src/pages/system/log/index.vue | 128 ++++----------- src/router/index.js | 1 + src/stores/modules/layout.js | 12 +- yarn.lock | 5 + 14 files changed, 667 insertions(+), 622 deletions(-) create mode 100644 src/hooks/useTable.js diff --git a/package.json b/package.json index b047b33..8e86124 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "@ant-design/icons-vue": "^7.0.1", "@ckeditor/ckeditor5-vue": "^7.3.0", + "@element-plus/icons-vue": "^2.3.2", "ant-design-vue": "^4.2.6", "axios": "^1.13.2", "ckeditor5": "^47.4.0", diff --git a/src/api/auth.js b/src/api/auth.js index 3472d8b..39d6891 100644 --- a/src/api/auth.js +++ b/src/api/auth.js @@ -2,171 +2,148 @@ import request from '@/utils/request' export default { login: { - url: `auth/login`, name: '用户登录', post: async function (params) { - return await request.post(this.url, params) + return await request.post('auth/login', params) }, }, logout: { - url: `auth/logout`, name: '用户登出', get: async function () { - return await request.get(this.url) + return await request.get('auth/logout') }, }, user: { - url: `auth/user`, name: '获取用户信息', get: async function () { - return await request.get(this.url) + return await request.get('auth/user') }, }, users: { list: { - url: `auth/users/index`, name: "获得用户列表", get: async function (params) { - return await request.get(this.url, { params }); + return await request.get('auth/users/index', { params }); }, }, add: { - url: `auth/users/add`, name: "添加用户", post: async function (params) { - return await request.post(this.url, params); + return await request.post('auth/users/add', params); }, }, edit: { - url: `auth/users/edit`, name: "编辑用户", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/users/edit', params); }, }, uppasswd: { - url: `auth/users/passwd`, name: "修改密码", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/users/passwd', params); }, }, uprole: { - url: `auth/users/uprole`, name: "设置角色", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/users/uprole', params); }, }, delete: { - url: `auth/users/delete`, name: "删除用户", post: async function (params) { - return await request.delete(this.url, params); + return await request.delete('auth/users/delete', params); }, }, }, role: { list: { - url: `auth/role/index`, name: "获得角色列表", get: async function (params) { - return await request.get(this.url, { params }); + return await request.get('auth/role/index', { params }); }, }, add: { - url: `auth/role/add`, name: "添加角色", post: async function (params) { - return await request.post(this.url, params); + return await request.post('auth/role/add', params); }, }, edit: { - url: `auth/role/edit`, name: "编辑角色", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/role/edit', params); }, }, auth: { - url: `auth/role/auth`, name: "角色授权", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/role/auth', params); }, }, delete: { - url: `auth/role/delete`, name: "删除角色", post: async function (params) { - return await request.delete(this.url, params); + return await request.delete('auth/role/delete', params); }, }, }, department: { list: { - url: `auth/department/index`, name: "获得部门列表", get: async function (params) { - return await request.get(this.url, { params }); + return await request.get('auth/department/index', { params }); }, }, add: { - url: `auth/department/add`, name: "添加部门", post: async function (params) { - return await request.post(this.url, params); + return await request.post('auth/department/add', params); }, }, edit: { - url: `auth/department/edit`, name: "编辑部门", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/department/edit', params); }, }, delete: { - url: `auth/department/delete`, name: "删除部门", post: async function (params) { - return await request.delete(this.url, params); + return await request.delete('auth/department/delete', params); }, }, }, menu: { my: { - url: `auth/menu/my`, name: '获取我的菜单', get: async function () { - return await request.get(this.url) + return await request.get('auth/menu/my') }, }, list: { - url: `auth/menu/index`, name: "获取菜单", get: async function (params) { - return await request.get(this.url, { params }); + return await request.get('auth/menu/index', { params }); }, }, add: { - url: `auth/menu/add`, name: "添加菜单", post: async function (params) { - return await request.post(this.url, params); + return await request.post('auth/menu/add', params); }, }, edit: { - url: `auth/menu/edit`, name: "编辑菜单", post: async function (params) { - return await request.put(this.url, params); + return await request.put('auth/menu/edit', params); }, }, delete: { - url: `auth/menu/delete`, name: "删除菜单", post: async function (params) { - return await request.delete(this.url, params); + return await request.delete('auth/menu/delete', params); }, }, }, diff --git a/src/api/system.js b/src/api/system.js index 97f7d57..722df7d 100644 --- a/src/api/system.js +++ b/src/api/system.js @@ -2,347 +2,301 @@ import request from '@/utils/request' export default { version: { - url: `system/index/version`, name: '获取最新版本号', get: async function () { - return await request.get(this.url) + return await request.get('system/index/version') }, }, clearcache: { - url: `system/index/clearcache`, name: '清除缓存', post: async function () { - return await request.post(this.url) + return await request.post('system/index/clearcache') }, }, info: { - url: `system/index/info`, name: '系统信息', get: function (params) { - return request.get(this.url, { params }) + return request.get('system/index/info', { params }) }, }, setting: { list: { - url: `system/setting/index`, name: '获取配置信息', get: function (params) { - return request.get(this.url, { params }) + return request.get('system/setting/index', { params }) }, }, fields: { - url: `system/setting/fields`, name: '获取配置字段', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/setting/fields', { params }) }, }, add: { - url: `system/setting/add`, name: '保存配置信息', post: function (data) { - return request.post(this.url, data) + return request.post('system/setting/add', data) }, }, edit: { - url: `system/setting/edit`, name: '编辑配置信息', post: function (data) { - return request.put(this.url, data) + return request.put('system/setting/edit', data) }, }, save: { - url: `system/setting/save`, name: '保存配置信息', post: function (data) { - return request.put(this.url, data) + return request.put('system/setting/save', data) }, }, }, dictionary: { category: { - url: `system/dict/category`, name: '获取字典树', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/dict/category', { params }) }, }, editcate: { - url: `system/dict/editcate`, name: '编辑字典树', post: async function (data = {}) { - return await request.put(this.url, data) + return await request.put('system/dict/editcate', data) }, }, addcate: { - url: `system/dict/addcate`, name: '添加字典树', post: async function (data = {}) { - return await request.post(this.url, data) + return await request.post('system/dict/addcate', data) }, }, delCate: { - url: `system/dict/deletecate`, name: '删除字典树', post: async function (data = {}) { - return await request.delete(this.url, data) + return await request.delete('system/dict/deletecate', data) }, }, list: { - url: `system/dict/lists`, name: '字典明细', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/dict/lists', { params }) }, }, get: { - url: `system/dict/detail`, name: '获取字典数据', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/dict/detail', { params }) }, }, edit: { - url: `system/dict/edit`, name: '编辑字典明细', post: async function (data = {}) { - return await request.put(this.url, data) + return await request.put('system/dict/edit', data) }, }, add: { - url: `system/dict/add`, name: '添加字典明细', post: async function (data = {}) { - return await request.post(this.url, data) + return await request.post('system/dict/add', data) }, }, delete: { - url: `system/dict/delete`, name: '删除字典明细', post: async function (data = {}) { - return await request.delete(this.url, data) + return await request.delete('system/dict/delete', data) }, }, detail: { - url: `system/dict/detail`, name: '字典明细', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/dict/detail', { params }) }, }, alldic: { - url: `system/dict/all`, name: '全部字典', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/dict/all', { params }) }, }, }, area: { list: { - url: `system/area/index`, name: '地区列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/area/index', { params }) }, }, add: { - url: `system/area/add`, name: '地区添加', post: async function (params) { - return await request.post(this.url, params) + return await request.post('system/area/add', params) }, }, edit: { - url: `system/area/edit`, name: '地区编辑', post: async function (params) { - return await request.put(this.url, params) + return await request.put('system/area/edit', params) }, }, }, app: { list: { - url: `system/app/list`, name: '应用列表', get: async function () { - return await request.get(this.url) + return await request.get('system/app/list') }, }, }, client: { list: { - url: `system/client/index`, name: '客户端列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/client/index', { params }) }, }, add: { - url: `system/client/add`, name: '客户端添加', post: async function (params) { - return await request.post(this.url, params) + return await request.post('system/client/add', params) }, }, edit: { - url: `system/client/edit`, name: '客户端编辑', post: async function (params) { - return await request.put(this.url, params) + return await request.put('system/client/edit', params) }, }, delete: { - url: `system/client/delete`, name: '客户端删除', post: async function (params) { - return await request.delete(this.url, params) + return await request.delete('system/client/delete', params) }, }, menu: { list: { - url: `system/menu/index`, name: '客户端菜单列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/menu/index', { params }) }, }, add: { - url: `system/menu/add`, name: '客户端菜单添加', post: async function (params) { - return await request.post(this.url, params) + return await request.post('system/menu/add', params) }, }, edit: { - url: `system/menu/edit`, name: '客户端菜单编辑', post: async function (params) { - return await request.put(this.url, params) + return await request.put('system/menu/edit', params) }, }, delete: { - url: `system/menu/delete`, name: '客户端菜单删除', post: async function (params) { - return await request.delete(this.url, params) + return await request.delete('system/menu/delete', params) }, }, }, }, log: { list: { - url: `system/log/index`, name: '日志列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/log/index', { params }) }, }, my: { - url: `system/log/my`, name: '我的日志', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/log/my', { params }) }, }, delete: { - url: `system/log/delete`, name: '日志删除', post: async function (params) { - return await request.delete(this.url, params) + return await request.delete('system/log/delete', params) }, }, }, tasks: { list: { - url: `system/tasks/index`, name: '任务列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/tasks/index', { params }) }, }, delete: { - url: `system/tasks/delete`, name: '任务删除', post: async function (params) { - return await request.delete(this.url, params) + return await request.delete('system/tasks/delete', params) }, }, }, crontab: { list: { - url: `system/crontab/index`, name: '定时任务列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/crontab/index', { params }) }, }, add: { - url: `system/crontab/add`, name: '定时任务添加', post: async function (params) { - return await request.post(this.url, params) + return await request.post('system/crontab/add', params) }, }, edit: { - url: `system/crontab/edit`, name: '定时任务编辑', post: async function (params) { - return await request.put(this.url, params) + return await request.put('system/crontab/edit', params) }, }, delete: { - url: `system/crontab/delete`, name: '定时任务删除', post: async function (params) { - return await request.delete(this.url, params) + return await request.delete('system/crontab/delete', params) }, }, log: { - url: `system/crontab/log`, name: '定时任务日志', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/crontab/log', { params }) }, }, reload: { - url: `system/crontab/reload`, name: '定时任务重载', post: async function (params) { - return await request.put(this.url, params) + return await request.put('system/crontab/reload', params) }, }, }, modules: { list: { - url: `system/modules/index`, name: '模块列表', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/modules/index', { params }) }, }, update: { - url: `system/modules/update`, name: '更新模块', post: async function (params) { - return await request.post(this.url, params) + return await request.post('system/modules/update', params) }, }, }, sms: { count: { - url: `system/sms/count`, name: '短信发送统计', get: async function (params) { - return await request.get(this.url, { params }) + return await request.get('system/sms/count', { params }) }, }, }, upload: { - url: `system/file/upload`, name: '文件上传', post: async function (params = {}) { - return await request.post(this.url, params) + return await request.post('system/file/upload', params) }, }, } diff --git a/src/boot.js b/src/boot.js index 1afecda..ee7ffbf 100644 --- a/src/boot.js +++ b/src/boot.js @@ -1,4 +1,5 @@ import * as AIcons from '@ant-design/icons-vue' +import * as ElementPlusIconsVue from '@element-plus/icons-vue' export default { install(app) { @@ -6,5 +7,9 @@ export default { for (let icon in AIcons) { app.component(`${icon}`, AIcons[icon]) } + + for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(`El${key}`, component) + } } } diff --git a/src/hooks/useTable.js b/src/hooks/useTable.js new file mode 100644 index 0000000..766a7b8 --- /dev/null +++ b/src/hooks/useTable.js @@ -0,0 +1,239 @@ +import { ref, reactive, computed, onMounted } from 'vue' +import { message } from 'ant-design-vue' + +/** + * 表格通用hooks + * @param {Object} options 配置选项 + * @param {Function} options.api 获取列表数据的API函数,必须返回包含data和total的响应 + * @param {Object} options.searchForm 搜索表单的初始值 + * @param {Array} options.columns 表格列配置 + * @param {String} options.rowKey 行的唯一标识,默认为'id' + * @param {Boolean} options.needPagination 是否需要分页,默认为true + * @param {Object} options.paginationConfig 分页配置,可选 + * @param {Boolean} options.needSelection 是否需要行选择,默认为false + * @param {Boolean} options.immediateLoad 是否在组件挂载时自动加载数据,默认为true + * @returns {Object} 返回表格相关的状态和方法 + */ +export function useTable(options = {}) { + const { + api, + searchForm: initialSearchForm = {}, + columns = [], + rowKey = 'id', + needPagination = true, + paginationConfig = {}, + needSelection = false, + immediateLoad = true + } = options + + // 表格引用 + const tableRef = ref(null) + + // 搜索表单 + const searchForm = reactive({ ...initialSearchForm }) + + // 表格数据 + const tableData = ref([]) + + // 加载状态 + const loading = ref(false) + + // 选中的行数据 + const selectedRows = ref([]) + + // 选中的行keys + const selectedRowKeys = computed(() => selectedRows.value.map(item => item[rowKey])) + + // 分页配置 + const defaultPaginationConfig = { + current: 1, + pageSize: 20, + total: 0, + showSizeChanger: true, + showTotal: (total) => `共 ${total} 条`, + pageSizeOptions: ['20', '50', '100', '200'] + } + + const pagination = reactive({ + ...defaultPaginationConfig, + ...paginationConfig + }) + + // 行选择配置 + const rowSelection = computed(() => { + if (!needSelection) return null + return { + selectedRowKeys: selectedRowKeys.value, + onChange: (keys, rows) => { + selectedRows.value = rows + } + } + }) + + // 行选择事件处理(用于scTable的@select事件) + const handleSelectChange = (record, selected, selectedRows) => { + if (!needSelection) return + if (selected) { + selectedRows.value.push(record) + } else { + const index = selectedRows.value.findIndex(item => item[rowKey] === record[rowKey]) + if (index > -1) { + selectedRows.value.splice(index, 1) + } + } + } + + // 全选/取消全选处理(用于scTable的@selectAll事件) + const handleSelectAll = (selected, selectedRows, changeRows) => { + if (!needSelection) return + if (selected) { + changeRows.forEach(record => { + if (!selectedRows.value.find(item => item[rowKey] === record[rowKey])) { + selectedRows.value.push(record) + } + }) + } else { + changeRows.forEach(record => { + const index = selectedRows.value.findIndex(item => item[rowKey] === record[rowKey]) + if (index > -1) { + selectedRows.value.splice(index, 1) + } + }) + } + } + + // 加载数据 + const loadData = async (params = {}) => { + if (!api) { + console.warn('useTable: 未提供api函数,无法加载数据') + return + } + + loading.value = true + try { + const requestParams = { + ...searchForm, + ...params + } + + // 如果需要分页,添加分页参数 + if (needPagination) { + requestParams.page = pagination.current + requestParams.limit = pagination.pageSize + } + + // 调用API函数,确保this上下文正确 + const res = await api(requestParams) + + if (res.code === 1) { + // 如果是分页数据 + if (needPagination) { + tableData.value = res.data?.data || [] + pagination.total = res.data?.total || 0 + } else { + // 非分页数据(如树形数据) + tableData.value = res.data || [] + } + } else { + message.error(res.message || '加载数据失败') + } + } catch (error) { + console.error('加载数据失败:', error) + message.error('加载数据失败') + } finally { + loading.value = false + } + } + + // 分页变化处理 + const handlePaginationChange = ({ page, pageSize }) => { + if (!needPagination) return + pagination.current = page + pagination.pageSize = pageSize + loadData() + } + + // 搜索 + const handleSearch = () => { + if (needPagination) { + pagination.current = 1 + } + loadData() + } + + // 重置 + const handleReset = () => { + // 重置搜索表单为初始值 + Object.keys(searchForm).forEach(key => { + searchForm[key] = initialSearchForm[key] + }) + // 清空选择 + selectedRows.value = [] + // 重置分页 + if (needPagination) { + pagination.current = 1 + } + // 重新加载数据 + loadData() + } + + // 刷新表格 + const refreshTable = () => { + loadData() + } + + // 清空选择 + const clearSelection = () => { + selectedRows.value = [] + } + + // 设置选中行 + const setSelectedRows = (rows) => { + selectedRows.value = rows + } + + // 更新搜索表单 + const setSearchForm = (data) => { + Object.assign(searchForm, data) + } + + // 直接设置表格数据(用于特殊场景) + const setTableData = (data) => { + tableData.value = data + } + + // 组件挂载时自动加载数据 + if (immediateLoad) { + onMounted(() => { + loadData() + }) + } + + return { + // ref + tableRef, + // 响应式数据 + searchForm, + tableData, + loading, + pagination, + selectedRows, + selectedRowKeys, + // 配置 + columns, + rowKey, + rowSelection, + // 方法 + loadData, + handleSearch, + handleReset, + handlePaginationChange, + handleSelectChange, + handleSelectAll, + refreshTable, + clearSelection, + setSelectedRows, + setSearchForm, + setTableData + } +} diff --git a/src/layouts/components/tags.vue b/src/layouts/components/tags.vue index 4bdf46f..c5a61e7 100644 --- a/src/layouts/components/tags.vue +++ b/src/layouts/components/tags.vue @@ -1,36 +1,23 @@ @@ -236,6 +317,7 @@ onMounted(() => { .tag-item { display: inline-flex; align-items: center; + gap: 4px; height: 28px; line-height: 28px; padding: 0 12px; @@ -245,6 +327,7 @@ onMounted(() => { border-radius: 2px; cursor: pointer; transition: all 0.3s; + user-select: none; &:hover { color: #1890ff; @@ -262,6 +345,28 @@ onMounted(() => { } } + &.tag-affix { + background-color: #fff7e6; + border-color: #ffd591; + color: #fa8c16; + + &.active { + background-color: #fa8c16; + border-color: #fa8c16; + color: #ffffff; + } + + &:hover { + background-color: #ffe7ba; + border-color: #ffa940; + } + + &.active:hover { + background-color: #d46b08; + border-color: #d46b08; + } + } + :deep(.ant-tag-close-icon) { color: inherit; @@ -289,4 +394,32 @@ onMounted(() => { } } } + +.context-menu { + background: #ffffff; + border-radius: 2px; + box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 9px 28px 8px rgba(0, 0, 0, 0.05); + border: 1px solid #f0f0f0; + padding: 4px 0; + min-width: 160px; + + :deep(.ant-menu) { + background: transparent; + border: none; + box-shadow: none; + padding: 0; + + .ant-menu-item { + margin: 0; + padding: 8px 12px; + height: auto; + line-height: normal; + + &:hover { + background-color: #f5f5f5; + } + } + } +} diff --git a/src/layouts/index.vue b/src/layouts/index.vue index 2100f48..ea33f7a 100644 --- a/src/layouts/index.vue +++ b/src/layouts/index.vue @@ -43,7 +43,7 @@ - + @@ -100,7 +100,7 @@ - + @@ -163,6 +163,9 @@ const layoutClass = computed(() => { } }) +// 获取刷新 key +const refreshKey = computed(() => layoutStore.refreshKey) + const openKeys = ref([]) const selectedKeys = ref([]) const menuList = computed(() => { diff --git a/src/pages/auth/department/index.vue b/src/pages/auth/department/index.vue index 212e5e9..3439709 100644 --- a/src/pages/auth/department/index.vue +++ b/src/pages/auth/department/index.vue @@ -22,14 +22,14 @@ - +
diff --git a/src/pages/auth/role/index.vue b/src/pages/auth/role/index.vue index 190e761..e68e644 100644 --- a/src/pages/auth/role/index.vue +++ b/src/pages/auth/role/index.vue @@ -23,17 +23,17 @@ - + - +