diff --git a/frontend/src/api/config/serviceName.ts b/frontend/src/api/config/serviceName.ts index 40c9e65..7fd825e 100644 --- a/frontend/src/api/config/serviceName.ts +++ b/frontend/src/api/config/serviceName.ts @@ -1,5 +1,9 @@ -// 系统&用户模块前缀 +// 系统模块前缀 export const ADMIN = "/admin"; +// 用户模块前缀 +export const USER = "/user-boot"; + + // todo... 其他业务模块前缀 \ No newline at end of file diff --git a/frontend/src/api/interface/index.ts b/frontend/src/api/interface/index.ts index 16aa1eb..36330cd 100644 --- a/frontend/src/api/interface/index.ts +++ b/frontend/src/api/interface/index.ts @@ -1,15 +1,34 @@ -// 请求响应参数(不包含data) +/** + * 该接口声明文件用来声明通用的接口定义,比如 请求参数Base、响应Base、分页等 + */ + +/** + * 请求响应参数(不包含data) + */ export interface Result { code: string; message: string; } -// 请求响应参数(包含data) +/** + * 请求响应参数(包含data) + */ export interface ResultData extends Result { data: T; } -// 分页响应参数 + +/** + * 分页请求参数 + */ +export interface ReqPage { + pageNum: number; + pageSize: number; +} + +/** + * 分页响应参数 + */ export interface ResPage { list: T[]; pageNum: number; @@ -17,74 +36,18 @@ export interface ResPage { total: number; } -// 分页请求参数 -export interface ReqPage { - pageNum: number; - pageSize: number; +/** + * Dict 字典属性 + * id: 唯一标识 + * label: 名称 + * code: 类型下唯一标识 + */ +export interface Dict { + id: string; + label: string; + code: string; + children?: Dict[]; } -// 文件上传模块 -export namespace Upload { - export interface ResFileUrl { - fileUrl: string; - } -} -// 登录模块 -export namespace Login { - export interface ReqLoginForm { - username: string; - password: string; - } - export interface ResLogin { - accessToken: string; - } - export interface ResAuthButtons { - [key: string]: string[]; - } -} -// 用户管理模块 -export namespace User { - export interface ReqUserParams extends ReqPage { - username: string; - gender: number; - idCard: string; - email: string; - address: string; - createTime: string[]; - status: number; - } - export interface ResUserList { - id: string; - username: string; - gender: number; - user: { detail: { age: number } }; - idCard: string; - email: string; - address: string; - createTime: string; - status: number; - avatar: string; - photo: any[]; - children?: ResUserList[]; - } - export interface ResStatus { - userLabel: string; - userValue: number; - } - export interface ResGender { - genderLabel: string; - genderValue: number; - } - export interface ResDepartment { - id: string; - name: string; - children?: ResDepartment[]; - } - export interface ResRole { - id: string; - name: string; - children?: ResDepartment[]; - } -} diff --git a/frontend/src/api/modules/login.ts b/frontend/src/api/modules/login.ts deleted file mode 100644 index 165bd07..0000000 --- a/frontend/src/api/modules/login.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Login } from "@/api/interface/index"; -import { ADMIN } from "@/api/config/serviceName"; -import http from "@/api"; - -/** - * @name 登录模块 - */ -// 用户登录 -export const loginApi = (params: Login.ReqLoginForm) => { - return http.post(ADMIN + `/login`, params, { loading: false }); // 正常 post json 请求 ==> application/json -}; - -// 获取菜单列表 -export const getAuthMenuListApi = () => { - return http.get(ADMIN + `/menu/list`, {}, { loading: false }); -}; - -// 获取按钮权限 -export const getAuthButtonListApi = () => { - return http.get(ADMIN + `/auth/buttons`, {}, { loading: false }); -}; - -// 用户退出登录 -export const logoutApi = () => { - return http.post(ADMIN + `/logout`); -}; diff --git a/frontend/src/api/system/dictData.ts b/frontend/src/api/system/dictData.ts new file mode 100644 index 0000000..5cdc655 --- /dev/null +++ b/frontend/src/api/system/dictData.ts @@ -0,0 +1,48 @@ +/** + * 模拟字典静态数据,有后端接口后,需要删除 todo... + */ +import { Dict } from '@/api/interface' + +const dictData: Dict[] = [ + { + id: "1", + code: 'sex', + label: '性别', + children: [ + { + id: "1", + label: '男', + code: 1, + }, + { + id: "2", + label: '女', + code: 2, + }, + { + id: "3", + label: '未知', + code: 3, + }, + ], + }, + { + id: "2", + code: 'status', + label: '状态', + children: [ + { + id: "123456789", + label: '启用', + code: 1, + }, + { + id: "987654321", + label: '禁用', + code: 0, + }, + ], + }, +] + +export default dictData \ No newline at end of file diff --git a/frontend/src/api/user/interface/index.ts b/frontend/src/api/user/interface/index.ts new file mode 100644 index 0000000..80f863d --- /dev/null +++ b/frontend/src/api/user/interface/index.ts @@ -0,0 +1,68 @@ +// 登录模块 +import type { ReqPage } from '@/api/interface' + +export namespace Login { + export interface ReqLoginForm { + username: string; + password: string; + } + export interface ResLogin { + accessToken: string; + } + export interface ResAuthButtons { + [key: string]: string[]; + } +} + + +// 用户管理模块 +export namespace User { + + // 用户列表 + export interface ResUserList { + id: string; + username: string; + gender: number; + age:number; + idCard: string; + email: string; + address: string; + createTime: string; + status: number; + avatar: string; + photo: any[]; + children?: ResUserList[]; + } + + export interface ReqUserParams extends ReqPage { + username: string; + gender: number; + idCard: string; + email: string; + address: string; + createTime: string[]; + status: number; + } + + export interface ResStatus { + userLabel: string; + userValue: number; + } + + export interface ResGender { + genderLabel: string; + genderValue: number; + } + + export interface ResDepartment { + id: string; + name: string; + children?: ResDepartment[]; + } + + export interface ResRole { + id: string; + name: string; + children?: ResDepartment[]; + } +} \ No newline at end of file diff --git a/frontend/src/api/user/login.ts b/frontend/src/api/user/login.ts new file mode 100644 index 0000000..58235e3 --- /dev/null +++ b/frontend/src/api/user/login.ts @@ -0,0 +1,26 @@ +import { Login } from './interface' +import { ADMIN as rePrefix } from '@/api/config/serviceName' +import http from '@/api' + +/** + * @name 登录模块 + */ +// 用户登录 +export const loginApi = (params: Login.ReqLoginForm) => { + return http.post(`${rePrefix}/login`, params, { loading: false }) +} + +// 获取菜单列表 +export const getAuthMenuListApi = () => { + return http.get(`${rePrefix}/menu/list`, {}, { loading: false }) +} + +// 获取按钮权限 +export const getAuthButtonListApi = () => { + return http.get(`${rePrefix}/auth/buttons`, {}, { loading: false }) +} + +// 用户退出登录 +export const logoutApi = () => { + return http.post(`${rePrefix}/logout`) +} diff --git a/frontend/src/api/modules/user.ts b/frontend/src/api/user/user.ts similarity index 51% rename from frontend/src/api/modules/user.ts rename to frontend/src/api/user/user.ts index 0374ab1..504aa81 100644 --- a/frontend/src/api/modules/user.ts +++ b/frontend/src/api/user/user.ts @@ -1,71 +1,72 @@ -import { ResPage, User } from "@/api/interface/index"; -import { ADMIN } from "@/api/config/serviceName"; -import http from "@/api"; +import { ResPage } from '@/api/interface' +import { User } from './interface' +import { ADMIN as rePrefix } from '@/api/config/serviceName' +import http from '@/api' /** * @name 用户管理模块 */ // 获取用户列表 export const getUserList = (params: User.ReqUserParams) => { - return http.post>(ADMIN + `/user/list`, params); -}; + return http.post>(`${rePrefix}/user/list`, params) +} // 获取树形用户列表 export const getUserTreeList = (params: User.ReqUserParams) => { - return http.post>(ADMIN + `/user/tree/list`, params); -}; + return http.post>(`${rePrefix}/user/tree/list`, params) +} // 新增用户 export const addUser = (params: { id: string }) => { - return http.post(ADMIN + `/user/add`, params); -}; + return http.post(`${rePrefix}/user/add`, params) +} // 批量添加用户 export const BatchAddUser = (params: FormData) => { - return http.post(ADMIN + `/user/import`, params); -}; + return http.post(`${rePrefix}/user/import`, params) +} // 编辑用户 export const editUser = (params: { id: string }) => { - return http.post(ADMIN + `/user/edit`, params); -}; + return http.post(`${rePrefix}/user/edit`, params) +} // 删除用户 export const deleteUser = (params: { id: string[] }) => { - return http.post(ADMIN + `/user/delete`, params); -}; + return http.post(`${rePrefix}/user/delete`, params) +} // 切换用户状态 export const changeUserStatus = (params: { id: string; status: number }) => { - return http.post(ADMIN + `/user/change`, params); -}; + return http.post(`${rePrefix}/user/change`, params) +} // 重置用户密码 export const resetUserPassWord = (params: { id: string }) => { - return http.post(ADMIN + `/user/rest_password`, params); -}; + return http.post(`${rePrefix}/user/rest_password`, params) +} // 导出用户数据 export const exportUserInfo = (params: User.ReqUserParams) => { - return http.download(ADMIN + `/user/export`, params); -}; + return http.download(`${rePrefix}/user/export`, params) +} // 获取用户状态字典 export const getUserStatus = () => { - return http.get(ADMIN + `/user/status`); -}; + return http.get(`${rePrefix}/user/status`) +} // 获取用户性别字典 export const getUserGender = () => { - return http.get(ADMIN + `/user/gender`); -}; + return http.get(`${rePrefix}/user/gender`) +} // 获取用户部门列表 export const getUserDepartment = () => { - return http.get(ADMIN + `/user/department`); -}; + return http.get(`${rePrefix}/user/department`) +} // 获取用户角色字典 export const getUserRole = () => { - return http.get(ADMIN + `/user/role`); -}; + return http.get(`${rePrefix}/user/role`) +} diff --git a/frontend/src/api/user/userData.ts b/frontend/src/api/user/userData.ts new file mode 100644 index 0000000..01cb7ea --- /dev/null +++ b/frontend/src/api/user/userData.ts @@ -0,0 +1,148 @@ +const data = [ + { + 'id': '623689732233728549', + 'username': '薛霞', + 'gender': 2, + 'age': 14, + 'idCard': '623689732233728549', + 'email': 'k.ckfkzrnhd@voyvhqubs.sl', + 'address': '浙江省 温州市', + 'createTime': '1985-04-15 15:42:29', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRqMK.jpg', + }, + { + 'id': '621003764863621316', + 'username': '冯敏', + 'gender': 1, + 'age': 16, + 'idCard': '621003764863621316', + 'email': 'h.obqq@cpyirry.bt', + 'address': '内蒙古自治区 兴安盟', + 'createTime': '2003-03-24 22:30:36', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRBHS.jpg', + }, + { + 'id': '652286556713195552', + 'username': '潘霞', + 'gender': 1, + 'age': 28, + 'idCard': '652286556713195552', + 'email': 'b.ttcn@xrxuorb.gov.cn', + 'address': '河南省 安阳市', + 'createTime': '1998-01-16 11:23:33', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRqMK.jpg', + }, + { + 'id': '373930342176416776', + 'username': '郝秀英', + 'gender': 1, + 'age': 17, + 'idCard': '373930342176416776', + 'email': 'x.fatyfu@udqgch.tv', + 'address': '黑龙江省 哈尔滨市', + 'createTime': '1987-09-22 06:43:43', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QR57a.jpg', + }, + { + 'id': '429621442453555775', + 'username': '吕洋', + 'gender': 1, + 'age': 22, + 'idCard': '429621442453555775', + 'email': 's.uirhkbc@bkkvzztn.cv', + 'address': '天津 天津市', + 'createTime': '1982-10-31 09:42:09', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QR57a.jpg', + }, + { + 'id': '387231964476618937', + 'username': '江磊', + 'gender': 1, + 'age': 28, + 'idCard': '387231964476618937', + 'email': 'c.pbov@vusetqkrnx.net', + 'address': '香港特别行政区 九龙', + 'createTime': '1999-12-24 09:06:37', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRqMK.jpg', + }, + { + 'id': '604013348875476647', + 'username': '姚静', + 'gender': 1, + 'age': 15, + 'idCard': '604013348875476647', + 'email': 'g.nplhpxqmm@bttefv.ru', + 'address': '西藏自治区 昌都地区', + 'createTime': '2020-08-05 12:22:15', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRa0s.jpg', + }, + { + 'id': '028222596330483467', + 'username': '龙艳', + 'gender': 1, + 'age': 17, + 'idCard': '028222596330483467', + 'email': 'e.acjsi@bbjk.ci', + 'address': '云南省 普洱市', + 'createTime': '1971-03-07 06:13:10', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRqMK.jpg', + }, + { + 'id': '739427478368274267', + 'username': '武涛', + 'gender': 1, + 'age': 18, + 'idCard': '739427478368274267', + 'email': 'x.hlwyeply@bcvejqss.bt', + 'address': '香港特别行政区 香港岛', + 'createTime': '1975-09-27 01:24:19', + 'status': 1, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRa0s.jpg', + }, + { + 'id': '448686878612127243', + 'username': '孙芳', + 'gender': 1, + 'age': 17, + 'idCard': '448686878612127243', + 'email': 'j.cmwtpc@xovygkdk.sc', + 'address': '云南省 西双版纳傣族自治州', + 'createTime': '1987-04-22 14:09:59', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRBHS.jpg', + }, + { + 'id': '448686878612127244', + 'username': '孙芳1', + 'gender': 1, + 'age': 17, + 'idCard': '448686878612127243', + 'email': 'j.cmwtpc@xovygkdk.sc', + 'address': '云南省 西双版纳傣族自治州', + 'createTime': '1987-04-22 14:09:59', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRBHS.jpg', + }, + { + 'id': '448686878612127245', + 'username': '孙芳2', + 'gender': 1, + 'age': 17, + 'idCard': '448686878612127243', + 'email': 'j.cmwtpc@xovygkdk.sc', + 'address': '云南省 西双版纳傣族自治州', + 'createTime': '1987-04-22 14:09:59', + 'status': 0, + 'avatar': 'https://i.imgtg.com/2023/01/16/QRBHS.jpg', + }, +] + +export default data \ No newline at end of file diff --git a/frontend/src/components/Grid/components/GridItem.vue b/frontend/src/components/Grid/components/GridItem.vue index c506cce..e3b8a2c 100644 --- a/frontend/src/components/Grid/components/GridItem.vue +++ b/frontend/src/components/Grid/components/GridItem.vue @@ -36,13 +36,13 @@ const isShow = ref(true); const breakPoint = inject>("breakPoint", ref("xl")); const shouldHiddenIndex = inject>("shouldHiddenIndex", ref(-1)); watch( - () => [shouldHiddenIndex.value, breakPoint.value], - n => { - if (!!attrs.index) { - isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0])); - } - }, - { immediate: true } + () => [shouldHiddenIndex.value, breakPoint.value], + n => { + if (!!attrs.index) { + isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0])); + } + }, + { immediate: true } ); const gap = inject("gap", 0); @@ -52,14 +52,14 @@ const style = computed(() => { let offset = props[breakPoint.value]?.offset ?? props.offset; if (props.suffix) { return { - gridColumnStart: cols.value - span - offset + 1, + gridColumnStart: cols.value - span - offset + 2, gridColumnEnd: `span ${span + offset}`, marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : "unset" }; } else { return { - gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset}/span ${ - span + offset > cols.value ? cols.value : span + offset + gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset }/span ${ + span + offset > cols.value ? cols.value : span + offset }`, marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : "unset" }; diff --git a/frontend/src/components/Grid/index.vue b/frontend/src/components/Grid/index.vue index 38200f4..9ca5c60 100644 --- a/frontend/src/components/Grid/index.vue +++ b/frontend/src/components/Grid/index.vue @@ -108,15 +108,15 @@ const findIndex = () => { let suffixCols = 0; if (suffix) { suffixCols = - ((suffix as VNode).props![breakPoint.value]?.span ?? (suffix as VNode).props?.span ?? 1) + - ((suffix as VNode).props![breakPoint.value]?.offset ?? (suffix as VNode).props?.offset ?? 0); + ((suffix as VNode).props![breakPoint.value]?.span ?? (suffix as VNode).props?.span ?? 1) + + ((suffix as VNode).props![breakPoint.value]?.offset ?? (suffix as VNode).props?.offset ?? 0); } try { let find = false; fields.reduce((prev = 0, current, index) => { prev += - ((current as VNode)!.props![breakPoint.value]?.span ?? (current as VNode)!.props?.span ?? 1) + - ((current as VNode)!.props![breakPoint.value]?.offset ?? (current as VNode)!.props?.offset ?? 0); + ((current as VNode)!.props![breakPoint.value]?.span ?? (current as VNode)!.props?.span ?? 1) + + ((current as VNode)!.props![breakPoint.value]?.offset ?? (current as VNode)!.props?.offset ?? 0); if (Number(prev) > props.collapsedRows * gridCols.value - suffixCols) { hiddenIndex.value = index; find = true; @@ -132,19 +132,19 @@ const findIndex = () => { // 断点变化时执行 findIndex watch( - () => breakPoint.value, - () => { - if (props.collapsed) findIndex(); - } + () => breakPoint.value, + () => { + if (props.collapsed) findIndex(); + } ); // 监听 collapsed watch( - () => props.collapsed, - value => { - if (value) return findIndex(); - hiddenIndex.value = -1; - } + () => props.collapsed, + value => { + if (value) return findIndex(); + hiddenIndex.value = -1; + } ); // 设置间距 diff --git a/frontend/src/layouts/components/Header/components/Avatar.vue b/frontend/src/layouts/components/Header/components/Avatar.vue index ca9cd98..87daba7 100644 --- a/frontend/src/layouts/components/Header/components/Avatar.vue +++ b/frontend/src/layouts/components/Header/components/Avatar.vue @@ -35,7 +35,7 @@ import { ref } from "vue"; import { LOGIN_URL } from "@/config"; import { useRouter } from "vue-router"; -import { logoutApi } from "@/api/modules/login"; +import { logoutApi } from "@/api/user/login"; import { useUserStore } from "@/stores/modules/user"; import { ElMessageBox, ElMessage } from "element-plus"; import InfoDialog from "./InfoDialog.vue"; diff --git a/frontend/src/stores/constant.ts b/frontend/src/stores/constant.ts index 247aade..4047d0c 100644 --- a/frontend/src/stores/constant.ts +++ b/frontend/src/stores/constant.ts @@ -14,3 +14,6 @@ export const TABS_STORE_KEY = "cn-tabs"; // pinia中user store的key export const USER_STORE_KEY = "cn-user"; +// pinia中dict store的key +export const DICT_STORE_KEY = "cn-dictData"; + diff --git a/frontend/src/stores/modules/auth.ts b/frontend/src/stores/modules/auth.ts index e5f70db..8e9ddcd 100644 --- a/frontend/src/stores/modules/auth.ts +++ b/frontend/src/stores/modules/auth.ts @@ -1,6 +1,6 @@ import { defineStore } from "pinia"; import { AuthState } from "@/stores/interface"; -import { getAuthButtonListApi, getAuthMenuListApi } from "@/api/modules/login"; +import { getAuthButtonListApi, getAuthMenuListApi } from "@/api/user/login"; import { getFlatMenuList, getShowMenuList, diff --git a/frontend/src/stores/modules/dict.ts b/frontend/src/stores/modules/dict.ts new file mode 100644 index 0000000..06aab62 --- /dev/null +++ b/frontend/src/stores/modules/dict.ts @@ -0,0 +1,22 @@ +import { defineStore } from 'pinia' +import piniaPersistConfig from '@/stores/helper/persist' +import { DICT_STORE_KEY } from '@/stores/constant' +// 模拟数据 +import dictData from '@/api/system/dictData' + +export const useDictStore = defineStore({ + id: DICT_STORE_KEY, + state: () => ({ + dictData, + }), + getters: {}, + actions: { + // 获取字典数据数组,如果为空则返回空数组 + getDictData(code: string) { + const dict = this.dictData.find(item => item.code === code ) + return dict?.children || [] + }, + // 初始化获取全部字典数据并缓存 + }, + persist: piniaPersistConfig(DICT_STORE_KEY), +}) diff --git a/frontend/src/views/demo/proTable/index.vue b/frontend/src/views/demo/proTable/index.vue new file mode 100644 index 0000000..70c1f19 --- /dev/null +++ b/frontend/src/views/demo/proTable/index.vue @@ -0,0 +1,213 @@ + + + diff --git a/frontend/src/views/login/components/LoginForm.vue b/frontend/src/views/login/components/LoginForm.vue index 392560f..7ed7519 100644 --- a/frontend/src/views/login/components/LoginForm.vue +++ b/frontend/src/views/login/components/LoginForm.vue @@ -58,7 +58,7 @@ import { HOME_URL } from "@/config"; import { getTimeState } from "@/utils"; import { Login } from "@/api/interface"; import { ElNotification } from "element-plus"; -import { loginApi } from "@/api/modules/login"; +import { loginApi } from "@/api/user/login"; import { useUserStore } from "@/stores/modules/user"; import { useTabsStore } from "@/stores/modules/tabs"; import { useKeepAliveStore } from "@/stores/modules/keepAlive"; diff --git a/frontend/src/views/machine/testScript/index.vue b/frontend/src/views/machine/testScript/index.vue index 17cace5..810daf7 100644 --- a/frontend/src/views/machine/testScript/index.vue +++ b/frontend/src/views/machine/testScript/index.vue @@ -1,10 +1,10 @@ \ No newline at end of file + diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 21d3001..f46b2ce 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -9,12 +9,14 @@ } ], "compilerOptions": { + "strict": true, + "alwaysStrict": true, + "strictFunctionTypes": true, "target": "esnext", "declaration": true, "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "Node", - "strict": true, "jsx": "preserve", "jsxImportSource": "vue", "allowJs": true,