SourceTermAnalysisSystem_vue/src/pages/tqybjs/tab-1/index.vue
2026-07-27 10:18:13 +08:00

682 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import {ElButton, ElOption, TableInstance, UploadInstance, UploadProps, UploadRawFile} from 'element-plus';
import dayjs from 'dayjs';
import { ElLoading, ElMessage, ElMessageBox, ElNotification, genFileId } from 'element-plus';
import SparkMD5 from 'spark-md5';
import { set } from 'vue'; // 引入 Vue 的 set 方法
import { useI18n } from 'vue-i18n';
import { add, deleteData, edit, getData, getTaskLog, resume, pinToTopOrUnpin } from '@/utils/axios/tqyb/task';
import log from '../log/index.vue';
const emit = defineEmits(['playback']);
const { t } = useI18n();
const upload = ref<UploadInstance>();
const configVisible = ref(false);
const configType = ref('');
/* 新增、编辑表单 */
const configForm = ref<any>({});
// 定义 ref 的类型
const fileInput: Ref<HTMLInputElement | null> = ref(null);
const taskList = ref<any[]>([]);
const logData = ref<any>([]);
const currentPage = ref(1);
const pageSize = ref(20);
const total = ref(0);
// 存储当前选中项
const currentSelection = ref<any>([]);
const multipleTableRef = ref<TableInstance>();
const logVisible = ref(false);
/* drawer侧边栏表单 */
const form = ref<any>({});
/* 任务列表搜索表单 */
const searchForm = reactive({});
interface OptionItem {
label: string;
value: number;
}
const taskStatusList = ref<OptionItem[]>([
// -1执行失败0未开始1等待中2运行中3已完成4检查未通过
{ label: '执行失败', value: -1 },
{ label: '未开始', value: 0 },
{ label: '等待中', value: 1 },
{ label: '运行中', value: 2 },
{ label: '已完成', value: 3 },
{ label: '检查未通过', value: 4 },
]);
function search() {
console.log('搜索条件:', searchForm);
getList();
}
function getList() {
let startDate, endDate;
if (searchForm.createTime && searchForm.createTime.length) {
startDate = searchForm.createTime[0];
endDate = searchForm.createTime[1];
}
getData({
...searchForm,
startDate,
endDate,
pageSize: pageSize.value,
pageNum: currentPage.value,
}, (res) => {
taskList.value = res.rows;
total.value = res.total;
});
}
// 置顶和取消置顶
const pinToTopTask = (row: any) => {
pinToTopOrUnpin({ id: row.id }, (res) => {
if (res.code === 200) {
ElMessage.success('操作成功!');
getList();
}
});
};
function start(task: any) {
console.log('开始运行', task);
resume({ taskId: task.id }, () => {
ElNotification({
title: 'Tips',
message: 'Execution Successful',
type: 'success',
duration: 1800,
});
getList();
});
}
function saveConfigForm() {
console.log('保存或新增');
if (configForm.value.leadTime % 6 !== 0) {
return ElNotification({
title: 'Tips',
message: '预测时长需为6的倍数',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.taskName) {
return ElNotification({
title: 'Tips',
message: '请填写任务名称',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.predictionModel) {
return ElNotification({
title: 'Tips',
message: '请填写预测模型',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.startDate) {
return ElNotification({
title: 'Tips',
message: '请选择预测日期',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.startTime && configForm.value.startTime !== 0) {
return ElNotification({
title: 'Tips',
message: '请填写预测时间',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.leadTime && configForm.value.leadTime !== 0) {
return ElNotification({
title: 'Tips',
message: '请填写预测时长',
type: 'error',
duration: 1800,
});
}
if (!configForm.value.dataSources) {
return ElNotification({
title: 'Tips',
message: '请选择数据来源',
type: 'error',
duration: 1800,
});
}
// const loading = ElLoading.service({
// background: 'rgba(0, 0, 0, 0.7)',
// fullscreen: true,
// text: 'Loading...',
// target: document.querySelector('.base-layout'),
// });
if (configType.value === 'add') {
const addForm = new FormData();
console.log('???', configForm.value.dataSources, typeof configForm.value.dataSources);
if (configForm.value.dataSources === 2 && configForm.value.file) {
addForm.append('file', configForm.value.file);
}
addForm.append('taskName', configForm.value.taskName);
addForm.append('predictionModel', configForm.value.predictionModel);
addForm.append('startDate', configForm.value.startDate);
addForm.append('startTime', configForm.value.startTime);
addForm.append('leadTime', configForm.value.leadTime);
addForm.append('dataSources', configForm.value.dataSources);
add(addForm, () => {
// loading.close();
ElNotification({
title: 'Tips',
message: 'Added successfully',
type: 'success',
duration: 1800,
});
getList();
});
}
if (configType.value === 'edit') {
// const editValue = configForm.value = {
// id: configForm.value.id,
// taskName: configForm.value.taskName,
// predictionModel: configForm.value.predictionModel,
// startDate: configForm.value.startDate,
// startTime: configForm.value.startTime,
// leadTime: configForm.value.leadTime,
// dataSources: configForm.value.dataSources,
// inputFile: configForm.value.dataSources === 2 ? configForm.value.inputFile : '',
//
// };
const editForm = new FormData();
editForm.append('id', configForm.value.id);
if (configForm.value.dataSources === 2 && configForm.value.file) {
editForm.append('file', configForm.value.file);
}
editForm.append('taskName', configForm.value.taskName);
editForm.append('predictionModel', configForm.value.predictionModel);
editForm.append('startDate', configForm.value.startDate);
editForm.append('startTime', configForm.value.startTime);
editForm.append('leadTime', configForm.value.leadTime);
editForm.append('dataSources', configForm.value.dataSources);
edit(editForm, () => {
// loading.close();
ElNotification({
title: 'Tips',
message: 'Saved successfully',
type: 'success',
duration: 1800,
});
getList();
});
}
configVisible.value = false;
}
function addTask() {
console.log('新增任务');
configForm.value = {};
configVisible.value = true;
configType.value = 'add';
}
function editTask(task: any, $index?: any) {
console.log('编辑任务', task, $index);
const serveType = task.serveId ? (task.serveId.includes('/') ? '服务名' : 'SID') : '';
console.log('serveType', serveType, task.serveId);
configForm.value = {
...task,
$index,
serveType,
};
console.log('编辑任务', configForm.value);
configVisible.value = true;
configType.value = 'edit';
}
function deleteTask(task: any) {
console.log('删除任务', task);
ElMessageBox.confirm(
t('isSureDelete'),
'Warning',
{
confirmButtonText: t('sure'),
cancelButtonText: t('cancel'),
type: 'warning',
},
)
.then(() => {
let arr = [];
arr.push(task.id);
deleteData(arr, (res) => {
getList();
});
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: `取消操作`,
// });
});
}
function refresh() {
console.log('刷新任务列表');
getList();
}
function showLog(task: any) {
console.log('显示运行日志');
getTaskLog({ taskId: task.id }, (res) => {
console.log('res', res);
logData.value = res;
logVisible.value = true;
});
}
function cancle() {
console.log('取消运行', form);
ElMessageBox.confirm(
t('isSureCancelTask'),
'Warning',
{
confirmButtonText: t('sure'),
cancelButtonText: t('cancel'),
type: 'warning',
},
)
.then(() => {
form.value = {
...form.value,
taskMode: '未开始',
};
ElMessage({
type: 'success',
message: `Cancelled successfully`,
});
})
.catch(() => {
});
}
function handleSelectionChange(selection: any[]) {
// multipleTableRef.value!.clearSelection()
// multipleSelection.value = val
// 如果选中项长度大于1说明是新选择了一项
if (selection.length > 1) {
// 清除之前的选择,只保留最新选中的项
const latestSelection = selection[selection.length - 1];
multipleTableRef.value?.clearSelection(); // 清空所有选择
multipleTableRef.value?.toggleRowSelection(latestSelection, true); // 选中最新项
currentSelection.value = [latestSelection];
}
else {
// 正常选择或取消选择
currentSelection.value = selection;
}
console.log('当前选中项:', currentSelection.value);
}
function playback() {
console.log('当前选中项:', currentSelection.value);
if (Object.keys(currentSelection.value).length === 0) {
ElMessage({
type: 'warning',
message: t(`isSelect`),
});
}
else {
const startTime = dayjs(currentSelection.value[0].startDate).add(0, 'hour').format('YYYY-MM-DD HH:mm:ss');
const params = {
dataType: currentSelection.value[0].predictionModel,
weatherType: 3,
startTime,
endTime: dayjs(startTime).add(currentSelection.value[0].leadTime, 'hour').format('YYYY-MM-DD HH:mm:ss'),
// hour: currentSelection.value[0].leadTime,
hour: 0,
};
emit('playback', params);
EventBusTool.getEventBus().publish('playData', {
key: 'setTaishiParam',
dataType: currentSelection.value[0].predictionModel,
weatherType: 3,
startTime,
// hour: currentSelection.value[0].leadTime,
hour: 0,
endTime: dayjs(startTime).add(currentSelection.value[0].leadTime, 'hour').format('YYYY-MM-DD HH:mm:ss'),
});
}
}
function handleClick(): void {
if (fileInput.value) {
fileInput.value.value = '';
fileInput.value.click();
}
}
// 处理文件选择事件
function handleFileChange(event: Event): void {
const target = event.target as HTMLInputElement;
const file = target.files?.[0];
if (!file) {
console.warn('未选择文件');
return;
}
configForm.value.file = file;
configForm.value.inputFile = file.name;
// const formData = new FormData();
// // 创建 FormData 对象
// formData.append('inputFile', file.name);
// formData.append('file', file);
// 调用接口现在importTask只需要formData和callback
// importFile(formData, (res:any) => {
// console.log('接口响应:', res);
// getList();
// });
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
pageSize.value = val;
getList();
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
currentPage.value = val;
getList();
}
getList();
</script>
<template>
<div class="ycrw">
<Dialog v-model="logVisible" :title="t('operationLog')" width="56vw" class="child-custom" style="top:230px;left:22vw">
<log :data="logData" />
</Dialog>
<!-- 增、改 -->
<Dialog v-model="configVisible" :title="configType === 'add' ? t('add') : t('edit')" width="40vw"
style="top:230px;left:30vw" class="config-dialog">
<ElForm label-position="top" label-width="120px" :model="configForm" class="config-custom-form">
<ElFormItem :label="t('taskName')">
<ElInput v-model="configForm.taskName" :placeholder="t('pleaseEnter')" class="config-custom-input" />
</ElFormItem>
<ElFormItem :label="t('predictionModel')">
<ElSelect v-model="configForm.predictionModel" :placeholder="t('pleaseSelect')"
popper-class="custom-select-dropdown" class="config-custom-select">
<ElOption label="盘古" :value="1" />
<ElOption label="Graphcast" :value="2" />
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('predictionStartDate')" class="config-custom-date">
<el-date-picker v-model="configForm.startDate" value-format="YYYY-MM-DD" width="100%" type="date"
:placeholder="t('pleaseSelect')" />
</ElFormItem>
<ElFormItem :label="t('predictionStartTime')">
<!-- <ElInput v-model="configForm.startTime" :placeholder="t('pleaseEnter')" class="config-custom-input" /> -->
<ElSelect v-model="configForm.startTime" :placeholder="t('pleaseSelect')" popper-class="custom-select-dropdown"
class="config-custom-select">
<ElOption :value="0" />
<ElOption :value="6" />
<ElOption :value="12" />
<ElOption :value="18" />
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('predictionDuration')">
<ElInput v-model="configForm.leadTime" :placeholder="t('pleaseEnter')" class="config-custom-input" />
</ElFormItem>
<ElFormItem :label="t('dataSource')">
<ElSelect v-model="configForm.dataSources" :placeholder="t('pleaseSelect')"
popper-class="custom-select-dropdown" class="config-custom-select">
<ElOption label="cds" :value="1" />
<ElOption label="本地文件" :value="2" />
</ElSelect>
</ElFormItem>
<ElFormItem v-if="configForm.dataSources === 2" :label="t('uploadFile')">
<!-- <el-upload -->
<!-- ref="upload" class="upload-demo" :data="configForm" action="/api/weatherTask/create" -->
<!-- :before-upload="beforeUpload" :limit="1" :auto-upload="false" -->
<!-- > -->
<!-- <template #trigger> -->
<ElInput v-model="configForm.inputFile" :placeholder="t('clickToUploadFile')" class="config-custom-input"
@click="handleClick" />
<input ref="fileInput" type="file" style="display: none" @change="handleFileChange">
<!-- </template> -->
<!-- </el-upload> -->
</ElFormItem>
</ElForm>
<template #footer>
<div class="config-custom-btn">
<el-button v-if="configType === 'add'" @click="saveConfigForm">
{{ t('add') }}
</el-button>
<el-button v-if="configType === 'edit'" @click="saveConfigForm">
{{ t('save') }}
</el-button>
<el-button type="warning" @click="configVisible = false">
{{ t('cancel') }}
</el-button>
</div>
</template>
</Dialog>
<!-- 主表 -->
<ElForm :inline="true" :model="searchForm" class="custom-form">
<ElFormItem label="">
<ElInput v-model="searchForm.taskName" :placeholder="`${t('keyword')}...`" class="custom-input" />
</ElFormItem>
<ElFormItem :label="t('taskStatus')">
<ElSelect v-model="searchForm.taskStatus" :placeholder="t('pleaseSelect')" clearable class="custom-select">
<ElOption v-for="item in taskStatusList" :key="item.value" :label="item.label" :value="item.value" />
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('predictionDate')">
<ElDatePicker v-model="searchForm.createTime" value-format="YYYY-MM-DD" type="daterange" range-separator="--"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" class="custom-date-picker" />
</ElFormItem>
<ElFormItem>
<ElButton type="primary" class="custom-btn" icon="Search" @click="search">
{{ t('search') }}
</ElButton>
</ElFormItem>
</ElForm>
<ElTable ref="multipleTableRef" :data="taskList" width="100%" max-height="60vh" class="custom-table"
@selection-change="handleSelectionChange">
<ElTableColumn type="selection" width="55" />
<ElTableColumn type="index" :label="t('serialNumber')" width="80" />
<ElTableColumn prop="taskName" :label="t('taskName')" />
<ElTableColumn :label="t('taskStatus')">
<template #default="scope">
<div v-if="scope.row.taskStatus === -1" style="color:#f42a2a;">执行失败</div>
<div v-if="scope.row.taskStatus === 0" style="color:#f42a2a;">未开始</div>
<div v-if="scope.row.taskStatus === 1" style="color:#ffcb40;">等待中</div>
<div v-if="scope.row.taskStatus === 2" style="color:#ffcb40;">运行中</div>
<div v-if="scope.row.taskStatus === 3" style="color:#2af442;">已完成</div>
<div v-if="scope.row.taskStatus === 4" style="color:#f42a2a;">检查未通过</div>
</template>
</ElTableColumn>
<ElTableColumn prop="model" :label="t('predictionModel')">
<template #default="scope">
<div v-if="scope.row.predictionModel === 1">
{{ '盘古' }}
</div>
<div v-if="scope.row.predictionModel === 2">
{{ 'Graphcast' }}
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="time" :label="t('predictionDate')">
<!-- 预测日期 -->
<template #default="scope">
<div>
{{ scope.row.startDate }}
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="startTime" :label="t('predictionStartTime')">
<!-- 预测时间 -->
<template #default="scope">
<div>
{{ scope.row.startTime }}
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="leadTime" :label="t('predictionDuration')">
<!-- 预测时长 -->
<template #default="scope">
<div>
{{ scope.row.leadTime }}小时
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="hours" :label="t('timeConsuming')">
<!-- 耗时 -->
<template #default="scope">
<div>
{{ (scope.row.timeConsuming) }}分钟
</div>
</template>
</ElTableColumn>
<!--<ElTableColumn prop="creator" :label="t('creator')">
<template #default="scope">
{{ scope.row.createBy || '暂无信息' }}
</template>
</ElTableColumn>-->
<ElTableColumn prop="createTime" :label="t('creationTime')" width="220" />
<ElTableColumn :label="t('operation')" width="280">
<template #default="scope">
<ElButton v-if="scope.row.taskStatus === 1" type="text" class="table-btn" @click="pinToTopTask(scope)">
{{ true ? t('pinToTop') : t('unpin') }}
</ElButton>
<ElButton v-else type="text" style="color:#588589;cursor:no-drop">
{{ true ? t('pinToTop') : t('unpin') }}
</ElButton>
<!-- -1执行失败0未开始1等待中2运行中3已完成4检查未通过-->
<!--任务处于等待中,运行中状态时,不能编辑和删除;处于未开始,已完成,检查未通过时可以删除;处于已完成状态时也不能编辑-->
<ElButton v-if="scope.row.taskStatus === 0 || scope.row.taskStatus === -1" type="text" class="custom-text-btn"
@click="start(scope.row, scope.$index)">
{{ t('start') }}
</ElButton>
<ElButton v-else type="text" style="color:#588589;cursor:no-drop">
{{ t('start') }}
</ElButton>
<ElButton type="text" class="custom-text-btn" @click="showLog(scope.row)">
{{ t('operationLog') }}
</ElButton>
<ElButton v-if="scope.row.taskStatus !== 1 && scope.row.taskStatus !== 2 && scope.row.taskStatus !== 3" type="text" class="custom-text-btn" @click="editTask(scope.row, scope.$index)">
{{ t('edit') }}
</ElButton>
<ElButton v-else type="text" style="color:#588589;cursor:no-drop">
{{ t('edit') }}
</ElButton>
<ElButton v-if="scope.row.taskStatus == 0 || scope.row.taskStatus === 3 || scope.row.taskStatus === 4" type="text" class="custom-text-btn" @click="deleteTask(scope.row)">
{{ t('delete') }}
</ElButton>
<ElButton v-else type="text" style="color:#588589;cursor:no-drop">
{{ t('delete') }}
</ElButton>
</template>
</ElTableColumn>
</ElTable>
<div class="pagination">
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[10, 20, 50, 100, 200]"
size="small" :background="true" layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
<div class="dialog-footer">
<el-button class="custom-btn" icon="VideoPlay" @click="playback">
{{ t('playback') }}
</el-button>
<el-button class="custom-btn" icon="Plus" @click="addTask">
{{ t('add') }}
</el-button>
<el-button type="primary" class="custom-btn" icon="Refresh" @click="refresh">
{{ t('refresh') }}
</el-button>
</div>
</div>
</template>
<style lang="less">
.ycrw {
.config-dialog {
margin-top: 35vh;
.config-custom-form {
padding: 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.config-custom-select,
.config-custom-input {
width: calc(20vw - 80px) !important;
}
.custom-select-dropdown {
max-width: 200px;
/* 根据实际需求调整 */
}
}
.config-custom-btn {
.el-button {
width: 92px;
height: 32px;
background-color: #08a7cf;
border-radius: 0;
border: 0;
color: #fff;
&:hover {
filter: brightness(1.3);
}
&:last-child {
background-color: #b98326;
}
}
}
}
.el-table__header-wrapper {
.el-checkbox {
display: none;
}
}
.config-custom-date {
.el-date-editor.el-input,
.el-date-editor.el-input__wrapper {
width: calc(20vw - 80px) !important;
}
}
.pagination {
width: 100%;
display: flex;
justify-content: left;
margin-top: 10px;
}
}
</style>