update:场景新增异常数据tab

This commit is contained in:
2026-04-13 19:09:00 +08:00
parent 3b5894b6f4
commit 4d0aeb90ed
7 changed files with 213 additions and 124 deletions

View File

@@ -181,3 +181,7 @@ export const checkDuplicateFileNameApi = (params: any) => {
export const uploadAttachmentApi = (params: any) => {
return upload(`${PREFIX}data/uploadAttachment`, params);
};
// 删除附件
export const deleteAttachmentApi = (params: any) => {
return get(`${PREFIX}data/deleteAttachment`, params);
};

View File

@@ -149,6 +149,16 @@
:disabled="attrs.disabled || (item.disabled && showDisabled)"
@change="(val: any) => changeFun(item.key, val)"
/>
<UploadFile
v-if="item.inputMode === 'uploadFile'"
:attrs="attrs"
v-model="formData[item.searchKey || item.key]"
:multiple="attrs.multiple"
:limit="attrs.limit"
:disabled="attrs.disabled || (item.disabled && showDisabled)"
@change="(val: any) => changeFun(item.key, val)"
@remove="(val: any) => removeFun(item.key, val)"
/>
<UserSelect
v-if="item.inputMode === 'userSelect'"
:attrs="attrs"
@@ -259,6 +269,7 @@
import { ref, watch } from 'vue';
import MultipleSelect from './multipleSelect.vue';
import UploadImg from '@/components/common/uploadImg/index.vue';
import UploadFile from '@/components/common/uploadFile/index.vue';
import ChoseFile from './choseFile.vue';
import UserSelect from '@/components/common/userSelect/index.vue';
import ProjectSelect from '@/components/common/projectSelect/index.vue';

View File

@@ -108,6 +108,7 @@
<el-option label="日期" value="date" />
<el-option label="日期范围" value="daterange" />
<el-option label="上传图片" value="uploadImg" />
<el-option label="上传文件" value="uploadFile" />
<el-option label="文件名称" value="fileName" />
<el-option label="文件大小" value="fileSize" />
<el-option label="选择文件" value="choseFile" />

View File

@@ -10,7 +10,7 @@
:width="formData?.nodeType === NODE_TYPE.TASK ? 1200 : 400"
>
<template #default>
<!-- <el-tabs
<el-tabs
v-if="enableConfigByTenant([TENANT_ENUM.LYRIC])"
v-model="tabName"
type="card"
@@ -21,7 +21,7 @@
<el-tab-pane label="附件信息" name="附件信息" />
<el-tab-pane label="异常信息" name="异常信息" />
<el-tab-pane label="日志信息" name="日志信息" />
</el-tabs> -->
</el-tabs>
<StandardSceneForm v-if="tabName !== '基础信息'" :tabName="tabName" :data="detail" />
<TableForm
v-if="visible && tabName === '基础信息'"
@@ -119,7 +119,7 @@ import { DIR_TYPE } from '@/utils/enum/data.ts';
import { useI18n } from 'vue-i18n';
import { useTaskStore } from '@/stores/taskPool';
import { useReportStore } from '@/stores/reportTemplate';
// import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
const taskStore = useTaskStore();
const reportStore = useReportStore();

View File

@@ -1,175 +1,196 @@
<template>
<div class="comp-content" :class="{ 'auto-width': !clearable }">
<div class="comp-upload-file">
<div class="content">
<template v-if="clearable">
<div v-if="fileId" class="preview">
<div class="file-name" @click="downloadFun">{{ fileName }}</div>
<div v-if="clearable" class="close" @click="removeFun">
<el-icon :size="20"><Delete /></el-icon>
<el-upload
v-model:file-list="fileList"
:auto-upload="false"
:multiple="multiple"
:limit="limit"
:disabled="disabled"
@change="changeFun"
>
<el-button type="primary">上传文件</el-button>
<template #file="{ file, index }">
<div :key="index" class="file-item">
<div class="file-icon">
<FileIcon :fileName="file.name" />
</div>
<div class="file-name">{{ file.name }}</div>
<div class="file-options">
<el-icon
v-if="file.fileId"
class="btn download"
:size="16"
@click="downloadFun(file)"
>
<Download />
</el-icon>
<el-icon v-if="file.fileId" class="btn preview" :size="16" @click="previewFun(file)">
<View />
</el-icon>
<el-icon class="btn del" :size="16" @click="removeFun(index)">
<Delete />
</el-icon>
</div>
</div>
</div>
<div v-else class="upload">
<el-upload :show-file-list="false" :before-upload="beforeUploadFun">
<div v-if="!uploading" class="btn">
<el-button type="primary">上传文件</el-button>
</div>
<div v-else class="progress">
<el-progress :stroke-width="8" :percentage="percentage" />
</div>
</el-upload>
</div>
</template>
<div v-else class="download">
<div class="file-name" @click="downloadFun">{{ fileName }}</div>
</div>
</template>
</el-upload>
</div>
<FilePreview v-model="previewVisible" :fileId="previewFileId" />
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Delete } from '@element-plus/icons-vue';
import { dataUploadFilesApi } from '@/api/data/data';
import { ElMessage } from 'element-plus';
import FileIcon from '@/components/common/fileIcon/index.vue';
import FilePreview from '@/components/common/filePreview/index.vue';
import { View, Delete, Download } from '@element-plus/icons-vue';
import { downloadFileById } from '@/utils/file';
import { uploadAttachmentApi, getFileBaseInfoApi } from '@/api/data/data';
interface Props {
modelValue: any;
name?: string;
clearable?: boolean;
dirId?: number | string;
multiple?: boolean;
disabled?: boolean;
limit?: any;
}
const props = withDefaults(defineProps<Props>(), {
modelValue: '',
name: '',
clearable: false,
dirId: '',
multiple: false,
disabled: false,
limit: null,
});
const emit = defineEmits(['update:modelValue']);
const emit = defineEmits(['update:modelValue', 'change', 'remove']);
const fileList = ref<any>([]);
const fileId = ref('');
const fileName = ref(props.name);
const uploading = ref(false);
const percentage = ref(0);
const loadFileFun = (fileId: any) => {
const params = {
fileId,
};
getFileBaseInfoApi(params).then((res: any) => {
if (res.code === 200) {
const { id, originalName, fileSize } = res.data;
const file = {
name: originalName,
fileId: id,
size: fileSize,
};
fileList.value.push(file);
}
});
};
watch(
() => props.modelValue,
(val: any) => {
if (val) {
fileId.value = val;
fileName.value = fileName.value || '文件下载';
const ids = String(props.modelValue).split(',') || [];
ids.forEach((item: any) => {
const hasFile = fileList.value.find((i: any) => i.fileId);
if (!hasFile) {
loadFileFun(item);
}
});
} else {
fileId.value = '';
fileName.value = '';
fileList.value = [];
}
},
{ deep: true, immediate: true }
);
const beforeUploadFun = (file: any) => {
uploading.value = true;
const { name } = file;
const params = {
fileName: name,
dirId: props.dirId,
file: file,
};
dataUploadFilesApi(params, (event: any) => {
const { loaded, total } = event;
const percent = (loaded / total) * 100;
percentage.value = Number(percent.toFixed(2));
})
.then((res: any) => {
if (res.code === 200) {
fileId.value = res.data.fileId;
fileName.value = name;
emit('update:modelValue', res.data.fileId);
ElMessage.success('上传成功');
watch(
() => fileList.value,
(val: any) => {
const ids: any = [];
val.forEach((item: any) => {
if (item.fileId) {
ids.push(item.fileId);
}
})
.finally(() => {
uploading.value = false;
percentage.value = 0;
});
return false;
emit('update:modelValue', ids.join(','));
},
{ deep: true, immediate: true }
);
const changeFun = async (file: any) => {
const fileId = await uploadFun(file);
file.fileId = fileId;
emit('change', file);
};
const downloadFun = () => {
const id: any = fileId.value;
downloadFileById(id);
const previewFileId = ref<any>('');
const previewVisible = ref<any>(false);
const previewFun = (data: any) => {
previewFileId.value = data.fileId;
previewVisible.value = true;
};
const removeFun = () => {
fileId.value = '';
fileName.value = '';
emit('update:modelValue', '');
const downloadFun = (data: any) => {
downloadFileById(data.fileId);
};
const removeFun = (index: number) => {
emit('remove', fileList.value[index]);
fileList.value.splice(index, 1);
};
const uploadFun = async (file: any) => {
const params = {
attachment: file.raw,
};
const res: any = await uploadAttachmentApi(params);
if (res.code === 200) {
fileList.value.some((item: any) => {
if (file.uid === item.uid && file.name === item.name) {
item.fileId = res.data;
return true;
}
});
return res.data;
} else {
return '';
}
};
</script>
<style lang="scss" scoped>
.comp-content {
.comp-upload-file {
width: 100%;
height: 100%;
margin: 0 var(--margin-tiny);
&.auto-width {
width: auto;
}
.content {
width: 100%;
height: 100%;
.preview {
.file-item {
width: 100%;
height: 100%;
display: flex;
align-items: center;
.file-name {
max-width: calc(100% - 30px);
height: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--el-color-primary);
cursor: pointer;
&:hover {
text-decoration: underline;
}
line-height: 18px;
padding: 0 4px;
.file-icon {
display: flex;
align-items: center;
}
.close {
.file-name {
flex: 1;
font-size: 14px;
color: var(--el-text-color-secondary);
padding-right: 5px;
word-break: break-word;
padding: 2px 4px;
}
.file-options {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
color: var(--el-color-danger);
padding-left: var(--padding-small);
cursor: pointer;
}
}
.download {
width: 100%;
height: 100%;
display: flex;
align-items: center;
.file-name {
height: 100%;
color: var(--el-color-primary);
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.upload {
width: 100%;
> div {
width: 100%;
.btn {
width: 100%;
}
.progress {
width: 100%;
margin-left: 8px;
cursor: pointer;
&.download,
&.preview {
color: var(--el-color-primary);
}
&.del {
color: var(--el-color-danger);
}
}
}
}

View File

@@ -73,11 +73,24 @@
:data="formData"
:itemNum="4"
:formAttrs="{
amount: {
min: 0,
},
confidence: {
min: 0,
max: 100,
},
closeReport: {
limit: 1,
multiple: false,
},
fileId: {
limit: 1,
multiple: false,
},
}"
@change="changeFun"
@remove="removeFun"
/>
<template #footer>
<div>
@@ -94,6 +107,7 @@ import { ref } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import Dialog from '@/components/common/dialog/index.vue';
import TableForm from '@/components/common/table/tableForm.vue';
import { deleteAttachmentApi } from '@/api/data/data';
import {
queryTaskPoolCloseLoopApi,
addTaskPoolCloseLoopItemApi,
@@ -107,6 +121,7 @@ import {
addTaskPoolLogItemApi,
} from '@/api/task/taskpool';
import { ElMessage } from 'element-plus';
import { formatFileSize, removeAttachmentFileIds } from '@/utils/file';
interface Props {
tabName: string;
@@ -190,6 +205,24 @@ const loadFun = () => {
});
};
const changeFun = (data: any) => {
if (data.key === 'fileId') {
formData.value.fileName = data.val.name;
if (props.tabName === '附件信息') {
formData.value.fileSize = formatFileSize(data.val.size);
}
}
};
const removeFun = (data: any) => {
if (data.key === 'fileId') {
formData.value.fileName = '';
if (props.tabName === '附件信息') {
formData.value.fileSize = '';
}
}
};
const errorData = ref<any>({
totalNum: 0,
totalCost: 0,
@@ -235,6 +268,7 @@ const sureFun = async () => {
ElMessage.success('操作成功');
closeFun();
loadFun();
removeAttachmentFileIds(oldFileId.value, params.fileId);
}
});
}
@@ -244,6 +278,10 @@ const delFun = (data: any) => {
const params = {
lineCode: data.lineCode,
};
// 删除附件文件
if (data.fileId) {
deleteAttachmentApi({ fileId: data.fileId });
}
optionsPbj[props.tabName].delApi(params).then((res: any) => {
if (res.code === 200) {
ElMessage.success('删除成功');
@@ -252,8 +290,10 @@ const delFun = (data: any) => {
});
};
const oldFileId = ref('');
const openFun = (data?: any) => {
formData.value = { ...(data || {}) };
oldFileId.value = formData.value.fileId;
delete formData.value._X_ROW_KEY;
formName.value = optionsPbj[props.tabName].tableName;
diaVisible.value = true;

View File

@@ -3,6 +3,7 @@ import {
queryFileIdByNodeIdApi,
systemDataDownloadFileApi,
getMinioPresignedUrlApi,
deleteAttachmentApi,
} from '@/api/data/data';
import { getDictionaryDataApi, getFormConfigureApi } from '@/api/system/systemData';
import { ElMessage } from 'element-plus';
@@ -584,3 +585,14 @@ export const isJSONFun = (str: any) => {
return false;
}
};
// 删除无用附件文件
export const removeAttachmentFileIds = (oldIds: string, newIds: any) => {
const oldList = oldIds.split(',');
const newList = newIds.split(',');
const newSet = new Set(newList);
const delIds: any[] = oldList.filter((id) => !newSet.has(id));
delIds.forEach((id: any) => {
deleteAttachmentApi({ fileId: id });
});
};