feat: user manage

This commit is contained in:
wangdan-fit2cloud 2025-05-29 18:41:44 +08:00
parent 165efaa1ab
commit 1b36e43ac5
21 changed files with 813 additions and 83 deletions

View 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
}

View File

@ -0,0 +1,2 @@
import { h } from 'vue'
export default {}

View File

@ -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,
}

View File

@ -135,6 +135,7 @@ defineExpose({
})
onMounted(() => {
tableHeight.value = window.innerHeight - 300
window.onresize = () => {
return (() => {

View File

@ -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;
}

View File

@ -8,9 +8,7 @@
<slot name="header">
<h4>{{ header }}</h4>
</slot>
<slot name="search">
<h4>{{ header }}</h4>
</slot>
<slot name="search"> </slot>
</div>
</div>

View File

@ -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>
<TopAbout></TopAbout>
<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'

View File

@ -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">

View File

@ -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,

View File

@ -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',

View File

@ -13,5 +13,5 @@ export default {
theme,
layout,
dynamicsForm,
common
common,
}

View File

@ -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 个字符'
},
captcha: {
label: '验证码',
placeholder: '请输入验证码'
},
nick_name: {
label: '姓名',
placeholder: '请输入姓名'
},
email: {
label: '邮箱',
placeholder: '请输入邮箱',
requiredMessage: '请输入邮箱',
validatorEmail: '请输入有效邮箱格式!'
},
phone: {
label: '手机号',
placeholder: '请输入手机号'
},
password: {
label: '登录密码',
placeholder: '请输入密码',
requiredMessage: '请输入密码',
lengthMessage: '长度在 6 到 20 个字符'
},
new_password: {
label: '新密码',
placeholder: '请输入新密码',
requiredMessage: '请输入新密码'
},
re_password: {
label: '确认密码',
placeholder: '请输入确认密码',
requiredMessage: '请输入确认密码',
validatorMessage: '密码不一致'
}
}
form: {
username: {
label: '用户名',
placeholder: '请输入用户名',
requiredMessage: '请输入用户名',
lengthMessage: '长度在 6 到 20 个字符',
},
captcha: {
label: '验证码',
placeholder: '请输入验证码',
},
nick_name: {
label: '姓名',
placeholder: '请输入姓名',
},
email: {
label: '邮箱',
placeholder: '请输入邮箱',
requiredMessage: '请输入邮箱',
validatorEmail: '请输入有效邮箱格式!',
},
phone: {
label: '手机号',
placeholder: '请输入手机号',
},
password: {
label: '登录密码',
placeholder: '请输入密码',
requiredMessage: '请输入密码',
lengthMessage: '长度在 6 到 20 个字符',
},
new_password: {
label: '新密码',
placeholder: '请输入新密码',
requiredMessage: '请输入新密码',
},
re_password: {
label: '确认密码',
placeholder: '请输入确认密码',
requiredMessage: '请输入确认密码',
validatorMessage: '密码不一致',
},
},
source: {
label: '用户类型',
label: '用户来源',
local: '系统用户',
wecom: '企业微信',
lark: '飞书',
dingtalk: '钉钉'
}
dingtalk: '钉钉',
},
}

View File

@ -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,

View File

@ -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: '飛書',

View File

@ -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
View 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}`
}

View File

@ -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()
}

View File

@ -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()
}

View 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>

View 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>

View File

@ -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>