feat: user manage
This commit is contained in:
parent
165efaa1ab
commit
1b36e43ac5
74
ui/src/api/user/user-manage.ts
Normal file
74
ui/src/api/user/user-manage.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { Result } from '@/request/Result'
|
||||
import { get, put, post, del } from '@/request/index'
|
||||
import type { pageRequest } from '@/api/type/common'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
const prefix = '/user_manage'
|
||||
/**
|
||||
* 用户分页列表
|
||||
* @query 参数
|
||||
email_or_username: string
|
||||
*/
|
||||
const getUserManage: (
|
||||
page: pageRequest,
|
||||
email_or_username: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<any>> = (page, email_or_username, loading) => {
|
||||
return get(
|
||||
`${prefix}/${page.current_page}/${page.page_size}`,
|
||||
email_or_username ? { email_or_username } : undefined,
|
||||
loading,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param 参数 user_id,
|
||||
*/
|
||||
const delUserManage: (user_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
|
||||
user_id,
|
||||
loading,
|
||||
) => {
|
||||
return del(`${prefix}/${user_id}`, undefined, {}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
const postUserManage: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||
data,
|
||||
loading,
|
||||
) => {
|
||||
return post(`${prefix}`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户
|
||||
*/
|
||||
const putUserManage: (
|
||||
user_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<any>> = (user_id, data, loading) => {
|
||||
return put(`${prefix}/${user_id}`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
const putUserManagePassword: (
|
||||
user_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (user_id, data, loading) => {
|
||||
return put(`${prefix}/${user_id}/re_password`, data, undefined, loading)
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
getUserManage,
|
||||
putUserManage,
|
||||
delUserManage,
|
||||
postUserManage,
|
||||
putUserManagePassword
|
||||
}
|
||||
2
ui/src/components/app-icon/icons/common.ts
Normal file
2
ui/src/components/app-icon/icons/common.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import { h } from 'vue'
|
||||
export default {}
|
||||
@ -138,6 +138,31 @@ export const iconMap: any = {
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-wordspace': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M523.477333 113.92l429.568 273.408a21.333333 21.333333 0 0 1 0 36.010667L523.52 696.704a21.333333 21.333333 0 0 1-22.912 0L70.954667 423.338667a21.333333 21.333333 0 0 1 0-36.010667l429.610666-273.365333a21.333333 21.333333 0 0 1 22.912 0zM201.6 405.333333L512 602.88l310.4-197.546667L512 207.786667 201.6 405.333333z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M110.805333 592.469333a21.333333 21.333333 0 0 0-29.354666 7.04l-22.314667 36.394667a21.333333 21.333333 0 0 0 7.04 29.312l390.613333 239.530667a84.992 84.992 0 0 0 89.088 0l390.613334-239.530667a21.333333 21.333333 0 0 0 7.04-29.312l-22.314667-36.394667a21.333333 21.333333 0 0 0-29.312-7.04L506.88 828.586667a10.666667 10.666667 0 0 1-11.136 0l-384.981333-236.074667z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
// 动态加载的图标
|
||||
...dynamicIcons,
|
||||
}
|
||||
|
||||
@ -135,6 +135,7 @@ defineExpose({
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
tableHeight.value = window.innerHeight - 300
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
|
||||
@ -83,7 +83,6 @@ function subHoveredEnter() {
|
||||
position: relative;
|
||||
min-height: var(--card-min-height);
|
||||
min-width: var(--card-min-width);
|
||||
border-radius: 8px;
|
||||
.card-header {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
@ -8,9 +8,7 @@
|
||||
<slot name="header">
|
||||
<h4>{{ header }}</h4>
|
||||
</slot>
|
||||
<slot name="search">
|
||||
<h4>{{ header }}</h4>
|
||||
</slot>
|
||||
<slot name="search"> </slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,18 +1,26 @@
|
||||
·
|
||||
<template>
|
||||
<div class="app-top-bar-container border-b flex-center">
|
||||
<div class="logo">
|
||||
<div class="logo mt-4">
|
||||
<LogoFull />
|
||||
</div>
|
||||
|
||||
<div class="flex-between w-full">
|
||||
<div><el-divider direction="vertical" />{{ $t('views.system.title') }}</div>
|
||||
<h4><el-divider class="ml-16 mr-16" direction="vertical" />{{ $t('views.system.title') }}</h4>
|
||||
<div>
|
||||
<TopAbout></TopAbout>
|
||||
<span class="mr-8 lighter flex align-center"
|
||||
><el-divider class="ml-8 mr-8" direction="vertical" />
|
||||
<el-button link @click="router.push({ path: '/' })">
|
||||
<AppIcon class="mr-8" iconName="app-wordspace" style="font-size: 16px"></AppIcon>
|
||||
{{ '返回工作空间' }}</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Avatar></Avatar>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TopMenu from './top-menu/index.vue'
|
||||
import Avatar from './avatar/index.vue'
|
||||
import TopAbout from './top-about/index.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
·
|
||||
<template>
|
||||
<div class="app-top-bar-container border-b flex-center">
|
||||
<div class="logo">
|
||||
<div class="logo mt-4">
|
||||
<LogoFull />
|
||||
</div>
|
||||
<div class="flex-between w-full">
|
||||
|
||||
@ -4,7 +4,7 @@ import applicationOverview from './application-overview'
|
||||
import dataset from './dataset'
|
||||
import system from './system'
|
||||
import tool from './tool'
|
||||
import user from './user'
|
||||
import userManage from './user-manage'
|
||||
import team from './team'
|
||||
import model from './model'
|
||||
import document from './document'
|
||||
@ -20,7 +20,7 @@ export default {
|
||||
applicationOverview,
|
||||
system,
|
||||
tool,
|
||||
user,
|
||||
userManage,
|
||||
team,
|
||||
model,
|
||||
dataset,
|
||||
|
||||
@ -2,6 +2,8 @@ export default {
|
||||
title: 'User',
|
||||
createUser: 'Create User',
|
||||
editUser: 'Edit User',
|
||||
info: 'Base Information',
|
||||
roleSetting: 'Role Setting',
|
||||
setting: {
|
||||
updatePwd: 'Change Password',
|
||||
},
|
||||
@ -50,7 +52,7 @@ export default {
|
||||
},
|
||||
},
|
||||
source: {
|
||||
label: 'User Type',
|
||||
label: 'User Source',
|
||||
local: 'System User',
|
||||
wecom: 'WeCom',
|
||||
lark: 'Lark',
|
||||
@ -13,5 +13,5 @@ export default {
|
||||
theme,
|
||||
layout,
|
||||
dynamicsForm,
|
||||
common
|
||||
common,
|
||||
}
|
||||
|
||||
@ -2,71 +2,73 @@ export default {
|
||||
title: '用户管理',
|
||||
createUser: '创建用户',
|
||||
editUser: '编辑用户',
|
||||
info: '基本信息',
|
||||
roleSetting: '角色设置',
|
||||
setting: {
|
||||
updatePwd: '修改用户密码'
|
||||
updatePwd: '修改用户密码',
|
||||
},
|
||||
tip: {
|
||||
professionalMessage: '社区版最多支持 2 个用户,如需拥有更多用户,请升级为专业版。',
|
||||
updatePwdSuccess: '修改用户密码成功'
|
||||
updatePwdSuccess: '修改用户密码成功',
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '是否删除用户:',
|
||||
confirmMessage: '删除用户,该用户创建的资源(应用、知识库、模型)都会删除,请谨慎操作。'
|
||||
confirmMessage: '删除用户,该用户创建的资源(应用、知识库、模型)都会删除,请谨慎操作。',
|
||||
},
|
||||
disabled: {
|
||||
confirmTitle: '是否禁用函数:',
|
||||
confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。'
|
||||
confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。',
|
||||
},
|
||||
userForm: {
|
||||
|
||||
form: {
|
||||
username: {
|
||||
label: '用户名',
|
||||
placeholder: '请输入用户名',
|
||||
requiredMessage: '请输入用户名',
|
||||
lengthMessage: '长度在 6 到 20 个字符'
|
||||
lengthMessage: '长度在 6 到 20 个字符',
|
||||
},
|
||||
captcha: {
|
||||
label: '验证码',
|
||||
placeholder: '请输入验证码'
|
||||
placeholder: '请输入验证码',
|
||||
},
|
||||
nick_name: {
|
||||
label: '姓名',
|
||||
placeholder: '请输入姓名'
|
||||
placeholder: '请输入姓名',
|
||||
},
|
||||
email: {
|
||||
label: '邮箱',
|
||||
placeholder: '请输入邮箱',
|
||||
requiredMessage: '请输入邮箱',
|
||||
validatorEmail: '请输入有效邮箱格式!'
|
||||
validatorEmail: '请输入有效邮箱格式!',
|
||||
},
|
||||
phone: {
|
||||
label: '手机号',
|
||||
placeholder: '请输入手机号'
|
||||
placeholder: '请输入手机号',
|
||||
},
|
||||
password: {
|
||||
label: '登录密码',
|
||||
placeholder: '请输入密码',
|
||||
requiredMessage: '请输入密码',
|
||||
lengthMessage: '长度在 6 到 20 个字符'
|
||||
lengthMessage: '长度在 6 到 20 个字符',
|
||||
},
|
||||
new_password: {
|
||||
label: '新密码',
|
||||
placeholder: '请输入新密码',
|
||||
requiredMessage: '请输入新密码'
|
||||
requiredMessage: '请输入新密码',
|
||||
},
|
||||
re_password: {
|
||||
label: '确认密码',
|
||||
placeholder: '请输入确认密码',
|
||||
requiredMessage: '请输入确认密码',
|
||||
validatorMessage: '密码不一致'
|
||||
}
|
||||
}
|
||||
validatorMessage: '密码不一致',
|
||||
},
|
||||
},
|
||||
|
||||
source: {
|
||||
label: '用户类型',
|
||||
label: '用户来源',
|
||||
local: '系统用户',
|
||||
wecom: '企业微信',
|
||||
lark: '飞书',
|
||||
dingtalk: '钉钉'
|
||||
}
|
||||
dingtalk: '钉钉',
|
||||
},
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import applicationOverview from './application-overview'
|
||||
import dataset from './dataset'
|
||||
import system from './system'
|
||||
import tool from './tool'
|
||||
import user from './user'
|
||||
import userManage from './user-manage'
|
||||
import team from './team'
|
||||
import model from './model'
|
||||
import document from './document'
|
||||
@ -20,7 +20,7 @@ export default {
|
||||
applicationOverview,
|
||||
system,
|
||||
tool,
|
||||
user,
|
||||
userManage,
|
||||
team,
|
||||
model,
|
||||
dataset,
|
||||
|
||||
@ -2,6 +2,8 @@ export default {
|
||||
title: '使用者管理',
|
||||
createUser: '建立使用者',
|
||||
editUser: '編輯使用者',
|
||||
info: '使用者資訊',
|
||||
roleSetting: '角色設定',
|
||||
setting: {
|
||||
updatePwd: '修改使用者密碼'
|
||||
},
|
||||
@ -59,7 +61,7 @@ export default {
|
||||
}
|
||||
},
|
||||
source: {
|
||||
label: '使用者類型',
|
||||
label: '使用者來源',
|
||||
local: '系統使用者',
|
||||
wecom: '企業微信',
|
||||
lark: '飛書',
|
||||
@ -19,8 +19,13 @@
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// card
|
||||
.el-card {
|
||||
--el-card-padding: calc(var(--app-base-px) * 2);
|
||||
--el-card-border-radius: 8px;
|
||||
box-shadow: 0px 2px 4px 0px rgba(31, 35, 41, 0.12) !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
// tree
|
||||
|
||||
30
ui/src/utils/time.ts
Normal file
30
ui/src/utils/time.ts
Normal file
@ -0,0 +1,30 @@
|
||||
const getCheckDate = (timestamp: any) => {
|
||||
if (!timestamp) return false
|
||||
const dt = new Date(timestamp)
|
||||
if (isNaN(dt.getTime())) return false
|
||||
return dt
|
||||
}
|
||||
export const datetimeFormat = (timestamp: any) => {
|
||||
const dt = getCheckDate(timestamp)
|
||||
if (!dt) return timestamp
|
||||
|
||||
const y = dt.getFullYear()
|
||||
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
|
||||
const d = (dt.getDate() + '').padStart(2, '0')
|
||||
const hh = (dt.getHours() + '').padStart(2, '0')
|
||||
const mm = (dt.getMinutes() + '').padStart(2, '0')
|
||||
const ss = (dt.getSeconds() + '').padStart(2, '0')
|
||||
|
||||
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
|
||||
}
|
||||
|
||||
export const dateFormat = (timestamp: any) => {
|
||||
const dt = getCheckDate(timestamp)
|
||||
if (!dt) return timestamp
|
||||
|
||||
const y = dt.getFullYear()
|
||||
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
|
||||
const d = (dt.getDate() + '').padStart(2, '0')
|
||||
|
||||
return `${y}-${m}-${d}`
|
||||
}
|
||||
@ -15,7 +15,7 @@
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.password"
|
||||
:placeholder="$t('views.user.userForm.form.password.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
@ -28,7 +28,7 @@
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.re_password"
|
||||
:placeholder="$t('views.user.userForm.form.re_password.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm..re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
@ -86,32 +86,32 @@ const rules = ref<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.re_password.requiredMessage'),
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.user.userForm.form.password.lengthMessage'),
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.re_password.requiredMessage'),
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.user.userForm.form.password.lengthMessage'),
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error(t('views.user.userForm.form.re_password.validatorMessage')))
|
||||
callback(new Error(t('views.login.loginForm.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.password"
|
||||
:placeholder="$t('views.user.userForm.form.password.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
@ -28,7 +28,7 @@
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.re_password"
|
||||
:placeholder="$t('views.user.userForm.form.re_password.placeholder')"
|
||||
:placeholder="$t('views.login.loginForm.re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
@ -86,32 +86,32 @@ const rules = ref<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.re_password.requiredMessage'),
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.user.userForm.form.password.lengthMessage'),
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.user.userForm.form.re_password.requiredMessage'),
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.user.userForm.form.password.lengthMessage'),
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error(t('views.user.userForm.form.re_password.validatorMessage')))
|
||||
callback(new Error(t('views.login.loginForm.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
|
||||
199
ui/src/views/user-manage/component/UserDrawer.vue
Normal file
199
ui/src/views/user-manage/component/UserDrawer.vue
Normal file
@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<el-drawer v-model="visible" size="60%">
|
||||
<template #header>
|
||||
<h4>{{ title }}</h4>
|
||||
</template>
|
||||
<h4 class="title-decoration-1 mb-16 mt-8">{{ $t('views.userManage.info') }}</h4>
|
||||
<el-form
|
||||
ref="userFormRef"
|
||||
:model="userForm"
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
@submit.prevent
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<el-form-item
|
||||
:prop="isEdit ? '' : 'username'"
|
||||
:label="$t('views.userManage.form.username.label')"
|
||||
>
|
||||
<el-input
|
||||
v-model="userForm.username"
|
||||
:placeholder="$t('views.userManage.form.username.placeholder')"
|
||||
maxlength="20"
|
||||
show-word-limit
|
||||
:disabled="isEdit"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.nick_name.label')">
|
||||
<el-input
|
||||
v-model="userForm.nick_name"
|
||||
:placeholder="$t('views.userManage.form.nick_name.placeholder')"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.email.label')" prop="email">
|
||||
<el-input
|
||||
type="email"
|
||||
v-model="userForm.email"
|
||||
:placeholder="$t('views.userManage.form.email.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.phone.label')">
|
||||
<el-input
|
||||
v-model="userForm.phone"
|
||||
:placeholder="$t('views.userManage.form.phone.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click.prevent="visible = false"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="submit(userFormRef)" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const userFormRef = ref()
|
||||
const userForm = ref<any>({
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
nick_name: '',
|
||||
})
|
||||
|
||||
const rules = reactive({
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.username.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.username.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.email.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
const visible = ref<boolean>(false)
|
||||
const loading = ref(false)
|
||||
const isEdit = ref(false)
|
||||
|
||||
watch(visible, (bool) => {
|
||||
if (!bool) {
|
||||
userForm.value = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
nick_name: '',
|
||||
}
|
||||
isEdit.value = false
|
||||
userFormRef.value?.clearValidate()
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
if (data) {
|
||||
userForm.value['id'] = data.id
|
||||
userForm.value.username = data.username
|
||||
userForm.value.email = data.email
|
||||
userForm.value.password = data.password
|
||||
userForm.value.phone = data.phone
|
||||
userForm.value.nick_name = data.nick_name
|
||||
isEdit.value = true
|
||||
}
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
if (isEdit.value) {
|
||||
userManageApi.putUserManage(userForm.value.id, userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
MsgSuccess(t('common.editSuccess'))
|
||||
visible.value = false
|
||||
})
|
||||
} else {
|
||||
userManageApi.postUserManage(userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
MsgSuccess(t('common.createSuccess'))
|
||||
visible.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
133
ui/src/views/user-manage/component/UserPwdDialog.vue
Normal file
133
ui/src/views/user-manage/component/UserPwdDialog.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<el-dialog :title="$t('views.userManage.setting.updatePwd')" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="userFormRef"
|
||||
:model="userForm"
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
@submit.prevent
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<el-form-item :label="$t('views.userManage.form.new_password.label')" prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.new_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.re_password.label')" prop="re_password">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.re_password"
|
||||
:placeholder="$t('views.userManage.form.re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="submit(userFormRef)" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import useStore from '@/stores'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { ResetPasswordRequest } from '@/api/type/user'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const { user } = useStore()
|
||||
|
||||
const userFormRef = ref()
|
||||
const userForm = ref<any>({
|
||||
password: '',
|
||||
re_password: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.new_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (userFormRef.value.password != userFormRef.value.re_password) {
|
||||
callback(new Error(t('views.userManage.form.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const loading = ref(false)
|
||||
const userId = ref('')
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
userForm.value = {
|
||||
password: '',
|
||||
re_password: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
userId.value = data.id
|
||||
dialogVisible.value = true
|
||||
userFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
userManageApi.putUserManagePassword(userId.value, userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
user.profile()
|
||||
MsgSuccess(t('views.userManage.tip.updatePwdSuccess'))
|
||||
dialogVisible.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,9 +1,259 @@
|
||||
<template>111</template>
|
||||
<template>
|
||||
<div class="p-16-24">
|
||||
<h4 class="mb-16">{{ $t('views.userManage.title') }}</h4>
|
||||
<el-card>
|
||||
<div class="flex-between mb-16">
|
||||
<el-button type="primary" @click="createUser">{{
|
||||
$t('views.userManage.createUser')
|
||||
}}</el-button>
|
||||
<div class="flex-between complex-search">
|
||||
<el-select
|
||||
class="complex-search__left"
|
||||
v-model="search_type"
|
||||
style="width: 120px"
|
||||
@change="search_type_change"
|
||||
>
|
||||
<el-option :label="$t('views.login.loginForm.username.label')" value="name" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-if="search_type === 'name'"
|
||||
v-model="search_form.name"
|
||||
@change="getList"
|
||||
:placeholder="$t('common.searchBar.placeholder')"
|
||||
style="width: 220px"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<app-table
|
||||
class="mt-16"
|
||||
:data="userTableData"
|
||||
:pagination-config="paginationConfig"
|
||||
@sizeChange="handleSizeChange"
|
||||
@changePage="getList"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column prop="nick_name" :label="$t('views.userManage.form.nick_name.label')" />
|
||||
<el-table-column prop="username" :label="$t('views.userManage.form.username.label')" />
|
||||
<el-table-column prop="is_active" :label="$t('common.status.label')">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.is_active" class="flex align-center">
|
||||
<el-icon class="color-success mr-8" style="font-size: 16px"
|
||||
><SuccessFilled
|
||||
/></el-icon>
|
||||
<span class="color-secondary">
|
||||
{{ $t('common.status.enabled') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex align-center">
|
||||
<AppIcon iconName="app-disabled" class="color-secondary mr-8"></AppIcon>
|
||||
<span class="color-secondary">
|
||||
{{ $t('common.status.disabled') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="email"
|
||||
:label="$t('views.userManage.form.email.label')"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ row.email || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" :label="$t('views.userManage.form.phone.label')">
|
||||
<template #default="{ row }">
|
||||
{{ row.phone || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="source" :label="$t('views.userManage.source.label')">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.source === 'LOCAL'
|
||||
? $t('views.userManage.source.local')
|
||||
: row.source === 'wecom'
|
||||
? $t('views.userManage.source.wecom')
|
||||
: row.source === 'lark'
|
||||
? $t('views.userManage.source.lark')
|
||||
: row.source === 'dingtalk'
|
||||
? $t('views.userManage.source.dingtalk')
|
||||
: row.source === 'OAUTH2' || row.source === 'OAuth2'
|
||||
? 'OAuth2'
|
||||
: row.source
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.createTime')" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ datetimeFormat(row.create_time) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.operation')" width="160" align="left" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<span @click.stop>
|
||||
<el-switch
|
||||
:disabled="row.role === 'ADMIN'"
|
||||
size="small"
|
||||
v-model="row.is_active"
|
||||
:before-change="() => changeState(row)"
|
||||
/>
|
||||
</span>
|
||||
<el-divider direction="vertical" />
|
||||
<span class="mr-8">
|
||||
<el-button type="primary" text @click.stop="editUser(row)" :title="$t('common.edit')">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
|
||||
<span class="mr-8">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
@click.stop="editPwdUser(row)"
|
||||
:title="$t('views.userManage.setting.updatePwd')"
|
||||
>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
<span>
|
||||
<el-button
|
||||
:disabled="row.role === 'ADMIN'"
|
||||
type="primary"
|
||||
text
|
||||
@click.stop="deleteUserManage(row)"
|
||||
:title="$t('common.delete')"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</app-table>
|
||||
</el-card>
|
||||
<UserDrawer :title="title" ref="UserDrawerRef" @refresh="refresh" />
|
||||
<UserPwdDialog ref="UserPwdDialogRef" @refresh="refresh" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, reactive, watch } from 'vue'
|
||||
import UserDrawer from './component/UserDrawer.vue'
|
||||
import UserPwdDialog from './component/UserPwdDialog.vue'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { datetimeFormat } from '@/utils/time'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const search_type = ref('name')
|
||||
const search_form = ref<{
|
||||
name: string
|
||||
}>({
|
||||
name: '',
|
||||
})
|
||||
|
||||
onMounted(() => {})
|
||||
const UserDrawerRef = ref()
|
||||
const UserPwdDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 20,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
const userTableData = ref<any[]>([])
|
||||
|
||||
const search_type_change = () => {
|
||||
search_form.value = { name: '' }
|
||||
}
|
||||
function handleSizeChange() {
|
||||
paginationConfig.current_page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function getList() {
|
||||
return userManageApi
|
||||
.getUserManage(paginationConfig, search_form.value.name, loading)
|
||||
.then((res) => {
|
||||
userTableData.value = res.data.records
|
||||
paginationConfig.total = res.data.total
|
||||
})
|
||||
}
|
||||
|
||||
function changeState(row: any) {
|
||||
const obj = {
|
||||
is_active: !row.is_active,
|
||||
}
|
||||
const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
|
||||
userManageApi
|
||||
.putUserManage(row.id, obj, loading)
|
||||
.then((res) => {
|
||||
getList()
|
||||
MsgSuccess(str)
|
||||
return true
|
||||
})
|
||||
.catch(() => {
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
const title = ref('')
|
||||
function editUser(row: any) {
|
||||
title.value = t('views.userManage.editUser')
|
||||
UserDrawerRef.value.open(row)
|
||||
}
|
||||
|
||||
function createUser() {
|
||||
// common.asyncGetValid(ValidType.User, ValidCount.User, loading).then(async (res: any) => {
|
||||
// if (res?.data) {
|
||||
// title.value = t('views.userManage.createUser')
|
||||
// UserDrawerRef.value.open()
|
||||
// } else if (res?.code === 400) {
|
||||
// MsgConfirm(t('common.tip'), t('views.userManage.tip.professionalMessage'), {
|
||||
// cancelButtonText: t('common.confirm'),
|
||||
// confirmButtonText: t('common.professional'),
|
||||
// })
|
||||
// .then(() => {
|
||||
// window.open('https://maxkb.cn/pricing.html', '_blank')
|
||||
// })
|
||||
// .catch(() => {})
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
function deleteUserManage(row: any) {
|
||||
MsgConfirm(
|
||||
`${t('views.user.delete.confirmTitle')}${row.username} ?`,
|
||||
t('views.user.delete.confirmMessage'),
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
loading.value = true
|
||||
userManageApi.delUserManage(row.id, loading).then(() => {
|
||||
MsgSuccess(t('common.deleteSuccess'))
|
||||
getList()
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
function editPwdUser(row: any) {
|
||||
UserPwdDialogRef.value.open(row)
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
getList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user