This commit is contained in:
2026-03-09 15:58:56 +08:00
17 changed files with 574 additions and 59 deletions

View File

@@ -16,3 +16,8 @@ export const getHourlyOnlineStatisticsApi = (params: any) => {
export const getUserLoginStatisticsApi = (params: any) => {
return post(`${PREFIX}systemLog/getUserLoginStatistics`, params);
};
// 统计某时间段(天)的文件下载数
export const getDailyOperateStatisticsApi = (params: any) => {
return post(`${PREFIX}systemLog/getDailyOperateStatistics`, params);
};

View File

@@ -26,17 +26,20 @@
@change="onFormChangeFun"
>
<template #form-nodeName>
<nodeNameMixed
<NodeNameMixed
v-model="formData.nodeName"
:nodeType="formData.nodeType"
:editable="true"
/>
</template>
<template #form-flowTemplate>
<flowTemplateSelect v-model="selectedFlowTemplate" />
<FlowTemplateSelect v-model="selectedFlowTemplate" />
</template>
<template #form-reportTemplate>
<ReportTemplateSelect v-model="formData.reportTemplate" />
</template>
<template #form-standard>
<knowledgeSelect v-model="standard" v-model:modelName="formData.standardName" />
<KnowledgeSelect v-model="standard" v-model:modelName="formData.standardName" />
</template>
</TableForm>
</template>
@@ -58,15 +61,18 @@ import { getTagKeyMap, NODE_TYPE } from '@/utils/enum/node';
import { disposeTaskMembers } from '@/utils/task';
import { disposeTagKey } from '@/views/task/projectDetail/components/project';
import { isCategoryType, isCategoryNodeType, validateCategoryLevel } from '@/utils/node';
import flowTemplateSelect from './flowTemplateSelect.vue';
import knowledgeSelect from './knowledgeSelect.vue';
import nodeNameMixed from './nodeNameMixed.vue';
import FlowTemplateSelect from './flowTemplateSelect.vue';
import ReportTemplateSelect from './reportTemplateSelect.vue';
import KnowledgeSelect from './knowledgeSelect.vue';
import NodeNameMixed from './nodeNameMixed.vue';
import { TABLE_NAME } from '@/utils/enum/tableName';
import { useDict } from '@/utils/useDict';
import { useI18n } from 'vue-i18n';
import { useTaskStore } from '@/stores/taskPool';
import { useReportStore } from '@/stores/reportTemplate';
const taskStore = useTaskStore();
const reportStore = useReportStore();
enum OPERATION_TYPE {
ADD = 'add',
EDIT = 'edit',
@@ -138,6 +144,7 @@ watch(
}
});
taskStore.fetchTemplates(true);
reportStore.fetchTemplates(true);
}
}
);

View File

