😎1、优化日志页面与主题颜色匹配 2、修复下拉表格选择器组件错误

This commit is contained in:
zuohuaijun 2025-08-17 17:05:06 +08:00
parent 3dbb59b4db
commit 07e85a9900
7 changed files with 417 additions and 379 deletions

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro", "name": "admin.net.pro",
"type": "module", "type": "module",
"version": "2.4.33", "version": "2.4.33",
"lastBuildTime": "2025.08.15", "lastBuildTime": "2025.08.17",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun", "author": "zuohuaijun",
"license": "MIT", "license": "MIT",
@ -26,8 +26,8 @@
"@vue-office/excel": "^1.7.14", "@vue-office/excel": "^1.7.14",
"@vue-office/pdf": "^2.0.10", "@vue-office/pdf": "^2.0.10",
"@vueuse/core": "^13.6.0", "@vueuse/core": "^13.6.0",
"@vxe-ui/plugin-export-xlsx": "^4.2.5", "@vxe-ui/plugin-export-xlsx": "^4.3.0",
"@vxe-ui/plugin-render-element": "^4.0.16", "@vxe-ui/plugin-render-element": "^4.1.0",
"@wangeditor/editor": "^5.1.23", "@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12", "@wangeditor/editor-for-vue": "^5.1.12",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
@ -88,7 +88,7 @@
"@iconify/vue": "^5.0.0", "@iconify/vue": "^5.0.0",
"@plugin-web-update-notification/vite": "^2.0.1", "@plugin-web-update-notification/vite": "^2.0.1",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^22.17.1", "@types/node": "^22.17.2",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8", "@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^8.39.1", "@typescript-eslint/eslint-plugin": "^8.39.1",
@ -97,7 +97,7 @@
"@vitejs/plugin-vue-jsx": "^5.0.1", "@vitejs/plugin-vue-jsx": "^5.0.1",
"@vue/compiler-sfc": "^3.5.18", "@vue/compiler-sfc": "^3.5.18",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"code-inspector-plugin": "^1.1.1", "code-inspector-plugin": "^1.2.0",
"colors": "^1.4.0", "colors": "^1.4.0",
"dotenv": "^17.2.1", "dotenv": "^17.2.1",
"eslint": "^9.33.0", "eslint": "^9.33.0",

View File

