feat(dict): apply dynamic dictionaries across user, menu and log pages
This commit is contained in:
parent
d50611c05b
commit
7c1bf63133
@ -51,10 +51,7 @@
|
||||
v-model:value="searchForm.loginStatus"
|
||||
placeholder="请选择登录状态"
|
||||
clearable
|
||||
:options="[
|
||||
{ label: '成功', value: '0' },
|
||||
{ label: '失败', value: '1' },
|
||||
]"
|
||||
:options="loginStatusOptions"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -196,12 +193,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, nextTick, onMounted, ref } from 'vue'
|
||||
import { computed, h, nextTick, onMounted, ref } from 'vue'
|
||||
import type { DataTableColumns, FormInst } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NSpace, NTag } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NSpace } from 'naive-ui'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import CoiEmpty from '@/components/common/CoiEmpty.vue'
|
||||
import CoiPagination from '@/components/common/CoiPagination.vue'
|
||||
import DictTag from '@/components/common/DictTag.vue'
|
||||
import {
|
||||
batchDeleteLoginLog,
|
||||
deleteLoginLog,
|
||||
@ -210,10 +208,21 @@ import {
|
||||
import type { LoginLogVo } from '@/service/api/system/loginlog'
|
||||
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
||||
import { PERMISSIONS } from '@/constants/permissions'
|
||||
import { usePermission } from '@/hooks/usePermission'
|
||||
import { useDict, usePermission } from '@/hooks'
|
||||
|
||||
// 权限相关
|
||||
const { hasPermission } = usePermission()
|
||||
const { dictOptions } = useDict(['sys_common_status'])
|
||||
|
||||
const loginStatusOptions = computed(() => {
|
||||
const options = dictOptions.sys_common_status || []
|
||||
return options
|
||||
.filter(option => option.dictValue === '1' || option.dictValue === '2')
|
||||
.map(option => ({
|
||||
label: option.dictLabel,
|
||||
value: option.dictValue === '1' ? '0' : '1',
|
||||
}))
|
||||
})
|
||||
|
||||
// 搜索表单数据
|
||||
interface LoginLogSearchForm {
|
||||
@ -320,17 +329,9 @@ const columns: DataTableColumns<LoginLogVo> = [
|
||||
{
|
||||
title: '登录状态',
|
||||
key: 'loginStatus',
|
||||
width: 100,
|
||||
width: 110,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const isSuccess = row.loginStatus === '0'
|
||||
return h(NTag, {
|
||||
type: isSuccess ? 'success' : 'error',
|
||||
size: 'small',
|
||||
}, {
|
||||
default: () => isSuccess ? '操作成功' : '操作失败',
|
||||
})
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_common_status', value: row.loginStatus === '0' ? '1' : '2' }),
|
||||
},
|
||||
{
|
||||
title: '登录信息',
|
||||
|
||||
@ -40,10 +40,7 @@
|
||||
v-model:value="searchForm.menuStatus"
|
||||
placeholder="请选择菜单状态"
|
||||
clearable
|
||||
:options="[
|
||||
{ label: '启用', value: '0' },
|
||||
{ label: '停用', value: '1' },
|
||||
]"
|
||||
:options="getSelectOptions('sys_switch_status')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -235,7 +232,7 @@
|
||||
:style="formData.parentId === '0' ? { color: themeColors.primary, fontWeight: '500' } : {}"
|
||||
@click="handleSelectParent('0', '最顶级菜单')"
|
||||
>
|
||||
<n-radio
|
||||
<NRadio
|
||||
:checked="formData.parentId === '0'"
|
||||
style="pointer-events: none;"
|
||||
/>
|
||||
@ -263,7 +260,7 @@
|
||||
@click="handleSelectParent(menu.value, menu.label)"
|
||||
@mouseenter="handleMenuHover(menu)"
|
||||
>
|
||||
<n-radio
|
||||
<NRadio
|
||||
:checked="formData.parentId === menu.value"
|
||||
style="pointer-events: none;"
|
||||
/>
|
||||
@ -303,7 +300,7 @@
|
||||
:style="formData.parentId === submenu.value ? { color: themeColors.primary, fontWeight: '500' } : {}"
|
||||
@click="handleSelectParent(submenu.value, submenu.label)"
|
||||
>
|
||||
<n-radio
|
||||
<NRadio
|
||||
:checked="formData.parentId === submenu.value"
|
||||
style="pointer-events: none;"
|
||||
/>
|
||||
@ -325,20 +322,18 @@
|
||||
|
||||
<!-- 菜单类型 -->
|
||||
<n-form-item label="菜单类型" path="menuType" class="mb-2">
|
||||
<n-radio-group
|
||||
<NRadioGroup
|
||||
v-model:value="formData.menuType"
|
||||
@update:value="handleMenuTypeChange"
|
||||
>
|
||||
<n-radio value="1">
|
||||
目录
|
||||
</n-radio>
|
||||
<n-radio value="2">
|
||||
菜单
|
||||
</n-radio>
|
||||
<n-radio value="3">
|
||||
按钮
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
<NRadio
|
||||
v-for="item in dictOptions.sys_menu_type || []"
|
||||
:key="item.dictValue"
|
||||
:value="item.dictValue"
|
||||
>
|
||||
{{ item.dictLabel }}
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 菜单图标 -->
|
||||
@ -392,14 +387,14 @@
|
||||
<n-grid :cols="2" :x-gap="10" class="mb-2">
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否隐藏" path="isHide">
|
||||
<n-radio-group v-model:value="formData.isHide">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isHide">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
@ -438,14 +433,14 @@
|
||||
<n-grid :cols="2" :x-gap="10" class="mb-2">
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否缓存" path="isKeepAlive">
|
||||
<n-radio-group v-model:value="formData.isKeepAlive">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isKeepAlive">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
@ -462,26 +457,26 @@
|
||||
<n-grid :cols="2" :x-gap="10" class="mb-2">
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否展开" path="isSpread">
|
||||
<n-radio-group v-model:value="formData.isSpread">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isSpread">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否固钉" path="isAffix">
|
||||
<n-radio-group v-model:value="formData.isAffix">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isAffix">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
@ -492,26 +487,26 @@
|
||||
<n-grid :cols="2" :x-gap="10" class="mb-2">
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否展开" path="isSpread">
|
||||
<n-radio-group v-model:value="formData.isSpread">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isSpread">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<n-form-item label="是否固钉" path="isAffix">
|
||||
<n-radio-group v-model:value="formData.isAffix">
|
||||
<n-radio value="0">
|
||||
<NRadioGroup v-model:value="formData.isAffix">
|
||||
<NRadio value="0">
|
||||
是
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
</NRadio>
|
||||
<NRadio value="1">
|
||||
否
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
@ -535,7 +530,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, h, nextTick, onMounted, ref } from 'vue'
|
||||
import type { DataTableColumns, FormInst, FormRules } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NSpace, NSwitch, NTag } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NRadio, NRadioGroup, NSpace, NSwitch, NTag } from 'naive-ui'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import IconParkOutlineEdit from '~icons/icon-park-outline/edit'
|
||||
import IconParkOutlinePlus from '~icons/icon-park-outline/plus'
|
||||
@ -543,8 +538,9 @@ import CoiDialog from '@/components/common/CoiDialog.vue'
|
||||
import CoiEmpty from '@/components/common/CoiEmpty.vue'
|
||||
import CoiIcon from '@/components/common/CoiIcon.vue'
|
||||
import IconSelect from '@/components/common/IconSelect.vue'
|
||||
import DictTag from '@/components/common/DictTag.vue'
|
||||
import { PERMISSIONS } from '@/constants/permissions'
|
||||
import { usePermission } from '@/hooks'
|
||||
import { useDict, usePermission } from '@/hooks'
|
||||
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
||||
import {
|
||||
addMenu,
|
||||
@ -587,6 +583,11 @@ const selectedRows = ref<MenuVo[]>([])
|
||||
const expandedKeys = ref<string[]>([])
|
||||
const isAllExpanded = ref(true)
|
||||
|
||||
const { dictOptions, getSelectOptions, getDictLabel } = useDict([
|
||||
'sys_menu_type',
|
||||
'sys_switch_status',
|
||||
])
|
||||
|
||||
// 弹框相关
|
||||
const menuDialogRef = ref()
|
||||
const formRef = ref<FormInst>()
|
||||
@ -716,15 +717,7 @@ const columns: DataTableColumns<MenuVo> = [
|
||||
key: 'menuType',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const typeMap = {
|
||||
1: { label: '目录', color: 'primary' },
|
||||
2: { label: '菜单', color: 'info' },
|
||||
3: { label: '按钮', color: 'warning' },
|
||||
}
|
||||
const type = typeMap[Number(row.menuType) as keyof typeof typeMap]
|
||||
return h(NTag, { type: type.color }, { default: () => type.label })
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_menu_type', value: row.menuType }),
|
||||
},
|
||||
{
|
||||
title: '展开/折叠',
|
||||
@ -818,6 +811,8 @@ const columns: DataTableColumns<MenuVo> = [
|
||||
render: (row) => {
|
||||
return h(NSwitch, {
|
||||
value: row.menuStatus === '0',
|
||||
checkedChildren: getDictLabel('sys_switch_status', '0', '启用'),
|
||||
uncheckedChildren: getDictLabel('sys_switch_status', '1', '停用'),
|
||||
onUpdateValue: value => handleStatusChange(row, value ? '0' : '1'),
|
||||
})
|
||||
},
|
||||
@ -1315,7 +1310,8 @@ async function handleStatusChange(menu: MenuVo, status: string) {
|
||||
// 更新本地数据的状态
|
||||
updateMenuStatusInData(tableData.value, menu.menuId, status)
|
||||
|
||||
coiMsgSuccess('状态修改成功')
|
||||
const statusLabel = getDictLabel('sys_switch_status', status, status === '0' ? '启用' : '停用')
|
||||
coiMsgSuccess(`状态已更新为「${statusLabel}」`)
|
||||
}
|
||||
catch {
|
||||
coiMsgError('状态修改失败')
|
||||
|
||||
@ -40,10 +40,7 @@
|
||||
v-model:value="searchForm.operStatus"
|
||||
placeholder="请选择操作状态"
|
||||
clearable
|
||||
:options="[
|
||||
{ label: '操作成功', value: '0' },
|
||||
{ label: '操作失败', value: '1' },
|
||||
]"
|
||||
:options="operStatusOptions"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -233,9 +230,7 @@
|
||||
{{ currentLogDetail.costTime || '-' }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="操作状态">
|
||||
<NTag :type="currentLogDetail.operStatus === '0' ? 'success' : 'error'" size="small">
|
||||
{{ currentLogDetail.operStatus === '0' ? '操作成功' : '操作失败' }}
|
||||
</NTag>
|
||||
<DictTag dict-type="sys_common_status" :value="currentLogDetail.operStatus === '0' ? '1' : '2'" />
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item v-if="currentLogDetail.operParam" label="请求参数" :span="2">
|
||||
<div class="json-container">
|
||||
@ -255,7 +250,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, nextTick, onMounted, ref } from 'vue'
|
||||
import { computed, h, nextTick, onMounted, ref } from 'vue'
|
||||
import type { DataTableColumns, FormInst } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NSpace, NTag } from 'naive-ui'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
@ -263,6 +258,7 @@ import IconParkOutlinePreviewOpen from '~icons/icon-park-outline/preview-open'
|
||||
import CoiDialog from '@/components/common/CoiDialog.vue'
|
||||
import CoiEmpty from '@/components/common/CoiEmpty.vue'
|
||||
import CoiPagination from '@/components/common/CoiPagination.vue'
|
||||
import DictTag from '@/components/common/DictTag.vue'
|
||||
import {
|
||||
batchDeleteOperLog,
|
||||
clearOperLog,
|
||||
@ -273,10 +269,21 @@ import {
|
||||
import type { OperLogSearchForm, OperLogVo } from '@/service/api/system/operlog'
|
||||
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
||||
import { PERMISSIONS } from '@/constants/permissions'
|
||||
import { usePermission } from '@/hooks/usePermission'
|
||||
import { useDict, usePermission } from '@/hooks'
|
||||
|
||||
// 权限相关
|
||||
const { hasButton } = usePermission()
|
||||
const { dictOptions } = useDict(['sys_oper_type', 'sys_common_status'])
|
||||
|
||||
const operStatusOptions = computed(() => {
|
||||
const options = dictOptions.sys_common_status || []
|
||||
return options
|
||||
.filter(option => option.dictValue === '1' || option.dictValue === '2')
|
||||
.map(option => ({
|
||||
label: option.dictLabel,
|
||||
value: option.dictValue === '1' ? '0' : '1',
|
||||
}))
|
||||
})
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
@ -339,16 +346,9 @@ const columns: DataTableColumns<OperLogVo> = [
|
||||
{
|
||||
title: '操作类型',
|
||||
key: 'operType',
|
||||
width: 90,
|
||||
width: 110,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(NTag, {
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
}, {
|
||||
default: () => row.operType,
|
||||
})
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_oper_type', value: row.operType }),
|
||||
},
|
||||
{
|
||||
title: '操作人员[登录名/用户名]',
|
||||
@ -419,15 +419,7 @@ const columns: DataTableColumns<OperLogVo> = [
|
||||
key: 'operStatus',
|
||||
width: 90,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const isSuccess = row.operStatus === '0'
|
||||
return h(NTag, {
|
||||
type: isSuccess ? 'success' : 'error',
|
||||
size: 'small',
|
||||
}, {
|
||||
default: () => isSuccess ? '操作成功' : '操作失败',
|
||||
})
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_common_status', value: row.operStatus === '0' ? '1' : '2' }),
|
||||
},
|
||||
{
|
||||
title: '操作时间',
|
||||
|
||||
@ -61,10 +61,7 @@
|
||||
v-model:value="searchForm.roleStatus"
|
||||
placeholder="请选择角色状态"
|
||||
clearable
|
||||
:options="[
|
||||
{ label: '启用', value: '0' },
|
||||
{ label: '停用', value: '1' },
|
||||
]"
|
||||
:options="getSelectOptions('sys_switch_status')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -269,14 +266,15 @@
|
||||
<n-grid :cols="2" :x-gap="10">
|
||||
<n-grid-item>
|
||||
<n-form-item label="角色状态" path="roleStatus" class="mb-2">
|
||||
<n-select
|
||||
v-model:value="formData.roleStatus"
|
||||
placeholder="请选择角色状态"
|
||||
:options="[
|
||||
{ label: '启用', value: '0' },
|
||||
{ label: '停用', value: '1' },
|
||||
]"
|
||||
/>
|
||||
<NRadioGroup v-model:value="formData.roleStatus">
|
||||
<NRadio
|
||||
v-for="item in dictOptions.sys_switch_status || []"
|
||||
:key="item.dictValue"
|
||||
:value="item.dictValue"
|
||||
>
|
||||
{{ item.dictLabel }}
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
@ -420,13 +418,14 @@
|
||||
<script setup lang="ts">
|
||||
import { h, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import type { DataTableColumns, FormInst } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NSpace, NSwitch, NTag, NTree } from 'naive-ui'
|
||||
import { NButton, NIcon, NPopconfirm, NRadio, NRadioGroup, NSpace, NSwitch, NTag, NTree } from 'naive-ui'
|
||||
import IconParkOutlineEditOne from '~icons/icon-park-outline/edit-one'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import IconParkOutlineKey from '~icons/icon-park-outline/key'
|
||||
import CoiDialog from '@/components/common/CoiDialog.vue'
|
||||
import CoiEmpty from '@/components/common/CoiEmpty.vue'
|
||||
import CoiPagination from '@/components/common/CoiPagination.vue'
|
||||
import DictTag from '@/components/common/DictTag.vue'
|
||||
import {
|
||||
addRole,
|
||||
batchDeleteRoles,
|
||||
@ -446,10 +445,11 @@ import {
|
||||
import type { MenuPermissionData, MenuVo } from '@/service/api/system/menu'
|
||||
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
||||
import { PERMISSIONS } from '@/constants/permissions'
|
||||
import { usePermission } from '@/hooks/usePermission'
|
||||
import { useDict, usePermission } from '@/hooks'
|
||||
|
||||
// 权限相关
|
||||
const { hasButton } = usePermission()
|
||||
const { dictOptions, getSelectOptions, getDictLabel } = useDict(['sys_switch_status'])
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
@ -546,28 +546,27 @@ const columns: DataTableColumns<RoleVo> = [
|
||||
key: 'roleCode',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(NTag, { type: 'primary', size: 'small' }, { default: () => row.roleCode })
|
||||
},
|
||||
render: row => h(NTag, { type: 'primary', size: 'small' }, { default: () => row.roleCode }),
|
||||
},
|
||||
{
|
||||
title: '角色状态',
|
||||
key: 'roleStatus',
|
||||
width: 100,
|
||||
width: 120,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h('div', { class: 'flex items-center justify-center' }, [
|
||||
return h('div', { class: 'flex items-center justify-center gap-2' }, [
|
||||
h(DictTag, { dictType: 'sys_switch_status', value: row.roleStatus }),
|
||||
h(NPopconfirm, {
|
||||
onPositiveClick: () => handleToggleStatus(row),
|
||||
negativeText: '取消',
|
||||
positiveText: '确定',
|
||||
}, {
|
||||
default: () => `确定要${row.roleStatus === '0' ? '停用' : '启用'}角色「${row.roleName}」吗?`,
|
||||
default: () => `确定要将角色「${row.roleName}」状态切换为「${getDictLabel('sys_switch_status', row.roleStatus === '0' ? '1' : '0')}」吗?`,
|
||||
trigger: () => h(NSwitch, {
|
||||
value: row.roleStatus === '0',
|
||||
size: 'small',
|
||||
checkedChildren: '启用',
|
||||
uncheckedChildren: '停用',
|
||||
checkedChildren: getDictLabel('sys_switch_status', '0', '启用'),
|
||||
uncheckedChildren: getDictLabel('sys_switch_status', '1', '停用'),
|
||||
loading: false,
|
||||
}),
|
||||
}),
|
||||
@ -966,7 +965,7 @@ async function handleBatchDelete() {
|
||||
async function handleToggleStatus(role: RoleVo) {
|
||||
try {
|
||||
const newStatus = role.roleStatus === '0' ? '1' : '0'
|
||||
const statusText = newStatus === '0' ? '启用' : '停用'
|
||||
const statusText = getDictLabel('sys_switch_status', newStatus, newStatus === '0' ? '启用' : '停用')
|
||||
|
||||
const { isSuccess } = await updateRoleStatus(role.roleId, newStatus)
|
||||
if (isSuccess) {
|
||||
|
||||
@ -72,10 +72,7 @@
|
||||
v-model:value="searchForm.userStatus"
|
||||
placeholder="请选择用户状态"
|
||||
clearable
|
||||
:options="[
|
||||
{ label: '启用', value: '0' },
|
||||
{ label: '停用', value: '1' },
|
||||
]"
|
||||
:options="getSelectOptions('sys_switch_status')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -313,11 +310,7 @@
|
||||
<n-select
|
||||
v-model:value="formData.userType"
|
||||
placeholder="请选择用户类型"
|
||||
:options="[
|
||||
{ label: '系统用户', value: '1' },
|
||||
{ label: '注册用户', value: '2' },
|
||||
{ label: '微信用户', value: '3' },
|
||||
]"
|
||||
:options="getSelectOptions('sys_user_type')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -327,11 +320,7 @@
|
||||
<n-select
|
||||
v-model:value="formData.sex"
|
||||
placeholder="请选择性别"
|
||||
:options="[
|
||||
{ label: '男', value: '1' },
|
||||
{ label: '女', value: '2' },
|
||||
{ label: '未知', value: '3' },
|
||||
]"
|
||||
:options="getSelectOptions('sys_user_sex')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
@ -367,14 +356,15 @@
|
||||
|
||||
<n-grid-item>
|
||||
<n-form-item label="用户状态" path="userStatus" class="mb-2">
|
||||
<n-radio-group v-model:value="formData.userStatus">
|
||||
<n-radio value="0">
|
||||
启用
|
||||
</n-radio>
|
||||
<n-radio value="1">
|
||||
停用
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
<NRadioGroup v-model:value="formData.userStatus">
|
||||
<NRadio
|
||||
v-for="item in dictOptions.sys_switch_status || []"
|
||||
:key="item.dictValue"
|
||||
:value="item.dictValue"
|
||||
>
|
||||
{{ item.dictLabel }}
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</n-form-item>
|
||||
</n-grid-item>
|
||||
|
||||
@ -585,11 +575,8 @@
|
||||
{{ currentAvatarUser?.avatar ? '用户头像' : '默认头像' }}
|
||||
</p>
|
||||
<div class="flex items-center justify-center gap-4 text-xs text-gray-400">
|
||||
<span>用户类型: {{
|
||||
currentAvatarUser?.userType === '1' ? '系统用户'
|
||||
: currentAvatarUser?.userType === '2' ? '注册用户' : '微信用户'
|
||||
}}</span>
|
||||
<span>状态: {{ currentAvatarUser?.userStatus === '0' ? '启用' : '停用' }}</span>
|
||||
<span>用户类型: {{ getDictLabel('sys_user_type', currentAvatarUser?.userType, '--') }}</span>
|
||||
<span>状态: {{ getDictLabel('sys_switch_status', currentAvatarUser?.userStatus, '--') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -704,7 +691,7 @@
|
||||
<script setup lang="ts">
|
||||
import { h, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import type { DataTableColumns, FormInst } from 'naive-ui'
|
||||
import { NButton, NCheckbox, NDropdown, NIcon, NPopconfirm, NProgress, NSpace, NSwitch, NTag, NUpload, NUploadDragger } from 'naive-ui'
|
||||
import { NButton, NCheckbox, NDropdown, NIcon, NPopconfirm, NProgress, NRadio, NRadioGroup, NSpace, NSwitch, NTag, NUpload, NUploadDragger } from 'naive-ui'
|
||||
import IconParkOutlineEditOne from '~icons/icon-park-outline/edit-one'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import IconParkOutlineRefresh from '~icons/icon-park-outline/refresh'
|
||||
@ -715,6 +702,7 @@ import IconParkOutlineFileCodeOne from '~icons/icon-park-outline/file-code-one'
|
||||
import CoiDialog from '@/components/common/CoiDialog.vue'
|
||||
import CoiEmpty from '@/components/common/CoiEmpty.vue'
|
||||
import CoiPagination from '@/components/common/CoiPagination.vue'
|
||||
import DictTag from '@/components/common/DictTag.vue'
|
||||
import {
|
||||
addUser,
|
||||
batchDeleteUsers,
|
||||
@ -739,7 +727,7 @@ import {
|
||||
import type { RoleVo } from '@/service/api/system/role'
|
||||
import { coiMsgBox, coiMsgError, coiMsgInfo, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
||||
import { PERMISSIONS } from '@/constants/permissions'
|
||||
import { usePermission } from '@/hooks/usePermission'
|
||||
import { useDict, usePermission } from '@/hooks'
|
||||
|
||||
// 权限相关
|
||||
const { hasButton } = usePermission()
|
||||
@ -790,6 +778,12 @@ const uploadProgress = ref(0)
|
||||
const progressInterval = ref<NodeJS.Timeout | null>(null)
|
||||
const createdBlobUrls = ref<string[]>([])
|
||||
|
||||
const { dictOptions, getSelectOptions, getDictLabel } = useDict([
|
||||
'sys_user_type',
|
||||
'sys_user_sex',
|
||||
'sys_switch_status',
|
||||
])
|
||||
|
||||
// 分页数据
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
@ -956,33 +950,14 @@ const columns: DataTableColumns<UserVo> = [
|
||||
key: 'userType',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const typeMap: Record<string, { label: string, type: any }> = {
|
||||
1: { label: '系统用户', type: 'primary' },
|
||||
2: { label: '注册用户', type: 'info' },
|
||||
3: { label: '微信用户', type: 'warning' },
|
||||
}
|
||||
const config = typeMap[row.userType] || { label: '未知', type: 'default' }
|
||||
return h(NTag, { type: config.type, size: 'small' }, { default: () => config.label })
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_user_type', value: row.userType }),
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
key: 'sex',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const sexMap: Record<string, { label: string, icon: string, color: string }> = {
|
||||
1: { label: '男', icon: '♂', color: 'text-blue-500' },
|
||||
2: { label: '女', icon: '♀', color: 'text-pink-500' },
|
||||
3: { label: '未知', icon: '?', color: 'text-gray-400' },
|
||||
}
|
||||
const config = sexMap[row.sex || '3']
|
||||
return h('div', { class: `flex items-center justify-center gap-1 ${config.color}` }, [
|
||||
h('span', { class: 'text-lg' }, config.icon),
|
||||
h('span', { class: 'text-xs' }, config.label),
|
||||
])
|
||||
},
|
||||
render: row => h(DictTag, { dictType: 'sys_user_sex', value: row.sex }),
|
||||
},
|
||||
{
|
||||
title: '用户状态',
|
||||
@ -990,18 +965,21 @@ const columns: DataTableColumns<UserVo> = [
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
const nextStatus = row.userStatus === '0' ? '1' : '0'
|
||||
const enableLabel = getDictLabel('sys_switch_status', '0', '启用')
|
||||
const disableLabel = getDictLabel('sys_switch_status', '1', '停用')
|
||||
return h('div', { class: 'flex items-center justify-center' }, [
|
||||
h(NPopconfirm, {
|
||||
onPositiveClick: () => handleToggleStatus(row),
|
||||
negativeText: '取消',
|
||||
positiveText: '确定',
|
||||
}, {
|
||||
default: () => `确定要${row.userStatus === '0' ? '停用' : '启用'}用户「${row.userName}」吗?`,
|
||||
default: () => `确定要将用户「${row.userName}」状态切换为「${getDictLabel('sys_switch_status', nextStatus)}」吗?`,
|
||||
trigger: () => h(NSwitch, {
|
||||
value: row.userStatus === '0',
|
||||
size: 'small',
|
||||
checkedChildren: '启用',
|
||||
uncheckedChildren: '停用',
|
||||
checkedChildren: enableLabel,
|
||||
uncheckedChildren: disableLabel,
|
||||
loading: false,
|
||||
}),
|
||||
}),
|
||||
@ -1357,7 +1335,7 @@ async function handleBatchDelete() {
|
||||
async function handleToggleStatus(user: UserVo) {
|
||||
try {
|
||||
const newStatus = user.userStatus === '0' ? '1' : '0'
|
||||
const statusText = newStatus === '0' ? '启用' : '停用'
|
||||
const statusText = getDictLabel('sys_switch_status', newStatus, newStatus === '0' ? '启用' : '停用')
|
||||
|
||||
const { isSuccess } = await updateUserStatus(user.userId, newStatus)
|
||||
if (isSuccess) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user