feat(工作台): 工作台首页联调卡片&柱状图饼图样式调整
This commit is contained in:
parent
622cc8c814
commit
9bd017a800
|
@ -17,7 +17,9 @@ import type {
|
|||
import {
|
||||
EditDashboardLayoutUrl,
|
||||
GetDashboardLayoutUrl,
|
||||
WorkApiCaseCountDetailUrl,
|
||||
WorkApiChangeListUrl,
|
||||
WorkApiCountDetailUrl,
|
||||
WorkAssociateCaseDetailUrl,
|
||||
WorkbenchApiCaseListUrl,
|
||||
WorkbenchBugListUrl,
|
||||
|
@ -26,13 +28,18 @@ import {
|
|||
WorkbenchScenarioListUrl,
|
||||
WorkbenchTestPlanListUrl,
|
||||
WorkbenchTestPlanStatisticUrl,
|
||||
WorkBugByMeCreatedUrl,
|
||||
WorkBugCountDetailUrl,
|
||||
WorkBugHandleByMeUrl,
|
||||
WorkBugHandlerDetailUrl,
|
||||
WorkCaseCountDetailUrl,
|
||||
WorkCaseReviewDetailUrl,
|
||||
WorkHandleUserOptionsUrl,
|
||||
WorkMemberViewDetailUrl,
|
||||
WorkMyCreatedDetailUrl,
|
||||
WorkProOverviewDetailUrl,
|
||||
WorkReviewListUrl,
|
||||
WorkScenarioCaseCountDetailUrl,
|
||||
WorkTodoBugListUrl,
|
||||
WorkTodoPlanListUrl,
|
||||
WorkTodoReviewListUrl,
|
||||
|
@ -75,15 +82,15 @@ export function workbenchApiCaseList(data: TableQueryParams) {
|
|||
|
||||
// 工作台首页概览
|
||||
export function workProOverviewDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<OverViewOfProject>({ url: WorkProOverviewDetailUrl, data });
|
||||
return MSR.post<OverViewOfProject>({ url: WorkProOverviewDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 我创建的
|
||||
export function workMyCreatedDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<OverViewOfProject>({ url: WorkMyCreatedDetailUrl, data });
|
||||
return MSR.post<OverViewOfProject>({ url: WorkMyCreatedDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 人员概览
|
||||
export function workMemberViewDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<OverViewOfProject>({ url: WorkMemberViewDetailUrl, data });
|
||||
return MSR.post<OverViewOfProject>({ url: WorkMemberViewDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 获取用户布局
|
||||
export function getDashboardLayout(orgId: string) {
|
||||
|
@ -97,21 +104,21 @@ export function editDashboardLayout(data: SelectedCardItem[], orgId: string) {
|
|||
|
||||
// 工作台-首页-用例数
|
||||
export function workCaseCountDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkCaseCountDetailUrl, data });
|
||||
return MSR.post<PassRateDataType>({ url: WorkCaseCountDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 工作台-首页-关联用例数
|
||||
export function workAssociateCaseDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkAssociateCaseDetailUrl, data });
|
||||
return MSR.post<PassRateDataType>({ url: WorkAssociateCaseDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-用例评审数
|
||||
export function workCaseReviewDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkCaseReviewDetailUrl, data });
|
||||
return MSR.post<PassRateDataType>({ url: WorkCaseReviewDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-缺陷处理人
|
||||
export function workBugHandlerDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<OverViewOfProject>({ url: WorkBugHandlerDetailUrl, data });
|
||||
return MSR.post<OverViewOfProject>({ url: WorkBugHandlerDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-接口变更
|
||||
|
@ -130,6 +137,41 @@ export function workReviewList(data: WorkHomePageDetail) {
|
|||
);
|
||||
}
|
||||
|
||||
// 工作台-首页-缺陷数量
|
||||
export function workBugCountDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkBugCountDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-我创建的缺陷
|
||||
export function workBugByMeCreated(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkBugByMeCreatedUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-待我处理的缺陷
|
||||
export function workBugHandleByMe(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkBugHandleByMeUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-接口数量
|
||||
export function workApiCountDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkApiCountDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-接口用例数量
|
||||
export function workApiCaseCountDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkApiCaseCountDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-场景用例数量
|
||||
export function workScenarioCaseCountDetail(data: WorkHomePageDetail) {
|
||||
return MSR.post<PassRateDataType>({ url: WorkScenarioCaseCountDetailUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 工作台-首页-缺陷处理人列表
|
||||
export function workHandleUserOptions(projectId: string) {
|
||||
return MSR.get({ url: WorkHandleUserOptionsUrl, params: projectId }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
||||
// 待办-用例评审列表
|
||||
export function workbenchTodoReviewList(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<ReviewItem>>({ url: WorkTodoReviewListUrl, data });
|
||||
|
|
|
@ -19,3 +19,10 @@ export const WorkBugHandlerDetailUrl = '/dashboard/bug_handle_user'; // 工作
|
|||
export const WorkApiChangeListUrl = '/dashboard/api_change'; // 工作台-首页-接口变更
|
||||
export const WorkCaseReviewDetailUrl = '/dashboard/review_case_count'; // 工作台-首页-用例评审数
|
||||
export const WorkReviewListUrl = '/dashboard/reviewing_by_me'; // 工作台-首页-待我评审
|
||||
export const WorkApiCountDetailUrl = '/dashboard/api_count'; // 工作台-首页-接口数量
|
||||
export const WorkApiCaseCountDetailUrl = '/dashboard/api_case_count'; // 工作台-首页-接口用例数量
|
||||
export const WorkScenarioCaseCountDetailUrl = '/dashboard/scenario_count'; // 工作台-首页-场景用例数量
|
||||
export const WorkHandleUserOptionsUrl = '/dashboard/bug_handle_user/list'; // 工作台-首页-缺陷处理人列表
|
||||
export const WorkBugCountDetailUrl = '/dashboard/bug_count'; // 工作台-首页-缺陷数量
|
||||
export const WorkBugByMeCreatedUrl = '/dashboard/create_bug_by_me'; // 工作台-首页-我创建的缺陷
|
||||
export const WorkBugHandleByMeUrl = '/dashboard/handle_bug_by_me'; // 工作台-首页-待我处理的缺陷
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { BarChart, LineChart, PieChart, RadarChart } from 'echarts/charts';
|
||||
import { BarChart, CustomChart, LineChart, PieChart, RadarChart } from 'echarts/charts';
|
||||
import {
|
||||
DataZoomComponent,
|
||||
GraphicComponent,
|
||||
|
@ -21,6 +21,7 @@
|
|||
use([
|
||||
CanvasRenderer,
|
||||
BarChart,
|
||||
CustomChart,
|
||||
LineChart,
|
||||
PieChart,
|
||||
RadarChart,
|
||||
|
|
|
@ -31,7 +31,7 @@ export interface SelectedCardItem {
|
|||
|
||||
// 查询入参
|
||||
export interface WorkHomePageDetail extends TableQueryParams {
|
||||
dayNumber: number | null;
|
||||
dayNumber: number | string;
|
||||
startTime: number | null;
|
||||
endTime: number | null;
|
||||
projectIds: string[];
|
||||
|
@ -40,9 +40,9 @@ export interface WorkHomePageDetail extends TableQueryParams {
|
|||
}
|
||||
|
||||
export interface TimeFormParams {
|
||||
dayNumber: number | null;
|
||||
startTime: number | null;
|
||||
endTime: number | null;
|
||||
dayNumber: number | string;
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
}
|
||||
|
||||
export interface OverViewOfProject {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
:search-keys="['name']"
|
||||
class="!w-[240px]"
|
||||
:prefix="t('workbench.homePage.project')"
|
||||
@change="changeProject"
|
||||
>
|
||||
</MsSelect>
|
||||
</div>
|
||||
|
@ -23,25 +24,25 @@
|
|||
<div class="case-count-item">
|
||||
<div v-for="(ele, index) of executionTimeValue" :key="index" class="case-count-item-content">
|
||||
<div class="case-count-item-title">{{ ele.name }}</div>
|
||||
<div class="case-count-item-number">{{ addCommasToNumber(ele.count) }}</div>
|
||||
<div class="case-count-item-number">{{ hasPermission ? addCommasToNumber(ele.count as number) : '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="case-count-item">
|
||||
<div v-for="(ele, index) of apiCountValue" :key="index" class="case-count-item-content">
|
||||
<div class="case-count-item-title">{{ ele.name }}</div>
|
||||
<div class="case-count-item-number">{{ addCommasToNumber(ele.count) }}</div>
|
||||
<div class="case-count-item-number">{{ hasPermission ? addCommasToNumber(ele.count as number) : '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="case-ratio-wrapper mt-[16px]">
|
||||
<div class="case-ratio-item">
|
||||
<RatioPie :data="coverData" :rate-config="coverTitleConfig" />
|
||||
<RatioPie :has-permission="hasPermission" :data="coverData" :rate-config="coverTitleConfig" />
|
||||
</div>
|
||||
<div class="case-ratio-item">
|
||||
<RatioPie :data="caseExecuteData" :rate-config="executeTitleConfig" />
|
||||
<RatioPie :has-permission="hasPermission" :data="caseExecuteData" :rate-config="executeTitleConfig" />
|
||||
</div>
|
||||
<div class="case-ratio-item">
|
||||
<RatioPie :data="casePassData" :rate-config="casePassTitleConfig" />
|
||||
<RatioPie :has-permission="hasPermission" :data="casePassData" :rate-config="casePassTitleConfig" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,6 +58,7 @@
|
|||
import MsSelect from '@/components/business/ms-select';
|
||||
import RatioPie from './ratioPie.vue';
|
||||
|
||||
import { workApiCaseCountDetail, workScenarioCaseCountDetail } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
|
@ -72,30 +74,34 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
||||
const projectId = ref<string>(innerProjectIds.value[0]);
|
||||
|
||||
const executionTimeValue = ref<{ name: string; count: number }[]>([
|
||||
const executionTimeValue = ref<{ name: string; count: number | string }[]>([
|
||||
{
|
||||
name: '执行次数',
|
||||
count: 100,
|
||||
count: '-',
|
||||
},
|
||||
]);
|
||||
|
||||
const apiCountValue = ref<{ name: string; count: number }[]>([
|
||||
const apiCountValue = ref<{ name: string; count: number | string }[]>([
|
||||
{
|
||||
name:
|
||||
props.item.key === WorkCardEnum.API_CASE_COUNT
|
||||
? t('workbench.homePage.apiUseCasesNumber')
|
||||
: t('workbench.homePage.scenarioUseCasesNumber'),
|
||||
count: 100,
|
||||
count: '-',
|
||||
},
|
||||
{
|
||||
name: t('workbench.homePage.misstatementCount'),
|
||||
count: 100,
|
||||
count: '-',
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -129,6 +135,7 @@
|
|||
name: t('common.executed'),
|
||||
},
|
||||
]);
|
||||
|
||||
const casePassData = ref<{ name: string; value: number }[]>([
|
||||
{
|
||||
value: 0,
|
||||
|
@ -143,8 +150,11 @@
|
|||
const coverTitleConfig = computed(() => {
|
||||
return {
|
||||
name: t('workbench.homePage.apiCoverage'),
|
||||
count: '80%',
|
||||
color: ['#EDEDF1', '#00C261'],
|
||||
tooltipText:
|
||||
props.item.key === WorkCardEnum.API_CASE_COUNT
|
||||
? t('workbench.homePage.apiCaseCountCoverRateTooltip')
|
||||
: t('workbench.homePage.scenarioCaseCountCoverRateTooltip'),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -152,13 +162,13 @@
|
|||
return props.item.key === WorkCardEnum.API_CASE_COUNT
|
||||
? {
|
||||
name: t('workbench.homePage.caseExecutionRate'),
|
||||
count: '80%',
|
||||
color: ['#EDEDF1', '#00C261'],
|
||||
color: ['#00C261', '#EDEDF1'],
|
||||
tooltipText: t('workbench.homePage.apiCaseCountExecuteRateTooltip'),
|
||||
}
|
||||
: {
|
||||
name: t('workbench.homePage.sceneExecutionRate'),
|
||||
count: '80%',
|
||||
color: ['#EDEDF1', '#00C261'],
|
||||
tooltipText: t('workbench.homePage.scenarioCaseCountExecuteRateTooltip'),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -166,17 +176,77 @@
|
|||
return props.item.key === WorkCardEnum.API_CASE_COUNT
|
||||
? {
|
||||
name: t('workbench.homePage.casePassedRate'),
|
||||
count: '80%',
|
||||
color: ['#00C261', '#ED0303'],
|
||||
tooltipText: t('workbench.homePage.apiCaseCountPassRateTooltip'),
|
||||
}
|
||||
: {
|
||||
name: t('workbench.homePage.executionRate'),
|
||||
count: '80%',
|
||||
color: ['#00C261', '#ED0303'],
|
||||
tooltipText: t('workbench.homePage.scenarioCaseCountPassRateTooltip'),
|
||||
};
|
||||
});
|
||||
|
||||
function initApiOrScenarioCount() {}
|
||||
const hasPermission = ref<boolean>(false);
|
||||
async function initApiOrScenarioCount() {
|
||||
try {
|
||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||
|
||||
const params = {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
startTime: dayNumber ? null : startTime,
|
||||
endTime: dayNumber ? null : endTime,
|
||||
dayNumber: dayNumber ?? null,
|
||||
projectIds: innerProjectIds.value,
|
||||
organizationId: appStore.currentOrgId,
|
||||
handleUsers: [],
|
||||
};
|
||||
let detail;
|
||||
if (props.item.key === WorkCardEnum.API_CASE_COUNT) {
|
||||
detail = await workApiCaseCountDetail(params);
|
||||
} else {
|
||||
detail = await workScenarioCaseCountDetail(params);
|
||||
}
|
||||
|
||||
hasPermission.value = detail.errorCode !== 109001;
|
||||
|
||||
caseExecuteData.value = (detail.statusStatisticsMap?.execRate || []).map((e) => {
|
||||
return {
|
||||
...e,
|
||||
value: e.count,
|
||||
};
|
||||
});
|
||||
|
||||
casePassData.value = (detail.statusStatisticsMap?.passRate || []).map((e) => {
|
||||
return {
|
||||
...e,
|
||||
value: e.count,
|
||||
};
|
||||
});
|
||||
|
||||
if (hasPermission.value) {
|
||||
// 执行次数
|
||||
executionTimeValue.value = detail.statusStatisticsMap?.execCount || [];
|
||||
// 数量
|
||||
const valueKey = props.item.key === WorkCardEnum.API_CASE_COUNT ? 'apiCaseCount' : 'apiScenarioCount';
|
||||
apiCountValue.value = detail.statusStatisticsMap?.[valueKey] || [];
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function changeProject() {
|
||||
nextTick(() => {
|
||||
initApiOrScenarioCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initApiOrScenarioCount();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => innerProjectIds.value,
|
||||
|
@ -184,7 +254,6 @@
|
|||
if (val) {
|
||||
const [newProjectId] = val;
|
||||
projectId.value = newProjectId;
|
||||
initApiOrScenarioCount();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
v-on="propsEvent"
|
||||
>
|
||||
<template #num="{ record }">
|
||||
<MsButton type="text">{{ record.num || '-' }}</MsButton>
|
||||
<MsButton type="text" @click="openDetail(record)">{{ record.num || '-' }}</MsButton>
|
||||
</template>
|
||||
<template v-if="isNoPermission" #empty>
|
||||
<div class="w-full">
|
||||
|
@ -61,9 +61,14 @@
|
|||
|
||||
import { workApiChangeList } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import type { ApiDefinitionDetail } from '@/models/apiTest/management';
|
||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
@ -72,6 +77,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -99,6 +108,7 @@
|
|||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'apiTestManagement.path',
|
||||
|
@ -147,6 +157,15 @@
|
|||
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
})
|
||||
);
|
||||
|
||||
// 跳转详情
|
||||
function openDetail(record: ApiDefinitionDetail) {
|
||||
openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, {
|
||||
dId: record.id,
|
||||
pId: projectId.value,
|
||||
});
|
||||
}
|
||||
|
||||
const isNoPermission = ref<boolean>(false);
|
||||
async function initData() {
|
||||
try {
|
||||
|
@ -169,7 +188,10 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
initData();
|
||||
nextTick(() => {
|
||||
initData();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -43,26 +43,31 @@
|
|||
* @desc 接口数量
|
||||
*/
|
||||
import { ref } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsChart from '@/components/pure/chart/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import PassRatePie from './passRatePie.vue';
|
||||
import TabCard from './tabCard.vue';
|
||||
|
||||
import { workApiCountDetail } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
|
||||
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const props = defineProps<{
|
||||
item: SelectedCardItem;
|
||||
projectIds: string[];
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
|
@ -79,18 +84,9 @@
|
|||
})
|
||||
);
|
||||
|
||||
const options = ref({});
|
||||
|
||||
// TODO 假数据
|
||||
const detail = ref<PassRateDataType>({
|
||||
statusStatisticsMap: null,
|
||||
statusPercentList: null,
|
||||
errorCode: 109001,
|
||||
});
|
||||
|
||||
const coverValueList = ref<{ value: string | number; label: string; name: string }[]>([]);
|
||||
|
||||
const passValueList = ref<{ value: string | number; label: string; name: string }[]>([]);
|
||||
const completeValueList = ref<{ value: string | number; label: string; name: string }[]>([]);
|
||||
const coverOptions = ref<Record<string, any>>({});
|
||||
const completeOptions = ref<Record<string, any>>({});
|
||||
const apiCountTabList = computed(() => {
|
||||
|
@ -105,7 +101,7 @@
|
|||
{
|
||||
label: '',
|
||||
value: 'pass',
|
||||
valueList: passValueList.value,
|
||||
valueList: completeValueList.value,
|
||||
options: { ...completeOptions.value },
|
||||
tooltip: 'workbench.homePage.apiCountCompleteRateTooltip',
|
||||
},
|
||||
|
@ -115,10 +111,10 @@
|
|||
const apiCountOptions = ref({});
|
||||
|
||||
const hasPermission = ref<boolean>(false);
|
||||
function initApiCount() {
|
||||
async function initApiCount() {
|
||||
try {
|
||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||
const params = {
|
||||
const detail = await workApiCountDetail({
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
startTime: dayNumber ? null : startTime,
|
||||
|
@ -127,28 +123,29 @@
|
|||
projectIds: innerProjectIds.value,
|
||||
organizationId: appStore.currentOrgId,
|
||||
handleUsers: [],
|
||||
};
|
||||
const { statusStatisticsMap, statusPercentList, errorCode } = detail.value;
|
||||
});
|
||||
const { statusStatisticsMap, statusPercentList, errorCode } = detail;
|
||||
|
||||
hasPermission.value = errorCode !== 109001;
|
||||
|
||||
apiCountOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||
|
||||
// 覆盖率
|
||||
const { options: covOptions, valueList: coverList } = handleUpdateTabPie(
|
||||
statusStatisticsMap?.cover || [],
|
||||
hasPermission.value,
|
||||
`${props.item.key}-cover`
|
||||
);
|
||||
coverValueList.value = coverList;
|
||||
coverOptions.value = covOptions;
|
||||
// 覆盖率 TODO 等接口
|
||||
// const { options: covOptions, valueList: coverList } = handleUpdateTabPie(
|
||||
// statusStatisticsMap?.cover || [],
|
||||
// hasPermission.value,
|
||||
// `${props.item.key}-cover`
|
||||
// );
|
||||
// coverValueList.value = coverList;
|
||||
// coverOptions.value = covOptions;
|
||||
|
||||
// 完成率
|
||||
const { options: comOptions, valueList: completedList } = handleUpdateTabPie(
|
||||
statusStatisticsMap?.cover || [],
|
||||
statusStatisticsMap?.completionRate || [],
|
||||
hasPermission.value,
|
||||
`${props.item.key}-complete`
|
||||
);
|
||||
passValueList.value = completedList;
|
||||
completeValueList.value = completedList;
|
||||
completeOptions.value = comOptions;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -157,11 +154,15 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
initApiCount();
|
||||
nextTick(() => {
|
||||
initApiCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initApiCount();
|
||||
emit('change');
|
||||
});
|
||||
|
||||
watch(
|
||||
|
|
|
@ -64,6 +64,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -149,7 +153,11 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
initCaseCount();
|
||||
emit('change');
|
||||
nextTick(() => {
|
||||
initCaseCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -61,6 +61,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -127,7 +131,10 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
initApiCount();
|
||||
nextTick(() => {
|
||||
initApiCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -46,10 +46,16 @@
|
|||
import MsSelect from '@/components/business/ms-select';
|
||||
import PassRatePie from './passRatePie.vue';
|
||||
|
||||
import { workBugByMeCreated, workBugCountDetail, workBugHandleByMe } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
import type {
|
||||
PassRateDataType,
|
||||
SelectedCardItem,
|
||||
TimeFormParams,
|
||||
WorkHomePageDetail,
|
||||
} from '@/models/workbench/homePage';
|
||||
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||
|
||||
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||
|
@ -62,6 +68,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -81,25 +91,16 @@
|
|||
|
||||
const legacyOptions = ref<Record<string, any>>({});
|
||||
|
||||
// TODO 假数据
|
||||
const detail = ref<PassRateDataType>({
|
||||
statusStatisticsMap: {
|
||||
legacy: [
|
||||
{ name: '遗留率', count: 10 },
|
||||
{ name: '缺陷总数', count: 2 },
|
||||
{ name: '遗留缺陷数', count: 1 },
|
||||
],
|
||||
},
|
||||
statusPercentList: [
|
||||
{ status: 'AAA', count: 1, percentValue: '10%' },
|
||||
{ status: 'BBB', count: 3, percentValue: '0%' },
|
||||
{ status: 'CCC', count: 6, percentValue: '0%' },
|
||||
],
|
||||
errorCode: 0,
|
||||
});
|
||||
|
||||
const countOptions = ref<Record<string, any>>({});
|
||||
|
||||
type SelectedBugCountKeys = WorkCardEnum.BUG_COUNT | WorkCardEnum.HANDLE_BUG_BY_ME | WorkCardEnum.CREATE_BUG_BY_ME;
|
||||
|
||||
const currentBugCount: (data: WorkHomePageDetail) => Promise<PassRateDataType> = {
|
||||
[WorkCardEnum.BUG_COUNT]: workBugCountDetail,
|
||||
[WorkCardEnum.HANDLE_BUG_BY_ME]: workBugHandleByMe,
|
||||
[WorkCardEnum.CREATE_BUG_BY_ME]: workBugByMeCreated,
|
||||
}[props.item.key as SelectedBugCountKeys];
|
||||
|
||||
const hasPermission = ref<boolean>(false);
|
||||
async function initCount() {
|
||||
try {
|
||||
|
@ -114,13 +115,16 @@
|
|||
organizationId: appStore.currentOrgId,
|
||||
handleUsers: [],
|
||||
};
|
||||
const { statusStatisticsMap, statusPercentList, errorCode } = detail.value;
|
||||
|
||||
const detail = await currentBugCount(params);
|
||||
|
||||
const { statusStatisticsMap, statusPercentList, errorCode } = detail;
|
||||
hasPermission.value = errorCode !== 109001;
|
||||
|
||||
countOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||
|
||||
const { options, valueList } = handleUpdateTabPie(
|
||||
statusStatisticsMap?.legacy || [],
|
||||
statusStatisticsMap?.retentionRate || [],
|
||||
hasPermission.value,
|
||||
`${props.item.key}-legacy`
|
||||
);
|
||||
|
@ -137,7 +141,10 @@
|
|||
});
|
||||
|
||||
function changeProject() {
|
||||
initCount();
|
||||
nextTick(() => {
|
||||
initCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -147,19 +154,21 @@
|
|||
watch(
|
||||
() => innerProjectIds.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
const [newProjectId] = val;
|
||||
projectId.value = newProjectId;
|
||||
}
|
||||
const [newProjectId] = val;
|
||||
projectId.value = newProjectId;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => projectId.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
innerProjectIds.value = [val];
|
||||
}
|
||||
innerProjectIds.value = [val];
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -45,8 +45,7 @@
|
|||
import MsChart from '@/components/pure/chart/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
|
||||
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
||||
import { workBugHandlerDetail } from '@/api/modules/workbench';
|
||||
import { workBugHandlerDetail, workHandleUserOptions } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
@ -62,6 +61,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -130,21 +133,27 @@
|
|||
|
||||
async function getMemberOptions() {
|
||||
const [newProjectId] = innerProjectIds.value;
|
||||
const res = await getProjectOptions(newProjectId);
|
||||
const res = await workHandleUserOptions(newProjectId);
|
||||
memberOptions.value = res.map((e: any) => ({
|
||||
label: e.name,
|
||||
value: e.id,
|
||||
label: e.text,
|
||||
value: e.value,
|
||||
}));
|
||||
}
|
||||
|
||||
function changeProject() {
|
||||
memberIds.value = [];
|
||||
getMemberOptions();
|
||||
getDefectMemberDetail();
|
||||
nextTick(() => {
|
||||
getDefectMemberDetail();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
function changeMember() {
|
||||
getDefectMemberDetail();
|
||||
nextTick(() => {
|
||||
getDefectMemberDetail();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
|
@ -193,4 +202,14 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="less">
|
||||
:deep(.arco-select-view-multiple.arco-select-view-size-medium .arco-select-view-tag) {
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
max-width: 80px;
|
||||
height: auto;
|
||||
min-height: 24px;
|
||||
line-height: 22px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
:has-all-select="true"
|
||||
:default-all-select="!(props.item.projectIds || []).length"
|
||||
:at-least-one="true"
|
||||
@change="changeProject"
|
||||
>
|
||||
</MsSelect>
|
||||
</div>
|
||||
|
@ -45,6 +46,7 @@
|
|||
import { contentTabList } from '@/config/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
|
||||
import type {
|
||||
ModuleCardItem,
|
||||
|
@ -62,6 +64,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
|
@ -111,14 +117,41 @@
|
|||
|
||||
// 处理data数据
|
||||
options.value.series = detail.projectCountList.map((item) => {
|
||||
const countData = item.count.map((e) => {
|
||||
return {
|
||||
name: item.name,
|
||||
value: e !== 0 ? e : undefined,
|
||||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
return {
|
||||
name: item.name,
|
||||
type: 'bar',
|
||||
barWidth: 12,
|
||||
legendHoverLink: true,
|
||||
large: true,
|
||||
itemStyle: {
|
||||
borderRadius: [2, 2, 0, 0], // 上边圆角
|
||||
},
|
||||
data: item.count,
|
||||
data: countData,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -149,6 +182,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
function changeProject() {
|
||||
emit('change');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initOverViewDetail();
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
:multiple="true"
|
||||
:has-all-select="true"
|
||||
:default-all-select="true"
|
||||
@change="changeMember"
|
||||
>
|
||||
</MsSelect>
|
||||
</div>
|
||||
|
@ -64,6 +65,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -138,8 +143,19 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
memberIds.value = [];
|
||||
getMemberOptions();
|
||||
initOverViewMemberDetail();
|
||||
nextTick(() => {
|
||||
initOverViewMemberDetail();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
function changeMember() {
|
||||
nextTick(() => {
|
||||
initOverViewMemberDetail();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
<template>
|
||||
<div class="rate-content">
|
||||
<MsChart :options="options" width="200px" />
|
||||
<div class="rate-content relative">
|
||||
<div class="relative flex h-full w-full items-center justify-center">
|
||||
<a-tooltip
|
||||
v-if="props.rateConfig.tooltipText"
|
||||
:mouse-enter-delay="500"
|
||||
:content="t(props.rateConfig.tooltipText || '')"
|
||||
position="bottom"
|
||||
>
|
||||
<div class="tooltip-rate-tooltip"></div>
|
||||
</a-tooltip>
|
||||
<MsChart :options="options" width="146px" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -10,18 +20,22 @@
|
|||
import MsChart from '@/components/pure/chart/index.vue';
|
||||
|
||||
import { toolTipConfig } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
data: { name: string; value: number }[];
|
||||
hasPermission: boolean;
|
||||
rateConfig: {
|
||||
name: string;
|
||||
count: string;
|
||||
color: string[];
|
||||
tooltipText: string;
|
||||
};
|
||||
}>();
|
||||
|
||||
const commonOptionConfig = ref({
|
||||
const options = ref<Record<string, any>>({
|
||||
title: {
|
||||
show: true,
|
||||
text: '',
|
||||
|
@ -47,6 +61,7 @@
|
|||
},
|
||||
tooltip: {
|
||||
...toolTipConfig,
|
||||
show: !!props.hasPermission,
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
|
@ -103,26 +118,54 @@
|
|||
},
|
||||
data: [],
|
||||
},
|
||||
graphic: {
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
bottom: 10,
|
||||
style: {
|
||||
text: t('workbench.homePage.notHasResPermission'),
|
||||
fontSize: 14,
|
||||
fill: '#959598',
|
||||
backgroundColor: '#F9F9FE',
|
||||
padding: [6, 16, 6, 16],
|
||||
borderRadius: 4,
|
||||
},
|
||||
invisible: false,
|
||||
},
|
||||
});
|
||||
const options = ref({});
|
||||
|
||||
function initOptions() {
|
||||
const { name, count, color } = props.rateConfig;
|
||||
options.value = {
|
||||
...commonOptionConfig.value,
|
||||
title: {
|
||||
...commonOptionConfig.value.title,
|
||||
text: name,
|
||||
subtext: count,
|
||||
},
|
||||
series: {
|
||||
...commonOptionConfig.value.series,
|
||||
data: [...props.data],
|
||||
color,
|
||||
},
|
||||
};
|
||||
const { name, color } = props.rateConfig;
|
||||
|
||||
if (props.hasPermission) {
|
||||
options.value.series.data = props.data.slice(1);
|
||||
|
||||
options.value.legend.formatter = (seriousName: string) => {
|
||||
const item = props.data.find((e) => e.name === seriousName);
|
||||
return `{a|${seriousName}} {b|${addCommasToNumber(item?.value || 0)}}`;
|
||||
};
|
||||
|
||||
options.value.title.subtext = `${props.data[0].value ?? 0}%`;
|
||||
} else {
|
||||
options.value.series.data = [];
|
||||
options.value.title.subtext = `-%`;
|
||||
}
|
||||
options.value.graphic.invisible = !!props.hasPermission;
|
||||
options.value.tooltip.show = !!props.hasPermission;
|
||||
options.value.title.text = name;
|
||||
|
||||
options.value.series.color = color;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (val) {
|
||||
initOptions();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
initOptions();
|
||||
});
|
||||
|
@ -130,6 +173,14 @@
|
|||
|
||||
<style scoped lang="less">
|
||||
.rate-content {
|
||||
height: 152px;
|
||||
height: 158px;
|
||||
}
|
||||
.tooltip-rate-tooltip {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
z-index: 9;
|
||||
width: 78px;
|
||||
height: 78px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -57,6 +57,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -120,7 +124,10 @@
|
|||
}
|
||||
|
||||
function changeProject() {
|
||||
getRelatedCaseCount();
|
||||
nextTick(() => {
|
||||
getRelatedCaseCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -57,12 +57,16 @@
|
|||
|
||||
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const props = defineProps<{
|
||||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
|
@ -190,12 +194,16 @@
|
|||
passOptions.value = passedOptions;
|
||||
completeOptions.value = comOptions;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function changeProject() {
|
||||
initTestPlanCount();
|
||||
nextTick(() => {
|
||||
initTestPlanCount();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -27,6 +27,13 @@
|
|||
class="mt-[16px]"
|
||||
v-on="propsEvent"
|
||||
>
|
||||
<template #num="{ record }">
|
||||
<a-tooltip :content="`${record.num}`">
|
||||
<a-button type="text" class="px-0 !text-[14px] !leading-[22px]" @click="openDetail(record.id)">
|
||||
<div class="one-line-text max-w-[168px]">{{ record.num }}</div>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #passRateColumn>
|
||||
<div class="flex items-center text-[var(--color-text-3)]">
|
||||
{{ t('caseManagement.caseReview.passRate') }}
|
||||
|
@ -58,6 +65,11 @@
|
|||
}}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #createUserName="{ record }">
|
||||
<a-tooltip :content="`${record.createUserName}`" position="tl">
|
||||
<div class="one-line-text">{{ record.createUserName }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-if="isNoPermission" #empty>
|
||||
<div class="w-full">
|
||||
<slot name="empty">
|
||||
|
@ -86,9 +98,13 @@
|
|||
|
||||
import { workReviewList } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
|
@ -98,6 +114,10 @@
|
|||
item: SelectedCardItem;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||
required: true,
|
||||
});
|
||||
|
@ -122,9 +142,10 @@
|
|||
},
|
||||
{
|
||||
title: 'caseManagement.caseReview.reviewName',
|
||||
slotName: 'reviewName',
|
||||
dataIndex: 'reviewName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.caseReview.passRate',
|
||||
|
@ -139,6 +160,12 @@
|
|||
showDrag: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'common.creator',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUser',
|
||||
width: 200,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(workReviewList, {
|
||||
|
@ -169,8 +196,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
function openDetail(id: number) {
|
||||
openNewPage(CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL, { id });
|
||||
}
|
||||
|
||||
function changeProject() {
|
||||
initData();
|
||||
nextTick(() => {
|
||||
initData();
|
||||
emit('change');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -56,57 +56,77 @@
|
|||
v-if="[WorkCardEnum.CREATE_BY_ME, WorkCardEnum.PROJECT_VIEW].includes(item.key)"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<OverviewMember
|
||||
v-else-if="item.key === WorkCardEnum.PROJECT_MEMBER_VIEW"
|
||||
v-model:projectIds="item.projectIds"
|
||||
v-model:handleUsers="item.handleUsers"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<CaseCount
|
||||
v-else-if="item.key === WorkCardEnum.CASE_COUNT"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<CaseCount v-else-if="item.key === WorkCardEnum.CASE_COUNT" v-model:projectIds="item.projectIds" :item="item" />
|
||||
<RelatedCaseCount
|
||||
v-else-if="item.key === WorkCardEnum.ASSOCIATE_CASE_COUNT"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<CaseReviewedCount
|
||||
v-else-if="item.key === WorkCardEnum.REVIEW_CASE_COUNT"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<WaitReviewList
|
||||
v-else-if="item.key === WorkCardEnum.REVIEWING_BY_ME"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<ApiAndScenarioCase
|
||||
v-else-if="[WorkCardEnum.API_CASE_COUNT, WorkCardEnum.SCENARIO_COUNT].includes(item.key)"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:type="item.key"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<ApiChangeList
|
||||
v-else-if="item.key === WorkCardEnum.API_CHANGE"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<DefectMemberBar
|
||||
v-else-if="item.key === WorkCardEnum.BUG_HANDLE_USER"
|
||||
v-model:projectIds="item.projectIds"
|
||||
v-model:handleUsers="item.handleUsers"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<DefectCount
|
||||
v-else-if="countOfBug.includes(item.key)"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
:type="item.key"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<ApiCount
|
||||
v-else-if="item.key === WorkCardEnum.API_COUNT"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<ApiCount v-else-if="item.key === WorkCardEnum.API_COUNT" v-model:projectIds="item.projectIds" :item="item" />
|
||||
<TestPlanCount
|
||||
v-else-if="item.key === WorkCardEnum.TEST_PLAN_COUNT"
|
||||
v-model:projectIds="item.projectIds"
|
||||
:item="item"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -142,13 +162,13 @@
|
|||
import DefectMemberBar from '@/views/workbench/homePage/components/defectMemberBar.vue';
|
||||
import OverviewMember from '@/views/workbench/homePage/components/overviewMember.vue';
|
||||
|
||||
import { getDashboardLayout } from '@/api/modules/workbench';
|
||||
import { editDashboardLayout, getDashboardLayout } from '@/api/modules/workbench';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useUserStore } from '@/store';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getLocalStorage, setLocalStorage } from '@/utils/local-storage';
|
||||
|
||||
import { SelectedCardItem } from '@/models/workbench/homePage';
|
||||
import { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
@ -159,12 +179,12 @@
|
|||
|
||||
const rangeTime = ref<number[]>([]);
|
||||
const tempRange = ref<(Date | string | number)[]>(['00:00:00', '00:00:00']);
|
||||
const initTime = {
|
||||
const initTime: TimeFormParams = {
|
||||
dayNumber: 3,
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
};
|
||||
const timeForm = ref({ ...initTime });
|
||||
const timeForm = ref<TimeFormParams>({ ...initTime });
|
||||
|
||||
function resetTime() {
|
||||
timeForm.value = { ...initTime };
|
||||
|
@ -173,13 +193,16 @@
|
|||
|
||||
// 改变时间类型
|
||||
function handleChangeTime(value: string | number | boolean, ev: Event) {
|
||||
resetTime();
|
||||
timeForm.value.dayNumber = value as number;
|
||||
setLocalStorage(`WORK_TIME_${userStore.id}`, JSON.stringify(timeForm.value));
|
||||
if (value) {
|
||||
resetTime();
|
||||
timeForm.value.dayNumber = value as number;
|
||||
setLocalStorage(`WORK_TIME_${userStore.id}`, JSON.stringify(timeForm.value));
|
||||
}
|
||||
}
|
||||
// 改变时间
|
||||
function handleTimeSelect(value: (Date | string | number | undefined)[]) {
|
||||
if (value) {
|
||||
timeForm.value.dayNumber = '';
|
||||
timeForm.value.startTime = 0;
|
||||
timeForm.value.endTime = 0;
|
||||
const start = (value as number[])[0];
|
||||
|
@ -228,6 +251,15 @@
|
|||
initDefaultList();
|
||||
}
|
||||
|
||||
async function changeHandler() {
|
||||
try {
|
||||
await editDashboardLayout(defaultWorkList.value, appStore.currentOrgId);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initDefaultList();
|
||||
const defaultTime = getLocalStorage(`WORK_TIME_${userStore.id}`);
|
||||
|
@ -236,11 +268,25 @@
|
|||
} else {
|
||||
timeForm.value = JSON.parse(defaultTime);
|
||||
const { startTime, endTime } = timeForm.value;
|
||||
rangeTime.value = [startTime, endTime];
|
||||
if (startTime && endTime) {
|
||||
rangeTime.value = [startTime, endTime];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
provide('timeForm', timeForm);
|
||||
const time = ref({ ...timeForm.value });
|
||||
|
||||
watch(
|
||||
() => timeForm.value,
|
||||
(val) => {
|
||||
if (val.dayNumber || (val.endTime && val.startTime)) {
|
||||
time.value = { ...val };
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
provide('timeForm', time);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -112,4 +112,5 @@ export default {
|
|||
'workbench.homePage.executeRate': 'Execution Rate',
|
||||
'workbench.homePage.completeRate': 'Completion Rate',
|
||||
'workbench.homePage.legacyRate': 'Legacy Rate',
|
||||
'workbench.homePage.unit': 'Unit: Number',
|
||||
};
|
||||
|
|
|
@ -98,4 +98,5 @@ export default {
|
|||
'workbench.homePage.executeRate': '执行率',
|
||||
'workbench.homePage.completeRate': '完成率',
|
||||
'workbench.homePage.legacyRate': '遗留率',
|
||||
'workbench.homePage.unit': '单位:个',
|
||||
};
|
||||
|
|
|
@ -10,9 +10,13 @@ import { WorkCardEnum } from '@/enums/workbenchEnum';
|
|||
const { t } = useI18n();
|
||||
// 通用颜色配置
|
||||
export const commonColorConfig = [
|
||||
'#783887',
|
||||
'#FFC14E',
|
||||
'#2DFCEF',
|
||||
'#811FA3',
|
||||
'#00D1FF',
|
||||
'#FFA53D',
|
||||
'#00C261',
|
||||
'#3370FF',
|
||||
'#AA4FBF',
|
||||
'#FFA1FF',
|
||||
'#EE50A3',
|
||||
|
@ -23,15 +27,17 @@ export const commonColorConfig = [
|
|||
'#62D256',
|
||||
'#14E1C6',
|
||||
'#50CEFB',
|
||||
'#3370FF',
|
||||
'#2B5FD9',
|
||||
'#76F0FF',
|
||||
'#935AF6',
|
||||
'#DC9BFF',
|
||||
'#FFC75E',
|
||||
'#D34400',
|
||||
'#F4D0BF',
|
||||
'#F4D0BF',
|
||||
'#FBD3E8',
|
||||
'#D9F457',
|
||||
'#0089D1',
|
||||
'#0089D1',
|
||||
'#62D256',
|
||||
'#87F578',
|
||||
];
|
||||
|
||||
|
@ -63,21 +69,9 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
|||
},
|
||||
displayMode: 'single',
|
||||
enterable: true,
|
||||
// TODO 单例模式
|
||||
// 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 style="color:#959598">${params.name}</div>
|
||||
// </div>
|
||||
// <div class="text-[#323233] font-medium">${addCommasToNumber(params.value)}</div>
|
||||
// </div>
|
||||
// `;
|
||||
// return html;
|
||||
// },
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
formatter(params: any) {
|
||||
const html = `
|
||||
<div class="w-[186px] ms-scroll-bar max-h-[206px] overflow-y-auto p-[16px] gap-[8px] flex flex-col">
|
||||
|
@ -129,8 +123,8 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
|||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '单位:个', // 设置单位
|
||||
type: 'log',
|
||||
name: t('workbench.homePage.unit'), // 设置单位
|
||||
position: 'left',
|
||||
nameTextStyle: {
|
||||
fontSize: 12,
|
||||
|
@ -146,8 +140,7 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
|||
type: 'dashed', // 水平线线型,可选 'solid'、'dashed'、'dotted'
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
max: 1,
|
||||
min: 1,
|
||||
},
|
||||
],
|
||||
graphic: {
|
||||
|
@ -166,7 +159,6 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
|||
},
|
||||
colorBy: 'series',
|
||||
series: [],
|
||||
barCategoryGap: '50%', // 控制 X 轴分布居中效果
|
||||
legend: {
|
||||
width: '60%',
|
||||
show: true,
|
||||
|
|
Loading…
Reference in New Issue