You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by le...@apache.org on 2022/01/21 08:05:32 UTC
[dolphinscheduler] branch dev updated: [Feature][UI Next] Security User Manage (#8133)
This is an automated email from the ASF dual-hosted git repository.
leonbao pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new e0dbf3e [Feature][UI Next] Security User Manage (#8133)
e0dbf3e is described below
commit e0dbf3edc6200ed2abd1dffbcfaff8b53d7996f4
Author: lilyzhou <lj...@outlook.com>
AuthorDate: Fri Jan 21 16:04:05 2022 +0800
[Feature][UI Next] Security User Manage (#8133)
---
.../src/locales/modules/en_US.ts | 32 +++
.../src/locales/modules/zh_CN.ts | 30 +++
.../src/router/modules/security.ts | 4 +-
.../src/service/modules/users/index.ts | 8 +-
dolphinscheduler-ui-next/src/utils/regex.ts | 4 +-
.../security/user-manage/components/use-modal.ts | 277 +++++++++++++++++++++
.../security/user-manage/components/user-modal.tsx | 133 ++++++++++
.../src/views/security/user-manage/index.tsx | 144 +++++++++++
.../src/views/security/user-manage/use-table.tsx | 212 ++++++++++++++++
9 files changed, 837 insertions(+), 7 deletions(-)
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index f90db5d..ca0b64e 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -434,6 +434,38 @@ const security = {
edit: 'Edit',
delete: 'Delete',
delete_confirm: 'Delete?'
+ },
+ user: {
+ user_manage: 'User Manage',
+ create_user: 'Create User',
+ update_user: 'Update User',
+ delete_user: 'Delete User',
+ delete_confirm: 'Are you sure to delete?',
+ delete_confirm_tip:
+ 'Deleting user is a dangerous operation,please be careful',
+ index: 'Index',
+ username: 'Username',
+ username_exists: 'The username already exists',
+ username_rule_msg: 'Please enter username',
+ user_password: 'Please enter password',
+ user_password_rule_msg:
+ 'Please enter a password containing letters and numbers with a length between 6 and 20',
+ user_type: 'User Type',
+ tenant_code: 'Tenant',
+ tenant_id_rule_msg: 'Please select tenant',
+ queue: 'Queue',
+ email: 'Email',
+ email_rule_msg: 'Please enter valid email',
+ phone: 'Phone',
+ phone_rule_msg: 'Please enter valid phone number',
+ state: 'State',
+ create_time: 'Create Time',
+ update_time: 'Update Time',
+ operation: 'Operation',
+ edit: 'Edit',
+ delete: 'Delete',
+ save_error_msg: 'Failed to save, please retry',
+ delete_error_msg: 'Failed to delete, please retry'
}
}
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index 1ee6f60..0b82718 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -433,6 +433,36 @@ const security = {
edit: '编辑',
delete: '删除',
delete_confirm: '确定删除吗?'
+ },
+ user: {
+ user_manage: '用户管理',
+ create_user: '创建用户',
+ update_user: '更新用户',
+ delete_user: '删除用户',
+ delete_confirm: '确定删除吗?',
+ delete_confirm_tip: '删除用户属于危险操作,请谨慎操作!',
+ index: '序号',
+ username: '用户名',
+ username_exists: '用户名已存在',
+ username_rule_msg: '请输入用户名',
+ user_password: '密码',
+ user_password_rule_msg: '请输入包含字母和数字,长度在6~20之间的密码',
+ user_type: '用户类型',
+ tenant_code: '租户',
+ tenant_id_rule_msg: '请选择租户',
+ queue: '队列',
+ email: '邮件',
+ email_rule_msg: '请输入正确的邮箱',
+ phone: '手机',
+ phone_rule_msg: '请输入正确的手机号',
+ state: '状态',
+ create_time: '创建时间',
+ update_time: '更新时间',
+ operation: '操作',
+ edit: '编辑',
+ delete: '删除',
+ save_error_msg: '保存失败,请重试',
+ delete_error_msg: '删除失败,请重试'
}
}
diff --git a/dolphinscheduler-ui-next/src/router/modules/security.ts b/dolphinscheduler-ui-next/src/router/modules/security.ts
index 44774e4..b50e3fb 100644
--- a/dolphinscheduler-ui-next/src/router/modules/security.ts
+++ b/dolphinscheduler-ui-next/src/router/modules/security.ts
@@ -39,9 +39,9 @@ export default {
}
},
{
- path: '/security/users',
+ path: '/security/user-manage',
name: 'users-manage',
- component: components['home'],
+ component: components['user-manage'],
meta: {
title: '用户管理',
showSide: true
diff --git a/dolphinscheduler-ui-next/src/service/modules/users/index.ts b/dolphinscheduler-ui-next/src/service/modules/users/index.ts
index 1e91571..7d56619 100644
--- a/dolphinscheduler-ui-next/src/service/modules/users/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/users/index.ts
@@ -65,7 +65,7 @@ export function createUser(data: UserReq): any {
})
}
-export function delUserById(data: IdReq): any {
+export function delUserById(data: IdReq) {
return axios({
url: '/users/delete',
method: 'post',
@@ -135,7 +135,7 @@ export function listAll(params?: ListAllReq): any {
})
}
-export function queryUserList(params: ListReq): any {
+export function queryUserList(params: ListReq) {
return axios({
url: '/users/list-paging',
method: 'get',
@@ -167,7 +167,7 @@ export function unauthorizedUser(params: AlertGroupIdReq): any {
})
}
-export function updateUser(data: IdReq & UserReq): any {
+export function updateUser(data: IdReq & UserReq) {
return axios({
url: '/users/update',
method: 'post',
@@ -175,7 +175,7 @@ export function updateUser(data: IdReq & UserReq): any {
})
}
-export function verifyUserName(params: UserNameReq): any {
+export function verifyUserName(params: UserNameReq) {
return axios({
url: '/users/verify-user-name',
method: 'get',
diff --git a/dolphinscheduler-ui-next/src/utils/regex.ts b/dolphinscheduler-ui-next/src/utils/regex.ts
index c660e8d..aa8715e 100644
--- a/dolphinscheduler-ui-next/src/utils/regex.ts
+++ b/dolphinscheduler-ui-next/src/utils/regex.ts
@@ -16,7 +16,9 @@
*/
const regex = {
- email: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/ // support Chinese mailbox
+ email: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, // support Chinese mailbox
+ phone: /^1\d{10}$/,
+ password: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/
}
export default regex
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-modal.ts b/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-modal.ts
new file mode 100644
index 0000000..e5f50ae
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-modal.ts
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ref, watch, computed, InjectionKey } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useMessage } from 'naive-ui'
+import { queryTenantList } from '@/service/modules/tenants'
+import { queryList } from '@/service/modules/queues'
+import {
+ createUser,
+ updateUser,
+ delUserById,
+ verifyUserName
+} from '@/service/modules/users'
+import regexUtils from '@/utils/regex'
+export type Mode = 'add' | 'edit' | 'delete'
+
+export type UserModalSharedStateType = ReturnType<
+ typeof useSharedUserModalState
+> & {
+ onSuccess?: (mode: Mode) => void
+}
+
+export const UserModalSharedStateKey: InjectionKey<UserModalSharedStateType> =
+ Symbol()
+
+export function useSharedUserModalState() {
+ return {
+ show: ref(false),
+ mode: ref<Mode>('add'),
+ user: ref()
+ }
+}
+
+export function useModal({
+ onSuccess,
+ show,
+ mode,
+ user
+}: UserModalSharedStateType) {
+ const message = useMessage()
+ const { t } = useI18n()
+ const formRef = ref()
+ const formValues = ref({
+ userName: '',
+ userPassword: '',
+ tenantId: 0,
+ email: '',
+ queue: '',
+ phone: '',
+ state: 1
+ })
+ const tenants = ref<any[]>([])
+ const queues = ref<any[]>([])
+ const optionsLoading = ref(false)
+ const confirmLoading = ref(false)
+
+ const formRules = computed(() => {
+ return {
+ userName: {
+ required: true,
+ message: t('security.user.username_rule_msg'),
+ trigger: 'blur'
+ },
+ userPassword: {
+ required: mode.value === 'add',
+ validator(rule: any, value?: string) {
+ if (mode.value !== 'add' && !value) {
+ return true
+ }
+ const msg = t('security.user.user_password_rule_msg')
+ if (!value || !regexUtils.password.test(value)) {
+ return new Error(msg)
+ }
+ return true
+ },
+ trigger: ['blur', 'input']
+ },
+ tenantId: {
+ required: true,
+ validator(rule: any, value?: number) {
+ const msg = t('security.user.tenant_id_rule_msg')
+ if (typeof value === 'number') {
+ return true
+ }
+ return new Error(msg)
+ },
+ trigger: 'blur'
+ },
+ email: {
+ required: true,
+ validator(rule: any, value?: string) {
+ const msg = t('security.user.email_rule_msg')
+ if (!value || !regexUtils.email.test(value)) {
+ return new Error(msg)
+ }
+ return true
+ },
+ trigger: ['blur', 'input']
+ },
+ phone: {
+ validator(rule: any, value?: string) {
+ const msg = t('security.user.phone_rule_msg')
+ if (value && !regexUtils.phone.test(value)) {
+ return new Error(msg)
+ }
+ return true
+ },
+ trigger: ['blur', 'input']
+ }
+ }
+ })
+
+ const titleMap: Record<Mode, string> = {
+ add: t('security.user.create_user'),
+ edit: t('security.user.update_user'),
+ delete: t('security.user.delete_user')
+ }
+
+ const setFormValues = () => {
+ const defaultValues = {
+ userName: '',
+ userPassword: '',
+ tenantId: tenants.value[0]?.value,
+ email: '',
+ queue: queues.value[0]?.value,
+ phone: '',
+ state: 1
+ }
+ if (!user.value) {
+ formValues.value = defaultValues
+ } else {
+ const v: any = {}
+ Object.keys(defaultValues).map((k) => {
+ v[k] = user.value[k]
+ })
+ v.userPassword = ''
+ formValues.value = v
+ }
+ }
+
+ const prepareOptions = async () => {
+ optionsLoading.value = true
+ Promise.all([queryTenantList(), queryList()])
+ .then((res) => {
+ tenants.value =
+ res[0]?.map((d: any) => ({
+ label: d.tenantCode,
+ value: d.id
+ })) || []
+ queues.value =
+ res[1]?.map((d: any) => ({
+ label: d.queueName,
+ value: d.queue
+ })) || []
+ })
+ .finally(() => {
+ optionsLoading.value = false
+ })
+ }
+
+ const onDelete = () => {
+ confirmLoading.value = true
+ delUserById({ id: user.value.id })
+ .then(
+ () => {
+ onSuccess?.(mode.value)
+ onModalCancel()
+ },
+ () => {
+ message.error(t('security.user.delete_error_msg'))
+ }
+ )
+ .finally(() => {
+ confirmLoading.value = false
+ })
+ }
+
+ const onCreateUser = () => {
+ confirmLoading.value = true
+ verifyUserName({ userName: formValues.value.userName })
+ .then(
+ () => createUser(formValues.value),
+ (error) => {
+ if (`${error.message}`.includes('exists')) {
+ message.error(t('security.user.username_exists'))
+ }
+ return false
+ }
+ )
+ .then(
+ (res) => {
+ if (res) {
+ onSuccess?.(mode.value)
+ onModalCancel()
+ }
+ },
+ () => {
+ message.error(t('security.user.save_error_msg'))
+ }
+ )
+ .finally(() => {
+ confirmLoading.value = false
+ })
+ }
+
+ const onUpdateUser = () => {
+ confirmLoading.value = true
+ updateUser({ id: user.value.id, ...formValues.value })
+ .then(
+ () => {
+ onSuccess?.(mode.value)
+ onModalCancel()
+ },
+ () => {
+ message.error(t('security.user.save_error_msg'))
+ }
+ )
+ .finally(() => {
+ confirmLoading.value = false
+ })
+ }
+
+ const onConfirm = () => {
+ if (mode.value === 'delete') {
+ onDelete()
+ } else {
+ formRef.value.validate((errors: any) => {
+ if (!errors) {
+ user.value ? onUpdateUser() : onCreateUser()
+ }
+ })
+ }
+ }
+
+ const onModalCancel = () => {
+ show.value = false
+ }
+
+ watch([show, mode], () => {
+ show.value && mode.value !== 'delete' && prepareOptions()
+ })
+
+ watch([queues, tenants, user], () => {
+ setFormValues()
+ })
+
+ return {
+ show,
+ mode,
+ user,
+ titleMap,
+ onModalCancel,
+ formRef,
+ formValues,
+ formRules,
+ tenants,
+ queues,
+ optionsLoading,
+ onConfirm,
+ confirmLoading
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/components/user-modal.tsx b/dolphinscheduler-ui-next/src/views/security/user-manage/components/user-modal.tsx
new file mode 100644
index 0000000..d23a1e2
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/components/user-modal.tsx
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent, inject } from 'vue'
+import { useI18n } from 'vue-i18n'
+import {
+ NInput,
+ NForm,
+ NFormItem,
+ NSelect,
+ NRadio,
+ NRadioGroup,
+ NSpace,
+ NAlert
+} from 'naive-ui'
+
+import Modal from '@/components/modal'
+import {
+ useModal,
+ useSharedUserModalState,
+ UserModalSharedStateKey
+} from './use-modal'
+
+export const UserModal = defineComponent({
+ name: 'user-modal',
+ setup() {
+ const { t } = useI18n()
+ const sharedState =
+ inject(UserModalSharedStateKey) || useSharedUserModalState()
+ const modalState = useModal(sharedState)
+
+ return {
+ t,
+ ...modalState
+ }
+ },
+ render() {
+ const { t } = this
+ return (
+ <Modal
+ show={this.show}
+ title={this.titleMap?.[this.mode || 'add']}
+ onCancel={this.onModalCancel}
+ confirmLoading={this.confirmLoading}
+ onConfirm={this.onConfirm}
+ >
+ {{
+ default: () => {
+ if (this.mode === 'delete') {
+ return (
+ <NAlert type='error' title={t('security.user.delete_confirm')}>
+ {t('security.user.delete_confirm_tip')}
+ </NAlert>
+ )
+ }
+ return (
+ <NForm
+ ref='formRef'
+ model={this.formValues}
+ rules={this.formRules}
+ labelPlacement='left'
+ labelAlign='left'
+ labelWidth={80}
+ >
+ <NFormItem label={t('security.user.username')} path='userName'>
+ <NInput
+ inputProps={{ autocomplete: 'off' }}
+ v-model:value={this.formValues.userName}
+ />
+ </NFormItem>
+ <NFormItem
+ label={t('security.user.user_password')}
+ path='userPassword'
+ >
+ <NInput
+ inputProps={{ autocomplete: 'off' }}
+ type='password'
+ v-model:value={this.formValues.userPassword}
+ />
+ </NFormItem>
+ <NFormItem
+ label={t('security.user.tenant_code')}
+ path='tenantId'
+ >
+ <NSelect
+ options={this.tenants}
+ v-model:value={this.formValues.tenantId}
+ />
+ </NFormItem>
+ <NFormItem label={t('security.user.queue')} path='queue'>
+ <NSelect
+ options={this.queues}
+ v-model:value={this.formValues.queue}
+ />
+ </NFormItem>
+ <NFormItem label={t('security.user.email')} path='email'>
+ <NInput v-model:value={this.formValues.email} />
+ </NFormItem>
+ <NFormItem label={t('security.user.phone')} path='phone'>
+ <NInput v-model:value={this.formValues.phone} />
+ </NFormItem>
+ <NFormItem label={t('security.user.state')} path='state'>
+ <NRadioGroup v-model:value={this.formValues.state}>
+ <NSpace>
+ <NRadio value={1}>启用</NRadio>
+ <NRadio value={0}>停用</NRadio>
+ </NSpace>
+ </NRadioGroup>
+ </NFormItem>
+ </NForm>
+ )
+ }
+ }}
+ </Modal>
+ )
+ }
+})
+
+export default UserModal
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/index.tsx b/dolphinscheduler-ui-next/src/views/security/user-manage/index.tsx
new file mode 100644
index 0000000..018c77f
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/index.tsx
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent, provide } from 'vue'
+import {
+ NCard,
+ NButton,
+ NInputGroup,
+ NInput,
+ NIcon,
+ NSpace,
+ NGrid,
+ NGridItem,
+ NDataTable,
+ NPagination,
+ NSkeleton
+} from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import { SearchOutlined } from '@vicons/antd'
+import { useTable } from './use-table'
+import UserModal from './components/user-modal'
+import {
+ useSharedUserModalState,
+ UserModalSharedStateKey,
+ Mode
+} from './components/use-modal'
+
+const UsersManage = defineComponent({
+ name: 'user-manage',
+ setup() {
+ const { t } = useI18n()
+ const { show, mode, user } = useSharedUserModalState()
+ const tableState = useTable({
+ onEdit: (u) => {
+ show.value = true
+ mode.value = 'edit'
+ user.value = u
+ },
+ onDelete: (u) => {
+ show.value = true
+ mode.value = 'delete'
+ user.value = u
+ }
+ })
+
+ const onSuccess = (mode: Mode) => {
+ if (mode === 'add') {
+ tableState.resetPage()
+ }
+ tableState.getUserList()
+ }
+
+ const onAddUser = () => {
+ show.value = true
+ mode.value = 'add'
+ user.value = undefined
+ }
+
+ provide(UserModalSharedStateKey, { show, mode, user, onSuccess })
+
+ return {
+ t,
+ onAddUser,
+ ...tableState
+ }
+ },
+ render() {
+ const { t, onSearchValOk, onSearchValClear, userListLoading } = this
+ return (
+ <>
+ <NGrid cols={1} yGap={16}>
+ <NGridItem>
+ <NCard>
+ <NSpace justify='space-between'>
+ <NButton onClick={this.onAddUser} type='primary'>
+ {t('security.user.create_user')}
+ </NButton>
+ <NInputGroup>
+ <NInput
+ v-model:value={this.searchInputVal}
+ clearable
+ onClear={onSearchValClear}
+ onKeyup={(e) => {
+ if (e.key === 'Enter') {
+ onSearchValOk()
+ }
+ }}
+ />
+ <NButton type='primary' onClick={onSearchValOk}>
+ <NIcon>
+ <SearchOutlined />
+ </NIcon>
+ </NButton>
+ </NInputGroup>
+ </NSpace>
+ </NCard>
+ </NGridItem>
+ <NGridItem>
+ <NCard>
+ {userListLoading ? (
+ <NSkeleton text repeat={6}></NSkeleton>
+ ) : (
+ <NSpace v-show={!userListLoading} vertical size={20}>
+ <NDataTable
+ columns={this.columns}
+ data={this.userList}
+ scrollX={this.scrollX}
+ bordered={false}
+ />
+ <NSpace justify='center'>
+ <NPagination
+ v-model:page={this.page}
+ v-model:page-size={this.pageSize}
+ pageCount={this.pageCount}
+ pageSizes={this.pageSizes}
+ showSizePicker
+ />
+ </NSpace>
+ </NSpace>
+ )}
+ </NCard>
+ </NGridItem>
+ </NGrid>
+ <UserModal />
+ </>
+ )
+ }
+})
+
+export default UsersManage
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/use-table.tsx b/dolphinscheduler-ui-next/src/views/security/user-manage/use-table.tsx
new file mode 100644
index 0000000..10b334b
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/use-table.tsx
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ref, watch, onBeforeMount } from 'vue'
+import { NSpace, NTooltip, NButton, NIcon, NTag } from 'naive-ui'
+import { EditOutlined, DeleteOutlined } from '@vicons/antd'
+import { queryUserList } from '@/service/modules/users'
+import { useI18n } from 'vue-i18n'
+
+type UseTableProps = {
+ onEdit: (user: any) => void
+ onDelete: (user: any) => void
+}
+
+function useColumns({ onEdit, onDelete }: UseTableProps) {
+ const { t } = useI18n()
+ const columns: any[] = [
+ {
+ title: t('security.user.index'),
+ key: 'index',
+ width: 80,
+ render: (rowData: any, rowIndex: number) => rowIndex + 1
+ },
+ {
+ title: t('security.user.username'),
+ key: 'userName'
+ },
+ {
+ title: t('security.user.tenant_code'),
+ key: 'tenantCode'
+ },
+ {
+ title: t('security.user.queue'),
+ key: 'queue'
+ },
+ {
+ title: t('security.user.email'),
+ key: 'email'
+ },
+ {
+ title: t('security.user.phone'),
+ key: 'phone'
+ },
+ {
+ title: t('security.user.state'),
+ key: 'state',
+ render: (rowData: any, rowIndex: number) => {
+ return rowData.state === 1 ? (
+ <NTag type='success'>启用</NTag>
+ ) : (
+ <NTag type='error'>停用</NTag>
+ )
+ }
+ },
+ {
+ title: t('security.user.create_time'),
+ key: 'createTime',
+ width: 200
+ },
+ {
+ title: t('security.user.update_time'),
+ key: 'updateTime',
+ width: 200
+ },
+ {
+ title: t('security.user.operation'),
+ key: 'operation',
+ fixed: 'right',
+ width: 120,
+ render: (rowData: any, rowIndex: number) => {
+ return (
+ <NSpace>
+ <NTooltip trigger='hover'>
+ {{
+ trigger: () => (
+ <NButton
+ circle
+ type='info'
+ size='small'
+ onClick={() => {
+ onEdit(rowData)
+ }}
+ >
+ {{
+ icon: () => (
+ <NIcon>
+ <EditOutlined />
+ </NIcon>
+ )
+ }}
+ </NButton>
+ ),
+ default: () => t('security.user.edit')
+ }}
+ </NTooltip>
+ <NTooltip trigger='hover'>
+ {{
+ trigger: () => (
+ <NButton
+ circle
+ type='error'
+ size='small'
+ onClick={() => {
+ onDelete(rowData)
+ }}
+ >
+ {{
+ icon: () => (
+ <NIcon>
+ <DeleteOutlined />
+ </NIcon>
+ )
+ }}
+ </NButton>
+ ),
+ default: () => t('security.user.delete')
+ }}
+ </NTooltip>
+ </NSpace>
+ )
+ }
+ }
+ ].map((d: any) => ({ ...d, width: d.width || 160 }))
+
+ const scrollX = columns.reduce((p, c) => p + c.width, 0)
+
+ return {
+ columns,
+ scrollX
+ }
+}
+
+export function useTable(props: UseTableProps) {
+ const page = ref(1)
+ const pageCount = ref(0)
+ const pageSize = ref(10)
+ const searchInputVal = ref()
+ const searchVal = ref('')
+ const pageSizes = [10, 30, 50]
+ const userListLoading = ref(false)
+ const userList = ref([])
+ const { columns, scrollX } = useColumns(props)
+
+ const getUserList = () => {
+ userListLoading.value = true
+ queryUserList({
+ pageNo: page.value,
+ pageSize: pageSize.value,
+ searchVal: searchVal.value
+ })
+ .then((res: any) => {
+ userList.value = res?.totalList || []
+ pageCount.value = res?.totalPage || 0
+ })
+ .finally(() => {
+ userListLoading.value = false
+ })
+ }
+
+ const resetPage = () => {
+ page.value = 1
+ }
+
+ const onSearchValOk = () => {
+ resetPage()
+ searchVal.value = searchInputVal.value
+ }
+
+ const onSearchValClear = () => {
+ resetPage()
+ searchVal.value = ''
+ }
+
+ onBeforeMount(() => {
+ getUserList()
+ })
+
+ watch([page, pageSize, searchVal], () => {
+ getUserList()
+ })
+
+ return {
+ userList,
+ userListLoading,
+ getUserList,
+ page,
+ pageCount,
+ pageSize,
+ searchVal,
+ searchInputVal,
+ pageSizes,
+ columns,
+ scrollX,
+ onSearchValOk,
+ onSearchValClear,
+ resetPage
+ }
+}