From dae0830d24a903e79693f7bc2b74a766141ce568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 21 Mar 2023 00:29:25 +0800 Subject: [PATCH] add dashboard/account --- backend/api.go | 25 ++++ backend/global/user.go | 14 +- backend/message.go | 2 +- backend/user.go | 53 +++++++- .../vben/src/api/demo/model/systemModel.ts | 18 +-- frontend/vben/src/api/demo/system.ts | 25 +++- frontend/vben/src/api/sys/model/userModel.ts | 9 ++ frontend/vben/src/api/sys/user.ts | 37 +++--- .../locales/lang/zh-CN/routes/dashboard.ts | 1 + .../src/router/menus/modules/dashboard.ts | 4 + .../src/router/routes/modules/dashboard.ts | 10 ++ .../views/dashboard/account/AccountModal.vue | 68 ++++++++++ .../views/dashboard/account/account.data.ts | 118 +++++++++++++++++ .../src/views/dashboard/account/index.vue | 124 ++++++++++++++++++ .../workbench/components/WorkbenchHeader.vue | 4 +- 15 files changed, 463 insertions(+), 49 deletions(-) create mode 100644 frontend/vben/src/views/dashboard/account/AccountModal.vue create mode 100644 frontend/vben/src/views/dashboard/account/account.data.ts create mode 100644 frontend/vben/src/views/dashboard/account/index.vue diff --git a/backend/api.go b/backend/api.go index b576e44..683c6e5 100644 --- a/backend/api.go +++ b/backend/api.go @@ -120,6 +120,31 @@ func init() { writeresult(w, codeSuccess, n, messageOk, typeSuccess) }} + apimap["/api/getUsersList"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("Authorization") + ret, err := getUsersList(token) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, &ret, messageOk, typeSuccess) + }} + + apimap["/api/isNameExist"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("Authorization") + name := r.URL.Query().Get("username") + if name == "" { + writeresult(w, codeError, nil, "empty username", typeError) + return + } + yes, err := isNameExist(token, name) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, yes, messageOk, typeSuccess) + }} + apimap["/api/setPassword"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) { type setpasswordbody struct { Token string `json:"token"` diff --git a/backend/global/user.go b/backend/global/user.go index ecc7729..9ffe1ec 100644 --- a/backend/global/user.go +++ b/backend/global/user.go @@ -160,7 +160,7 @@ func (u *UserDatabase) AddUser(user *User, opname string) error { } // UpdateUserInfo ... -func (u *UserDatabase) UpdateUserInfo(id int, nick, avtr, desc string) error { +func (u *UserDatabase) UpdateUserInfo(id int, opname, nick, avtr, desc string) error { user, err := u.GetUserByID(id) if err != nil { return err @@ -180,7 +180,7 @@ func (u *UserDatabase) UpdateUserInfo(id int, nick, avtr, desc string) error { if err != nil { return err } - return u.SendMessage("更新了个人信息", user.Name, *user.ID) + return u.SendMessage("更新了个人信息", opname, *user.ID) } // UpdateUserRole ... @@ -203,7 +203,7 @@ func (u *UserDatabase) UpdateUserRole(id int, nr UserRole, opname string) error } // UpdateUserPassword ... -func (u *UserDatabase) UpdateUserPassword(id int, npwd string) error { +func (u *UserDatabase) UpdateUserPassword(id int, opname, npwd string) error { if npwd == "" { return ErrEmptyPassword } @@ -220,11 +220,11 @@ func (u *UserDatabase) UpdateUserPassword(id int, npwd string) error { if err != nil { return err } - return u.SendMessage("更新了密码", user.Name, *user.ID) + return u.SendMessage("更新了密码", opname, *user.ID) } // UpdateUserContact ... -func (u *UserDatabase) UpdateUserContact(id int, ncont string) error { +func (u *UserDatabase) UpdateUserContact(id int, opname, ncont string) error { if ncont == "" { return ErrEmptyContact } @@ -240,7 +240,7 @@ func (u *UserDatabase) UpdateUserContact(id int, ncont string) error { if err != nil { return err } - return u.SendMessage("更新了联系方式", user.Name, *user.ID) + return u.SendMessage("更新了联系方式", opname, *user.ID) } // GetUserByName avoids sql injection by limiting username to 0-9A-Za-z @@ -307,7 +307,7 @@ func (u *UserDatabase) GetUsers() (users []User, err error) { user.Pswd = "" users[i] = user i++ - if i >= n { + if i > n { return ErrInvalidUsersCount } return nil diff --git a/backend/message.go b/backend/message.go index 87b7e01..2a5a722 100644 --- a/backend/message.go +++ b/backend/message.go @@ -88,7 +88,7 @@ func acceptMessage(token string, id int) error { if err != nil { return err } - return global.UserDB.UpdateUserPassword(*u.ID, "123456") + return global.UserDB.UpdateUserPassword(*u.ID, user.Name, "123456") default: return errNothingToDo } diff --git a/backend/user.go b/backend/user.go index 8ee442f..3f1242a 100644 --- a/backend/user.go +++ b/backend/user.go @@ -18,7 +18,8 @@ const ( ) var ( - errInvalidToken = errors.New("invalid token") + errInvalidToken = errors.New("invalid token") + errNoListUsersPermission = errors.New("no list users permission") ) type getUserInfoResult struct { @@ -89,6 +90,50 @@ func getUsersCount(token string) (int, error) { return global.UserDB.GetUsersCount() } +type getUsersListResult struct { + ID int `json:"id"` + Name string `json:"name"` + Nick string `json:"nick"` + Role string `json:"role"` + Date string `json:"date"` + Desc string `json:"desc"` +} + +func getUsersList(token string) ([]getUsersListResult, error) { + user := usertokens.Get(token) + if user == nil { + return nil, errInvalidToken + } + if !user.IsSuper() { + return nil, errNoListUsersPermission + } + us, err := global.UserDB.GetUsers() + if err != nil { + return nil, err + } + ret := make([]getUsersListResult, len(us)) + for i, u := range us { + ret[i].ID = *u.ID + ret[i].Name = u.Name + ret[i].Nick = u.Nick + ret[i].Role = u.Role.Nick() + ret[i].Date = time.Unix(user.Date, 0).Format(chineseDateLayout) + ret[i].Desc = u.Desc + } + return ret, nil +} + +func isNameExist(token, name string) (bool, error) { + user := usertokens.Get(token) + if user == nil { + return false, errInvalidToken + } + if !user.IsSuper() { + return false, errNoListUsersPermission + } + return global.UserDB.IsNameExists(name), nil +} + func setUserPassword(id int, token, npwd string) error { user, err := global.UserDB.GetUserByID(id) if err != nil { @@ -100,7 +145,7 @@ func setUserPassword(id int, token, npwd string) error { if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) { return errInvalidToken } - return global.UserDB.UpdateUserPassword(id, npwd) + return global.UserDB.UpdateUserPassword(id, user.Name, npwd) } func setUserContact(id int, token, ncont string) error { @@ -114,7 +159,7 @@ func setUserContact(id int, token, ncont string) error { if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) { return errInvalidToken } - return global.UserDB.UpdateUserContact(id, ncont) + return global.UserDB.UpdateUserContact(id, user.Name, ncont) } // setUserInfo may change the arguments @@ -144,7 +189,7 @@ func setUserInfo(id int, nick, desc, avtr *string) error { if a == user.Avtr { a = "" } - return global.UserDB.UpdateUserInfo(id, n, a, d) + return global.UserDB.UpdateUserInfo(id, user.Name, n, a, d) } func resetPassword(ip, name, mobile string) error { diff --git a/frontend/vben/src/api/demo/model/systemModel.ts b/frontend/vben/src/api/demo/model/systemModel.ts index bb40ad0..4926ddd 100644 --- a/frontend/vben/src/api/demo/model/systemModel.ts +++ b/frontend/vben/src/api/demo/model/systemModel.ts @@ -23,14 +23,12 @@ export type MenuParams = { } export interface AccountListItem { - id: string - account: string - email: string - nickname: string + id: number + name: string + nick: string role: number - createTime: string - remark: string - status: number + date: string + desc: string } export interface DeptListItem { @@ -52,12 +50,8 @@ export interface MenuListItem { } export interface RoleListItem { - id: string roleName: string - roleValue: string - status: number - orderNo: string - createTime: string + value: string } /** diff --git a/frontend/vben/src/api/demo/system.ts b/frontend/vben/src/api/demo/system.ts index 4233e32..e8e819d 100644 --- a/frontend/vben/src/api/demo/system.ts +++ b/frontend/vben/src/api/demo/system.ts @@ -2,13 +2,14 @@ import { AccountParams, DeptListItem, MenuParams, - RoleParams, + // RoleParams, RolePageParams, MenuListGetResultModel, DeptListGetResultModel, AccountListGetResultModel, RolePageListGetResultModel, - RoleListGetResultModel, + // RoleListGetResultModel, + RoleListItem, } from './model/systemModel' import { defHttp } from '/@/utils/http/axios' @@ -19,7 +20,7 @@ enum Api { setRoleStatus = '/system/setRoleStatus', MenuList = '/system/getMenuList', RolePageList = '/system/getRoleListByPage', - GetAllRoleList = '/system/getAllRoleList', + // GetAllRoleList = '/system/getAllRoleList', } export const getAccountList = (params: AccountParams) => @@ -34,8 +35,22 @@ export const getMenuList = (params?: MenuParams) => export const getRoleListByPage = (params?: RolePageParams) => defHttp.get({ url: Api.RolePageList, params }) -export const getAllRoleList = (params?: RoleParams) => - defHttp.get({ url: Api.GetAllRoleList, params }) +export const getAllRoleList = () => { + return [ + { + roleName: '课程组长', + value: 'super', + }, + { + roleName: '归档代理', + value: 'filemgr', + }, + { + roleName: '课程组员', + value: 'user', + }, + ] as RoleListItem[] +} export const setRoleStatus = (id: number, status: string) => defHttp.post({ url: Api.setRoleStatus, params: { id, status } }) diff --git a/frontend/vben/src/api/sys/model/userModel.ts b/frontend/vben/src/api/sys/model/userModel.ts index c1bb7de..fc0877f 100644 --- a/frontend/vben/src/api/sys/model/userModel.ts +++ b/frontend/vben/src/api/sys/model/userModel.ts @@ -102,3 +102,12 @@ export interface GetUserInfoModel { export interface GetLoginSaltModel { salt: string } + +export interface GetUsersListModel { + id: number + name: string + nick: string + role: number + date: string + desc: string +} diff --git a/frontend/vben/src/api/sys/user.ts b/frontend/vben/src/api/sys/user.ts index dba8616..c6729b8 100644 --- a/frontend/vben/src/api/sys/user.ts +++ b/frontend/vben/src/api/sys/user.ts @@ -11,6 +11,7 @@ import { ResetPasswordResultModel, RegisterResultModel, GetLoginSaltModel, + GetUsersListModel, } from './model/userModel' import { ErrorMessageMode } from '/#/axios' @@ -26,8 +27,8 @@ enum Api { Register = '/register', GetUserInfo = '/getUserInfo', GetUsersCount = '/getUsersCount', - GetPermCode = '/getPermCode', - TestRetry = '/testRetry', + GetUsersList = '/getUsersList', + IsNameExist = '/isNameExist', } /** @@ -141,23 +142,23 @@ export function getUsersCount() { return defHttp.get({ url: Api.GetUsersCount }, { errorMessageMode: 'none' }) } -/*export function getPermCode() { - return defHttp.get({ url: Api.GetPermCode }) -}*/ +/** + * @description: getUsersList + */ +export function getUsersList() { + return defHttp.get({ url: Api.GetUsersList }, { errorMessageMode: 'none' }) +} + +/** + * @description: isNameExist + */ +export function isNameExist(username: string) { + return defHttp.get( + { url: Api.IsNameExist, params: { username } }, + { errorMessageMode: 'none' }, + ) +} export function doLogout() { return defHttp.get({ url: Api.Logout }, { errorMessageMode: 'none' }) } - -/*export function testRetry() { - return defHttp.get( - { url: Api.TestRetry }, - { - retryRequest: { - isOpenRetry: true, - count: 5, - waitTime: 1000, - }, - }, - ) -}*/ diff --git a/frontend/vben/src/locales/lang/zh-CN/routes/dashboard.ts b/frontend/vben/src/locales/lang/zh-CN/routes/dashboard.ts index 2c26a9a..b00c166 100644 --- a/frontend/vben/src/locales/lang/zh-CN/routes/dashboard.ts +++ b/frontend/vben/src/locales/lang/zh-CN/routes/dashboard.ts @@ -3,4 +3,5 @@ export default { about: '关于', workbench: '工作台', analysis: '分析页', + account: '用户管理', } diff --git a/frontend/vben/src/router/menus/modules/dashboard.ts b/frontend/vben/src/router/menus/modules/dashboard.ts index eb07d25..6aa921e 100644 --- a/frontend/vben/src/router/menus/modules/dashboard.ts +++ b/frontend/vben/src/router/menus/modules/dashboard.ts @@ -11,6 +11,10 @@ const menu: MenuModule = { path: 'analysis', name: t('routes.dashboard.analysis'), }, + { + path: 'account', + name: t('routes.dashboard.account'), + }, { path: 'workbench', name: t('routes.dashboard.workbench'), diff --git a/frontend/vben/src/router/routes/modules/dashboard.ts b/frontend/vben/src/router/routes/modules/dashboard.ts index 33cae3b..5de608e 100644 --- a/frontend/vben/src/router/routes/modules/dashboard.ts +++ b/frontend/vben/src/router/routes/modules/dashboard.ts @@ -25,6 +25,16 @@ const dashboard: AppRouteModule = { roles: [RoleEnum.SUPER], }, }, + { + path: 'account', + name: 'Account', + component: () => import('/@/views/dashboard/account/index.vue'), + meta: { + // affix: true, + title: t('routes.dashboard.account'), + roles: [RoleEnum.SUPER], + }, + }, { path: 'workbench', name: 'Workbench', diff --git a/frontend/vben/src/views/dashboard/account/AccountModal.vue b/frontend/vben/src/views/dashboard/account/AccountModal.vue new file mode 100644 index 0000000..d3c34df --- /dev/null +++ b/frontend/vben/src/views/dashboard/account/AccountModal.vue @@ -0,0 +1,68 @@ + + diff --git a/frontend/vben/src/views/dashboard/account/account.data.ts b/frontend/vben/src/views/dashboard/account/account.data.ts new file mode 100644 index 0000000..fd2e30f --- /dev/null +++ b/frontend/vben/src/views/dashboard/account/account.data.ts @@ -0,0 +1,118 @@ +import { isNameExist } from '/@/api/sys/user' +import { BasicColumn } from '/@/components/Table' +import { FormSchema } from '/@/components/Table' + +export const columns: BasicColumn[] = [ + { + title: '用户名', + dataIndex: 'name', + width: 120, + }, + { + title: '昵称', + dataIndex: 'nick', + width: 120, + }, + { + title: '创建时间', + dataIndex: 'date', + width: 180, + }, + { + title: '角色', + dataIndex: 'role', + width: 200, + }, + { + title: '简介', + dataIndex: 'desc', + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + field: 'name', + label: '用户名', + component: 'Input', + colProps: { span: 8 }, + }, + { + field: 'nick', + label: '昵称', + component: 'Input', + colProps: { span: 8 }, + }, +] + +export const nameFormSchema: FormSchema[] = [ + { + field: 'name', + label: '用户名', + component: 'Input', + helpMessage: ['不能输入带有admin的用户名'], + rules: [ + { + required: true, + message: '请输入用户名', + }, + { + validator(_, value) { + return new Promise((resolve, reject) => { + isNameExist(value) + .then((v) => { + if (v) resolve() + else reject('用户名已存在') + }) + .catch((err) => { + reject(err.message || '验证失败') + }) + }) + }, + }, + ], + }, + { + field: 'pwd', + label: '密码', + component: 'InputPassword', + required: true, + ifShow: false, + }, + { + label: '角色', + field: 'role', + component: 'ApiSelect', + componentProps: { + api: () => { + return [ + { + roleName: '课程组长', + value: 'super', + }, + { + roleName: '归档代理', + value: 'filemgr', + }, + { + roleName: '课程组员', + value: 'user', + }, + ] + }, + labelField: 'roleName', + valueField: 'value', + }, + required: true, + }, + { + field: 'nick', + label: '昵称', + component: 'Input', + required: true, + }, + { + label: '简介', + field: 'desc', + component: 'InputTextArea', + }, +] diff --git a/frontend/vben/src/views/dashboard/account/index.vue b/frontend/vben/src/views/dashboard/account/index.vue new file mode 100644 index 0000000..7cd814f --- /dev/null +++ b/frontend/vben/src/views/dashboard/account/index.vue @@ -0,0 +1,124 @@ + + diff --git a/frontend/vben/src/views/dashboard/workbench/components/WorkbenchHeader.vue b/frontend/vben/src/views/dashboard/workbench/components/WorkbenchHeader.vue index 0a94935..21a7747 100644 --- a/frontend/vben/src/views/dashboard/workbench/components/WorkbenchHeader.vue +++ b/frontend/vben/src/views/dashboard/workbench/components/WorkbenchHeader.vue @@ -36,8 +36,8 @@ const userStore = useUserStore() const userinfo = computed(() => userStore.getUserInfo) const enterDays = computed(() => { - const date: Date = new Date(new Date().getTime() - userStore.getUserInfo.date * 1000) - return date.getDay() + const date: number = new Date().getTime() - userStore.getUserInfo.date * 1000 + return (date / 1000 / 3600 / 24).toFixed(2) }) const userscount = ref(0) getUsersCount().then((value: number) => {