diff --git a/src/api/service/types.d.ts b/src/api/service/types.d.ts index 8334d9b..4de84be 100644 --- a/src/api/service/types.d.ts +++ b/src/api/service/types.d.ts @@ -7,6 +7,17 @@ export interface BaseResult { message: string; } +export interface ResultTable { + /** 列表数据 */ + list: Array; + /** 总条目数 */ + total?: number; + /** 每页显示条目个数 */ + pageSize?: number; + /** 当前页数 */ + pageNo?: number; +} + export type resultType = { accessToken?: string; }; diff --git a/src/api/v1/i18n.ts b/src/api/v1/i18n.ts index 18b8eea..ec5d74d 100644 --- a/src/api/v1/i18n.ts +++ b/src/api/v1/i18n.ts @@ -1,9 +1,65 @@ import { http } from '@/api/service/mockRequest'; -import type { Result } from '@/types/store/baseStoreState'; +import type { BaseResult } from '@/api/service/types'; /** * * 获取多语言内容 */ export const fetchGetI18n = () => { - return http.request>('get', 'getI18n'); + return http.request>('get', 'i18n/getI18n'); +}; + +/** + * 多语言管理---获取多语言列表 + */ +export const fetchGetI18nList = (data: any) => { + return http.request>('get', `i18n/getI18nList/${data.page}/${data.pageSize}`, { data }); +}; + +/** + * 多语言管理---添加多语言 + */ +export const fetchAddI18n = (data: any) => { + return http.request>('post', 'i18n/addI18n', { data }); +}; + +/** + * 多语言管理---更新多语言 + */ +export const fetchUpdateI18n = (data: any) => { + return http.request>('put', 'i18n/updateI18n', { data }); +}; + +/** + * 多语言管理---删除多语言 + */ +export const fetchDeleteI18n = (data: any) => { + return http.request>('put', 'i18n/deleteI18n', { data }); +}; + +/** + * 多语言类型管理---获取多语言类型列表 + */ +export const fetchGetI18nTypeList = () => { + return http.request>('get', 'i18nType/getI18nTypeList'); +}; + +/** + * 多语言类型管理---添加多语言类型 + */ +export const fetchAddI18nType = (data: any) => { + return http.request>('post', 'i18nType/addI18nType', { data }); +}; + +/** + * 多语言类型管理---更新多语言类型 + */ +export const fetchUpdateI18nType = (data: any) => { + return http.request>('put', 'i18nType/updateI18nType', { data }); +}; + +/** + * 多语言类型管理---删除多语言类型 + */ +export const fetchDeleteI18nType = (data: any) => { + return http.request>('put', 'i18nType/deleteI18nType', { data }); }; diff --git a/src/api/v1/system.ts b/src/api/v1/system.ts index f139dad..291506a 100644 --- a/src/api/v1/system.ts +++ b/src/api/v1/system.ts @@ -1,38 +1,32 @@ import { http } from '@/api/service/request'; -import type { BaseResult } from '@/api/service/types'; - -type ResultTable = { - /** 列表数据 */ - list: Array; - /** 总条目数 */ - total?: number; - /** 每页显示条目个数 */ - pageSize?: number; - /** 当前页数 */ - pageNo?: number; -}; +import type { BaseResult, ResultTable } from '@/api/service/types'; /** 系统管理-用户路由获取 */ export const getRouterAsync = () => { return http.request>('get', 'router/getRouterAsync'); }; -/** 系统管理-菜单管理列表 */ +/** 图标管理-获取系统图标 */ +export const getMenuIconList = (data: any) => { + return http.request>('get', `menuIcon/getMenuIconList/${data.page}/${data.limit}`, { data }); +}; + +/** 菜单管理-列表 */ export const getMenuList = (data?: any) => { return http.request>('get', `router/getMenus`, { data }); }; -/** 系统管理-添加菜单 */ +/** 菜单管理-添加菜单 */ export const addMenu = (data?: any) => { return http.request>('post', `router/addMenu`, { data }); }; -/** 系统管理-更新菜单 */ +/** 菜单管理-更新菜单 */ export const updateMenu = (data?: any) => { return http.request>('put', `router/updateMenu`, { data }); }; -/** 系统管理-删除菜单 */ +/** 菜单管理-删除菜单 */ export const deletedMenuByIds = (data?: any) => { return http.request>('delete', `router/deletedMenuByIds`, { data }); }; diff --git a/src/components/BaseDialog/SimpleDialog.vue b/src/components/BaseDialog/SimpleDialog.vue new file mode 100644 index 0000000..06e70e7 --- /dev/null +++ b/src/components/BaseDialog/SimpleDialog.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/components/ReIcon/src/LocalSelect.vue b/src/components/ReIcon/src/LocalSelect.vue new file mode 100644 index 0000000..f19c6a8 --- /dev/null +++ b/src/components/ReIcon/src/LocalSelect.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/src/components/ReIcon/src/Select.vue b/src/components/ReIcon/src/Select.vue index aad1042..37abdeb 100644 --- a/src/components/ReIcon/src/Select.vue +++ b/src/components/ReIcon/src/Select.vue @@ -1,268 +1,62 @@ - diff --git a/src/components/ReIcon/src/hooks.ts b/src/components/ReIcon/src/hooks.ts index 5a377da..f4ef904 100644 --- a/src/components/ReIcon/src/hooks.ts +++ b/src/components/ReIcon/src/hooks.ts @@ -1,6 +1,8 @@ -import type { iconType } from "./types"; -import { h, defineComponent, type Component } from "vue"; -import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index"; +import type { iconType } from './types'; +import { type Component, defineComponent, h, ref } from 'vue'; +import { FontIcon, IconifyIconOffline, IconifyIconOnline } from '../index'; + +export const inputValue = ref(); /** * 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标 @@ -10,52 +12,48 @@ import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index"; * @returns Component */ export function useRenderIcon(icon: any, attrs?: iconType): Component { - // iconfont - const ifReg = /^IF-/; - // typeof icon === "function" 属于SVG - if (ifReg.test(icon)) { - // iconfont - const name = icon.split(ifReg)[1]; - const iconName = name.slice( - 0, - name.indexOf(" ") == -1 ? name.length : name.indexOf(" ") - ); - const iconType = name.slice(name.indexOf(" ") + 1, name.length); - return defineComponent({ - name: "FontIcon", - render() { - return h(FontIcon, { - icon: iconName, - iconType, - ...attrs - }); - } - }); - } else if (typeof icon === "function" || typeof icon?.render === "function") { - // svg - return attrs ? h(icon, { ...attrs }) : icon; - } else if (typeof icon === "object") { - return defineComponent({ - name: "OfflineIcon", - render() { - return h(IconifyIconOffline, { - icon: icon, - ...attrs - }); - } - }); - } else { - // 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之 - return defineComponent({ - name: "Icon", - render() { - const IconifyIcon = - icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline; - return h(IconifyIcon, { - icon: icon, - ...attrs - }); - } - }); - } + // iconfont + const ifReg = /^IF-/; + // typeof icon === "function" 属于SVG + if (ifReg.test(icon)) { + // iconfont + const name = icon.split(ifReg)[1]; + const iconName = name.slice(0, name.indexOf(' ') == -1 ? name.length : name.indexOf(' ')); + const iconType = name.slice(name.indexOf(' ') + 1, name.length); + return defineComponent({ + name: 'FontIcon', + render() { + return h(FontIcon, { + icon: iconName, + iconType, + ...attrs, + }); + }, + }); + } else if (typeof icon === 'function' || typeof icon?.render === 'function') { + // svg + return attrs ? h(icon, { ...attrs }) : icon; + } else if (typeof icon === 'object') { + return defineComponent({ + name: 'OfflineIcon', + render() { + return h(IconifyIconOffline, { + icon: icon, + ...attrs, + }); + }, + }); + } else { + // 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之 + return defineComponent({ + name: 'Icon', + render() { + const IconifyIcon = icon && icon.includes(':') ? IconifyIconOnline : IconifyIconOffline; + return h(IconifyIcon, { + icon: icon, + ...attrs, + }); + }, + }); + } } diff --git a/src/components/TableBar/src/TableIsDefaultTag.vue b/src/components/TableBar/src/TableIsDefaultTag.vue new file mode 100644 index 0000000..43a591b --- /dev/null +++ b/src/components/TableBar/src/TableIsDefaultTag.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/components/TableBar/src/TablePlusBar.vue b/src/components/TableBar/src/TablePlusBar.vue index 2ef4572..921105c 100644 --- a/src/components/TableBar/src/TablePlusBar.vue +++ b/src/components/TableBar/src/TablePlusBar.vue @@ -1,95 +1,82 @@ diff --git a/src/components/TableBar/src/bar.tsx b/src/components/TableBar/src/bar.tsx index 6af00b1..a3fffdf 100644 --- a/src/components/TableBar/src/bar.tsx +++ b/src/components/TableBar/src/bar.tsx @@ -169,19 +169,16 @@ export default defineComponent({ }; const isFixedColumn = (label: string) => { - return dynamicColumns.value.filter(item => $t(item.label) === $t(label))[0].fixed ? true : false; + return !!dynamicColumns.value.filter(item => $t(item.label) === $t(label))[0].fixed; }; - const rendTippyProps = (content: string) => { - // https://vue-tippy.netlify.app/props - return { - content, - offset: [0, 18], - duration: [300, 0], - followCursor: true, - hideOnClick: 'toggle', - }; - }; + const rendTippyProps = (content: string) => ({ + content, + offset: [0, 18], + duration: [300, 0], + followCursor: true, + hideOnClick: 'toggle', + }); const reference = { reference: () => , @@ -198,9 +195,7 @@ export default defineComponent({ <> onExpand()} /> @@ -245,12 +240,7 @@ export default defineComponent({ - onFullscreen()} - /> + {slots.default({ diff --git a/src/enums/baseConstant.ts b/src/enums/baseConstant.ts new file mode 100644 index 0000000..1f4dc58 --- /dev/null +++ b/src/enums/baseConstant.ts @@ -0,0 +1,28 @@ +/** + * * 是否默认 + */ +export const isDefaultOptions = [ + { value: true, label: '是' }, + { value: false, label: '否' }, +]; + +/** + * * 是否显示 + */ +export const isDefaultVisibleOptions = [ + { value: true, label: '显示' }, + { value: false, label: '不显示' }, +]; + +/** + * * 性别 + */ +export const sexConstant = [ + { value: 1, label: '男' }, + { value: 0, label: '女' }, +]; + +/** + * * 分页默认数组个数 + */ +export const pageSizes: number[] = [15, 30, 50, 100, 150, 200, 300]; diff --git a/src/store/i18n/i18n.ts b/src/store/i18n/i18n.ts index 1e3ba14..d0e6810 100644 --- a/src/store/i18n/i18n.ts +++ b/src/store/i18n/i18n.ts @@ -1,6 +1,7 @@ -// import { fetchGetI18n } from '@/api/mock/i18n'; import { defineStore } from 'pinia'; -import { fetchGetI18n } from '@/api/v1/i18n'; +import { fetchAddI18n, fetchDeleteI18n, fetchGetI18n, fetchGetI18nList, fetchUpdateI18n } from '@/api/v1/i18n'; +import { pageSizes } from '@/enums/baseConstant'; +import { storeMessage } from '@/utils/message'; export const userI18nStore = defineStore('i18nStore', { persist: true, @@ -8,6 +9,24 @@ export const userI18nStore = defineStore('i18nStore', { return { // ? 多语言内容 i18n: {}, + // 多语言列表 + i18nDataList: [], + // 多语言类型 + i18nTypeList: [], + isAddShown: false, + // ? 分页查询结果 + pagination: { + currentPage: 1, + pageSize: 150, + total: 100, + pageSizes, + }, + // 加载 + loading: false, + // 添加弹窗 + addDialogVisible: false, + // 更新弹窗 + updateDialogVisible: false, }; }, getters: {}, @@ -29,5 +48,36 @@ export const userI18nStore = defineStore('i18nStore', { this.i18n = data; } }, + /** + * * 获取多语言列表 + */ + async getI18nMangeList(data: any) { + const result = await fetchGetI18nList(data); + return storeMessage(result); + }, + + /** + * * 添加多语言 + */ + async addI18n(data: any) { + const result = await fetchAddI18n(data); + return storeMessage(result); + }, + + /** + * * 更新多语言 + */ + async updateI18n(data: any) { + const result = await fetchUpdateI18n(data); + return storeMessage(result); + }, + + /** + * * 删除多语言 + */ + async deleteI18n(data: any) { + const result = await fetchDeleteI18n(data); + return storeMessage(result); + }, }, }); diff --git a/src/store/i18n/i18nType.ts b/src/store/i18n/i18nType.ts new file mode 100644 index 0000000..d5a0114 --- /dev/null +++ b/src/store/i18n/i18nType.ts @@ -0,0 +1,62 @@ +import { defineStore } from 'pinia'; +import { fetchAddI18nType, fetchDeleteI18nType, fetchGetI18nTypeList, fetchUpdateI18nType } from '@/api/v1/i18n'; +import { pageSizes } from '@/enums/baseConstant'; +import { storeMessage } from '@/utils/message'; + +export const userI18nTypeStore = defineStore('i18nTypeStore', { + persist: true, + state() { + return { + // 多语言列表 + datalist: [], + isAddShown: false, + // ? 分页查询结果 + pagination: { + currentPage: 1, + pageSize: 150, + total: 100, + pageSizes, + }, + // 加载 + loading: false, + // 添加弹窗 + addDialogVisible: false, + // 更新弹窗 + updateDialogVisible: false, + }; + }, + getters: {}, + actions: { + /** + * * 获取多语言类型 + */ + async getI18nTypeList() { + const result = await fetchGetI18nTypeList(); + return storeMessage(result); + }, + + /** + * * 添加多语言类型 + */ + async addI18nType(data: any) { + const result = await fetchAddI18nType(data); + return storeMessage(result); + }, + + /** + * * 修改多语言类型 + */ + async updateI18nType(data: any) { + const result = await fetchUpdateI18nType(data); + return storeMessage(result); + }, + + /** + * * 删除多语言类型 + */ + async deleteI18nType(data: any) { + const result = await fetchDeleteI18nType(data); + return storeMessage(result); + }, + }, +}); diff --git a/src/store/modules/menuIcon.ts b/src/store/modules/menuIcon.ts new file mode 100644 index 0000000..846df75 --- /dev/null +++ b/src/store/modules/menuIcon.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia'; +import { getMenuIconList } from '@/api/v1/system'; + +export const userMenuIconStore = defineStore('menuIconStore', { + state() { + return { + menuIconList: [], + menuIconPage: { page: 1, limit: 30, total: 0 }, + }; + }, + getters: {}, + actions: { + /** + * * 获取系统图标列表 + */ + async getMenuIconList() { + const result = await getMenuIconList(this.menuIconPage); + if (result.code === 200) { + this.menuIconList = result.data.list; + } + }, + }, +}); diff --git a/src/utils/message.ts b/src/utils/message.ts index 47f9e2b..b2e9922 100644 --- a/src/utils/message.ts +++ b/src/utils/message.ts @@ -1,6 +1,6 @@ import type { VNode } from 'vue'; import { isFunction } from '@pureadmin/utils'; -import { ElMessage, type MessageHandler } from 'element-plus'; +import { ElMessage, ElMessageBox, type MessageHandler } from 'element-plus'; import type { BaseResult } from '@/api/service/types'; type messageStyle = 'el' | 'antd'; @@ -31,6 +31,15 @@ interface MessageParams { onClose?: Function | null; } +// 消息盒 +interface MessageBox { + message: string | undefined; + title: string | undefined; + confirmMessage: any; + cancelMessage: any; + showMessage: boolean; +} + /** 用法非常简单,参考 src/views/components/message/index.vue 文件 */ /** @@ -91,3 +100,34 @@ export const storeMessage = (result: BaseResult) => { message(result.message, { type: 'success' }); return true; }; + +const defaultBoxOption: MessageBox = { + showMessage: false, + message: '', + title: '', + confirmMessage: undefined, + cancelMessage: undefined, +}; + +/** + * 消息弹窗确认 + * @param type + * @param option + */ +export const messageBox = async (option: MessageBox = defaultBoxOption, type: any = 'warning') => { + return ElMessageBox.confirm(option.message, option.title, { + confirmButtonText: '确认', + cancelButtonText: '返回', + type, + draggable: true, + overflow: true, + }) + .then(() => { + option.showMessage && ElMessage({ type: 'success', message: option.confirmMessage }); + return true; + }) + .catch(() => { + ElMessage({ type: 'warning', message: option.cancelMessage }); + return false; + }); +}; diff --git a/src/views/i18n/i18n-setting/index.vue b/src/views/i18n/i18n-setting/index.vue new file mode 100644 index 0000000..f51946f --- /dev/null +++ b/src/views/i18n/i18n-setting/index.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/views/i18n/i18n-setting/language-add.vue b/src/views/i18n/i18n-setting/language-add.vue new file mode 100644 index 0000000..894fb82 --- /dev/null +++ b/src/views/i18n/i18n-setting/language-add.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/views/i18n/language-setting/language-dialog.vue b/src/views/i18n/i18n-setting/language-dialog.vue similarity index 69% rename from src/views/i18n/language-setting/language-dialog.vue rename to src/views/i18n/i18n-setting/language-dialog.vue index a3c82ba..9ad419c 100644 --- a/src/views/i18n/language-setting/language-dialog.vue +++ b/src/views/i18n/i18n-setting/language-dialog.vue @@ -1,10 +1,9 @@ + + diff --git a/src/views/i18n/language-setting/utils/columns.tsx b/src/views/i18n/i18n-setting/utils/columns.tsx similarity index 50% rename from src/views/i18n/language-setting/utils/columns.tsx rename to src/views/i18n/i18n-setting/utils/columns.tsx index bc2d8d0..c7a32cf 100644 --- a/src/views/i18n/language-setting/utils/columns.tsx +++ b/src/views/i18n/i18n-setting/utils/columns.tsx @@ -1,17 +1,16 @@ // 多语言表格列字段 import { reactive } from 'vue'; import type { FormRules } from 'element-plus'; -import { $t } from '@/plugins/i18n'; export const columns: TableColumnList = [ - { type: 'selection' }, - { type: 'index', label: $t('table.tableNumber'), width: 100 }, - { label: $t('i18n.keyName'), prop: 'keyName' }, - { label: $t('i18n.translate'), prop: 'translate' }, - { label: $t('i18n.languageSummary'), prop: 'languageSummary' }, - { label: $t('i18n.languageName'), prop: 'languageName' }, - { label: $t('i18n.parentKeyName'), prop: 'parentKeyName' }, - { label: $t('table.operation'), prop: 'operation', slot: 'operation' }, + // { type: 'selection' }, + // { type: 'index', label: 'table.tableNumber', width: 100 }, + { label: 'i18n.keyName', prop: 'keyName' }, + { label: 'i18n.translate', prop: 'translate' }, + { label: 'i18n.languageSummary', prop: 'languageSummary' }, + { label: 'i18n.languageName', prop: 'languageName' }, + { label: 'i18n.parentKeyName', prop: 'parentKeyName' }, + { label: 'table.operation', prop: 'operation', slot: 'operation' }, ]; // 添加多语言表单规则 diff --git a/src/views/i18n/i18n-setting/utils/hook.ts b/src/views/i18n/i18n-setting/utils/hook.ts new file mode 100644 index 0000000..076eb2d --- /dev/null +++ b/src/views/i18n/i18n-setting/utils/hook.ts @@ -0,0 +1,125 @@ +import { reactive, ref } from 'vue'; +import { userI18nStore } from '@/store/i18n/i18n'; +import { messageBox } from '@/utils/message'; + +export const addDialogVisible = ref(false); +export const updateDialogVisible = ref(false); + +const i18nStore = userI18nStore(); +// 更新表单数据 +export const updateForm = reactive({ + id: '', + languageId: '', + keyName: '', + translate: '', + parentId: '', +}); +// 彻底删除 id列表 +const ids = ref([]); + +/** + * * 查询内容 + */ +export const getI18nDataList = async () => { + i18nStore.loading = true; + await i18nStore.getI18nMangeList(); + i18nStore.loading = false; +}; + +/** + * * 当前页改变时 + */ +export const onCurrentPageChange = async (value: number) => { + i18nStore.pagination.currentPage = value; + await getI18nDataList(); +}; + +/** + * * 当分页发生变化 + * @param value + */ +export const onPageSizeChange = async (value: number) => { + i18nStore.pagination.pageSize = value; + await getI18nDataList(); +}; + +/** + * * 选择框点击的行 + * @param row + */ +export const onSelectionChange = (row: any) => { + ids.value = row.map((item: any) => item.id); +}; + +/** + * * 行内容添加 + * 打开添加弹窗 + */ +export const onRowAdd = () => { + addDialogVisible.value = true; +}; + +/** + * * 批量彻底删除行 + */ +export const onRowDelete = async () => { + const isConfirm = await messageBox({ + message: '是否确认批量删除(此操作不可逆)', + title: '删除警告', + showMessage: false, + confirmMessage: '删除成功', + cancelMessage: '取消删除', + }); + + if (isConfirm) { + const data = ids.value; + await i18nStore.deleteI18n(data); + await getI18nDataList(); + } +}; +/** + * * 批量彻底删除行 + */ +export const onRowDeleteWithChildren = async () => { + const isConfirm = await messageBox({ + message: '是否确认批量删除(此操作不可逆)', + title: '删除警告', + showMessage: false, + confirmMessage: '删除成功', + cancelMessage: '取消删除', + }); + + if (isConfirm) { + const data = ids.value; + await i18nStore.deleteI18n(data); + await getI18nDataList(); + } +}; + +/** + * * 当表格修改时 + */ +export const onUpdate = (row: any) => { + const data = row.row; + + // 赋值内容 + updateForm.id = data.id; + updateForm.languageId = data.parentKeyName; + updateForm.keyName = data.keyName; + updateForm.translate = data.translate; + data.parentId != 0 && (updateForm.parentId = data.parentId); + + // 打开弹窗 + updateDialogVisible.value = true; +}; + +/** + * * 当删除时 + * @param row + */ +export const onDelete = async (row: any) => { + const id = row.row.id; + const form = { id }; + await i18nStore.deleteI18n(form); + await i18nStore.getI18nMangeList(); +}; diff --git a/src/views/i18n/language-type-setting/add-language-tyoe.vue b/src/views/i18n/i18n-type-setting/add-i18n-type.vue similarity index 76% rename from src/views/i18n/language-type-setting/add-language-tyoe.vue rename to src/views/i18n/i18n-type-setting/add-i18n-type.vue index 22a75ac..c96cf74 100644 --- a/src/views/i18n/language-type-setting/add-language-tyoe.vue +++ b/src/views/i18n/i18n-type-setting/add-i18n-type.vue @@ -1,17 +1,18 @@