@@ -0,0 +1,210 @@
<template>
<div class="full">
<el-select-v2
v-if="editable"
v-model="selected"
:options="options"
class="full"
:clearable="clearable"
:size="size"
:multiple="multiple"
:collapse-tags="multiple"
:collapse-tags-tooltip="multiple"
:fit-input-width="false"
@change="onChange"
/>
<span v-else class="plain-label">
<template v-if="selectedTemplates.length === 1">
<el-icon
class="view"
@click="previewReport(selectedTemplates[0].uuid)"
:title="$t('通用.预览')"
>
<View />
</el-icon>
<OverflowTooltip :content="selectedTemplates[0].templateName" max-width="120px" />
</template>
<template v-else-if="selectedTemplates.length >= 2">
<el-popover
placement="bottom"
trigger="hover"
:width="400"
popper-class="report-template-select-popover"
>
<template #reference>
<span class="link-text">
{{ $t('工况库.关联N个报告模版', { count: selectedTemplates.length }) }}
</span>
</template>
<div class="template-list">
<div v-for="item in selectedTemplates" :key="item.uuid" class="template-item">
<el-icon class="view" :title="$t('通用.预览')" @click="previewReport(item.uuid)">
<View />
</el-icon>
<OverflowTooltip :content="item.templateName" class="item-name" />
</div>
</div>
</el-popover>
</template>
</span>
<ReportViewDialog
v-if="reportViewVisible"
v-model:showDialog="reportViewVisible"
:reportFileId="currentPreviewFileId"
:reportUuid="currentPreviewUuid"
/>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue';
import { useReportStore } from '@/stores/reportTemplate';
import ReportViewDialog from '@/components/common/report/reportViewDialog.vue';
import OverflowTooltip from '@/components/common/text/overflowTooltip.vue';
import { View } from '@element-plus/icons-vue';
interface Props {
modelValue?: any;
clearable?: boolean;
editable?: boolean;
size?: '' | 'large' | 'default' | 'small';
multiple?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
modelValue: '',
clearable: false,
editable: true,
size: 'default',
multiple: true,
});
const emits = defineEmits(['update:modelValue', 'change']);
const parseValue = (value: string): string[] | string => {
if (!value) return props.multiple ? [] : '';
if (props.multiple) {
return value.split(',').filter((v) => v.trim());
}
return value;
};
const stringifyValue = (value: string[] | string): string => {
if (props.multiple && Array.isArray(value)) {
return value.join(',');
}
return String(value || '');
};
const selected = ref<string[] | string>(parseValue(props.modelValue));
watch(
() => props.modelValue,
(v) => {
selected.value = parseValue(v);
}
);
watch(selected, (v) => {
const stringValue = stringifyValue(v);
emits('update:modelValue', stringValue);
});
const reportStore = useReportStore();
const options = computed(() => reportStore.options);
const selectedCodes = computed(() => {
if (props.multiple && Array.isArray(selected.value)) {
return selected.value;
}
return selected.value ? [selected.value] : [];
});
const selectedTemplates = computed(() => {
return reportStore.templates.filter((t: any) => selectedCodes.value.includes(t.templateCode));
});
const onChange = (val: string[] | string) => {
emits('change', stringifyValue(val));
};
const reportViewVisible = ref(false);
const currentPreviewUuid = ref('');
const currentPreviewFileId = ref('');
const previewReport = (uuid: string) => {
const template = reportStore.templates.find((t: any) => t.uuid === uuid);
if (template) {
currentPreviewUuid.value = uuid;
currentPreviewFileId.value = template.fileId || '';
reportViewVisible.value = true;
}
};
</script>
<style scoped lang="scss">
.full {
width: 100%;
}
.plain-label {
display: inline-flex;
align-items: center;
gap: 6px;
vertical-align: middle;
line-height: 1;
max-width: 100%;
.view {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
cursor: pointer;
color: var(--el-color-primary);
flex-shrink: 0;
}
.link-text {
color: var(--el-color-primary);
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.template-list {
max-height: 400px;
overflow-y: auto;
.template-item {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid var(--el-border-color-lighter);
&:last-child {
border-bottom: none;
}
.item-name {
flex: 1;
min-width: 0;
}
.view {
flex-shrink: 0;
cursor: pointer;
color: var(--el-color-primary);
margin-right: 8px;
}
}
}
</style>
<style lang="scss">
.report-template-select-popover {
max-height: 450px;
overflow: hidden;
}
</style>

View File

@@ -322,6 +322,21 @@
<template #flowTemplate-edit="{ row }">
<flowTemplateSelect v-model="row.flowTemplate" size="small" />
</template>
<!-- 报告模板 -->
<template #reportTemplate="{ row, icon }">
<TreeEditItem
v-if="[NODE_TYPE.TASK].includes(row.nodeType) || isMixedNodeType(row.nodeType)"
:data="row.reportTemplate"
:editMode="editMode"
:icon="icon"
hideTitle
>
<reportTemplateSelect v-model="row.reportTemplate" :editable="false" size="small" />
</TreeEditItem>
</template>
<template #reportTemplate-edit="{ row }">
<reportTemplateSelect v-model="row.reportTemplate" size="small" />
</template>
<!-- 标准规范 -->
<template #standard="{ row, icon }">
<TreeEditItem
@@ -565,9 +580,11 @@ import dictLabel from './dictLabel.vue';
import nodeNameMixed from './nodeNameMixed.vue';
import { poolCategoryTypeOptions } from '@/utils/project';
import flowTemplateSelect from './flowTemplateSelect.vue';
import reportTemplateSelect from './reportTemplateSelect.vue';
import knowledgeSelect from './knowledgeSelect.vue';
import uploadImg from '@/components/common/table/uploadImg.vue';
import { useTaskStore } from '@/stores/taskPool';
import { useReportStore } from '@/stores/reportTemplate';
import userSelect from '../userSelect/index.vue';
import { disposeMemberList } from '@/views/task/projectDetail/components/project';
import { getMemberListIds } from '@/utils/task';
@@ -614,6 +631,7 @@ const { TASK_ACHIEVE_STATUS, RESULT_ACHIEVE_STATUS, TASK_APPROVE_STATUS, TASK_PR
const treeData = ref<any>([]);
const taskStore = useTaskStore();
const reportStore = useReportStore();
const treeDataFormatFun = (data: any, build: any, pId: any) => {
data.forEach((item: any) => {
@@ -721,6 +739,7 @@ const seeApproveDetailFun = async (row: any) => {
onMounted(() => {
initProjectDicts();
taskStore.fetchTemplates();
reportStore.fetchTemplates();
});
defineExpose({

View File

@@ -9,6 +9,7 @@
:remote="remote"
:remote-method="getUserDataByKeyFun"
clearable
:collapse-tags="multiple"
:disabled="disabled"
:multiple="multiple"
:fit-input-width="fitInputWidth"

View File

@@ -15,13 +15,14 @@
<knowledgeSelect v-model="standard" />
</template>
</TableForm>
<!-- 展示任务的操作日志 开发中 等后端接口 -->
<!-- 展示任务的操作日志 -->
<div class="oprate-log" v-if="false">
<BaseTable
listTitle="操作日志"
listTitle="任务操作日志"
tableName="SYSTEM_LOGS"
:api="pageApi"
:actionList="[]"
:params="searchParams"
fullHeight
hideSearch
>
@@ -68,6 +69,9 @@ const formAttrs = ref({
step: 0.01,
},
});
const searchParams = ref<any>({
businessId: props.taskInfo.uuid,
});
const localDetail = ref<any>({});
@@ -186,7 +190,8 @@ onMounted(() => {});
}
}
.oprate-log {
flex: 1;
// flex: 1;
height: calc(100% - 210px);
}
}
</style>

View File

@@ -0,0 +1,57 @@
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { queryReportTemplateApi } from '@/api/capability/report';
import { REPORT_TEMPLATE_PUBLIC_STATUS, FLOW_USE_STATUS } from '@/utils/enum/report';
interface ReportTemplate {
templateName?: string;
templateCode?: string;
[k: string]: any;
}
export const useReportStore = defineStore('reportTemplate', () => {
const templates = ref<ReportTemplate[]>([]);
const loaded = ref(false);
let pendingPromise: Promise<ReportTemplate[]> | null = null;
const options = computed(() =>
templates.value.map((item) => ({
label: item.templateName || '',
value: item.templateCode || '',
}))
);
const fetchTemplates = async (force = false) => {
if (!force && loaded.value && templates.value.length) return templates.value;
if (pendingPromise) return pendingPromise;
pendingPromise = (async () => {
try {
const req = {
current: 1,
size: 99999,
type: REPORT_TEMPLATE_PUBLIC_STATUS.PUBLIC,
templateStatus: FLOW_USE_STATUS.USED,
};
const res: any = await queryReportTemplateApi(req);
if (res && res.code === 200) {
const list = res.data?.data || res.data || [];
templates.value = Array.isArray(list) ? list : [];
} else {
templates.value = [];
}
loaded.value = true;
} catch {
templates.value = [];
loaded.value = true;
} finally {
pendingPromise = null;
}
return templates.value;
})();
return pendingPromise;
};
return { templates, options, fetchTemplates, loaded };
});

View File

@@ -108,6 +108,7 @@ export const poolNodePropPickMap = {
'days',
'flowTemplate',
'standard',
'reportTemplate',
'analyseTarget',
'confidence',
'analyseSoftware',

View File

@@ -87,6 +87,9 @@ const lang = {
: 'Project Detail',
: 'Task Creation',
仿: 'Task Execution',
: 'Work Report List',
: 'I Confirmed',
: 'I Responsible',
: 'Application Center',
: 'Data Management',
: 'Data Overview',
@@ -201,6 +204,7 @@ const lang = {
: 'No modified data to submit for approval',
: 'Performance Pool List',
N个流程模版: 'Associated {count} Flow Templates',
N个报告模版: 'Associated {count} Report Templates',
N个执行规范: 'Associated {count} Standards',
N个工况: 'Associated {count} Tasks',
: 'Please select task pool',
@@ -329,6 +333,7 @@ const lang = {
'指标完成统计(学科)': 'Performance Completion Statistics (Discipline)',
: 'Workspace Review Statistics',
: 'Project Task Completion Statistics',
: 'File Operate Statistics',
},
: {
: 'Phase',

View File

@@ -86,6 +86,9 @@ const lang = {
: '项目详情',
: '任务创建',
仿: '仿真执行',
: '报工列表',
: '我确认的',
: '我负责的',
: '应用中心',
: '数据管理',
: '数据总览',
@@ -197,6 +200,7 @@ const lang = {
: '没有修改的数据需要提交审批',
: '指标库列表',
N个流程模版: '关联{count}个流程模版',
N个报告模版: '关联{count}个报告模版',
N个执行规范: '关联{count}个执行规范',
N个工况: '关联{count}个工况',
: '请选择工况库',
@@ -324,6 +328,7 @@ const lang = {
'指标完成统计(学科)': '指标完成统计(学科)',
: '工位评审通过统计',
: '项目任务完成情况统计',
: '文件操作统计',
},
: {
: '阶段',

View File

@@ -7,13 +7,16 @@
v-model:data="formData"
showDisabled
:itemNum="6"
:hideKeys="hideKeys"
@change="changeFun"
@remove="removeFun"
:formAttrs="{
templateId: {
moduleCode: 'PARAM_APPROVAL',
},
files: {
accept: '.json',
multiple: false,
},
}"
/>
@@ -55,22 +58,37 @@ const closeFun = () => {
};
const onConfirmFun = async () => {
if (!formData.value.files.length) {
formData.value.templateId = '';
formData.value.templateName = '';
}
const valid = await tableFormRef.value?.validateFun();
if (valid) {
emits('createFun', formData.value);
}
};
const hideKeys = ref<any>(['templateId']);
const changeFun = (data: any) => {
const { key, val } = data;
if (key === 'files') {
formData.value.file = val.raw;
formData.value.fileName = val.name;
hideKeys.value = [];
}
if (key === 'templateId') {
formData.value.templateName = val.label;
}
};
const removeFun = (data: any) => {
const { key } = data;
if (key === 'files') {
formData.value.file = '';
formData.value.fileName = '';
hideKeys.value = ['templateId'];
}
};
onMounted(() => {
if (props.libTypeInfo) {

View File

@@ -421,10 +421,12 @@ const creatLibParamObjFun = async (data: any) => {
parameterLibraryId: data.parameterLibraryId,
parameterLibraryCategoryId: data.parameterLibraryCategoryId,
parameterLibraryCategoryObjectName: data.parameterLibraryCategoryObjectName,
...(data.file && {
fileName: data.fileName,
file: data.file,
templateId: data.templateId,
templateName: data.templateName,
}),
});
if (res && res.code === 200) {
@@ -434,6 +436,8 @@ const creatLibParamObjFun = async (data: any) => {
return item.name === data.parameterLibraryCategoryObjectName;
});
libTreeRef.value.append(node, currentNode.value.nodeKey);
} else {
ElMessage.warning(res.message);
}
showParamObjVisible.value = false;
};
@@ -454,15 +458,25 @@ const deleteConfirmFun = () => {
const deleteParamFun = async (flag: any, row?: any) => {
currentNode.value = { ...row };
// 如果删除的是参数,要走审批流程
// 如果删除的是参数对象
if (flag === 'param') {
// 有参数 要走审批流程,没参数可以直接删
const res: any = await getSimulationParameterLibraryCategoryObjectApi({
ObjectId: row.id,
});
if (res && res.code === 200) {
if (res.data && res.data.parameterJsonValue && res.data.parameterJsonValue.length) {
delParams.value = {
// type: currentNode.value.type,
// id: currentNode.value.id,
type: row.type,
id: row.id,
};
approveDelShow.value = true;
} else {
// 直接删除
deleteAction(flag, row);
}
}
return;
} else {
// 0228需求 参数库、分类删除逻辑修改下级有参数data=true走审核流程下级没有参数直接删除
@@ -478,6 +492,12 @@ const deleteParamFun = async (flag: any, row?: any) => {
};
approveDelShow.value = true;
} else {
deleteAction(flag, row);
}
}
};
const deleteAction = (flag: any, row: any) => {
// 走删除流程
ElMessageBox.confirm(
`确认要删除这个${flag === 'lib' ? '参数库' : flag === 'type' ? '参数库分类' : '参数对象'}吗?`,
@@ -500,8 +520,6 @@ const deleteParamFun = async (flag: any, row?: any) => {
paramObjInfo.value = '';
}
});
}
}
};
const updateParams = ref<any>({});

View File

@@ -45,7 +45,7 @@
<el-button @click="closeFun">取消</el-button>
<el-button
type="primary"
v-if="dialogType !== REPORT_OPERATION_TYPE.UPGRADE"
v-if="!(dialogType === REPORT_OPERATION_TYPE.UPGRADE && hasChangeLoadcase)"
@click="confirmFun('ok')"
:loading="loadingInterface"
>确定</el-button
@@ -99,12 +99,14 @@ const confirmFun = async (type: string) => {
if (await tableFormRef.value.validateFun()) {
loadingInterface.value = true;
const flowForm = tableFormRef.value.getFormDataFun();
flowForm.simulationPoolInfoList = simulationPoolInfoList.value;
if (
props.dialogType === REPORT_OPERATION_TYPE.CREATE ||
props.dialogType === REPORT_OPERATION_TYPE.COPY
) {
const formData = new FormData();
formData.append('templateVersion', 'V1.0');
formData.append('simulationPoolInfoListStr', JSON.stringify(simulationPoolInfoList.value));
for (const key in flowForm) {
if (key === 'file') {
// 就算复制模板,如果上传了新的文件就不复制文件了
@@ -122,7 +124,8 @@ const confirmFun = async (type: string) => {
key !== 'templateStatus' &&
key !== 'creatorName' &&
key !== 'createTime' &&
key !== 'approveType'
key !== 'approveType' &&
key !== 'simulationPoolInfoList'
) {
formData.append(key, flowForm[key] ? flowForm[key] : '');
}
@@ -130,17 +133,27 @@ const confirmFun = async (type: string) => {
}
const flowUuid = await createFlow(formData);
emits('confirm', { type, uuid: flowUuid });
} else if (props.dialogType === REPORT_OPERATION_TYPE.UPGRADE) {
} else {
if (type === 'ok') {
await editReport(flowForm);
emits('confirm', { type, uuid: flowForm.uuid, tVersion: props.templateVersion });
}
if (type === 'next') {
if (oldComment.value !== flowForm.comment) {
// 升版时只更新描述,不更新工况,工况在提交审批时传递给接口
await editReport({ ...flowForm, simulationPoolInfoList: oldSimulationPoolInfoList.value });
}
emits('confirm', {
type,
uuid: flowForm.uuid,
comment: flowForm.comment,
file: flowForm.file,
fileId: flowForm.file[0].id,
tVersion: props.templateVersion,
// 不更新工况,工况在提交审批时传递给升版接口
simulationPoolInfoList: hasChangeLoadcase.value ? simulationPoolInfoList.value : null,
});
} else {
await editReport(flowForm);
emits('confirm', { type, uuid: flowForm.uuid });
}
}
loadingInterface.value = false;
}
@@ -188,6 +201,7 @@ const editReport = async (params: any) => {
formData.append('extras', params.extras);
formData.append('fileId', oldFormData.value.fileId);
formData.append('templateContent', oldFormData.value.templateContent);
formData.append('simulationPoolInfoListStr', JSON.stringify(params.simulationPoolInfoList));
if (params.file && params.file.length > 0) {
if (params.file[0].raw) {
formData.append('file', params.file[0].raw);
@@ -217,12 +231,17 @@ const closeFun = () => {
const oldFormData = ref<any>({});
const editRowInfo = ref<any>({});
const editRowInfo = ref({});
const oldSimulationPoolInfoList = ref<any[]>([]);
const oldComment = ref('');
const setEditForm = (val: any) => {
oldFormData.value = val;
// nextTick(() => {
simulationPoolInfoList.value = val.simulationPoolInfoList || [];
oldSimulationPoolInfoList.value = val.simulationPoolInfoList || [];
oldComment.value = val.comment;
// tableFormRef.value.setFormDataFun({ ...val });
editRowInfo.value = { ...val };
// });
@@ -245,6 +264,29 @@ const setOptionsFun = (key: string, options: any[]) => {
tableFormRef.value.setOptionsFun(key, options);
};
const hasChangeLoadcase = ref(false);
watch(
() => simulationPoolInfoList.value,
() => {
const oldIds: any[] = [];
oldSimulationPoolInfoList.value.forEach((item) => {
oldIds.push(...item.simulationPoolTaskIds);
});
const newIds: any[] = [];
simulationPoolInfoList.value.forEach((item) => {
newIds.push(...item.simulationPoolTaskIds);
});
oldIds.sort();
newIds.sort();
if (JSON.stringify(oldIds) !== JSON.stringify(newIds)) {
hasChangeLoadcase.value = true;
} else {
hasChangeLoadcase.value = false;
}
}
);
watch(
() => props.showDialog,
async () => {

View File

@@ -28,6 +28,7 @@
import { onMounted, ref, provide } from 'vue';
import { getThemeColor } from '@/utils/theme';
// 引入子组件
import fileOperateChart from './dataStatistics/fileOperateChart.vue';
import userGroupProjectChart from './dataStatistics/userGroupProjectChart.vue';
import userTaskCompleteChart from './dataStatistics/userTaskCompleteChart.vue';
import userDifficultyCoefficientChart from './dataStatistics/userDifficultyCoefficientChart.vue';
@@ -145,6 +146,11 @@ const baseList = ref([
processNodeColorList,
},
},
{
id: 'fileOperate',
component: fileOperateChart,
props: {},
},
]);
// 当前展示的图表
const currentList = ref();

View File

@@ -0,0 +1,115 @@
<template>
<commonFilterChart
:title="$t('数据统计.文件操作统计')"
:charts-id="'chart-1-fileOperate'"
:bar-type="'barChart'"
:option="chartOption"
:showChangeModel="true"
:filterItems="[]"
:extraFilters="extraFilters"
@update="initUserProjectStatistics"
>
<template #extraFilters="{ extraFilters }">
<el-form-item label="日期范围">
<el-date-picker
v-model="extraFilters.dateRange"
type="daterange"
value-format="YYYY-MM-DD"
start-placeholder="开始日期"
end-placeholder="结束日期"
:disabled-date="disabledDate"
:clearable="false"
/>
</el-form-item>
</template>
</commonFilterChart>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import commonFilterChart from '@/components/common/echartCard/commonFilterChart.vue';
import { getDailyOperateStatisticsApi } from '@/api/system/systemLog';
import { getThemeColor } from '@/utils/theme';
import dayjs from 'dayjs';
const extraFilters = ref<any>({
// dateRange默认设置近30天
dateRange: [
dayjs(new Date()).subtract(30, 'day').format('YYYY-MM-DD'),
dayjs(new Date()).format('YYYY-MM-DD'),
],
});
const disabledDate = (time: Date) => {
return time.getTime() > Date.now();
};
const getDailyOperate = async (date: any) => {
const xData: any = [];
const previewData: any = [];
const downloadData: any = [];
try {
const res: any = await getDailyOperateStatisticsApi({
createTimeArr: date.dateRange,
});
if (res.code === 200) {
const data = res.data.reverse();
data.forEach((item: any) => {
xData.push(item.date);
previewData.push(item.previewCount || 0);
downloadData.push(item.downloadCount || 0);
});
}
} catch {}
return {
xData,
previewData,
downloadData,
};
};
// 初始化用户组项目统计
const chartOption = ref();
const initUserProjectStatistics = async (data: any) => {
const { xData, previewData, downloadData } = await getDailyOperate(data);
chartOption.value = {
legend: {
data: ['预览', '下载'],
},
grid: {
bottom: '50',
},
xAxis: {
data: xData,
},
yAxis: {
name: '次数',
minInterval: 1,
},
dataZoom: xData.length > 4,
series: [
{
type: 'bar',
name: '预览',
data: previewData,
itemStyle: {
color: getThemeColor('--el-color-primary'),
},
},
{
type: 'bar',
name: '下载',
data: downloadData,
itemStyle: {
color: getThemeColor('--el-color-success'),
},
},
],
};
};
onMounted(() => {
// getDailyOperate();
// initUserProjectStatistics();
});
</script>

View File

@@ -86,6 +86,7 @@ const baseTable = [
{ key: 'performanceCompletionMechine', title: '指标完成统计(机台)', inBoard: true },
{ key: 'performanceCompletionDiscipline', title: '指标完成统计(学科)', inBoard: true },
{ key: 'reviewPassed', title: '工位评审通过统计', inBoard: true },
{ key: 'fileOperate', title: '文件下载统计', inBoard: true },
];
const vxeTableRef = ref<any>();

View File

@@ -9,7 +9,7 @@
show-footer
>
<div class="page-inner">
<el-tabs v-model="activeTab" class="tabs-demo">
<el-tabs v-model="activeTab" class="tabs-demo" type="card">
<!-- <el-tab-pane label="仿真报告" name="report">
<div class="task-tab-content">
<taskReport
@@ -23,8 +23,8 @@
</el-tab-pane> -->
<el-tab-pane label="任务详情" name="info">
<el-radio-group v-model="activeRadio">
<el-radio-button label="仿真报告" value="report" />
<el-radio-button label="任务详情" value="detail" v-if="showTaskInfo" />
<el-radio-button label="仿真报告" value="report" />
<el-radio-button label="关联需求" value="demand" />
</el-radio-group>
@@ -350,7 +350,7 @@ const reportInpDiaShow = ref(false);
const dialogVisible = ref(true);
// const activeTab = ref(props.showTaskInfo ? 'info' : 'model-3d');
const activeTab = ref('info');
const activeRadio = ref('report');
const activeRadio = ref('detail');
const keyResultType = ref('performance');
const taskPerformanceRef = ref();
const taskInfoRef = ref();