Compare commits
1 Commits
e3454655d1
...
feat-repor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f2b8e6468 |
@@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
210
src/components/common/treeCaseTable/reportTemplateSelect.vue
Normal file
210
src/components/common/treeCaseTable/reportTemplateSelect.vue
Normal 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>
|
||||
@@ -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({
|
||||
|
||||
57
src/stores/reportTemplate.ts
Normal file
57
src/stores/reportTemplate.ts
Normal 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 };
|
||||
});
|
||||
@@ -108,6 +108,7 @@ export const poolNodePropPickMap = {
|
||||
'days',
|
||||
'flowTemplate',
|
||||
'standard',
|
||||
'reportTemplate',
|
||||
'analyseTarget',
|
||||
'confidence',
|
||||
'analyseSoftware',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -86,6 +86,9 @@ const lang = {
|
||||
项目详情: '项目详情',
|
||||
任务创建: '任务创建',
|
||||
仿真执行: '仿真执行',
|
||||
报工列表: '报工列表',
|
||||
我确认的: '我确认的',
|
||||
我负责的: '我负责的',
|
||||
应用中心: '应用中心',
|
||||
数据管理: '数据管理',
|
||||
数据总览: '数据总览',
|
||||
@@ -197,6 +200,7 @@ const lang = {
|
||||
没有修改的数据需要提交审批: '没有修改的数据需要提交审批',
|
||||
指标库列表: '指标库列表',
|
||||
关联N个流程模版: '关联{count}个流程模版',
|
||||
关联N个报告模版: '关联{count}个报告模版',
|
||||
关联N个执行规范: '关联{count}个执行规范',
|
||||
关联N个工况: '关联{count}个工况',
|
||||
请选择工况库: '请选择工况库',
|
||||
|
||||
@@ -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) {
|
||||
emits('confirm', {
|
||||
type,
|
||||
uuid: flowForm.uuid,
|
||||
comment: flowForm.comment,
|
||||
file: flowForm.file,
|
||||
fileId: flowForm.file[0].id,
|
||||
});
|
||||
} else {
|
||||
await editReport(flowForm);
|
||||
emits('confirm', { type, uuid: flowForm.uuid });
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
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 () => {
|
||||
|
||||
Reference in New Issue
Block a user