update 看板个性配置组件封装

This commit is contained in:
2026-04-07 11:33:31 +08:00
parent 365554fb72
commit dd149586f4
3 changed files with 228 additions and 166 deletions

View File

@@ -0,0 +1,192 @@
<template>
<div class="dashboard-setting">
<!-- 配置按钮 -->
<div class="icon-btn" v-if="showSettingBtn">
<el-tooltip :content="$t('个性化配置')" placement="top">
<div class="setting-btn" @click="settingDiaVisible = true">
<el-icon :size="18">
<Setting />
</el-icon>
</div>
</el-tooltip>
</div>
<!-- 配置弹窗 -->
<settingDia
v-model="settingDiaVisible"
:configJson="configJson"
:baseList="baseList"
@updateConfig="updateConfigFun"
/>
<!-- 图表容器 -->
<div class="content" v-if="!loading">
<div v-for="config in currentList" :key="config.id" class="chart-box">
<component :is="config.component" v-bind="config.props" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { getUserId, getUserTenantId } from '@/utils/user';
import { ElMessage } from 'element-plus';
import { Setting } from '@element-plus/icons-vue';
import settingDia from './settingDia.vue';
import {
addUserFormConfigureApi,
getUserFormConfigureApi,
updateUserFormConfigureApi,
} from '@/api/system/systemData';
interface ChartConfig {
id: string;
title: string;
component: any;
props: Record<string, any>;
}
interface Props {
baseList: ChartConfig[];
showSettingBtn?: boolean;
formNamePrefix?: string;
}
const props = withDefaults(defineProps<Props>(), {
showSettingBtn: true,
formNamePrefix: 'data_Statistics_Setting',
});
const emit = defineEmits(['configUpdated']);
// 状态
const settingDiaVisible = ref(false);
const currentList = ref<ChartConfig[]>([]);
const loading = ref(false);
const hasConfig = ref(false);
const configJson = ref('');
// 获取表单名称
const getFormName = () => {
return `${props.formNamePrefix}_${getUserId()}_${getUserTenantId()}`;
};
// 配置弹窗点击确定
const updateConfigFun = async (info: any) => {
try {
let res: any;
// 新增 or 修改
if (hasConfig.value) {
res = await updateUserFormConfigureApi({
formName: getFormName(),
formConfig: info,
});
} else {
res = await addUserFormConfigureApi({
formName: getFormName(),
formConfig: info,
});
}
// 接口成功后才更新 configJson
if (res.code === 200) {
ElMessage.success('配置成功');
configJson.value = info;
hasConfig.value = true;
// 根据配置的结果对展示的图表进行排序
setConfig(info);
emit('configUpdated', info);
}
} catch (error) {
console.error('更新配置失败:', error);
}
};
// 设置 参数json
const setConfig = (dataStatisticsSetting: any) => {
if (dataStatisticsSetting) {
const configInfo = JSON.parse(dataStatisticsSetting);
// 根据配置的结果对展示的图表进行排序
const list = configInfo
.filter((config: any) => config.inBoard)
.map((config: any) => props.baseList.find((item) => item.id === config.key))
.filter(Boolean);
currentList.value = list as ChartConfig[];
} else {
currentList.value = props.baseList;
}
};
// 获取该用户的配置
const getFormConfigure = async () => {
loading.value = true;
const params = {
formName: getFormName(),
};
try {
// 临时保存原始的 ElMessage.warning
const originalWarning = ElMessage.warning;
// 临时禁用警告消息
ElMessage.warning = () => ({ close: () => {} }) as any;
const res: any = await getUserFormConfigureApi(params);
if (res.code === 200) {
// 如果存在配置,则使用配置
hasConfig.value = true;
configJson.value = res.data.formConfig;
setConfig(res.data.formConfig);
} else {
// 如果不存在配置,则使用默认配置
hasConfig.value = false;
setConfig('');
}
// 恢复原始的 ElMessage.warning
ElMessage.warning = originalWarning;
} finally {
loading.value = false;
}
};
// 监听baseList变化
watch(
() => props.baseList,
() => {
if (!hasConfig.value) {
setConfig('');
}
},
{ deep: true }
);
onMounted(() => {
getFormConfigure();
});
</script>
<style lang="scss" scoped>
.dashboard-setting {
.icon-btn {
height: 20px;
background: var(--el-bg-color);
display: flex;
justify-content: flex-end;
padding-right: 8px;
.setting-btn {
cursor: pointer;
}
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.chart-box {
width: calc(50% - 8px);
height: 400px;
position: relative;
margin-bottom: 16px;
&:nth-last-child(-n + 2) {
margin-bottom: 0;
}
}
}
}
</style>

View File

