From 4ebdfd21c4933691912ba9bc634f04f1c5b5a7af Mon Sep 17 00:00:00 2001 From: valarchie <343928303@qq.com> Date: Wed, 12 Jul 2023 16:08:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E5=85=AC=E5=91=8A=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/common.ts | 4 +- src/api/system.ts | 56 +++++ src/components/RePureTableBar/src/bar.tsx | 17 +- src/main.ts | 10 +- src/store/modules/types.ts | 5 + src/store/modules/user.ts | 46 +++- src/utils/http/index.ts | 2 + src/views/login/index.vue | 2 + src/views/monitor/hooks.ts | 39 +++ src/views/system/notice/form.vue | 71 ++++-- src/views/system/notice/index.vue | 146 +++++------ src/views/system/notice/utils/hook.tsx | 282 ++++++++++++---------- src/views/system/notice/utils/types.ts | 24 +- src/views/system/role/form.vue | 55 +++++ src/views/system/role/index.vue | 216 +++++++++++++++++ src/views/system/role/utils/hook.tsx | 241 ++++++++++++++++++ src/views/system/role/utils/rule.ts | 8 + src/views/system/role/utils/types.ts | 15 ++ src/views/tool/hooks.ts | 39 +++ types/index.d.ts | 10 + 20 files changed, 1035 insertions(+), 253 deletions(-) create mode 100644 src/views/monitor/hooks.ts create mode 100644 src/views/system/role/form.vue create mode 100644 src/views/system/role/index.vue create mode 100644 src/views/system/role/utils/hook.tsx create mode 100644 src/views/system/role/utils/rule.ts create mode 100644 src/views/system/role/utils/types.ts create mode 100644 src/views/tool/hooks.ts diff --git a/src/api/common.ts b/src/api/common.ts index e6c65bd..45ba6f6 100644 --- a/src/api/common.ts +++ b/src/api/common.ts @@ -11,7 +11,7 @@ export type ConfigDTO = { /** 验证码开关 */ isCaptchaOn: boolean; /** 系统字典配置(下拉选项之类的) */ - dictTypes: Map>; + dictionary: Map>; }; export type LoginByPasswordDTO = { @@ -43,7 +43,7 @@ export type CurrentLoginUserDTO = { export type DictionaryData = { label: string; - value: Number; + value: number; cssTag: string; }; diff --git a/src/api/system.ts b/src/api/system.ts index 169d79c..c28e387 100644 --- a/src/api/system.ts +++ b/src/api/system.ts @@ -19,6 +19,30 @@ type ResultDept = { data?: Array; }; +interface SystemNoticeQuery extends BasePageQuery { + noticeType: string; + noticeTitle: string; + creatorName: string; +} + +type SystemNoticeDTO = { + noticeId: string; + noticeTitle: string; + noticeType: number; + noticeContent: string; + status: number; + createTime: Date; + creatorName: string; +}; + +export type SystemNoticeRequest = { + noticeId?: number; + noticeTitle: string; + noticeType: number; + noticeContent: string; + status: number; +}; + /** 获取用户管理列表 */ export const getUserList = (data?: object) => { return http.request("post", "/user", { data }); @@ -33,3 +57,35 @@ export const getRoleList = (data?: object) => { export const getDeptList = (data?: object) => { return http.request("post", "/dept", { data }); }; + +/** 获取系统通知列表 */ +export const getSystemNoticeListApi = (params?: SystemNoticeQuery) => { + return http.request>>( + "get", + "/system/notice/list", + { + params + } + ); +}; + +/** 添加系统通知 */ +export const addSystemNoticeApi = (data: SystemNoticeRequest) => { + return http.request>("post", "/system/notice/", { + data + }); +}; + +/** 修改系统通知 */ +export const updateSystemNoticeApi = (data: SystemNoticeRequest) => { + return http.request>("put", "/system/notice/", { + data + }); +}; + +/** 删除系统通知 */ +export const deleteSystemNoticeApi = (data: Array) => { + return http.request>("delete", `/system/notice/${data}`, { + data + }); +}; diff --git a/src/components/RePureTableBar/src/bar.tsx b/src/components/RePureTableBar/src/bar.tsx index 30aa6d3..092f427 100644 --- a/src/components/RePureTableBar/src/bar.tsx +++ b/src/components/RePureTableBar/src/bar.tsx @@ -1,6 +1,12 @@ import { useEpThemeStoreHook } from "@/store/modules/epTheme"; -import { delay, getKeyList, cloneDeep } from "@pureadmin/utils"; import { defineComponent, ref, computed, type PropType, nextTick } from "vue"; +import { + delay, + cloneDeep, + isBoolean, + isFunction, + getKeyList +} from "@pureadmin/utils"; import Sortable from "sortablejs"; import DragIcon from "./svg/drag.svg?component"; @@ -37,8 +43,13 @@ export default defineComponent({ const loading = ref(false); const checkAll = ref(true); const isIndeterminate = ref(false); + const filterColumns = cloneDeep(props?.columns).filter(column => + isBoolean(column?.hide) + ? !column.hide + : !(isFunction(column?.hide) && column?.hide()) + ); let checkColumnList = getKeyList(cloneDeep(props?.columns), "label"); - const checkedColumns = ref(checkColumnList); + const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label")); const dynamicColumns = ref(cloneDeep(props?.columns)); const getDropdownItemStyle = computed(() => { @@ -120,7 +131,7 @@ export default defineComponent({ dynamicColumns.value = cloneDeep(props?.columns); checkColumnList = []; checkColumnList = await getKeyList(cloneDeep(props?.columns), "label"); - checkedColumns.value = checkColumnList; + checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label"); } const dropdown = { diff --git a/src/main.ts b/src/main.ts index 60db439..c2a6149 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,7 +8,7 @@ import { MotionPlugin } from "@vueuse/motion"; // import { useEcharts } from "@/plugins/echarts"; import { injectResponsiveStorage } from "@/utils/responsive"; -// import Table from "@pureadmin/table"; +import Table from "@pureadmin/table"; // import PureDescriptions from "@pureadmin/descriptions"; // 引入重置样式 @@ -49,9 +49,11 @@ getServerConfig(app).then(async config => { await router.isReady(); injectResponsiveStorage(app, config); setupStore(app); - app.use(MotionPlugin).use(ElementPlus); - // .use(useEcharts); - // .use(Table); + app + .use(MotionPlugin) + .use(ElementPlus) + // .use(useEcharts); + .use(Table); // .use(PureDescriptions); app.mount("#app"); }); diff --git a/src/store/modules/types.ts b/src/store/modules/types.ts index d744e64..9ceeb72 100644 --- a/src/store/modules/types.ts +++ b/src/store/modules/types.ts @@ -1,4 +1,5 @@ import { RouteRecordName } from "vue-router"; +import { DictionaryData } from "../../api/common"; export type cacheType = { mode: string; @@ -38,4 +39,8 @@ export type setType = { export type userType = { username?: string; roles?: Array; + /** 字典ListMap 用于下拉框直接展示 */ + dictionaryList: Map>; + /** 字典MapMap 用于匹配值展示 */ + dictionaryMap: Map>; }; diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index c184101..c3a3e38 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -5,8 +5,12 @@ import { routerArrays } from "@/layout/types"; import { router, resetRouter } from "@/router"; import { storageSession } from "@pureadmin/utils"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; -import { type removeToken, sessionKey } from "@/utils/auth"; -import { TokenDTO } from "@/api/common"; +import { removeToken, sessionKey } from "@/utils/auth"; +import { DictionaryData, TokenDTO } from "@/api/common"; +import { storageLocal } from "@pureadmin/utils"; + +const dictionaryListKey = "ag-dictionary-list"; +const dictionaryMapKey = "ag-dictionary-map"; export const useUserStore = defineStore({ id: "ag-user", @@ -18,17 +22,53 @@ export const useUserStore = defineStore({ // 页面级别权限 roles: storageSession().getItem(sessionKey)?.currentUser.roleKey ? [storageSession().getItem(sessionKey)?.currentUser.roleKey] - : [] + : [], + dictionaryList: + storageLocal().getItem>>( + dictionaryListKey + ) ?? new Map(), + dictionaryMap: + storageLocal().getItem>>( + dictionaryMapKey + ) ?? new Map() }), actions: { /** 存储用户名 */ SET_USERNAME(username: string) { + /** TODO 这里不是应该再进一步存到sessionStorage中吗 */ this.username = username; }, /** 存储角色 */ SET_ROLES(roles: Array) { this.roles = roles; }, + /** 存储系统内的字典值 并拆分为Map形式和List形式 */ + SET_DICTIONARY(dictionary: Map>) { + /** 由于localStorage不能存储Map对象,所以用Obj来装载数据 */ + const dictionaryMapTmp = {}; + + for (const obj in dictionary) { + dictionaryMapTmp[obj] = dictionary[obj].reduce((map, dict) => { + map[dict.value] = dict; + return map; + }, {}); + } + + /** 将字典分成List形式和Map形式 List便于下拉框展示 Map便于匹配值 */ + this.dictionaryList = dictionary; + this.dictionaryMap = dictionaryMapTmp; + + storageLocal().setItem>>( + dictionaryListKey, + dictionary + ); + + storageLocal().setItem>>( + dictionaryMapKey, + dictionaryMapTmp as Map> + ); + }, + /** 前端登出(不调用接口) */ logOut() { this.username = ""; diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index b62e4c6..92d6811 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -128,6 +128,8 @@ class PureHttp { } else { // 其余情况弹出错误提示框 message(response.data.msg, { type: "error" }); + NProgress.done(); + return Promise.reject(response.data.msg); } } diff --git a/src/views/login/index.vue b/src/views/login/index.vue index e46b737..5338710 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -40,6 +40,7 @@ import Lock from "@iconify-icons/ri/lock-fill"; import User from "@iconify-icons/ri/user-3-fill"; import * as CommonAPI from "@/api/common"; import { setTokenFromBackend } from "../../utils/auth"; +import { useUserStoreHook } from "../../store/modules/user"; defineOptions({ name: "Login" @@ -128,6 +129,7 @@ watch(isRememberMe, newVal => { onBeforeMount(async () => { await CommonAPI.getConfig().then(res => { isCaptchaOn.value = res.data.isCaptchaOn; + useUserStoreHook().SET_DICTIONARY(res.data.dictionary); }); if (isCaptchaOn.value) { diff --git a/src/views/monitor/hooks.ts b/src/views/monitor/hooks.ts new file mode 100644 index 0000000..5465d94 --- /dev/null +++ b/src/views/monitor/hooks.ts @@ -0,0 +1,39 @@ +// 抽离可公用的工具函数等用于系统管理页面逻辑 +import { computed } from "vue"; +import { useDark } from "@pureadmin/utils"; + +export function usePublicHooks() { + const { isDark } = useDark(); + + const switchStyle = computed(() => { + return { + "--el-switch-on-color": "#6abe39", + "--el-switch-off-color": "#e84749" + }; + }); + + const tagStyle = computed(() => { + return (status: number) => { + return status === 1 + ? { + "--el-tag-text-color": isDark.value ? "#6abe39" : "#389e0d", + "--el-tag-bg-color": isDark.value ? "#172412" : "#f6ffed", + "--el-tag-border-color": isDark.value ? "#274a17" : "#b7eb8f" + } + : { + "--el-tag-text-color": isDark.value ? "#e84749" : "#cf1322", + "--el-tag-bg-color": isDark.value ? "#2b1316" : "#fff1f0", + "--el-tag-border-color": isDark.value ? "#58191c" : "#ffa39e" + }; + }; + }); + + return { + /** 当前网页是否为`dark`模式 */ + isDark, + /** 表现更鲜明的`el-switch`组件 */ + switchStyle, + /** 表现更鲜明的`el-tag`组件 */ + tagStyle + }; +} diff --git a/src/views/system/notice/form.vue b/src/views/system/notice/form.vue index 65d4ef0..45ac2a7 100644 --- a/src/views/system/notice/form.vue +++ b/src/views/system/notice/form.vue @@ -2,52 +2,81 @@ import { ref } from "vue"; import { formRules } from "./utils/rule"; import { FormProps } from "./utils/types"; +import { useUserStoreHook } from "@/store/modules/user"; +/** TODO 有其他方式 来换掉这个props 父子组件传值吗? */ const props = withDefaults(defineProps(), { formInline: () => ({ - name: "", - code: "", - remark: "" + noticeTitle: "", + noticeType: "", + status: "", + noticeContent: "" }) }); -const ruleFormRef = ref(); -const newFormInline = ref(props.formInline); +const noticeData = ref(props.formInline); -function getRef() { - return ruleFormRef.value; +const formRuleRef = ref(); + +function getFormRuleRef() { + return formRuleRef.value; } -defineExpose({ getRef }); +defineExpose({ getFormRuleRef });