diff --git a/practical_training/api/pt/neConfig.ts b/practical_training/api/pt/neConfig.ts new file mode 100644 index 00000000..6e45d4d9 --- /dev/null +++ b/practical_training/api/pt/neConfig.ts @@ -0,0 +1,107 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 保存为示例配置 (仅管理员操作) + * @param query 查询参数 + * @returns object + */ +export function ptSaveAsDefault(neType: string, neid: string) { + return request({ + url: `/pt/neConfigData/saveAsDefault`, + method: 'post', + data: { neType, neid }, + }); +} + +/** + * 重置为示例配置 (仅学生/教师操作) + * @param query 查询参数 + * @returns object + */ +export function ptResetAsDefault(neType: string) { + return request({ + url: `/pt/neConfigData/resetAsDefault`, + method: 'post', + data: { neType }, + }); +} + +/** + * 数据比较示例 + * @param params 查询参数 + * @returns object + */ +export function ptContrastAsDefault(params: Record) { + return request({ + url: `/pt/neConfigData/contrast`, + params, + method: 'get', + }); +} + +/** + * 配置数据导出Excel + * @param student 仅教师 student + * @returns object + */ +export function ptExport(student: string|undefined) { + return request({ + url: `/pt/neConfigData/export`, + method: 'get', + params: { student }, + responseType: 'blob', + timeout: 180_000, + }); +} + +/** + * 网元参数配置信息 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigData(params: Record) { + return request({ + url: `/pt/neConfigData`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置数据更新 + * @param data 数据 {neType,paramName:"参数名",paramData:{参数},loc:"层级index仅array"} + * @returns object + */ +export function editPtNeConfigData(data: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'put', + data: data, + }); +} + +/** + * 网元参数配置新增(array) + * @param data 数据 {neType,paramName:"参数名",paramData:{参数},loc:"层级index"} + * @returns object + */ +export function addPtNeConfigData(data: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'post', + data: data, + }); +} + +/** + * 网元参数配置删除(array) + * @param params 数据 {neType,paramName:"参数名",loc:"层级index"} + * @returns object + */ +export function delPtNeConfigData(params: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'delete', + params, + }); +} diff --git a/practical_training/api/pt/neConfigApply.ts b/practical_training/api/pt/neConfigApply.ts new file mode 100644 index 00000000..5fdca195 --- /dev/null +++ b/practical_training/api/pt/neConfigApply.ts @@ -0,0 +1,53 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 班级学生列表 (仅教师操作) + * @param params 数据 {userName} + * @returns object + */ +export function getPtClassStudents(params?: Record) { + return request({ + url: `/pt/neConfigApply/students`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置应用申请列表 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigApplyList(params: Record) { + return request({ + url: `/pt/neConfigApply/list`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置应用申请提交(仅学生操作) + * @param data 数据 { "neType": "MME", "status": "1" } + * @returns object + */ +export function stuPtNeConfigApply(data: Record) { + return request({ + url: `/pt/neConfigApply`, + method: 'post', + data: data, + }); +} + +/** + * 网元参数配置应用申请状态变更(仅管理员/教师操作) + * @param data 数据 { "applyId": "1", "neType": "MME", "status": "3", "backInfo": "sgw参数错误" } + * @returns object + */ +export function updatePtNeConfigApply(data: Record) { + return request({ + url: `/pt/neConfigApply`, + method: 'put', + data: data, + }); +} diff --git a/practical_training/api/pt/neConfigDataLog.ts b/practical_training/api/pt/neConfigDataLog.ts new file mode 100644 index 00000000..54c2dc0c --- /dev/null +++ b/practical_training/api/pt/neConfigDataLog.ts @@ -0,0 +1,27 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 网元参数配置数据变更日志信息 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigDataLogList(params: Record) { + return request({ + url: `/pt/neConfigDataLog`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置数据变更日志还原到数据 + * @param data 数据 { "id": "1", "value": "old" } + * @returns object + */ +export function restorePtNeConfigDataLog(data: Record) { + return request({ + url: `/pt/neConfigDataLog/restore`, + method: 'put', + data: data, + }); +} diff --git a/practical_training/api/pt/user.ts b/practical_training/api/pt/user.ts new file mode 100644 index 00000000..e7804e73 --- /dev/null +++ b/practical_training/api/pt/user.ts @@ -0,0 +1,42 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 导入用户模板数据 + * @param data 表单数据对象 + * @returns object + */ +export function importData(data: FormData) { + return request({ + url: '/pt/system/user/importData', + method: 'post', + data, + dataType: 'form-data', + timeout: 180_000, + }); +} + +/** + * 导入用户模板下载 + * @returns bolb + */ +export function importTemplate() { + return request({ + url: '/pt/system/user/importTemplate', + method: 'get', + responseType: 'blob', + }); +} + +/** + * 用户列表导出 + * @param query 查询参数 + * @returns bolb + */ +export function exportUser(query: Record) { + return request({ + url: '/pt/system/user/export', + method: 'post', + data: query, + responseType: 'blob', + }); +} diff --git a/practical_training/views/plugins/auth-user.ts b/practical_training/plugins/auth-user.ts similarity index 100% rename from practical_training/views/plugins/auth-user.ts rename to practical_training/plugins/auth-user.ts diff --git a/practical_training/views/store/modules/user.ts b/practical_training/store/modules/user.ts similarity index 100% rename from practical_training/views/store/modules/user.ts rename to practical_training/store/modules/user.ts diff --git a/practical_training/views/system/user/index.vue b/practical_training/views/system/user/index.vue new file mode 100644 index 00000000..02bf317f --- /dev/null +++ b/practical_training/views/system/user/index.vue @@ -0,0 +1,1584 @@ + + + + + diff --git a/src/api/pt/neConfig.ts b/src/api/pt/neConfig.ts new file mode 100644 index 00000000..6e45d4d9 --- /dev/null +++ b/src/api/pt/neConfig.ts @@ -0,0 +1,107 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 保存为示例配置 (仅管理员操作) + * @param query 查询参数 + * @returns object + */ +export function ptSaveAsDefault(neType: string, neid: string) { + return request({ + url: `/pt/neConfigData/saveAsDefault`, + method: 'post', + data: { neType, neid }, + }); +} + +/** + * 重置为示例配置 (仅学生/教师操作) + * @param query 查询参数 + * @returns object + */ +export function ptResetAsDefault(neType: string) { + return request({ + url: `/pt/neConfigData/resetAsDefault`, + method: 'post', + data: { neType }, + }); +} + +/** + * 数据比较示例 + * @param params 查询参数 + * @returns object + */ +export function ptContrastAsDefault(params: Record) { + return request({ + url: `/pt/neConfigData/contrast`, + params, + method: 'get', + }); +} + +/** + * 配置数据导出Excel + * @param student 仅教师 student + * @returns object + */ +export function ptExport(student: string|undefined) { + return request({ + url: `/pt/neConfigData/export`, + method: 'get', + params: { student }, + responseType: 'blob', + timeout: 180_000, + }); +} + +/** + * 网元参数配置信息 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigData(params: Record) { + return request({ + url: `/pt/neConfigData`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置数据更新 + * @param data 数据 {neType,paramName:"参数名",paramData:{参数},loc:"层级index仅array"} + * @returns object + */ +export function editPtNeConfigData(data: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'put', + data: data, + }); +} + +/** + * 网元参数配置新增(array) + * @param data 数据 {neType,paramName:"参数名",paramData:{参数},loc:"层级index"} + * @returns object + */ +export function addPtNeConfigData(data: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'post', + data: data, + }); +} + +/** + * 网元参数配置删除(array) + * @param params 数据 {neType,paramName:"参数名",loc:"层级index"} + * @returns object + */ +export function delPtNeConfigData(params: Record) { + return request({ + url: `/pt/neConfigData`, + method: 'delete', + params, + }); +} diff --git a/src/api/pt/neConfigApply.ts b/src/api/pt/neConfigApply.ts new file mode 100644 index 00000000..5fdca195 --- /dev/null +++ b/src/api/pt/neConfigApply.ts @@ -0,0 +1,53 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 班级学生列表 (仅教师操作) + * @param params 数据 {userName} + * @returns object + */ +export function getPtClassStudents(params?: Record) { + return request({ + url: `/pt/neConfigApply/students`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置应用申请列表 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigApplyList(params: Record) { + return request({ + url: `/pt/neConfigApply/list`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置应用申请提交(仅学生操作) + * @param data 数据 { "neType": "MME", "status": "1" } + * @returns object + */ +export function stuPtNeConfigApply(data: Record) { + return request({ + url: `/pt/neConfigApply`, + method: 'post', + data: data, + }); +} + +/** + * 网元参数配置应用申请状态变更(仅管理员/教师操作) + * @param data 数据 { "applyId": "1", "neType": "MME", "status": "3", "backInfo": "sgw参数错误" } + * @returns object + */ +export function updatePtNeConfigApply(data: Record) { + return request({ + url: `/pt/neConfigApply`, + method: 'put', + data: data, + }); +} diff --git a/src/api/pt/neConfigDataLog.ts b/src/api/pt/neConfigDataLog.ts new file mode 100644 index 00000000..54c2dc0c --- /dev/null +++ b/src/api/pt/neConfigDataLog.ts @@ -0,0 +1,27 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 网元参数配置数据变更日志信息 + * @param params 数据 {neType,paramName} + * @returns object + */ +export function getPtNeConfigDataLogList(params: Record) { + return request({ + url: `/pt/neConfigDataLog`, + params, + method: 'get', + }); +} + +/** + * 网元参数配置数据变更日志还原到数据 + * @param data 数据 { "id": "1", "value": "old" } + * @returns object + */ +export function restorePtNeConfigDataLog(data: Record) { + return request({ + url: `/pt/neConfigDataLog/restore`, + method: 'put', + data: data, + }); +} diff --git a/src/api/pt/user.ts b/src/api/pt/user.ts new file mode 100644 index 00000000..e7804e73 --- /dev/null +++ b/src/api/pt/user.ts @@ -0,0 +1,42 @@ +import { request } from '@/plugins/http-fetch'; + +/** + * 导入用户模板数据 + * @param data 表单数据对象 + * @returns object + */ +export function importData(data: FormData) { + return request({ + url: '/pt/system/user/importData', + method: 'post', + data, + dataType: 'form-data', + timeout: 180_000, + }); +} + +/** + * 导入用户模板下载 + * @returns bolb + */ +export function importTemplate() { + return request({ + url: '/pt/system/user/importTemplate', + method: 'get', + responseType: 'blob', + }); +} + +/** + * 用户列表导出 + * @param query 查询参数 + * @returns bolb + */ +export function exportUser(query: Record) { + return request({ + url: '/pt/system/user/export', + method: 'post', + data: query, + responseType: 'blob', + }); +} diff --git a/src/plugins/auth-user.ts b/src/plugins/auth-user.ts index f736c6d3..e2fb9efb 100644 --- a/src/plugins/auth-user.ts +++ b/src/plugins/auth-user.ts @@ -1,6 +1,18 @@ import { ADMIN_PERMISSION, ADMIN_ROLE_KEY } from '@/constants/admin-constants'; import useUserStore from '@/store/modules/user'; +/** + * 是否系统管理员 + * @returns true | false + */ +export function isSystemAdmin(): boolean { + const userPermissions = useUserStore().permissions; + if (userPermissions.includes(ADMIN_PERMISSION)) return true; + const userRoles = useUserStore().roles; + if (userRoles.includes(ADMIN_ROLE_KEY)) return true; + return false; +} + /** * 只需含有其中权限 * @param role 权限字符数组 diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index a7bb65a6..3b8b5d42 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -133,12 +133,18 @@ const useUserStore = defineStore('user', { } // 水印文字信息=用户昵称 手机号 - // let waterMarkContent = this.userName; - // if (this.phonenumber) { - // waterMarkContent = `${this.userName} ${this.phonenumber}`; - // } + let waterMarkContent = this.userName; + if (this.phonenumber) { + waterMarkContent = `${this.userName} ${this.phonenumber}`; + } // useLayoutStore().changeWaterMark(waterMarkContent); useLayoutStore().changeWaterMark(''); + // 学生布局用不一样的 + if (this.roles.includes('student')) { + useLayoutStore().changeConf('layout', 'side'); + useLayoutStore().changeConf('menuTheme', 'dark'); + useLayoutStore().changeConf('tabRender', false); + } } // 网络错误时退出登录状态 if (res.code === 0) { diff --git a/src/views/store/modules/user.ts b/src/views/store/modules/user.ts deleted file mode 100644 index 3b8b5d42..00000000 --- a/src/views/store/modules/user.ts +++ /dev/null @@ -1,171 +0,0 @@ -import defaultAvatar from '@/assets/images/default_avatar.png'; -import useLayoutStore from './layout'; -import { login, logout, getInfo } from '@/api/login'; -import { setToken, removeToken } from '@/plugins/auth-token'; -import { defineStore } from 'pinia'; -import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants'; -import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; -import { parseUrlPath } from '@/plugins/file-static-url'; - -/**用户信息类型 */ -type UserInfo = { - /**用户ID */ - userId: string; - /**登录账号 */ - userName: string; - /**用户角色 字符串数组 */ - roles: string[]; - /**用户权限 字符串数组 */ - permissions: string[]; - /**用户头像 */ - avatar: string; - /**用户昵称 */ - nickName: string; - /**用户手机号 */ - phonenumber: string; - /**用户邮箱 */ - email: string; - /**用户性别 */ - sex: string | undefined; - /**其他信息 */ - profile: Record; -}; - -const useUserStore = defineStore('user', { - state: (): UserInfo => ({ - userId: '', - userName: '', - roles: [], - permissions: [], - avatar: '', - nickName: '', - phonenumber: '', - email: '', - sex: undefined, - profile: {}, - }), - getters: { - /** - * 获取正确头像地址 - * @param state 内部属性不用传入 - * @returns 头像地址url - */ - getAvatar(state) { - if (!state.avatar) { - return defaultAvatar; - } - return parseUrlPath(state.avatar); - }, - /** - * 获取基础信息属性 - * @param state 内部属性不用传入 - * @returns 基础信息 - */ - getBaseInfo(state) { - return { - nickName: state.nickName, - phonenumber: state.phonenumber, - email: state.email, - sex: state.sex, - }; - }, - }, - actions: { - /** - * 更新基础信息属性 - * @param data 变更信息 - */ - setBaseInfo(data: Record) { - this.nickName = data.nickName; - this.phonenumber = data.phonenumber; - this.email = data.email; - this.sex = data.sex; - }, - /** - * 更新头像 - * @param avatar 上传后的地址 - */ - setAvatar(avatar: string) { - this.avatar = avatar; - }, - /** - * 获取正确头像地址 - * @param avatar - */ - fnAvatar(avatar: string) { - if (!avatar) { - return defaultAvatar; - } - return parseUrlPath(avatar); - }, - // 登录 - async fnLogin(loginBody: Record) { - const res = await login(loginBody); - if (res.code === RESULT_CODE_SUCCESS && res.data) { - const token = res.data[TOKEN_RESPONSE_FIELD]; - setToken(token); - } - return res; - }, - // 获取用户信息 - async fnGetInfo() { - const res = await getInfo(); - if (res.code === RESULT_CODE_SUCCESS && res.data) { - const { user, roles, permissions } = res.data; - this.userId = user.userId; - // 登录账号 - this.userName = user.userName; - // 用户头像 - this.avatar = user.avatar; - // 基础信息 - this.nickName = user.nickName; - this.phonenumber = user.phonenumber; - this.email = user.email; - this.sex = user.sex; - - // 验证返回的roles是否是一个非空数组 - if (Array.isArray(roles) && roles.length > 0) { - this.roles = roles; - this.permissions = permissions; - } else { - this.roles = ['ROLE_DEFAULT']; - this.permissions = []; - } - - // 水印文字信息=用户昵称 手机号 - let waterMarkContent = this.userName; - if (this.phonenumber) { - waterMarkContent = `${this.userName} ${this.phonenumber}`; - } - // useLayoutStore().changeWaterMark(waterMarkContent); - useLayoutStore().changeWaterMark(''); - // 学生布局用不一样的 - if (this.roles.includes('student')) { - useLayoutStore().changeConf('layout', 'side'); - useLayoutStore().changeConf('menuTheme', 'dark'); - useLayoutStore().changeConf('tabRender', false); - } - } - // 网络错误时退出登录状态 - if (res.code === 0) { - removeToken(); - window.location.reload(); - } - return res; - }, - // 退出系统 - async fnLogOut() { - try { - await logout(); - } catch (error) { - throw error; - } finally { - this.roles = []; - this.permissions = []; - removeToken(); - } - }, - }, -}); - -export default useUserStore; diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index f30d787c..02bf317f 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -8,9 +8,6 @@ import { MenuInfo } from 'ant-design-vue/es/menu/src/interface'; import { ColumnsType } from 'ant-design-vue/es/table'; import UploadModal from '@/components/UploadModal/index.vue'; import { - importData, - importTemplate, - exportUser, changeUserStatus, listUser, resetUserPwd, @@ -19,6 +16,7 @@ import { updateUser, addUser, } from '@/api/system/user'; +import { importData, importTemplate, exportUser } from '@/api/pt/user'; import { deptTreeSelect } from '@/api/system/dept'; import { saveAs } from 'file-saver'; import useI18n from '@/hooks/useI18n'; @@ -442,6 +440,11 @@ function fnModalOk() { .then(() => { modalState.confirmLoading = true; const from = toRaw(modalState.from); + // 教师角色只能新增学生 + if (!from.userId && userStore.roles.includes('teacher')) { + from.postIds = ['3']; + from.roleIds = ['4']; + } const user = from.userId ? updateUser(from) : addUser(from); const key = 'user'; message.loading({ content: t('common.loading'), key }); @@ -763,6 +766,16 @@ function fnGetDeptTree() { }); } +/**选择指定只能一个 */ +function fnSelectOne(v: string, type: string) { + if (type === 'postId') { + modalState.from.postIds = [v]; + } + if (type === 'roleId') { + modalState.from.roleIds = [v]; + } +} + onMounted(() => { // 初始字典数据 Promise.allSettled([ @@ -1163,7 +1176,7 @@ onMounted(() => { - + { :options="modalState.options.posts" :field-names="{ label: 'postName', value: 'postId' }" :placeholder="t('common.selectPlease')" + @select="(value:any) => fnSelectOne(value, 'postId')" > - + { :options="modalState.options.roles" :field-names="{ label: 'roleName', value: 'roleId' }" :placeholder="t('common.selectPlease')" + @select="(value:any) => fnSelectOne(value, 'roleId')" > @@ -1445,6 +1460,7 @@ onMounted(() => { :label="t('views.system.user.fromClass')" name="deptId" :label-col="{ span: 3 }" + v-perms:has="['system:user:editPost']" >