@@ -2,7 +2,7 @@
<div class="comp-content">
<Dialog
v-model="diaVisible"
diaTitle="数据统计看板布局设置"
diaTitle="看板布局设置"
top="2vh"
width="500"
height="80%"
@@ -66,28 +66,26 @@ import Dialog from '@/components/common/dialog/index.vue';
interface Props {
modelValue: boolean;
configJson?: string;
baseList: any[];
}
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
configJson: '',
baseList: () => [],
});
const emit = defineEmits(['update:modelValue', 'updateConfig']);
const diaVisible = ref(false);
const tableData = ref<any>([]);
const getBaseTable = () => [
{ key: 'userGroupProject', title: '用户组项目统计', inBoard: true },
{ key: 'userDifficultyCoefficient', title: '用户组难度系数统计', inBoard: true },
{ key: 'userTaskComplete', title: '用户组任务完成情况统计', inBoard: true },
{ key: 'projectTaskComplete', title: '项目任务完成情况统计', inBoard: true },
{ key: 'taskCompletionMechine', title: '任务完成统计(机台)', inBoard: true },
{ key: 'taskCompletionDiscipline', title: '任务完成统计(学科)', inBoard: true },
{ key: 'performanceCompletionMechine', title: '指标完成统计(机台)', inBoard: true },
{ key: 'performanceCompletionDiscipline', title: '指标完成统计(学科)', inBoard: true },
{ key: 'reviewPassed', title: '工位评审通过统计', inBoard: true },
{ key: 'fileOperate', title: '文件下载统计', inBoard: true },
];
// baseList
const getBaseTable = () => {
return props.baseList.map((item) => ({
key: item.id,
title: item.title,
inBoard: true,
}));
};
const vxeTableRef = ref<any>();

View File

