This commit is contained in:
2026-03-05 13:53:51 +08:00
18 changed files with 278 additions and 139 deletions

View File

@@ -5,9 +5,9 @@
v-bind="$attrs"
:title="title"
ref="chartRef"
:option="option"
:charts-id="chartsId"
:bar-type="barType"
@refresh="refreshChart"
>
<template #formSlot v-if="filterItems.length > 0 || Object.keys(extraFilters).length > 0">
<el-form :model="formData" label-width="auto">
@@ -156,20 +156,6 @@ const filterChange = () => {
emit('update', formatEmitData());
};
// 初始化图表
const refreshChart = async () => {
if (!chartRef.value?.commonChartRef) return;
chartRef.value.commonChartRef.disposeEchartsByKey(props.chartsId);
chartRef.value.commonChartRef.option = props.option;
chartRef.value.commonChartRef.initChart();
};
// 监听配置项
watch(
() => props.option,
async () => {
await refreshChart();
}
);
// 监听插槽中的额外筛选条件
watch(
() => props.extraFilters,

View File

@@ -13,7 +13,7 @@ const commonEchartColor = {
// y轴文字颜色
yAxisColor: '#333',
// 分割线颜色
splitLineColor: '#00000015',
splitLineColor: 'rgba(0,0,0,0.05)',
// 提示框背景色
tooltipBgColor: '#fff',
// 提示框文字颜色
@@ -268,6 +268,8 @@ const barChart = (
},
]),
};
} else {
item.showBackground = false;
}
return item;
}) ?? [];

View File