@ -58,7 +58,7 @@ const props = defineProps({
/** /**
* 获取表数据的异步方法 * 获取表数据的异步方法
* @example * @example
* // * //
* const handleSysUserTable = (params: any) => { * const handleSysUserTable = (params: any) => {
* return getAPI(SysUserApi).apiSysUserPagePost(params); * return getAPI(SysUserApi).apiSysUserPagePost(params);
* }; * };
@ -240,7 +240,7 @@ const remoteMethod = debounce((query) => {
state.tableQuery = query; state.tableQuery = query;
} }
props.fetchOptions(Object.assign({}, props.queryParams, state.tableQuery)).then((res: any) => { props.fetchOptions(Object.assign({}, props.queryParams, state.tableQuery)).then((res: any) => {
const result = res.data?.result; const result = res.data?.result;
state.tableData.items = result?.items ?? []; state.tableData.items = result?.items ?? [];
state.tableData.total = result.total; state.tableData.total = result.total;
state.loading = false; state.loading = false;
@ -293,12 +293,13 @@ const setDefaultOptions = (options: any[]) => {
// //
const setQueryParams = (query: any, append: boolean = true) => { const setQueryParams = (query: any, append: boolean = true) => {
if (!pagination) { // if (!props.pagination) {
query = Object.assign(query, { //
page: 1, query = Object.assign(query, {
pageSize: 99999, page: 1,
}); pageSize: 99999,
} });
}
query = Object.assign({}, props.queryParams, query ?? {}); query = Object.assign({}, props.queryParams, query ?? {});
state.tableQuery = append ? Object.assign(state.tableQuery, query) : query; state.tableQuery = append ? Object.assign(state.tableQuery, query) : query;
}; };
@ -320,72 +321,79 @@ defineExpose({
setDefaultOptions, setDefaultOptions,
}); });
</script> </script>
<template> <template>
<el-select <el-select
v-model="state.selectedValues" v-model="state.selectedValues"
:clearable="clearable" :clearable="clearable"
:multiple="multiple" :multiple="multiple"
:disabled="disabled" :disabled="disabled"
:placeholder="placeholder" :placeholder="placeholder"
:allow-create="allowCreate" :allow-create="allowCreate"
:remote-method="remoteMethod" :remote-method="remoteMethod"
:default-first-option="allowCreate" :default-first-option="allowCreate"
@visible-change="(val: boolean) => (val ? handleQuery() : null)" @visible-change="(val: boolean) => (val ? handleQuery() : null)"
popper-class="popper-class" popper-class="popper-class"
ref="selectRef" ref="selectRef"
remote-show-suffix remote-show-suffix
filterable filterable
remote remote
> >
<!-- 隐藏的选项用于占位 --> <!-- 隐藏的选项用于占位 -->
<el-option style="width: 0; height: 0" /> <el-option style="width: 0; height: 0" />
<!-- 默认选项用于回显数据 --> <!-- 默认选项用于回显数据 -->
<el-option v-for="item in (state.defaultOptions ?? []).filter((e) => !state.tableData?.items?.find((e2) => e2[valueProp] === e[valueProp]))" :key="item[valueProp]" :label="labelFormat(item) || item[labelProp]" :value="item[valueProp]" style="width: 0; height: 0" /> <el-option
v-for="item in (state.defaultOptions ?? []).filter((e) => !state.tableData?.items?.find((e2) => e2[valueProp] === e[valueProp]))"
:key="item[valueProp]"
:label="labelFormat(item) || item[labelProp]"
:value="item[valueProp]"
style="width: 0; height: 0"
/>
<!-- 下拉框内容区域 --> <!-- 下拉框内容区域 -->
<div class="w100" v-loading="state.loading"> <div class="w100" v-loading="state.loading">
<el-form :model="state.tableQuery" v-if="$slots.queryForm" class="mg5 query-form" @click.stop> <el-form :model="state.tableQuery" v-if="$slots.queryForm" class="mg5 query-form" @click.stop>
<el-row :gutter="10"> <el-row :gutter="10">
<!-- 查询表单插槽内容 --> <!-- 查询表单插槽内容 -->
<slot name="queryForm" :query="state.tableQuery" :handleQuery="handleQuery"></slot> <slot name="queryForm" :query="state.tableQuery" :handleQuery="handleQuery"></slot>
<!-- 查询和重置按钮 --> <!-- 查询和重置按钮 -->
<el-button-group style="position: absolute; right: 10px;"> <el-button-group style="position: absolute; right: 10px">
<el-button type="primary" icon="ele-Search" @click="remoteMethod(state.tableQuery)"> 查询 </el-button> <el-button type="primary" icon="ele-Search" @click="remoteMethod(state.tableQuery)"> 查询 </el-button>
<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button> <el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
</el-button-group> </el-button-group>
</el-row> </el-row>
</el-form> </el-form>
<!-- 数据表格 --> <!-- 数据表格 -->
<el-table <el-table
ref="tableRef" ref="tableRef"
@row-click="handleChange" @row-click="handleChange"
:data="state.tableData?.items ?? []" :data="state.tableData?.items ?? []"
:height="`calc(${dropdownHeight} - 175px${$slots.queryForm ? ' - 35px' : ''})`" :height="`calc(${dropdownHeight} - 175px${$slots.queryForm ? ' - 35px' : ''})`"
:style="{ width: dropdownWidth }" :style="{ width: dropdownWidth }"
highlight-current-row highlight-current-row
> >
<template #empty><el-empty :image-size="25" /></template> <template #empty><el-empty :image-size="25" /></template>
<slot name="columns"></slot> <slot name="columns"></slot>
</el-table> </el-table>
<!-- 分页组件 --> <!-- 分页组件 -->
<el-pagination <el-pagination
v-if="props.showPagination" v-if="props.pagination"
:disabled="state.loading" :disabled="state.loading"
:currentPage="state.tableQuery.page" :currentPage="state.tableQuery.page"
:page-size="state.tableQuery.pageSize" :page-size="state.tableQuery.pageSize"
:total="state.tableData.total" :total="state.tableData.total"
:pager-count="4" :pager-count="4"
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
layout="prev, pager, next" layout="prev, pager, next"
size="small" size="small"
background background
/> />
</div> </div>
</el-select> </el-select>
</template> </template>
<style scoped> <style scoped>
.query-form { .query-form {
@ -399,4 +407,4 @@ defineExpose({
.popper-class { .popper-class {
min-width: 400px !important; min-width: 400px !important;
} }
</style> </style>

View File

@ -16,7 +16,7 @@
* @constant * @constant
*/ */
const RENDER_TYPES = ['tag', 'select', 'radio', 'checkbox', 'radio-button'] as const; const RENDER_TYPES = ['tag', 'select', 'radio', 'checkbox', 'radio-button'] as const;
type RenderType = typeof RENDER_TYPES[number]; type RenderType = (typeof RENDER_TYPES)[number];
/** /**
* 支持的标签类型常量 * 支持的标签类型常量
@ -24,7 +24,7 @@ type RenderType = typeof RENDER_TYPES[number];
* @constant * @constant
*/ */
const TAG_TYPES = ['success', 'warning', 'info', 'primary', 'danger'] as const; const TAG_TYPES = ['success', 'warning', 'info', 'primary', 'danger'] as const;
type TagType = typeof TAG_TYPES[number]; type TagType = (typeof TAG_TYPES)[number];
/** /**
* 字典项数据结构 * 字典项数据结构
@ -36,12 +36,12 @@ type TagType = typeof TAG_TYPES[number];
* @property {string|number} [value] - * @property {string|number} [value] -
*/ */
interface DictItem { interface DictItem {
[key: string]: any; [key: string]: any;
tagType?: TagType; tagType?: TagType;
styleSetting?: string; styleSetting?: string;
classSetting?: string; classSetting?: string;
label?: string; label?: string;
value?: string | number; value?: string | number;
} }
/** /**
@ -51,8 +51,8 @@ interface DictItem {
* @property {string} Comma - 逗号分隔模式'1,2,3' * @property {string} Comma - 逗号分隔模式'1,2,3'
*/ */
enum MultipleModel { enum MultipleModel {
Array = 'array', Array = 'array',
Comma = 'comma', Comma = 'comma',
} }
/** /**
@ -62,7 +62,7 @@ enum MultipleModel {
* @returns {value is RenderType} - 是否为合法的渲染类型 * @returns {value is RenderType} - 是否为合法的渲染类型
*/ */
function isRenderType(value: any): value is RenderType { function isRenderType(value: any): value is RenderType {
return RENDER_TYPES.includes(value); return RENDER_TYPES.includes(value);
} }
/** /**
@ -72,7 +72,7 @@ function isRenderType(value: any): value is RenderType {
* @returns {value is MultipleModel} - 是否为合法的多选模式 * @returns {value is MultipleModel} - 是否为合法的多选模式
*/ */
function isMultipleModel(value: any): value is MultipleModel { function isMultipleModel(value: any): value is MultipleModel {
return Object.values(MultipleModel).includes(value); return Object.values(MultipleModel).includes(value);
} }
</script> </script>
@ -87,125 +87,125 @@ const emit = defineEmits(['update:modelValue']);
* 组件属性定义 * 组件属性定义
*/ */
const props = defineProps({ const props = defineProps({
/** /**
* 绑定值支持多种类型 * 绑定值支持多种类型
* @type {string|number|boolean|Array|null} * @type {string|number|boolean|Array|null}
* @required * @required
* @example * @example
* // * //
* <g-sys-dict v-model="selectedValue" code="gender" renderAs="select" /> * <g-sys-dict v-model="selectedValue" code="gender" renderAs="select" />
* *
* // * //
* <g-sys-dict v-model="selectedValues" code="roles" renderAs="select" multiple /> * <g-sys-dict v-model="selectedValues" code="roles" renderAs="select" multiple />
* *
* // * //
* <g-sys-dict v-model="selectedValues" code="roles" renderAs="select" multiple multiple-model="comma" /> * <g-sys-dict v-model="selectedValues" code="roles" renderAs="select" multiple multiple-model="comma" />
*/ */
modelValue: { modelValue: {
type: [String, Number, Boolean, Array, null] as PropType<string | number | boolean | any[] | null>, type: [String, Number, Boolean, Array, null] as PropType<string | number | boolean | any[] | null>,
default: null, default: null,
required: true, required: true,
}, },
/** /**
* 字典编码用于从字典中获取数据 * 字典编码用于从字典中获取数据
* @type {string} * @type {string}
* @required * @required
* @example 'gender' * @example 'gender'
*/ */
code: { code: {
type: String, type: String,
required: true, required: true,
}, },
/** /**
* 是否为常量字典true从常量列表获取false从字典列表获取 * 是否为常量字典true从常量列表获取false从字典列表获取
* @type {boolean} * @type {boolean}
* @default false * @default false
* @example true * @example true
*/ */
isConst: { isConst: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
/** /**
* 字典项中用于显示的字段名 * 字典项中用于显示的字段名
* @type {string} * @type {string}
* @default 'label' * @default 'label'
* @example 'name' * @example 'name'
*/ */
propLabel: { propLabel: {
type: String, type: String,
default: 'label', default: 'label',
}, },
/** /**
* 字典项中用于取值的字段名 * 字典项中用于取值的字段名
* @type {string} * @type {string}
* @default 'value' * @default 'value'
* @example 'id' * @example 'id'
*/ */
propValue: { propValue: {
type: String, type: String,
default: 'value', default: 'value',
}, },
/** /**
* 字典项过滤函数 * 字典项过滤函数
* @type {Function} * @type {Function}
* @param {DictItem} dict - 当前字典项 * @param {DictItem} dict - 当前字典项
* @returns {boolean} - 是否保留该项 * @returns {boolean} - 是否保留该项
* @default (dict) => true * @default (dict) => true
* @example * @example
* // * //
* :onItemFilter="(dict) => dict.status === 1" * :onItemFilter="(dict) => dict.status === 1"
*/ */
onItemFilter: { onItemFilter: {
type: Function as PropType<(dict: DictItem) => boolean>, type: Function as PropType<(dict: DictItem) => boolean>,
default: () => true, default: () => true,
}, },
/** /**
* 字典项显示内容格式化函数 * 字典项显示内容格式化函数
* @type {Function} * @type {Function}
* @param {DictItem} dict - 当前字典项 * @param {DictItem} dict - 当前字典项
* @returns {string|undefined|null} - 格式化后的显示内容 * @returns {string|undefined|null} - 格式化后的显示内容
* @default () => undefined * @default () => undefined
* @example * @example
* // * //
* :onItemFormatter="(dict) => `${dict.label} <icon-user />`" * :onItemFormatter="(dict) => `${dict.label} <icon-user />`"
*/ */
onItemFormatter: { onItemFormatter: {
type: Function as PropType<(dict: DictItem) => string | undefined | null>, type: Function as PropType<(dict: DictItem) => string | undefined | null>,
default: () => undefined, default: () => undefined,
}, },
/** /**
* 组件渲染方式 * 组件渲染方式
* @type {'tag'|'select'|'radio'|'checkbox'|'radio-button'} * @type {'tag'|'select'|'radio'|'checkbox'|'radio-button'}
* @default 'tag' * @default 'tag'
* @example 'select' * @example 'select'
*/ */
renderAs: { renderAs: {
type: String as PropType<RenderType>, type: String as PropType<RenderType>,
default: 'tag', default: 'tag',
validator: isRenderType, validator: isRenderType,
}, },
/** /**
* 是否多选仅在renderAs为select/checkbox时有效 * 是否多选仅在renderAs为select/checkbox时有效
* @type {boolean} * @type {boolean}
* @default false * @default false
* @example true * @example true
*/ */
multiple: { multiple: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
/** /**
* 多选值模式仅在multiple为true时有效 * 多选值模式仅在multiple为true时有效
* @type {'array'|'comma'} * @type {'array'|'comma'}
* @default 'array' * @default 'array'
* @example 'comma' * @example 'comma'
*/ */
multipleModel: { multipleModel: {
type: String as PropType<MultipleModel>, type: String as PropType<MultipleModel>,
default: MultipleModel.Array, default: MultipleModel.Array,
validator: isMultipleModel, validator: isMultipleModel,
}, },
}); });
/** /**
@ -214,13 +214,11 @@ const props = defineProps({
* @returns {DictItem[]} - 过滤并格式化后的字典数据 * @returns {DictItem[]} - 过滤并格式化后的字典数据
*/ */
const formattedDictData = computed(() => { const formattedDictData = computed(() => {
return state.dictData return state.dictData.filter(props.onItemFilter).map((item) => ({
.filter(props.onItemFilter) ...item,
.map(item => ({ label: item[props.propLabel],
...item, value: item[props.propValue],
label: item[props.propLabel], }));
value: item[props.propValue],
}));
}); });
/** /**
@ -229,17 +227,15 @@ const formattedDictData = computed(() => {
* @returns {DictItem|DictItem[]|null} - 当前选中的字典项或字典项数组 * @returns {DictItem|DictItem[]|null} - 当前选中的字典项或字典项数组
*/ */
const currentDictItems = computed(() => { const currentDictItems = computed(() => {
if (!state.value) return null; if (!state.value) return null;
if (Array.isArray(state.value)) { if (Array.isArray(state.value)) {
// //
const uniqueValues = [...new Set(state.value)]; const uniqueValues = [...new Set(state.value)];
return formattedDictData.value.filter(item => return formattedDictData.value.filter((item) => uniqueValues.includes(item.value));
uniqueValues.includes(item.value) }
);
}
return formattedDictData.value.find(item => item.value == state.value) || null; return formattedDictData.value.find((item) => item.value == state.value) || null;
}); });
/** /**
@ -249,26 +245,24 @@ const currentDictItems = computed(() => {
* @throws {Error} - 获取数据失败时抛出错误 * @throws {Error} - 获取数据失败时抛出错误
*/ */
const getDataList = (): DictItem[] => { const getDataList = (): DictItem[] => {
try { try {
if (!props.code) { if (!props.code) {
console.error('字典编码不能为空'); console.error('字典编码不能为空');
return []; return [];
} }
const source = props.isConst ? userStore.constList : userStore.dictList; const source = props.isConst ? userStore.constList : userStore.dictList;
const data = props.isConst const data = props.isConst ? (source?.find((x: any) => x.code === props.code)?.data?.result ?? []) : (source[props.code] ?? []);
? source?.find((x: any) => x.code === props.code)?.data?.result ?? []
: source[props.code] ?? [];
return data.map((item: any) => ({ return data.map((item: any) => ({
...item, ...item,
label: item[props.propLabel] ?? item.name, label: item[props.propLabel] ?? item.name,
value: item[props.propValue] ?? item.code, value: item[props.propValue] ?? item.code,
})); }));
} catch (error) { } catch (error) {
console.error(`获取字典[${props.code}]数据失败:`, error); console.error(`获取字典[${props.code}]数据失败:`, error);
return []; return [];
} }
}; };
/** /**
@ -277,13 +271,13 @@ const getDataList = (): DictItem[] => {
* @param {any} value - 待处理的值 * @param {any} value - 待处理的值
*/ */
const processNumericValues = (value: any) => { const processNumericValues = (value: any) => {
if (typeof value === 'number' || (Array.isArray(value) && typeof value[0] === 'number')) { if (typeof value === 'number' || (Array.isArray(value) && typeof value[0] === 'number')) {
state.dictData.forEach(item => { state.dictData.forEach((item) => {
if (item.value) { if (item.value) {
item.value = Number(item.value); item.value = Number(item.value);
} }
}); });
} }
}; };
/** /**
@ -293,51 +287,54 @@ const processNumericValues = (value: any) => {
* @returns {any} - 解析后的值 * @returns {any} - 解析后的值
*/ */
const parseMultipleValue = (value: any): any => { const parseMultipleValue = (value: any): any => {
// //
if (value === null || value === undefined || value === '') { if (value === null || value === undefined || value === '') {
return props.multiple ? [] : value; return props.multiple ? [] : value;
} }
// //
if (typeof value === 'string') { if (typeof value === 'string') {
const trimmedValue = value.trim(); const trimmedValue = value.trim();
// JSON // JSON
if (trimmedValue.startsWith('[') && trimmedValue.endsWith(']')) { if (trimmedValue.startsWith('[') && trimmedValue.endsWith(']')) {
try { try {
const parsed = JSON.parse(trimmedValue); const parsed = JSON.parse(trimmedValue);
if (Array.isArray(parsed)) { if (Array.isArray(parsed)) {
// //
return [...new Set(parsed.filter(Boolean))]; return [...new Set(parsed.filter(Boolean))];
} }
return parsed; return parsed;
} catch (error) { } catch (error) {
console.warn('[g-sys-dict] 解析多选值失败:', error); console.warn('[g-sys-dict] 解析多选值失败:', error);
return []; return [];
} }
} }
// //
if (props.multipleModel === MultipleModel.Comma && trimmedValue.includes(',')) { if (props.multipleModel === MultipleModel.Comma && trimmedValue.includes(',')) {
// //
return [...new Set( return [
trimmedValue.split(',') ...new Set(
.map(item => item.trim()) trimmedValue
.filter(Boolean) .split(',')
)]; .map((item) => item.trim())
} .filter(Boolean)
),
];
}
// //
return props.multiple ? [trimmedValue] : trimmedValue; return props.multiple ? [trimmedValue] : trimmedValue;
} }
// - // -
if (Array.isArray(value)) { if (Array.isArray(value)) {
return [...new Set(value.filter(Boolean))]; return [...new Set(value.filter(Boolean))];
} }
// //
return value; return value;
}; };
/** /**
@ -346,24 +343,24 @@ const parseMultipleValue = (value: any): any => {
* @param {any} newValue - 新值 * @param {any} newValue - 新值
*/ */
const updateValue = (newValue: any) => { const updateValue = (newValue: any) => {
// //
let processedValue = newValue; let processedValue = newValue;
if (Array.isArray(newValue)) { if (Array.isArray(newValue)) {
processedValue = [...new Set(newValue.filter(v => v !== null && v !== undefined && v !== ''))]; processedValue = [...new Set(newValue.filter((v) => v !== null && v !== undefined && v !== ''))];
} }
let emitValue = processedValue; let emitValue = processedValue;
if (props.multipleModel === MultipleModel.Comma) { if (props.multipleModel === MultipleModel.Comma) {
if (Array.isArray(processedValue)) { if (Array.isArray(processedValue)) {
emitValue = processedValue.length > 0 ? processedValue.join(',') : ''; emitValue = processedValue.length > 0 ? processedValue.join(',') : '';
} else if (processedValue === null || processedValue === undefined) { } else if (processedValue === null || processedValue === undefined) {
emitValue = ''; emitValue = '';
} }
} }
state.value = processedValue; state.value = processedValue;
emit('update:modelValue', emitValue); emit('update:modelValue', emitValue);
}; };
/** /**
@ -373,7 +370,7 @@ const updateValue = (newValue: any) => {
* @returns {TagType} - 合法的标签类型 * @returns {TagType} - 合法的标签类型
*/ */
const ensureTagType = (item: DictItem): TagType => { const ensureTagType = (item: DictItem): TagType => {
return TAG_TYPES.includes(item.tagType as TagType) ? item.tagType as TagType : 'primary'; return TAG_TYPES.includes(item.tagType as TagType) ? (item.tagType as TagType) : 'primary';
}; };
/** /**
@ -383,9 +380,9 @@ const ensureTagType = (item: DictItem): TagType => {
* @returns {string} - 显示文本 * @returns {string} - 显示文本
*/ */
const getDisplayText = (dict?: DictItem): string => { const getDisplayText = (dict?: DictItem): string => {
if (!dict) return String(state.value || ''); if (!dict) return String(state.value || '');
const formattedText = props.onItemFormatter?.(dict); const formattedText = props.onItemFormatter?.(dict);
return formattedText ?? dict[props.propLabel] ?? ''; return formattedText ?? dict[props.propLabel] ?? '';
}; };
/** /**
@ -393,12 +390,12 @@ const getDisplayText = (dict?: DictItem): string => {
* @function * @function
*/ */
const initData = () => { const initData = () => {
state.dictData = getDataList(); state.dictData = getDataList();
processNumericValues(props.modelValue); processNumericValues(props.modelValue);
const initialValue = parseMultipleValue(props.modelValue); const initialValue = parseMultipleValue(props.modelValue);
if (initialValue !== state.value) { if (initialValue !== state.value) {
state.value = initialValue; state.value = initialValue;
} }
}; };
/** /**
@ -407,58 +404,61 @@ const initData = () => {
* @property {any} value - 当前值 * @property {any} value - 当前值
*/ */
const state = reactive({ const state = reactive({
dictData: [] as DictItem[], dictData: [] as DictItem[],
value: parseMultipleValue(props.modelValue), value: parseMultipleValue(props.modelValue),
}); });
// //
watch(() => props.modelValue, (newValue) => { watch(
state.value = parseMultipleValue(newValue); () => props.modelValue,
}); (newValue) => {
state.value = parseMultipleValue(newValue);
}
);
watch(() => [userStore.dictList, userStore.constList], initData, { immediate: true }); watch(() => [userStore.dictList, userStore.constList], initData, { immediate: true });
</script> </script>
<template> <template>
<!-- 渲染标签 --> <!-- 渲染标签 -->
<template v-if="props.renderAs === 'tag'"> <template v-if="props.renderAs === 'tag'">
<template v-if="Array.isArray(currentDictItems)"> <template v-if="Array.isArray(currentDictItems)">
<el-tag v-for="(item, index) in currentDictItems" :key="index" v-bind="$attrs" :type="ensureTagType(item)" :style="item.styleSetting" :class="item.classSetting" class="mr2"> <el-tag v-for="(item, index) in currentDictItems" :key="index" v-bind="$attrs" :type="ensureTagType(item)" :style="item.styleSetting" :class="item.classSetting" class="mr2">
{{ getDisplayText(item) }} {{ getDisplayText(item) }}
</el-tag> </el-tag>
</template> </template>
<template v-else> <template v-else>
<el-tag v-if="currentDictItems" v-bind="$attrs" :type="ensureTagType(currentDictItems)" :style="currentDictItems.styleSetting" :class="currentDictItems.classSetting"> <el-tag v-if="currentDictItems" v-bind="$attrs" :type="ensureTagType(currentDictItems)" :style="currentDictItems.styleSetting" :class="currentDictItems.classSetting">
{{ getDisplayText(currentDictItems) }} {{ getDisplayText(currentDictItems) }}
</el-tag> </el-tag>
<span v-else>{{ getDisplayText() }}</span> <span v-else>{{ getDisplayText() }}</span>
</template> </template>
</template> </template>
<!-- 渲染选择器 --> <!-- 渲染选择器 -->
<el-select v-else-if="props.renderAs === 'select'" v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="updateValue" clearable> <el-select v-else-if="props.renderAs === 'select'" v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="updateValue" clearable>
<el-option v-for="(item, index) in formattedDictData" :key="index" :label="getDisplayText(item)" :value="item.value" /> <el-option v-for="(item, index) in formattedDictData" :key="index" :label="getDisplayText(item)" :value="item.value" />
</el-select> </el-select>
<!-- 渲染复选框多选 --> <!-- 渲染复选框多选 -->
<el-checkbox-group v-else-if="props.renderAs === 'checkbox'" v-model="state.value" v-bind="$attrs" @change="updateValue"> <el-checkbox-group v-else-if="props.renderAs === 'checkbox'" v-model="state.value" v-bind="$attrs" @change="updateValue">
<el-checkbox-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value"> <el-checkbox-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value">
{{ getDisplayText(item) }} {{ getDisplayText(item) }}
</el-checkbox-button> </el-checkbox-button>
</el-checkbox-group> </el-checkbox-group>
<!-- 渲染单选框 --> <!-- 渲染单选框 -->
<el-radio-group v-else-if="props.renderAs === 'radio'" v-model="state.value" v-bind="$attrs" @change="updateValue"> <el-radio-group v-else-if="props.renderAs === 'radio'" v-model="state.value" v-bind="$attrs" @change="updateValue">
<el-radio v-for="(item, index) in formattedDictData" :key="index" :value="item.value"> <el-radio v-for="(item, index) in formattedDictData" :key="index" :value="item.value">
{{ getDisplayText(item) }} {{ getDisplayText(item) }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<!-- 渲染单选框按钮 --> <!-- 渲染单选框按钮 -->
<el-radio-group v-else-if="props.renderAs === 'radio-button'" v-model="state.value" v-bind="$attrs" @change="updateValue"> <el-radio-group v-else-if="props.renderAs === 'radio-button'" v-model="state.value" v-bind="$attrs" @change="updateValue">
<el-radio-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value"> <el-radio-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value">
{{ getDisplayText(item) }} {{ getDisplayText(item) }}
</el-radio-button> </el-radio-button>
</el-radio-group> </el-radio-group>
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -134,6 +134,10 @@ const state = reactive({
logMaxValue: 1, logMaxValue: 1,
}); });
//
const colors = ['--el-color-primary-light-9', '--el-color-primary-light-7', '--el-color-primary-light-5', '--el-color-primary-light-3', '--el-color-primary-light-1', '--el-color-primary'].map(
(variable) => getComputedStyle(document.documentElement).getPropertyValue(variable).trim()
);
const echartsOption = ref({ const echartsOption = ref({
title: { title: {
top: 30, top: 30,
@ -148,9 +152,12 @@ const echartsOption = ref({
}, },
visualMap: { visualMap: {
show: true, show: true,
// inRange: { inRange: {
// color: ['#fbeee2', '#f2cac9', '#efafad', '#f19790', '#f1908c', '#f17666', '#f05a46', '#ed3b2f', '#ec2b24', '#de2a18'], color: colors,
// }, },
outOfRange: {
color: ['#000000'],
},
min: 0, min: 0,
max: 1000, max: 1000,
maxOpen: { maxOpen: {

View File

@ -176,6 +176,10 @@ const state = reactive({
logMaxValue: 1, logMaxValue: 1,
}); });
//
const colors = ['--el-color-primary-light-9', '--el-color-primary-light-7', '--el-color-primary-light-5', '--el-color-primary-light-3', '--el-color-primary-light-1', '--el-color-primary'].map(
(variable) => getComputedStyle(document.documentElement).getPropertyValue(variable).trim()
);
const echartsOption = ref({ const echartsOption = ref({
title: { title: {
top: 30, top: 30,
@ -190,9 +194,12 @@ const echartsOption = ref({
}, },
visualMap: { visualMap: {
show: true, show: true,
// inRange: { inRange: {
// color: ['#fbeee2', '#f2cac9', '#efafad', '#f19790', '#f1908c', '#f17666', '#f05a46', '#ed3b2f', '#ec2b24', '#de2a18'], color: colors,
// }, },
outOfRange: {
color: ['#000000'],
},
min: 0, min: 0,
max: 1000, max: 1000,
maxOpen: { maxOpen: {

View File

@ -136,6 +136,10 @@ const state = reactive({
logMaxValue: 1, logMaxValue: 1,
}); });
//
const colors = ['--el-color-primary-light-9', '--el-color-primary-light-7', '--el-color-primary-light-5', '--el-color-primary-light-3', '--el-color-primary-light-1', '--el-color-primary'].map(
(variable) => getComputedStyle(document.documentElement).getPropertyValue(variable).trim()
);
const echartsOption = ref({ const echartsOption = ref({
title: { title: {
top: 30, top: 30,
@ -150,9 +154,12 @@ const echartsOption = ref({
}, },
visualMap: { visualMap: {
show: true, show: true,
// inRange: { inRange: {
// color: ['#fbeee2', '#f2cac9', '#efafad', '#f19790', '#f1908c', '#f17666', '#f05a46', '#ed3b2f', '#ec2b24', '#de2a18'], color: colors,
// }, },
outOfRange: {
color: ['#000000'],
},
min: 0, min: 0,
max: 1000, max: 1000,
maxOpen: { maxOpen: {

View File

@ -1,23 +1,32 @@
<template> <template>
<div class="weChatPay-container"> <div class="weChatPay-container">
<el-card shadow="hover" :body-style="{ paddingBottom: '0' }"> <el-card shadow="hover" :body-style="{ padding: '5px 5px 0 5px', display: 'flex', width: '100%', height: '100%', alignItems: 'start' }">
<el-form :model="state.queryParams" ref="queryForm" :inline="true"> <el-form :model="state.queryParams" ref="queryForm" :show-message="false" :inlineMessage="true" label-width="auto" style="flex: 1 1 0%">
<el-form-item label="订单号"> <el-row :gutter="10">
<el-input v-model="state.queryParams.keyword" clearable="" placeholder="请输入订单号" /> <el-col class="mb5" :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
</el-form-item> <el-form-item label="订单号">
<el-form-item label="创建时间"> <el-input v-model="state.queryParams.keyword" clearable="" placeholder="请输入订单号" />
<el-date-picker placeholder="请选择创建时间" value-format="YYYY/MM/DD" type="daterange" v-model="state.queryParams.createTimeRange" /> </el-form-item>
</el-form-item> </el-col>
<el-form-item> <el-col class="mb5" :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-button-group> <el-form-item label="创建时间">
<el-button type="primary" icon="ele-Search" @click="handleQuery()"> 查询 </el-button> <el-date-picker placeholder="请选择创建时间" value-format="YYYY/MM/DD" type="daterange" v-model="state.queryParams.createTimeRange" />
<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button> </el-form-item>
</el-button-group> </el-col>
</el-form-item> </el-row>
<el-form-item>
<el-button type="primary" icon="ele-Plus" @click="openAddDialog">新增模拟数据</el-button>
</el-form-item>
</el-form> </el-form>
<el-divider style="height: calc(100% - 5px); margin: 0 10px" direction="vertical" />
<el-row>
<el-col>
<el-button-group>
<el-button type="primary" icon="ele-Search" @click="handleQuery()"> {{ $t('message.list.query') }} </el-button>
<el-button icon="ele-Refresh" @click="resetQuery"> {{ $t('message.list.reset') }} </el-button>
</el-button-group>
<el-button type="primary" icon="ele-Plus" @click="openAddDialog" style="margin-left: 10px">新增模拟数据</el-button>
</el-col>
</el-row>
</el-card> </el-card>
<el-card class="full-table" shadow="hover" style="margin-top: 5px"> <el-card class="full-table" shadow="hover" style="margin-top: 5px">