@@ -1,31 +1,10 @@
<template>
<div class="gl-page-content-grey data-statistics" v-loading="loading">
<!-- 配置按钮 -->
<div class="icon-btn">
<el-tooltip :content="$t('个性化配置')" placement="top">
<div class="setting-btn" @click="settingDiaVisible = true">
<el-icon :size="18">
<Setting />
</el-icon>
</div>
</el-tooltip>
</div>
<settingDia
v-model="settingDiaVisible"
:configJson="configJson"
@updateConfig="updateConfigFun"
/>
<!-- echart 图表 -->
<div class="content">
<div v-for="config in currentList" :key="config.id" class="chart-box">
<component :is="config.component" v-bind="config.props" />
</div>
</div>
<div class="gl-page-content-grey">
<dashboard-setting :baseList="baseList" @configUpdated="handleConfigUpdated" />
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getThemeColor } from '@/utils/theme';
// 引入子组件
import fileOperateChart from './dataStatistics/fileOperateChart.vue';
@@ -36,29 +15,21 @@ import taskCompletion from './dataStatistics/taskCompletion.vue';
import performanceCompletion from './dataStatistics/performanceCompletion.vue';
import projectTaskComplete from './dataStatistics/projectTaskComplete.vue';
import reviewPassed from './dataStatistics/reviewPassed.vue';
import settingDia from './dataStatistics/settingDia.vue';
import { getUserId, getUserTenantId } from '@/utils/user';
import { ElMessage } from 'element-plus';
import {
addUserFormConfigureApi,
getUserFormConfigureApi,
updateUserFormConfigureApi,
} from '@/api/system/systemData';
import { getTaskStatusColorList } from '@/utils/enum/task';
import dashboardSetting from '@/components/common/dashboardSetting/index.vue';
import { useDict } from '@/utils/useDict';
import { useProjectList } from '@/utils/useProjectList';
import { getTaskStatusColorList, getAchieveColorList } from '@/utils/enum/task';
// 统一请求项目列表
useProjectList();
const { TASK_ACHIEVE_STATUS } = useDict('TASK_ACHIEVE_STATUS');
const { TASK_ACHIEVE_STATUS, RESULT_ACHIEVE_STATUS } = useDict(
'TASK_ACHIEVE_STATUS',
'RESULT_ACHIEVE_STATUS'
);
const statusColorList = getTaskStatusColorList(Object.keys(TASK_ACHIEVE_STATUS.value.O));
const performanceColorList = getAchieveColorList(Object.keys(RESULT_ACHIEVE_STATUS.value.O));
const performanceColorList = [
'rgb(200, 201, 204)', // 未分析
getThemeColor('--el-color-danger'), // 不合格
getThemeColor('--el-color-success'), // 合格
];
// 难度系数颜色列表
const difficultyCountColorList = [
'#67c23a',
@@ -75,17 +46,18 @@ const processNodeColorList = [
getThemeColor('--el-color-success'), // 已通过
getThemeColor('--el-color-danger'), // 已拒绝
];
// 设置弹窗
const settingDiaVisible = ref(false);
// 组件基础配置数组
const baseList = ref([
const baseList = [
{
id: 'userGroupProject',
title: '用户组项目统计',
component: userGroupProjectChart, // 用户组项目统计
props: {},
},
{
id: 'userDifficultyCoefficient',
title: '用户组难度系数统计',
component: userDifficultyCoefficientChart, // 用户组难度系数统计
props: {
difficultyCountColorList,
@@ -93,6 +65,7 @@ const baseList = ref([
},
{
id: 'userTaskComplete',
title: '用户组任务完成情况统计',
component: userTaskCompleteChart, // 用户组任务完成情况统计
props: {
statusColorList,
@@ -100,6 +73,7 @@ const baseList = ref([
},
{
id: 'projectTaskComplete',
title: '项目任务完成情况统计',
component: projectTaskComplete, // 项目任务完成情况统计
props: {
statusColorList,
@@ -107,6 +81,7 @@ const baseList = ref([
},
{
id: 'taskCompletionMechine',
title: '任务完成统计(机台)',
component: taskCompletion, // 任务完成统计(机台)
props: {
statusColorList,
@@ -115,6 +90,7 @@ const baseList = ref([
},
{
id: 'taskCompletionDiscipline',
title: '任务完成统计(学科)',
component: taskCompletion, // 任务完成统计(学科)
props: {
statusColorList,
@@ -123,6 +99,7 @@ const baseList = ref([
},
{
id: 'performanceCompletionMechine',
title: '指标完成统计(机台)',
component: performanceCompletion, // 指标完成统计(机台)
props: {
performanceColorList,
@@ -131,6 +108,7 @@ const baseList = ref([
},
{
id: 'performanceCompletionDiscipline',
title: '指标完成统计(学科)',
component: performanceCompletion, // 指标完成统计(学科)
props: {
performanceColorList,
@@ -139,6 +117,7 @@ const baseList = ref([
},
{
id: 'reviewPassed',
title: '工位评审通过统计',
component: reviewPassed, // 工位评审通过统计
props: {
processNodeColorList,
@@ -146,121 +125,14 @@ const baseList = ref([
},
{
id: 'fileOperate',
title: '文件下载统计',
component: fileOperateChart,
props: {},
},
]);
// 当前展示的图表
const currentList = ref();
const loading = ref(false);
// 配置弹窗点击确定
const updateConfigFun = async (info: any) => {
try {
let res: any;
// 新增 or 修改
if (hasConfig.value) {
res = await updateUserFormConfigureApi({
formName: 'data_Statistics_Setting' + '_' + getUserId() + '_' + getUserTenantId(),
formConfig: info,
});
} else {
res = await addUserFormConfigureApi({
formName: 'data_Statistics_Setting' + '_' + getUserId() + '_' + getUserTenantId(),
formConfig: info,
});
}
// 接口成功后才更新 configJson
if (res.code === 200) {
ElMessage.success('配置成功');
configJson.value = info;
hasConfig.value = true;
// 根据配置的结果对展示的图表进行排序
setConfig(info);
}
} catch (error) {
console.error('更新配置失败:', error);
}
};
];
// 设置 参数json
const setConfig = (dataStatisticsSetting: any) => {
if (dataStatisticsSetting) {
const configInfo = JSON.parse(dataStatisticsSetting);
// 根据配置的结果对展示的图表进行排序
const list = configInfo
.filter((config: any) => config.inBoard)
.map((config: any) => baseList.value.find((item) => item.id === config.key))
.filter(Boolean);
currentList.value = list;
} else {
currentList.value = baseList.value;
}
// 配置更新回调
const handleConfigUpdated = () => {
// console.log('配置已更新:', config);
};
// 是否配置过
const hasConfig = ref(false);
// 配置规则
const configJson = ref('');
// 获取该用户的配置
const getFormConfigure = async () => {
loading.value = true;
const params = {
formName: 'data_Statistics_Setting' + '_' + getUserId() + '_' + getUserTenantId(),
};
try {
// 临时保存原始的 ElMessage.warning
const originalWarning = ElMessage.warning;
// 临时禁用警告消息
ElMessage.warning = () => ({ close: () => {} }) as any;
const res: any = await getUserFormConfigureApi(params);
if (res.code === 200) {
// 如果存在配置,则使用配置
hasConfig.value = true;
configJson.value = res.data.formConfig;
setConfig(res.data.formConfig);
} else {
// 如果不存在配置,则使用默认配置
hasConfig.value = false;
setConfig('');
}
// 恢复原始的 ElMessage.warning
ElMessage.warning = originalWarning;
} finally {
loading.value = false;
}
};
onMounted(() => {
getFormConfigure();
});
</script>
<style lang="scss" scoped>
.gl-page-content-grey {
.icon-btn {
height: 20px;
background: var(--el-bg-color);
display: flex;
justify-content: flex-end;
padding-right: 8px;
.setting-btn {
cursor: pointer;
}
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.chart-box {
width: calc(50% - 8px);
height: 400px;
position: relative;
margin-bottom: 16px;
&:nth-last-child(-n + 2) {
margin-bottom: 0;
}
}
}
}
</style>