@@ -5,6 +5,13 @@
<div class="operation-container">
<slot v-if="showFilterContent" name="formSlot"></slot>
<el-space>
<el-icon
v-if="showChangeModel && barType === 'barChart' && option?.series?.length > 1"
class="common-icon-style"
:title="isStack ? '切换为平铺模式' : '切换为堆叠模式'"
@click="changeModel"
><Switch
/></el-icon>
<el-popover
v-if="$slots.formSlot && !showFilterContent"
:visible="popoverVisible"
@@ -61,6 +68,7 @@ const props = withDefaults(
loading?: boolean; // 加载状态
nodata?: boolean; // 无数据状态
option?: any;
showChangeModel?: boolean; // 是否展示切换堆叠/平铺的按钮
}>(),
{
title: '',
@@ -71,6 +79,7 @@ const props = withDefaults(
loading: false,
nodata: false,
option: () => {},
showChangeModel: false,
}
);
// const emits = defineEmits(['refresh']);
@@ -91,16 +100,43 @@ defineExpose({
const refreshChart = async () => {
if (!commonChartRef.value) return;
commonChartRef.value.disposeEchartsByKey(props.chartsId);
commonChartRef.value.option = props.option;
commonChartRef.value.option = chartOption.value;
commonChartRef.value.initChart();
};
// 监听配置项
const chartOption = ref<any>();
const isStack = ref(false);
watch(
() => props.option,
async () => {
chartOption.value = props.option;
isStack.value = chartOption.value.series?.[0]?.stack === 'total';
await refreshChart();
}
);
// 切换柱状图状态
const changeModel = async () => {
if (isStack.value) {
chartOption.value.series.forEach((item: any) => {
delete item.stack;
item.label.show = false;
});
isStack.value = false;
} else {
chartOption.value.series.forEach((item: any) => {
item.stack = 'total';
item.label = {
show: true,
formatter: (params: any) => {
return params.value || '';
},
};
});
isStack.value = true;
}
await refreshChart();
};
</script>
<style scoped lang="scss">
.container {

View File

@@ -27,7 +27,7 @@ export const FILE_TYPE = {
MODEL_3D_FILE: 13,
/** 试验数据闭环报告 */
TEST_CLOSURE_REPORT: 14,
/** 复盘报告 */
/** 复盘报告仅Lyric租户 */
REVIEW_FILE: 15,
/** 结果视频 */
VIDEO_FILE: 16,

View File

@@ -135,9 +135,11 @@ export const disposeDisabledExeStatus = (
// 审批未通过的 不能改成 已完成 、已关闭 、已闭环
if (
Number(taskInfo.approvalStatus) !== TASK_APPROVE_STATUS_ENUM.APPROVED &&
(option.value === TASK_PROCESS_STATUS.COMPLETED ||
option.value === TASK_PROCESS_STATUS.CLOSED_LOOP ||
option.value === TASK_PROCESS_STATUS.CLOSED)
[
TASK_PROCESS_STATUS.COMPLETED,
TASK_PROCESS_STATUS.CLOSED_LOOP,
TASK_PROCESS_STATUS.CLOSED,
].includes(option.value)
) {
return true;
}

View File

@@ -5,12 +5,7 @@
ref="inputModelTableRef"
tableName="RESULT_MODEL"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.MODEL_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getParamsByTypeFun(FILE_TYPE.MODEL_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -44,12 +39,7 @@
ref="calcModelTableRef"
tableName="RESULT_FILE"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.CALCULATION_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getParamsByTypeFun(FILE_TYPE.CALCULATION_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -58,21 +48,21 @@
</div>
<div v-else-if="currentNode === 'calcResult'" class="detail-content">
<BaseTable
ref="calcResultTableRef"
tableName="RESULT_FILE"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.CALCULATION_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
showIndex
:fullHeight="true"
hideSearch
:actionList="calcFileActionList"
/>
<div class="sim-params-tabs">
<el-radio-group v-model="currentCalcResultNodeId" @change="flowNodeRadioChangeFun">
<el-radio-button v-for="item in flowNodeList" :key="item.uuid" :value="item.uuid">
{{ item.nodeName }}
</el-radio-button>
</el-radio-group>
</div>
<div class="sim-params-content">
<RunDataPage
v-if="currentCalcResultNode"
:nodeInfo="currentCalcResultNode"
:fileId="currentCalcResultNode.outputDirId"
:readonly="true"
/>
</div>
</div>
<div v-else-if="currentNode === 'keyResult'" class="detail-content">
@@ -81,6 +71,7 @@
<el-radio-button value="1">{{ $t('数据谱系.云图结果') }}</el-radio-button>
<el-radio-button value="2">{{ $t('数据谱系.曲线结果') }}</el-radio-button>
<el-radio-button value="3">{{ $t('数据谱系.数值指标') }}</el-radio-button>
<el-radio-button value="4">{{ $t('数据谱系.视频文件') }}</el-radio-button>
</el-radio-group>
</div>
<div class="key-result-content">
@@ -89,12 +80,7 @@
ref="cloudImageTableRef"
tableName="RESULT_PNG"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.PNG_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getKeyResultParamsFun(FILE_TYPE.PNG_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -105,12 +91,7 @@
ref="curveTableRef"
tableName="RESULT_CURVE"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.CANVAS_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getKeyResultParamsFun(FILE_TYPE.CANVAS_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -131,6 +112,17 @@
{{ PERFORMANCE_UNIT.O[row.unit] }}
</template>
</BaseTable>
<BaseTable
v-else-if="keyResultType === '4'"
ref="videoTableRef"
tableName="RESULT_REPORT"
:api="getFileListApiFun"
:params="getKeyResultParamsFun(FILE_TYPE.VIDEO_FILE)"
showIndex
:fullHeight="true"
hideSearch
:actionList="videoActionList"
/>
</div>
</div>
@@ -139,12 +131,7 @@
ref="reportTableRef"
tableName="RESULT_REPORT"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.REPORT_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getParamsByTypeFun(FILE_TYPE.REPORT_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -157,12 +144,7 @@
ref="testDataTableRef"
tableName="RESULT_REPORT"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.TEST_CLOSURE_REPORT),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getParamsByTypeFun(FILE_TYPE.TEST_CLOSURE_REPORT)"
showIndex
:fullHeight="true"
hideSearch
@@ -170,17 +152,15 @@
/>
</div>
<div v-else-if="currentNode === 'reviewReport'" class="detail-content">
<div
v-else-if="currentNode === 'reviewReport' && enableConfigByTenant([TENANT_ENUM.LYRIC])"
class="detail-content"
>
<BaseTable
ref="reviewReportTableRef"
tableName="RESULT_REPORT"
:api="getFileListApiFun"
:params="{
uuid: runId,
fileTypeDictValue: String(FILE_TYPE.REVIEW_FILE),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
}"
:params="getParamsByTypeFun(FILE_TYPE.REVIEW_FILE)"
showIndex
:fullHeight="true"
hideSearch
@@ -199,6 +179,7 @@ import { getSimulationTaskFileApi } from '@/api/data/dataAnalysis';
import { getRunPerformanceApi } from '@/api/task/taskpool';
import { FILE_TYPE } from '@/utils/enum/file';
import FlowNodeParamTable from '@/components/flow/flowNodeParamTable.vue';
import RunDataPage from '@/views/task/execution/components/runDetailPage/runPagecomponent/runDataPage.vue';
import { listSimulationFlowNodeApi } from '@/api/project/run';
import { getRunListByRunIdListApi } from '@/api/project/node';
import { queryFlowTemplateDetailApi } from '@/api/capability/flow';
@@ -206,6 +187,7 @@ import { useDict } from '@/utils/useDict';
import FilePreview from '@/components/common/filePreview/index.vue';
import { downloadFileById } from '@/utils/file';
import { cloneDeep } from 'lodash-es';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
const FILE_DICT_CLASS = 'ALL_FILE_TYPE';
const DICT_TAGS = ['fileTypeDictClass', 'fileTypeDictValue'];
@@ -213,14 +195,18 @@ const DICT_TAGS = ['fileTypeDictClass', 'fileTypeDictValue'];
interface Props {
currentNode?: string;
runId?: string;
taskId?: string;
rowData?: Record<string, any>;
pedigreeType?: 'task' | 'run';
defaultKeyResultType?: '1' | '2' | '3' | string;
}
const props = withDefaults(defineProps<Props>(), {
currentNode: 'inputModel',
runId: '',
taskId: '',
rowData: () => ({}),
pedigreeType: 'run',
defaultKeyResultType: '1',
});
const { PERFORMANCE_UNIT } = useDict('PERFORMANCE_UNIT');
@@ -262,17 +248,23 @@ const reviewReportActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const videoActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const keyResultType = ref('1');
const flowNodeList = ref<any[]>([]);
const currentFlowNodeId = ref<string>('');
const runInfo = ref<any>({});
const paramTableRef = ref();
const currentFlowNode = ref<any>(null);
const currentPageInfo = ref<any>({});
const nodeConfigList = ref<any>({});
const currentCalcResultNodeId = ref<string>('');
const currentCalcResultNode = ref<any>(null);
const fetchFlowNodesFun = async () => {
if (!props.runId) {
flowNodeList.value = [];
@@ -318,6 +310,10 @@ const fetchFlowNodesFun = async () => {
currentFlowNodeId.value = flowNodeList.value[0].uuid;
flowNodeRadioChangeFun(flowNodeList.value[0].uuid);
}
if (flowNodeList.value.length > 0 && !currentCalcResultNodeId.value) {
currentCalcResultNodeId.value = flowNodeList.value[0].uuid;
flowNodeRadioChangeFun(flowNodeList.value[0].uuid);
}
} else {
flowNodeList.value = [];
}
@@ -357,22 +353,53 @@ const mergeUserParamsFun = (list: any[], userParams: any): any[] => {
};
const getFileListApiFun = async (params: any) => {
const res: any = await getSimulationTaskFileApi({
...params,
runId: props.runId,
});
return res;
if (props.pedigreeType === 'task') {
const res: any = await getSimulationTaskFileApi({
...params,
runId: props.runId,
});
return res;
} else {
const res: any = await getSimulationTaskFileApi({
...params,
runId: props.runId,
});
return res;
}
};
const getParamsByTypeFun = (fileType: number) => {
if (props.pedigreeType === 'task') {
return {
uuid: props.taskId,
fileBizType: String(fileType),
level: 'task',
};
} else {
return {
uuid: props.runId,
fileTypeDictValue: String(fileType),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
};
}
};
const getKeyResultParamsFun = (fileType: number) => {
return getParamsByTypeFun(fileType);
};
const cloudImageTableRef = ref();
const curveTableRef = ref();
const performanceTableRef = ref();
const videoTableRef = ref();
const refreshKeyResultTableFun = () => {
const tableRefMap: Record<string, any> = {
'1': cloudImageTableRef,
'2': curveTableRef,
'3': performanceTableRef,
'4': videoTableRef,
};
if (keyResultType.value === '3') {
fetchPerformanceListFun();
@@ -392,6 +419,8 @@ const flowNodeRadioChangeFun = (uuid: string) => {
const nodeName = selectedNode.nodeName || '';
const templateConfig = nodeConfigList.value[nodeName] || [];
currentNodeParams.value = mergeUserParamsFun(templateConfig, userParams);
currentCalcResultNode.value = selectedNode;
}
};
@@ -401,6 +430,9 @@ watch(
if (newVal === 'simParams') {
currentFlowNodeId.value = '';
fetchFlowNodesFun();
} else if (newVal === 'calcResult') {
currentCalcResultNodeId.value = '';
fetchFlowNodesFun();
} else if (newVal === 'keyResult' && props.defaultKeyResultType) {
keyResultType.value = props.defaultKeyResultType;
refreshKeyResultTableFun();

View File

@@ -1,5 +1,10 @@
<template>
<Dialog v-model="visible" :diaTitle="$t('数据谱系.算例数据谱系')" width="90%" height="90%">
<Dialog
v-model="visible"
:diaTitle="pedigreeType === 'task' ? $t('数据谱系.任务数据谱系') : $t('数据谱系.算例数据谱系')"
width="90%"
height="90%"
>
<div class="pedigree-dialog-content">
<div class="flow-section">
<div class="section-title">
@@ -7,7 +12,12 @@
<span class="title-text">{{ $t('数据谱系.谱系图') }}</span>
</div>
<div class="flow-wrapper">
<PedigreeFlow ref="flowRef" :currentNodeId="currentNodeId" @nodeClick="nodeClickFun" />
<PedigreeFlow
ref="flowRef"
:currentNodeId="currentNodeId"
:pedigreeType="pedigreeType"
@nodeClick="nodeClickFun"
/>
</div>
</div>
@@ -20,7 +30,9 @@
<PedigreeDetail
:currentNode="currentNodeId"
:runId="runId"
:taskId="taskId"
:rowData="rowData"
:pedigreeType="pedigreeType"
:defaultKeyResultType="defaultKeyResultType"
/>
</div>
@@ -42,12 +54,14 @@ interface Props {
modelValue?: boolean;
rowData?: Record<string, any>;
dataType?: '模型文件' | '仿真报告' | '计算文件' | '结果曲线' | '结果云图' | string;
pedigreeType?: 'task' | 'run';
}
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
rowData: () => ({}),
dataType: '',
pedigreeType: 'run',
});
const emits = defineEmits(['update:modelValue', 'close']);
@@ -103,6 +117,10 @@ const runId = computed(() => {
return props.rowData?.ownRunId || props.rowData?.runId || '';
});
const taskId = computed(() => {
return props.rowData?.owntaskId || props.rowData?.taskId || '';
});
const nodeClickFun = (nodeId: string) => {
currentNodeId.value = nodeId;
};

View File

@@ -8,15 +8,18 @@
import { ref, onMounted, onBeforeUnmount, nextTick, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { Graph } from '@antv/x6';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
const { t, locale } = useI18n();
interface Props {
currentNodeId?: string;
pedigreeType?: 'task' | 'run';
}
const props = withDefaults(defineProps<Props>(), {
currentNodeId: 'inputModel',
pedigreeType: 'run',
});
const emits = defineEmits(['nodeClick']);
@@ -27,21 +30,41 @@ const resizeObserver = ref<ResizeObserver>();
const nodeWidth = computed(() => (locale.value === 'EN' ? 160 : 100));
const nodeGap = computed(() => (locale.value === 'EN' ? 40 : 60));
const totalWidth = computed(() => 8 * nodeWidth.value + 7 * nodeGap.value);
const flowNodesConfig = [
const taskFlowNodesConfig = computed(() => {
const baseNodes = [
{ id: 'inputModel', labelKey: '数据谱系.输入模型' },
{ id: 'calcModel', labelKey: '数据谱系.计算模型' },
{ id: 'keyResult', labelKey: '数据谱系.关键结果' },
{ id: 'simReport', labelKey: '数据谱系.仿真报告' },
{ id: 'testData', labelKey: '数据谱系.试验数据' },
];
if (enableConfigByTenant([TENANT_ENUM.LYRIC])) {
baseNodes.push({ id: 'reviewReport', labelKey: '数据谱系.复盘报告' });
}
return baseNodes;
});
const runFlowNodesConfig = [
{ id: 'inputModel', labelKey: '数据谱系.输入模型' },
{ id: 'simParams', labelKey: '数据谱系.仿真参数' },
{ id: 'calcModel', labelKey: '数据谱系.计算模型' },
{ id: 'calcResult', labelKey: '数据谱系.计算结果' },
{ id: 'keyResult', labelKey: '数据谱系.关键结果' },
{ id: 'simReport', labelKey: '数据谱系.仿真报告' },
{ id: 'testData', labelKey: '数据谱系.试验数据' },
{ id: 'reviewReport', labelKey: '数据谱系.复盘报告' },
];
const flowNodesConfig = computed(() => {
return props.pedigreeType === 'task' ? taskFlowNodesConfig.value : runFlowNodesConfig;
});
const totalWidth = computed(() => {
const nodeCount = flowNodesConfig.value.length;
return nodeCount * nodeWidth.value + (nodeCount - 1) * nodeGap.value;
});
const flowNodesData = computed(() =>
flowNodesConfig.map((node) => ({
flowNodesConfig.value.map((node) => ({
id: node.id,
label: t(node.labelKey),
}))
@@ -51,15 +74,17 @@ const getStartXFun = (containerWidth: number) => {
return containerWidth >= totalWidth.value ? (containerWidth - totalWidth.value) / 2 : 20;
};
const flowEdges = [
{ source: 'inputModel', target: 'simParams' },
{ source: 'simParams', target: 'calcModel' },
{ source: 'calcModel', target: 'calcResult' },
{ source: 'calcResult', target: 'keyResult' },
{ source: 'keyResult', target: 'simReport' },
{ source: 'simReport', target: 'testData' },
{ source: 'testData', target: 'reviewReport' },
];
const flowEdges = computed(() => {
const nodes = flowNodesConfig.value;
const edges = [];
for (let i = 0; i < nodes.length - 1; i++) {
edges.push({
source: nodes[i].id,
target: nodes[i + 1].id,
});
}
return edges;
});
const defaultBodyAttrs = {
fill: '#fff',
@@ -137,7 +162,7 @@ const initGraphFun = () => {
});
});
flowEdges.forEach((edge) => {
flowEdges.value.forEach((edge) => {
graph.value?.addEdge({
source: edge.source,
target: edge.target,
@@ -208,7 +233,7 @@ const updateNodesLabelFun = () => {
return;
}
flowNodesConfig.forEach((nodeConfig) => {
flowNodesConfig.value.forEach((nodeConfig) => {
const node = graph.value?.getCellById(nodeConfig.id);
if (node && node.isNode()) {
node.attr('label/text', t(nodeConfig.labelKey));
@@ -224,7 +249,7 @@ const updateNodesSizeAndPositionFun = () => {
const containerWidth = containerRef.value.clientWidth || 1200;
const startX = getStartXFun(containerWidth);
flowNodesConfig.forEach((nodeConfig, index) => {
flowNodesConfig.value.forEach((nodeConfig, index) => {
const node = graph.value?.getCellById(nodeConfig.id);
if (node && node.isNode()) {
const x = startX + (nodeWidth.value + nodeGap.value) * index;
@@ -239,6 +264,19 @@ watch(locale, () => {
updateNodesSizeAndPositionFun();
});
watch(
() => props.pedigreeType,
() => {
if (graph.value) {
graph.value.dispose();
graph.value = undefined;
}
nextTick(() => {
initGraphFun();
});
}
);
defineExpose({
setSelectedNodeFun,
});

View File

@@ -284,12 +284,8 @@
v-model="pedigreeVisible"
:rowData="currentPedigreeRow"
:dataType="currentModel"
:pedigreeType="pedigreeType"
/>
<TaskPedigreeDialog
v-model="taskPedigreeVisible"
:rowData="currentPedigreeRow"
:dataType="currentModel"
></TaskPedigreeDialog>
</div>
</template>
<script setup lang="ts">
@@ -333,7 +329,6 @@ import { downloadFileById } from '@/utils/file';
import { exportToPdf } from '@/utils/exportPdf';
import dayjs from 'dayjs';
import { CommonStore } from '@/stores/common';
import TaskPedigreeDialog from './components/Taskpedigree/pedigreeDialog.vue';
const commonStore = CommonStore();
@@ -349,7 +344,7 @@ const showRunDetailDialog = ref(false);
const showPerformanceInfoDialog = ref(false);
const showAnalysisDialog = ref(false);
const pedigreeVisible = ref(false);
const taskPedigreeVisible = ref(false);
const pedigreeType = ref<'task' | 'run'>('run');
const currentPedigreeRow = ref<any>({});
const dictModeOptions = commonStore.getDictData('ALL_FILE_TYPE').A || [];
const tableRef = ref();
@@ -525,6 +520,7 @@ const actionList = ref<any>([
return;
}
currentPedigreeRow.value = row;
pedigreeType.value = 'run';
pedigreeVisible.value = true;
},
hide: (row: any) => {
@@ -541,7 +537,8 @@ const actionList = ref<any>([
return;
}
currentPedigreeRow.value = row;
taskPedigreeVisible.value = true;
pedigreeType.value = 'task';
pedigreeVisible.value = true;
},
hide: (row: any) => {
return !row.owntaskId || row.ownRunId;

View File

@@ -56,9 +56,9 @@ const statusColorList = [
'rgb(179, 225, 157)', // 已闭环
];
const performanceColorList = [
'rgb(200, 201, 204)',
getThemeColor('--el-color-danger'),
getThemeColor('--el-color-success'),
'rgb(200, 201, 204)', // 未分析
getThemeColor('--el-color-danger'), // 不合格
getThemeColor('--el-color-success'), // 合格
];
// 难度系数颜色列表
const difficultyCountColorList = [

View File

@@ -8,6 +8,7 @@
:charts-id="'performanceCompletion-' + resultTagType"
:bar-type="'barChart'"
:option="chartOption"
:showChangeModel="true"
:filterItems="['projectName', 'projectCode']"
@update="initCompleteChart"
/>
@@ -16,12 +17,13 @@
<script lang="ts" setup>
import { ref } from 'vue';
import commonFilterChart from '@/components/common/echartCard/commonFilterChart.vue';
import { TASK_CALCULATE_STATUS_OBJ } from '@/utils/enum/task';
import {
getCommonCompleteStatisticsApi,
getPerformanceCompleteStatisticsByDisciplineApi,
} from '@/api/project/node';
import { useDict } from '@/utils/useDict';
const { RESULT_ACHIEVE_STATUS } = useDict('RESULT_ACHIEVE_STATUS');
const props = defineProps({
// x轴 机台、学科discipline
resultTagType: {
@@ -61,17 +63,12 @@ const initCompleteChart = async (formData: any) => {
res.data?.result?.map((item: any) => {
return item.name;
}) || [];
const allExeStatus = Object.keys(TASK_CALCULATE_STATUS_OBJ);
titles =
allExeStatus?.map((item: any) => {
return TASK_CALCULATE_STATUS_OBJ[item] || item;
}) || [];
const names = allExeStatus || [];
for (let i = 0; i < names.length; i++) {
const str = names[i];
const allExeStatus = Object.keys(RESULT_ACHIEVE_STATUS.value.O);
titles = Object.values(RESULT_ACHIEVE_STATUS.value.O);
for (let i = 0; i < allExeStatus.length; i++) {
const str = allExeStatus[i];
const obj: any = {
name: TASK_CALCULATE_STATUS_OBJ[str] || str,
name: titles[i],
type: 'bar',
emphasis: {

View File

@@ -6,6 +6,7 @@
:option="chartOption"
:filterItems="['projectName', 'projectCode']"
:projectMultiple="true"
:showChangeModel="true"
@update="initProjectTaskCompleteChart"
/>
</template>
@@ -50,7 +51,7 @@ const getProjectGroupTaskCompleteStatistics = async (formData: any) => {
label: {
show: true,
formatter: (params: any) => {
return params.value;
return params.value || '';
},
},
};

View File

@@ -6,6 +6,7 @@
:option="chartOption"
:filterItems="['projectName', 'projectCode', 'discipline']"
:extraFilters="extraFilters"
:showChangeModel="true"
@update="initReviewPassedChart"
>
<!-- <template #extraFilters="{ extraFilters }">

View File

@@ -9,6 +9,7 @@
:bar-type="'barChart'"
:option="chartOption"
:filterItems="['projectName', 'projectCode']"
:showChangeModel="true"
@update="initTaskCompleteChart"
/>
</template>

View File

@@ -4,6 +4,7 @@
:charts-id="'chart-3-userDifficulty'"
:bar-type="'barChart'"
:option="chartOption"
:showChangeModel="true"
:filterItems="['userGroup', 'user', 'projectName', 'projectCode', 'discipline']"
@update="initUserDifficultyCoefficientChart"
/>

View File

@@ -4,6 +4,7 @@
:charts-id="'chart-2-UserTaskComplete'"
:bar-type="'barChart'"
:option="chartOption"
:showChangeModel="true"
:filterItems="['userGroup', 'user', 'projectName', 'projectCode', 'discipline']"
@update="initUserTaskCompleteChart"
/>
@@ -47,7 +48,7 @@ const getUserGroupTaskCompleteStatistics = async (formData: any) => {
label: {
show: true,
formatter: (params: any) => {
return params.value;
return params.value || '';
},
},
};

View File

@@ -21,7 +21,7 @@
:full-height="true"
:show-setting="false"
>
<template #leftOptions>
<template #leftOptions v-if="!readonly">
<el-button type="" @click="asyncFileFun">归档</el-button>
<el-upload :show-file-list="false" :before-upload="beforeUploadFun">
<el-button class="ml10" type="primary">上传</el-button>
@@ -29,6 +29,9 @@
<el-button type="primary" class="ml10" @click="downLoadFileFun">下载</el-button>
<el-button type="danger" @click="deleteFileFun">删除</el-button>
</template>
<template #leftOptions v-else>
<el-button type="primary" @click="downLoadFileFun">下载</el-button>
</template>
<template #fileSize="{ row }">
<span>{{ formatFileSize(row.fileSize) }}</span>
</template>
@@ -94,6 +97,10 @@ const props = defineProps({
type: String,
default: '',
},
readonly: {
type: Boolean,
default: false,
},
});
const baseTableRef = ref();
const showSyncFileTypeSelectFlag = ref(false);
@@ -210,6 +217,9 @@ const actionList = ref([
{
title: '删除',
type: 'danger',
hide: () => {
return props.readonly;
},
click: async (row: any) => {
const res: any = await dataDelFileApi({ delFileId: row.id });
if (res && res.code === 200) {

View File

@@ -8,6 +8,7 @@
:bar-type="'barChart'"
:nodata="taskCompletionAtWorkstations?.xAxis.data.length === 0"
:option="taskCompletionAtWorkstations"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -18,6 +19,7 @@
:bar-type="'barChart'"
:nodata="taskCompletionAtDisciplineOption?.xAxis.data.length === 0"
:option="taskCompletionAtDisciplineOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -29,6 +31,7 @@
:bar-type="'barChart'"
:nodata="taskAchieveAtWorkstations?.xAxis.data.length === 0"
:option="taskAchieveAtWorkstations"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -39,6 +42,7 @@
:bar-type="'barChart'"
:nodata="taskAchieveAtDisciplineOption?.xAxis.data.length === 0"
:option="taskAchieveAtDisciplineOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -49,6 +53,7 @@
:bar-type="'barChart'"
:nodata="performanceCompletionAtWorkstationsOption?.xAxis.data.length === 0"
:option="performanceCompletionAtWorkstationsOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -59,6 +64,7 @@
:bar-type="'barChart'"
:nodata="performanceCompletionAtDisciplineOption?.xAxis.data.length === 0"
:option="performanceCompletionAtDisciplineOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -69,6 +75,7 @@
:bar-type="'barChart'"
:nodata="userTaskCompleteOption?.xAxis.data.length === 0"
:option="userTaskCompleteOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -79,6 +86,7 @@
:bar-type="'barChart'"
:nodata="userDifficultyCoefficientOption?.xAxis.data.length === 0"
:option="userDifficultyCoefficientOption"
:showChangeModel="true"
>
</EchartCard>
</div>
@@ -100,9 +108,10 @@ import { useDict } from '@/utils/useDict';
import { TASK_CALCULATE_STATUS_OPTIONS } from '@/utils/enum/task';
import { getThemeColor } from '@/utils/theme';
const { TASK_ACHIEVE_STATUS, DIFFICULTY_COEFFICIENT } = useDict(
const { TASK_ACHIEVE_STATUS, DIFFICULTY_COEFFICIENT, RESULT_ACHIEVE_STATUS } = useDict(
'TASK_ACHIEVE_STATUS',
'DIFFICULTY_COEFFICIENT'
'DIFFICULTY_COEFFICIENT',
'RESULT_ACHIEVE_STATUS'
);
const taskCalculateStatusLegendData = TASK_CALCULATE_STATUS_OPTIONS.map((item) => ({
name: item.label,
@@ -146,6 +155,11 @@ const completionStatusColorList = [
getThemeColor('--el-color-danger'),
getThemeColor('--el-color-success'),
];
const performanceColorList = [
'rgb(200, 201, 204)', // 未分析
getThemeColor('--el-color-danger'), // 不合格
getThemeColor('--el-color-success'), // 合格
];
const difficultyCountColorList = [
'#67c23a',
'rgb(179, 225, 157)',
@@ -437,8 +451,9 @@ const queryPerfCompletionByWorkspace = async () => {
xData = res.data.result.map((item: any) => {
return item.name;
});
for (let i = 0; i < TASK_CALCULATE_STATUS_OPTIONS.length; i++) {
const item = TASK_CALCULATE_STATUS_OPTIONS[i];
const allExeStatus = RESULT_ACHIEVE_STATUS.value.A;
for (let i = 0; i < allExeStatus.length; i++) {
const item = allExeStatus[i];
const obj: any = {
name: item.label,
type: 'bar',
@@ -454,9 +469,9 @@ const queryPerfCompletionByWorkspace = async () => {
}
}
const option = {
color: completionStatusColorList,
color: performanceColorList,
legend: {
data: taskCalculateStatusLegendData,
data: Object.values(RESULT_ACHIEVE_STATUS.value.O),
},
xAxis: {
data: xData,
@@ -531,8 +546,9 @@ const queryPerfCompletionByDiscipline = async () => {
xData = res.data.result.map((item: any) => {
return item.name;
});
for (let i = 0; i < TASK_CALCULATE_STATUS_OPTIONS.length; i++) {
const item = TASK_CALCULATE_STATUS_OPTIONS[i];
const allExeStatus = RESULT_ACHIEVE_STATUS.value.A;
for (let i = 0; i < allExeStatus.length; i++) {
const item = allExeStatus[i];
const obj: any = {
name: item.label,
type: 'bar',
@@ -548,9 +564,9 @@ const queryPerfCompletionByDiscipline = async () => {
}
}
const option = {
color: completionStatusColorList,
color: performanceColorList,
legend: {
data: taskCalculateStatusLegendData,
data: Object.values(RESULT_ACHIEVE_STATUS.value.O),
},
xAxis: {
data: xData,