refactor(工作台): 重构工作台首页项目概览和我创建的卡片调整人员概览交互调整
This commit is contained in:
parent
555f9845c4
commit
3723d803ad
|
@ -349,15 +349,6 @@ export default defineComponent(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.defaultAllSelect,
|
|
||||||
(val) => {
|
|
||||||
if (val) {
|
|
||||||
handleSelectAllChange(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 检测全选状态变化,全选时需要覆盖选择器的输入框内容,展示文本 ‘全部’;非全选时则移除文本 ‘全部’
|
// 检测全选状态变化,全选时需要覆盖选择器的输入框内容,展示文本 ‘全部’;非全选时则移除文本 ‘全部’
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const innerDom = selectRef.value?.$el.nextElementSibling.querySelector('.arco-select-view-inner') as HTMLElement;
|
const innerDom = selectRef.value?.$el.nextElementSibling.querySelector('.arco-select-view-inner') as HTMLElement;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
<MsSelect
|
<MsSelect
|
||||||
:key="props.refreshKey"
|
|
||||||
v-model:model-value="innerHandleUsers"
|
v-model:model-value="innerHandleUsers"
|
||||||
:options="memberOptions"
|
:options="memberOptions"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
@ -215,7 +214,8 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
import { contentTabList } from '@/config/workbench';
|
import { contentTabList } from '@/config/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { addCommasToNumber } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ModuleCardItem,
|
ModuleCardItem,
|
||||||
|
@ -63,9 +63,9 @@
|
||||||
SelectedCardItem,
|
SelectedCardItem,
|
||||||
TimeFormParams,
|
TimeFormParams,
|
||||||
} from '@/models/workbench/homePage';
|
} from '@/models/workbench/homePage';
|
||||||
import { WorkCardEnum, WorkOverviewEnum } from '@/enums/workbenchEnum';
|
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||||
|
|
||||||
import { getColorScheme, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
import { getColorScheme, getCommonBarOptions, getSeriesData, handleNoDataDisplay } from '../utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -114,85 +114,26 @@
|
||||||
|
|
||||||
function handleData(detail: OverViewOfProject) {
|
function handleData(detail: OverViewOfProject) {
|
||||||
// 处理模块顺序
|
// 处理模块顺序
|
||||||
const tempAxisData = detail.xaxis.map((xAxisKey) => {
|
cardModuleList.value = contentTabList
|
||||||
const data = contentTabList.find((e) => e.value === xAxisKey);
|
.map((item) => {
|
||||||
return {
|
return {
|
||||||
...data,
|
...item,
|
||||||
label: t(data?.label || ''),
|
label: t(item.label),
|
||||||
count: detail.caseCountMap[xAxisKey as WorkOverviewEnum],
|
count: detail.caseCountMap[item.value],
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
|
.filter((e) => Object.keys(detail.caseCountMap).includes(e.value as string));
|
||||||
|
|
||||||
cardModuleList.value = tempAxisData as ModuleCardItem[];
|
|
||||||
options.value = getCommonBarOptions(hasRoom.value, getColorScheme(detail.projectCountList.length));
|
options.value = getCommonBarOptions(hasRoom.value, getColorScheme(detail.projectCountList.length));
|
||||||
const { invisible, text } = handleNoDataDisplay(detail.xaxis, hasPermission.value);
|
const { invisible, text } = handleNoDataDisplay(detail.xaxis, hasPermission.value);
|
||||||
options.value.graphic.invisible = invisible;
|
options.value.graphic.invisible = invisible;
|
||||||
options.value.graphic.style.text = text;
|
options.value.graphic.style.text = text;
|
||||||
// x轴
|
// x轴
|
||||||
options.value.xAxis.data = cardModuleList.value.map((e) => e.label);
|
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
||||||
|
|
||||||
let maxAxis = 5;
|
const { maxAxis, data } = getSeriesData(detail.projectCountList);
|
||||||
|
options.value.series = data;
|
||||||
// 处理data数据
|
options.value.yAxis[0].max = maxAxis;
|
||||||
options.value.series = detail.projectCountList.map((item) => {
|
|
||||||
const countData: Record<string, any>[] = item.count.map((e) => {
|
|
||||||
return {
|
|
||||||
name: item.name,
|
|
||||||
value: e,
|
|
||||||
originValue: e,
|
|
||||||
tooltip: {
|
|
||||||
show: true,
|
|
||||||
trigger: 'item',
|
|
||||||
enterable: true,
|
|
||||||
formatter(params: any) {
|
|
||||||
const html = `
|
|
||||||
<div class="w-[186px] h-[50px] p-[16px] flex items-center justify-between">
|
|
||||||
<div class=" flex items-center">
|
|
||||||
<div class="mb-[2px] mr-[8px] h-[8px] w-[8px] rounded-sm bg-[${params.color}]" style="background:${
|
|
||||||
params.color
|
|
||||||
}"></div>
|
|
||||||
<div class="one-line-text max-w-[100px]"" style="color:#959598">${params.name}</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-[#323233] font-medium">${addCommasToNumber(params.value)}</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const itemMax = Math.max(...item.count);
|
|
||||||
|
|
||||||
maxAxis = Math.max(itemMax, maxAxis);
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: item.name,
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
legendHoverLink: true,
|
|
||||||
large: true,
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: [2, 2, 0, 0], // 上边圆角
|
|
||||||
},
|
|
||||||
z: 10,
|
|
||||||
data: countData,
|
|
||||||
barMinHeight: ((optionData: Record<string, any>[]) => {
|
|
||||||
optionData.forEach((itemValue: any, index: number) => {
|
|
||||||
if (itemValue.value === 0) optionData[index].value = null;
|
|
||||||
});
|
|
||||||
let hasZero = false;
|
|
||||||
for (let i = 0; i < optionData.length; i++) {
|
|
||||||
if (optionData[i].value === 0) {
|
|
||||||
hasZero = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasZero ? 0 : 5;
|
|
||||||
})(countData),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
options.value.yAxis[0].max = maxAxis < 100 ? 100 : maxAxis + 50;
|
|
||||||
}
|
}
|
||||||
const showSkeleton = ref(false);
|
const showSkeleton = ref(false);
|
||||||
const selectAll = computed(() => appStore.projectList.length === innerProjectIds.value.length);
|
const selectAll = computed(() => appStore.projectList.length === innerProjectIds.value.length);
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[200px]"
|
class="!w-[200px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
@change="changeProject"
|
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
|
|
||||||
<MsSelect
|
<MsSelect
|
||||||
:key="props.refreshKey"
|
|
||||||
v-model:model-value="innerHandleUsers"
|
v-model:model-value="innerHandleUsers"
|
||||||
:options="memberOptions"
|
:options="memberOptions"
|
||||||
allow-search
|
allow-search
|
||||||
|
@ -58,14 +56,13 @@
|
||||||
import CardSkeleton from './cardSkeleton.vue';
|
import CardSkeleton from './cardSkeleton.vue';
|
||||||
|
|
||||||
import { workMemberViewDetail, workProjectMemberOptions } from '@/api/modules/workbench';
|
import { workMemberViewDetail, workProjectMemberOptions } from '@/api/modules/workbench';
|
||||||
import { contentTabList } from '@/config/workbench';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { characterLimit, sleep } from '@/utils';
|
import { characterLimit, sleep } from '@/utils';
|
||||||
|
|
||||||
import type { OverViewOfProject, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { OverViewOfProject, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
|
|
||||||
import { getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
import { getColorScheme, getCommonBarOptions, getSeriesData, handleNoDataDisplay } from '../utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
@ -100,57 +97,18 @@
|
||||||
|
|
||||||
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
||||||
const options = ref<Record<string, any>>({});
|
const options = ref<Record<string, any>>({});
|
||||||
const color = ['#811FA3', '#FFCA59', '#00C261', '#FFA1FF', '#F9F871', '#3370FF', '#F24F4F'];
|
|
||||||
|
|
||||||
function handleData(detail: OverViewOfProject) {
|
function handleData(detail: OverViewOfProject) {
|
||||||
options.value = getCommonBarOptions(detail.xaxis.length >= 7, color);
|
options.value = getCommonBarOptions(detail.xaxis.length >= 7, getColorScheme(7));
|
||||||
const { invisible, text } = handleNoDataDisplay(detail.xaxis, hasPermission.value);
|
const { invisible, text } = handleNoDataDisplay(detail.xaxis, hasPermission.value);
|
||||||
options.value.graphic.invisible = invisible;
|
options.value.graphic.invisible = invisible;
|
||||||
options.value.graphic.style.text = text;
|
options.value.graphic.style.text = text;
|
||||||
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
||||||
|
|
||||||
let maxAxis = 5;
|
const { maxAxis, data } = getSeriesData(detail.projectCountList);
|
||||||
|
|
||||||
// 处理data数据
|
options.value.series = data;
|
||||||
options.value.series = detail.projectCountList.map((item, sid) => {
|
options.value.yAxis[0].max = maxAxis;
|
||||||
const countData: Record<string, any>[] = item.count.map((e) => {
|
|
||||||
return {
|
|
||||||
name: item.name,
|
|
||||||
value: e,
|
|
||||||
originValue: e,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const itemMax = Math.max(...item.count);
|
|
||||||
|
|
||||||
maxAxis = Math.max(itemMax, maxAxis);
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: t(contentTabList[sid].label),
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
legendHoverLink: true,
|
|
||||||
large: true,
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: countData,
|
|
||||||
barMinHeight: ((optionData: Record<string, any>[]) => {
|
|
||||||
optionData.forEach((itemValue: any, index: number) => {
|
|
||||||
if (itemValue.value === 0) optionData[index].value = null;
|
|
||||||
});
|
|
||||||
let hasZero = false;
|
|
||||||
for (let i = 0; i < optionData.length; i++) {
|
|
||||||
if (optionData[i].value === 0) {
|
|
||||||
hasZero = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasZero ? 0 : 5;
|
|
||||||
})(countData),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
options.value.yAxis[0].max = maxAxis < 100 ? 100 : maxAxis + 50;
|
|
||||||
}
|
}
|
||||||
const showSkeleton = ref(false);
|
const showSkeleton = ref(false);
|
||||||
|
|
||||||
|
@ -187,21 +145,16 @@
|
||||||
label: e.name,
|
label: e.name,
|
||||||
value: e.id,
|
value: e.id,
|
||||||
}));
|
}));
|
||||||
|
innerHandleUsers.value = innerHandleUsers.value.filter((id: string) =>
|
||||||
|
memberOptions.value.some((member) => member.value === id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const isInit = ref(true);
|
const isInit = ref(true);
|
||||||
|
|
||||||
function changeProject() {
|
function changeMember(value: string[]) {
|
||||||
innerHandleUsers.value = [];
|
|
||||||
nextTick(() => {
|
|
||||||
getMemberOptions();
|
|
||||||
initOverViewMemberDetail();
|
|
||||||
emit('change');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeMember() {
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
initOverViewMemberDetail();
|
initOverViewMemberDetail();
|
||||||
|
innerHandleUsers.value = value;
|
||||||
emit('change');
|
emit('change');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -241,19 +194,26 @@
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
isInit.value = false;
|
isInit.value = false;
|
||||||
initOverViewMemberDetail();
|
|
||||||
if (props.item.projectIds.length) {
|
if (props.item.projectIds.length) {
|
||||||
getMemberOptions();
|
getMemberOptions();
|
||||||
}
|
}
|
||||||
|
initOverViewMemberDetail();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch([() => props.refreshKey, () => projectId.value], async () => {
|
watch([() => props.refreshKey, () => projectId.value], async ([_key, newProjectId]) => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
initOverViewMemberDetail();
|
|
||||||
await sleep(50);
|
if (newProjectId) {
|
||||||
|
innerHandleUsers.value = [];
|
||||||
|
emit('change');
|
||||||
|
}
|
||||||
|
|
||||||
if (props.item.projectIds.length) {
|
if (props.item.projectIds.length) {
|
||||||
getMemberOptions();
|
getMemberOptions();
|
||||||
}
|
}
|
||||||
|
await sleep(50);
|
||||||
|
|
||||||
|
initOverViewMemberDetail();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import { toolTipConfig } from '@/config/testPlan';
|
import { toolTipConfig } from '@/config/testPlan';
|
||||||
import { commonRatePieOptions, defaultValueMap } from '@/config/workbench';
|
import { commonRatePieOptions, contentTabList, defaultValueMap } from '@/config/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { addCommasToNumber } from '@/utils';
|
import { addCommasToNumber } from '@/utils';
|
||||||
|
|
||||||
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// 通用颜色配置
|
// TODO 通用颜色配置注: 目前柱状图只用到了7种色阶,其他色阶暂时保留
|
||||||
const commonColorConfig: Record<number, string[]> = {
|
const commonColorConfig: Record<number, string[]> = {
|
||||||
2: ['#783887', '#FFC14E'],
|
2: ['#783887', '#FFC14E'],
|
||||||
4: ['#783887', '#FFC14E', '#2DFCEF', '#3370FF'],
|
4: ['#783887', '#FFC14E', '#2DFCEF', '#3370FF'],
|
||||||
|
7: ['#811FA3', '#00C261', '#FF9964', '#50CEFB', '#EE50A3', '#3370FF', '#D34400'],
|
||||||
8: ['#783887', '#FFC14E', '#2DFCEF', '#3370FF', '#811FA3', '#00D1FF', '#FFA53D', '#00C261'],
|
8: ['#783887', '#FFC14E', '#2DFCEF', '#3370FF', '#811FA3', '#00D1FF', '#FFA53D', '#00C261'],
|
||||||
12: [
|
12: [
|
||||||
'#AA4FBF',
|
'#AA4FBF',
|
||||||
|
@ -55,6 +56,7 @@ const commonColorConfig: Record<number, string[]> = {
|
||||||
export function getColorScheme(dataLength: number): string[] {
|
export function getColorScheme(dataLength: number): string[] {
|
||||||
if (dataLength <= 2) return commonColorConfig[2];
|
if (dataLength <= 2) return commonColorConfig[2];
|
||||||
if (dataLength <= 4) return commonColorConfig[4];
|
if (dataLength <= 4) return commonColorConfig[4];
|
||||||
|
if (dataLength <= 7) return commonColorConfig[7];
|
||||||
if (dataLength <= 8) return commonColorConfig[8];
|
if (dataLength <= 8) return commonColorConfig[8];
|
||||||
if (dataLength <= 12) return commonColorConfig[12];
|
if (dataLength <= 12) return commonColorConfig[12];
|
||||||
return commonColorConfig[13];
|
return commonColorConfig[13];
|
||||||
|
@ -543,3 +545,75 @@ export function handleUpdateTabPie(
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSeriesData(
|
||||||
|
projectCountList: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
count: number[];
|
||||||
|
}[]
|
||||||
|
) {
|
||||||
|
let maxAxis = 5;
|
||||||
|
const seriesData = projectCountList.map((item, sid) => {
|
||||||
|
const countData: Record<string, any>[] = item.count.map((e) => {
|
||||||
|
return {
|
||||||
|
name: t(contentTabList[sid].label),
|
||||||
|
value: e,
|
||||||
|
originValue: e,
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'item',
|
||||||
|
enterable: true,
|
||||||
|
formatter(params: any) {
|
||||||
|
const html = `
|
||||||
|
<div class="w-[186px] h-[50px] p-[16px] flex items-center justify-between">
|
||||||
|
<div class=" flex items-center">
|
||||||
|
<div class="mb-[2px] mr-[8px] h-[8px] w-[8px] rounded-sm bg-[${params.color}]" style="background:${
|
||||||
|
params.color
|
||||||
|
}"></div>
|
||||||
|
<div class="one-line-text max-w-[100px]"" style="color:#959598">${params.name}</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-[#323233] font-medium">${addCommasToNumber(params.value)}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemMax = Math.max(...item.count);
|
||||||
|
|
||||||
|
maxAxis = Math.max(itemMax, maxAxis);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: t(contentTabList[sid].label),
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: 12,
|
||||||
|
legendHoverLink: true,
|
||||||
|
large: true,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: [2, 2, 0, 0],
|
||||||
|
},
|
||||||
|
data: countData,
|
||||||
|
barMinHeight: ((optionData: Record<string, any>[]) => {
|
||||||
|
optionData.forEach((itemValue: any, index: number) => {
|
||||||
|
if (itemValue.value === 0) optionData[index].value = null;
|
||||||
|
});
|
||||||
|
let hasZero = false;
|
||||||
|
for (let i = 0; i < optionData.length; i++) {
|
||||||
|
if (optionData[i].value === 0) {
|
||||||
|
hasZero = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasZero ? 0 : 5;
|
||||||
|
})(countData),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: seriesData,
|
||||||
|
maxAxis: maxAxis < 100 ? 100 : maxAxis + 50,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue