chore:字典组件优化,支持数组格式,其他模块代码优化
This commit is contained in:
parent
8b1be45eb5
commit
8c5ea2ae72
@ -50,6 +50,7 @@
|
||||
"@sa/hooks": "workspace:*",
|
||||
"@sa/materials": "workspace:*",
|
||||
"@sa/utils": "workspace:*",
|
||||
"@tinymce/tinymce-vue": "^6.1.0",
|
||||
"@vueuse/core": "12.5.0",
|
||||
"clipboard": "2.0.11",
|
||||
"dayjs": "1.11.13",
|
||||
|
@ -8,14 +8,16 @@ defineOptions({ name: 'DictSelect' });
|
||||
interface Props {
|
||||
dictCode: string;
|
||||
immediate?: boolean;
|
||||
multiple?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
immediate: false
|
||||
immediate: false,
|
||||
multiple: false
|
||||
});
|
||||
|
||||
const value = defineModel<string | null>('value', { required: false });
|
||||
const value = defineModel<string | string[] | null>('value', { required: false });
|
||||
|
||||
const attrs: SelectProps = useAttrs();
|
||||
const { options } = useDict(props.dictCode, props.immediate);
|
||||
@ -24,6 +26,7 @@ const { options } = useDict(props.dictCode, props.immediate);
|
||||
<template>
|
||||
<NSelect
|
||||
v-model:value="value"
|
||||
:multiple="multiple"
|
||||
:loading="!options.length"
|
||||
:options="options"
|
||||
:clear-filter-after-select="false"
|
||||
|
@ -7,10 +7,10 @@ import { isNotNull } from '@/utils/common';
|
||||
defineOptions({ name: 'DictTag' });
|
||||
|
||||
interface Props {
|
||||
value?: string | number;
|
||||
value?: string[] | number[] | string | number;
|
||||
dictCode?: string;
|
||||
immediate?: boolean;
|
||||
dictData?: Api.System.DictData;
|
||||
dictData?: Api.System.DictData[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@ -18,29 +18,38 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
immediate: false,
|
||||
dictData: undefined,
|
||||
dictCode: '',
|
||||
value: ''
|
||||
value: () => []
|
||||
});
|
||||
|
||||
const attrs = useAttrs() as TagProps;
|
||||
|
||||
const dictTagData = computed(() => {
|
||||
const dictTagData = computed<Api.System.DictData[]>(() => {
|
||||
if (props.dictData) {
|
||||
return props.dictData;
|
||||
}
|
||||
// 避免 props.value 为 0 时,无法触发
|
||||
if (props.dictCode && isNotNull(props.value)) {
|
||||
const { transformDictData } = useDict(props.dictCode, props.immediate);
|
||||
return transformDictData(String(props.value));
|
||||
return transformDictData(props.value) || [];
|
||||
}
|
||||
|
||||
return null;
|
||||
return [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NTag v-if="dictTagData" :class="dictTagData.cssClass" :type="dictTagData.listClass" v-bind="attrs">
|
||||
{{ dictTagData.dictLabel }}
|
||||
</NTag>
|
||||
<div v-if="dictTagData.length">
|
||||
<NTag
|
||||
v-for="item in dictTagData"
|
||||
:key="item.dictValue"
|
||||
class="mb-2 mr-2"
|
||||
:class="[item.cssClass]"
|
||||
:type="item.listClass"
|
||||
v-bind="attrs"
|
||||
>
|
||||
{{ item.dictLabel }}
|
||||
</NTag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -51,20 +51,19 @@ const jsonData = computed(() => {
|
||||
|
||||
<template>
|
||||
<div class="json-preview">
|
||||
<template v-if="jsonData">
|
||||
<VueJsonPretty
|
||||
:data="jsonData"
|
||||
:deep="deep"
|
||||
:show-double-quotes="showDoubleQuotes"
|
||||
:show-length="showLength"
|
||||
:show-line="showLine"
|
||||
:show-line-number="showLineNumber"
|
||||
:show-icon="showIcon"
|
||||
:show-select-controller="showSelectController"
|
||||
:collapsed-level="collapsedLevel"
|
||||
:highlight-mouseover-node="highlightMouseoverNode"
|
||||
/>
|
||||
</template>
|
||||
<VueJsonPretty
|
||||
v-if="jsonData"
|
||||
:data="jsonData"
|
||||
:deep="deep"
|
||||
:show-double-quotes="showDoubleQuotes"
|
||||
:show-length="showLength"
|
||||
:show-line="showLine"
|
||||
:show-line-number="showLineNumber"
|
||||
:show-icon="showIcon"
|
||||
:show-select-controller="showSelectController"
|
||||
:collapsed-level="collapsedLevel"
|
||||
:highlight-mouseover-node="highlightMouseoverNode"
|
||||
/>
|
||||
<span v-else-if="props.data">{{ props.data }}</span>
|
||||
<div v-else class="empty-data">暂无数据</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@ import { ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { fetchGetDictDataByType } from '@/service/api/system';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
import { isNull } from '@/utils/common';
|
||||
export function useDict(dictType: string, immediate: boolean = true) {
|
||||
const dictStore = useDictStore();
|
||||
const { dictData: dictList } = storeToRefs(dictStore);
|
||||
@ -40,9 +40,12 @@ export function useDict(dictType: string, immediate: boolean = true) {
|
||||
options.value = data.value.map(dict => ({ label: dict.dictLabel!, value: dict.dictValue! }));
|
||||
}
|
||||
|
||||
function transformDictData(dictValue: string): Api.System.DictData | undefined {
|
||||
if (!data.value.length || !dictValue) return undefined;
|
||||
return data.value.find(dict => dict.dictValue === dictValue);
|
||||
function transformDictData(dictValue: string[] | number[] | string | number) {
|
||||
if (!data.value.length || isNull(dictValue)) return undefined;
|
||||
if (Array.isArray(dictValue)) {
|
||||
return data.value.filter(dict => dictValue.some(value => dict.dictValue === value.toString()));
|
||||
}
|
||||
return data.value.filter(dict => dict.dictValue === dictValue.toString());
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
|
83
src/typings/api/system.api.d.ts
vendored
83
src/typings/api/system.api.d.ts
vendored
@ -511,5 +511,88 @@ declare namespace Api {
|
||||
|
||||
/** tenant package select list */
|
||||
type TenantPackageSelectList = Common.CommonRecord<Pick<TenantPackage, 'packageId' | 'packageName'>>;
|
||||
|
||||
/** notice */
|
||||
type Notice = Common.CommonRecord<{
|
||||
/** 公告ID */
|
||||
noticeId: CommonType.IdType;
|
||||
/** 租户编号 */
|
||||
tenantId: CommonType.IdType;
|
||||
/** 公告标题 */
|
||||
noticeTitle: string;
|
||||
/** 公告类型 */
|
||||
noticeType: string;
|
||||
/** 公告内容 */
|
||||
noticeContent: string;
|
||||
/** 公告状态 */
|
||||
status: string;
|
||||
/** 创建者 */
|
||||
createByName: string;
|
||||
/** 备注 */
|
||||
remark: string;
|
||||
}>;
|
||||
|
||||
/** notice search params */
|
||||
type NoticeSearchParams = CommonType.RecordNullable<
|
||||
Pick<Api.System.Notice, 'noticeTitle' | 'noticeType'> & Api.Common.CommonSearchParams
|
||||
>;
|
||||
|
||||
/** notice operate params */
|
||||
type NoticeOperateParams = CommonType.RecordNullable<
|
||||
Pick<Api.System.Notice, 'noticeId' | 'noticeTitle' | 'noticeType' | 'noticeContent' | 'status'>
|
||||
>;
|
||||
|
||||
/** notice list */
|
||||
type NoticeList = Api.Common.PaginatingQueryRecord<Notice>;
|
||||
|
||||
/** client */
|
||||
type Client = Common.CommonRecord<{
|
||||
/** id */
|
||||
id: CommonType.IdType;
|
||||
/** 客户端id */
|
||||
clientId: string;
|
||||
/** 客户端key */
|
||||
clientKey: string;
|
||||
/** 客户端秘钥 */
|
||||
clientSecret: string;
|
||||
/** 授权类型 */
|
||||
grantType: string;
|
||||
/** 授权类型列表 */
|
||||
grantTypeList: string[];
|
||||
/** 设备类型 */
|
||||
deviceType: string;
|
||||
/** token活跃超时时间 */
|
||||
activeTimeout: number;
|
||||
/** token固定超时 */
|
||||
timeout: number;
|
||||
/** 状态 */
|
||||
status: string;
|
||||
/** 删除标志(0代表存在 1代表删除) */
|
||||
delFlag: string;
|
||||
}>;
|
||||
|
||||
/** client search params */
|
||||
type ClientSearchParams = CommonType.RecordNullable<
|
||||
Pick<Api.System.Client, 'clientKey' | 'clientSecret' | 'status'> & Api.Common.CommonSearchParams
|
||||
>;
|
||||
|
||||
/** client operate params */
|
||||
type ClientOperateParams = CommonType.RecordNullable<
|
||||
Pick<
|
||||
Api.System.Client,
|
||||
| 'id'
|
||||
| 'clientId'
|
||||
| 'clientKey'
|
||||
| 'clientSecret'
|
||||
| 'grantTypeList'
|
||||
| 'deviceType'
|
||||
| 'activeTimeout'
|
||||
| 'timeout'
|
||||
| 'status'
|
||||
>
|
||||
>;
|
||||
|
||||
/** client list */
|
||||
type ClientList = Api.Common.PaginatingQueryRecord<Client>;
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,11 @@ export function isNotNull(value: any) {
|
||||
return value !== undefined && value !== null && value !== '' && value !== 'undefined' && value !== 'null';
|
||||
}
|
||||
|
||||
/** 判断是否为空 */
|
||||
export function isNull(value: any) {
|
||||
return value === undefined || value === null || value === '' || value === 'undefined' || value === 'null';
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造树型结构数据
|
||||
*
|
||||
|
@ -31,8 +31,8 @@ function closeDrawer() {
|
||||
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
|
||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||
<NDescriptions label-placement="left" :column="1" size="small" bordered>
|
||||
<NDescriptionsItem label="用户账号">
|
||||
{{ props.rowData?.userName }}
|
||||
<NDescriptionsItem label="账号信息">
|
||||
{{ props.rowData?.userName }} | {{ props.rowData?.ipaddr }} | {{ props.rowData?.loginLocation }}
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem label="客户端">
|
||||
{{ props.rowData?.clientKey }}
|
||||
@ -40,12 +40,6 @@ function closeDrawer() {
|
||||
<NDescriptionsItem label="设备类型">
|
||||
<DictTag size="small" :value="props.rowData?.deviceType" dict-code="sys_device_type" />
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem label="登录IP地址">
|
||||
{{ props.rowData?.ipaddr }}
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem label="登录地点">
|
||||
{{ props.rowData?.loginLocation }}
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem label="浏览器类型">
|
||||
<div class="flex items-center gap-2">
|
||||
<SvgIcon :icon="getBrowserIcon(props.rowData?.browser ?? '')" />
|
||||
|
@ -10,6 +10,7 @@ import { useAppStore } from '@/store/modules/app';
|
||||
import { useDownload } from '@/hooks/business/download';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import DictTag from '@/components/custom/dict-tag.vue';
|
||||
import { useDict } from '@/hooks/business/dict';
|
||||
import PostOperateDrawer from './modules/post-operate-drawer.vue';
|
||||
import PostSearch from './modules/post-search.vue';
|
||||
|
||||
@ -17,6 +18,7 @@ defineOptions({
|
||||
name: 'PostList'
|
||||
});
|
||||
|
||||
useDict('sys_normal_disable');
|
||||
const appStore = useAppStore();
|
||||
const { download } = useDownload();
|
||||
const { hasAuth } = useAuth();
|
||||
@ -170,7 +172,6 @@ async function handleExport() {
|
||||
const { loading: treeLoading, startLoading: startTreeLoading, endLoading: endTreeLoading } = useLoading();
|
||||
const deptPattern = ref<string>();
|
||||
const deptData = ref<Api.Common.CommonTreeRecord>([]);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
|
||||
async function getTreeData() {
|
||||
startTreeLoading();
|
||||
@ -184,7 +185,6 @@ async function getTreeData() {
|
||||
getTreeData();
|
||||
|
||||
function handleClickTree(keys: string[]) {
|
||||
selectedKeys.value = keys;
|
||||
searchParams.belongDeptId = keys.length ? keys[0] : null;
|
||||
checkedRowKeys.value = [];
|
||||
getDataByPage();
|
||||
@ -192,7 +192,6 @@ function handleClickTree(keys: string[]) {
|
||||
|
||||
function handleResetTreeData() {
|
||||
deptPattern.value = undefined;
|
||||
selectedKeys.value = [];
|
||||
searchParams.belongDeptId = null;
|
||||
getTreeData();
|
||||
getDataByPage();
|
||||
@ -212,7 +211,6 @@ function handleResetTreeData() {
|
||||
<NInput v-model:value="deptPattern" clearable :placeholder="$t('common.keywordSearch')" />
|
||||
<NSpin class="dept-tree" :show="treeLoading">
|
||||
<NTree
|
||||
v-model:selected-keys="selectedKeys"
|
||||
block-node
|
||||
show-line
|
||||
:data="deptData as []"
|
||||
|
@ -261,7 +261,7 @@ watch(visible, () => {
|
||||
class="w-full"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem label="用户数量" path="accountCount">
|
||||
<NFormItem path="accountCount">
|
||||
<template #label>
|
||||
<div class="flex-center">
|
||||
<FormTip content="-1不限制用户数量" />
|
||||
@ -270,7 +270,7 @@ watch(visible, () => {
|
||||
</template>
|
||||
<NInputNumber v-model:value="model.accountCount" placeholder="请输入用户数量" min="-1" class="w-full" />
|
||||
</NFormItem>
|
||||
<NFormItem label="绑定域名" path="domain">
|
||||
<NFormItem path="domain">
|
||||
<template #label>
|
||||
<div class="flex-center">
|
||||
<FormTip
|
||||
|
Loading…
Reference in New Issue
Block a user