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