521 lines
17 KiB
Vue
521 lines
17 KiB
Vue
<template>
|
|
<div class="report-engine-report-container">
|
|
<el-card shadow="hover">
|
|
<!-- 业务 Tab -->
|
|
<div class="biz-tabs-header mb15">
|
|
<el-tabs v-model="activeBusinessCode" type="card" @tab-click="handleTabClick" @tab-remove="handleTabRemove" class="biz-tabs">
|
|
<el-tab-pane
|
|
v-for="biz in businesses"
|
|
:key="biz.businessCode"
|
|
:name="biz.businessCode"
|
|
closable
|
|
>
|
|
<template #label>
|
|
<span class="custom-tab-label">
|
|
<span class="tab-name">{{ biz.businessName }}</span>
|
|
<el-icon class="tab-edit-btn" @click.stop="onOpenBusinessEdit(biz)">
|
|
<ele-EditPen />
|
|
</el-icon>
|
|
</span>
|
|
</template>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
<el-button
|
|
size="default"
|
|
type="primary"
|
|
@click="onOpenBusinessAdd"
|
|
class="biz-add-btn"
|
|
>
|
|
<el-icon><ele-Plus /></el-icon>
|
|
<span>新增业务</span>
|
|
</el-button>
|
|
</div>
|
|
|
|
<!-- 搜索栏 -->
|
|
<div class="system-user-search mb15">
|
|
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="80px">
|
|
<el-form-item label="报表名称" prop="reportName">
|
|
<el-input
|
|
v-model="tableData.param.reportName"
|
|
placeholder="请输入报表名称"
|
|
clearable
|
|
size="default"
|
|
style="width: 220px"
|
|
@keyup.enter.native="getList"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button size="default" type="primary" @click="getList">
|
|
<el-icon><ele-Search /></el-icon>
|
|
查询
|
|
</el-button>
|
|
<el-button size="default" @click="resetQuery">
|
|
<el-icon><ele-Refresh /></el-icon>
|
|
重置
|
|
</el-button>
|
|
<el-button size="default" type="success" @click="onOpenReportAdd">
|
|
<el-icon><ele-Plus /></el-icon>
|
|
新增报表
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</div>
|
|
|
|
<!-- 报表表格 -->
|
|
<el-table :data="tableData.data" style="width: 100%" v-loading="tableData.loading">
|
|
<el-table-column type="index" label="序号" width="60" />
|
|
<el-table-column prop="reportCode" label="报表编码" show-overflow-tooltip />
|
|
<el-table-column prop="reportName" label="报表名称" show-overflow-tooltip />
|
|
<el-table-column prop="status" label="状态" width="90" align="center">
|
|
<template #default="scope">
|
|
<el-tag :type="scope.row.status === 'ACTIVE' ? 'success' : 'danger'" size="small">
|
|
{{ scope.row.status === 'ACTIVE' ? '启用' : '停用' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="description" label="描述" show-overflow-tooltip />
|
|
<el-table-column prop="statTableName" label="统计表名" show-overflow-tooltip />
|
|
<el-table-column label="操作" width="320" fixed="right">
|
|
<template #default="scope">
|
|
<el-button size="small" text type="primary" @click="onOpenReportEdit(scope.row)">编辑</el-button>
|
|
<el-button size="small" text type="primary" @click="onOpenExtractConfig(scope.row)">抽取配置</el-button>
|
|
<el-button size="small" text type="success" @click="onDailyExtract(scope.row)">按天回刷</el-button>
|
|
<el-button size="small" text type="danger" @click="onExtractConfigDel(scope.row)" v-if="scope.row.extractConfigIds">删除抽取配置</el-button>
|
|
<el-button size="small" text type="danger" @click="onReportDel(scope.row)">删除</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页 -->
|
|
<pagination
|
|
v-show="tableData.total > 0"
|
|
:total="tableData.total"
|
|
v-model:page="tableData.param.pageNum"
|
|
v-model:limit="tableData.param.pageSize"
|
|
@pagination="getList"
|
|
/>
|
|
</el-card>
|
|
|
|
<!-- 业务管理弹窗 -->
|
|
<BusinessManager
|
|
v-model:visible="businessDialog.visible"
|
|
:edit-data="businessDialog.editData"
|
|
@confirm="onBusinessConfirm"
|
|
/>
|
|
|
|
<!-- 报表表单弹窗 -->
|
|
<ReportForm
|
|
v-model:visible="reportDialog.visible"
|
|
:edit-id="reportDialog.editId"
|
|
:business-code="activeBusinessCode"
|
|
@confirm="onReportConfirm"
|
|
/>
|
|
|
|
<!-- 抽取配置弹窗 -->
|
|
<ExtractConfigForm
|
|
v-model:visible="extractDialog.visible"
|
|
:edit-id="extractDialog.editId"
|
|
:business-code="extractDialog.businessCode"
|
|
:report-code="extractDialog.reportCode"
|
|
:report-name="extractDialog.reportName"
|
|
@confirm="onExtractConfigConfirm"
|
|
/>
|
|
|
|
<!-- 按天回刷弹窗 -->
|
|
<el-dialog
|
|
v-model="dailyExtractDialog.visible"
|
|
title="按天回刷"
|
|
width="420px"
|
|
destroy-on-close
|
|
>
|
|
<el-form label-width="100px">
|
|
<el-form-item label="报表编码">
|
|
<el-input :model-value="dailyExtractDialog.reportCode" disabled />
|
|
</el-form-item>
|
|
<el-form-item label="日期范围" required>
|
|
<el-date-picker
|
|
v-model="dailyExtractDialog.dateRange"
|
|
type="daterange"
|
|
range-separator="至"
|
|
start-placeholder="开始日期"
|
|
end-placeholder="结束日期"
|
|
value-format="YYYY-MM-DD"
|
|
style="width: 100%"
|
|
:disabled-date="(t: Date) => t > new Date()"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="dailyExtractDialog.visible = false">取消</el-button>
|
|
<el-button type="primary" :loading="dailyExtractDialog.loading" @click="onDailyExtractConfirm">确认回刷</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
export default { name: 'reportEngineReport' };
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, onMounted } from 'vue';
|
|
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
|
import { listBusinesses, saveBusiness, deleteBusiness, saveReportWithFields, deleteReport, listReports, deleteExtractConfig, execDailyBackfill } from '/@/api/report-engine/report';
|
|
import BusinessManager from './components/BusinessManager.vue';
|
|
import ReportForm from './components/ReportForm.vue';
|
|
import ExtractConfigForm from './components/ExtractConfigForm.vue';
|
|
|
|
const queryRef = ref<FormInstance>();
|
|
|
|
// --- 业务列表 ---
|
|
const businesses = ref<any[]>([]);
|
|
const activeBusinessCode = ref('');
|
|
|
|
// --- 报表表格数据 ---
|
|
const tableData = reactive({
|
|
data: [] as any[],
|
|
total: 0,
|
|
loading: false,
|
|
param: {
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
reportName: '',
|
|
},
|
|
});
|
|
|
|
// --- 业务弹窗 ---
|
|
const businessDialog = reactive({
|
|
visible: false,
|
|
editData: null as { id?: number; businessCode: string; businessName: string } | null,
|
|
});
|
|
|
|
// --- 报表弹窗 ---
|
|
const reportDialog = reactive({
|
|
visible: false,
|
|
editId: null as number | null,
|
|
});
|
|
|
|
// --- 抽取配置弹窗 ---
|
|
const extractDialog = reactive({
|
|
visible: false,
|
|
editId: null as number | null,
|
|
businessCode: '',
|
|
reportCode: '',
|
|
reportName: '',
|
|
});
|
|
|
|
// --- 按天回刷弹窗 ---
|
|
const dailyExtractDialog = reactive({
|
|
visible: false,
|
|
businessCode: '',
|
|
reportCode: '',
|
|
dateRange: [] as string[],
|
|
loading: false,
|
|
});
|
|
|
|
// ========== 业务相关 ==========
|
|
|
|
const loadBusinesses = async () => {
|
|
try {
|
|
const res = await listBusinesses();
|
|
businesses.value = res.data?.list || res.data || [];
|
|
if (businesses.value.length > 0 && !activeBusinessCode.value) {
|
|
activeBusinessCode.value = businesses.value[0].businessCode;
|
|
getList();
|
|
}
|
|
} catch (_e) {
|
|
ElMessage.error('获取业务列表失败');
|
|
}
|
|
};
|
|
|
|
const handleTabClick = (pane?: any) => {
|
|
const code = pane?.props?.name;
|
|
if (code) activeBusinessCode.value = code;
|
|
tableData.param.pageNum = 1;
|
|
getList();
|
|
};
|
|
|
|
const handleTabRemove = (name: string) => {
|
|
const biz = businesses.value.find((b) => b.businessCode === name);
|
|
if (!biz || !biz.id) return;
|
|
const label = biz.businessName;
|
|
ElMessageBox.confirm(`确定要删除业务「${label}」吗?该操作同时会删除该业务下所有报表配置。`, '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning',
|
|
})
|
|
.then(async () => {
|
|
try {
|
|
await deleteBusiness(biz.id);
|
|
ElMessage.success('删除成功');
|
|
const idx = businesses.value.findIndex((b) => b.businessCode === name);
|
|
await loadBusinesses();
|
|
if (businesses.value.length > 0) {
|
|
const newIdx = Math.min(idx, businesses.value.length - 1);
|
|
activeBusinessCode.value = businesses.value[newIdx].businessCode;
|
|
} else {
|
|
activeBusinessCode.value = '';
|
|
tableData.data = [];
|
|
tableData.total = 0;
|
|
}
|
|
getList();
|
|
} catch (_e) {
|
|
ElMessage.error('删除失败');
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
};
|
|
|
|
const onOpenBusinessAdd = () => {
|
|
businessDialog.editData = null;
|
|
businessDialog.visible = true;
|
|
};
|
|
|
|
const onOpenBusinessEdit = (biz: { id?: number; businessCode: string; businessName: string }) => {
|
|
businessDialog.editData = { ...biz };
|
|
businessDialog.visible = true;
|
|
};
|
|
|
|
const onBusinessConfirm = async (data: { id?: number; businessCode: string; businessName: string }) => {
|
|
try {
|
|
const isEdit = !!data.id;
|
|
await saveBusiness(data);
|
|
ElMessage.success(isEdit ? '修改成功' : '新增成功');
|
|
businessDialog.visible = false;
|
|
await loadBusinesses();
|
|
activeBusinessCode.value = data.businessCode;
|
|
getList();
|
|
} catch (_e) {
|
|
ElMessage.error(data.id ? '修改失败' : '新增失败');
|
|
}
|
|
};
|
|
|
|
// ========== 报表相关 ==========
|
|
|
|
const getList = async () => {
|
|
if (!activeBusinessCode.value) return;
|
|
tableData.loading = true;
|
|
try {
|
|
const res = await listReports(
|
|
activeBusinessCode.value,
|
|
tableData.param.pageNum,
|
|
tableData.param.pageSize,
|
|
tableData.param.reportName || undefined
|
|
);
|
|
const raw = res.data;
|
|
if (Array.isArray(raw)) {
|
|
tableData.data = raw;
|
|
tableData.total = raw.length;
|
|
} else if (raw) {
|
|
tableData.data = raw.list || raw.records || raw.rows || [];
|
|
tableData.total = raw.total || tableData.data.length;
|
|
}
|
|
} catch (_e) {
|
|
tableData.data = [];
|
|
tableData.total = 0;
|
|
} finally {
|
|
tableData.loading = false;
|
|
}
|
|
};
|
|
|
|
const resetQuery = () => {
|
|
if (!queryRef.value) return;
|
|
queryRef.value.resetFields();
|
|
tableData.param.pageNum = 1;
|
|
getList();
|
|
};
|
|
|
|
const onOpenReportAdd = () => {
|
|
reportDialog.editId = null;
|
|
reportDialog.visible = true;
|
|
};
|
|
|
|
const onOpenReportEdit = async (row: any) => {
|
|
reportDialog.editId = row.id;
|
|
reportDialog.visible = true;
|
|
};
|
|
|
|
const onReportConfirm = async (data: any) => {
|
|
try {
|
|
const isEdit = reportDialog.editId !== null;
|
|
await saveReportWithFields(data);
|
|
ElMessage.success(isEdit ? '修改成功' : '新增成功');
|
|
reportDialog.visible = false;
|
|
getList();
|
|
} catch (_e) {
|
|
ElMessage.error(reportDialog.editId ? '修改失败' : '新增失败');
|
|
}
|
|
};
|
|
|
|
const onReportDel = (row: any) => {
|
|
ElMessageBox.confirm(`确定要删除报表「${row.reportName}」吗?`, '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning',
|
|
})
|
|
.then(async () => {
|
|
try {
|
|
const res = await deleteReport(row.id);
|
|
if (res.data?.success === false) {
|
|
// 业务层面拒绝删除(如存在关联字段)
|
|
ElMessage.warning(res.data?.message || '无法删除');
|
|
return;
|
|
}
|
|
ElMessage.success('删除成功');
|
|
getList();
|
|
} catch (_e) {
|
|
ElMessage.error('删除失败');
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
};
|
|
|
|
// ========== 抽取配置 ==========
|
|
|
|
const onOpenExtractConfig = (row: any) => {
|
|
extractDialog.businessCode = row.businessCode;
|
|
extractDialog.reportCode = row.reportCode;
|
|
extractDialog.reportName = row.reportName;
|
|
extractDialog.editId = row.extractConfigIds ? Number(row.extractConfigIds) : null;
|
|
extractDialog.visible = true;
|
|
};
|
|
|
|
const onExtractConfigConfirm = () => {
|
|
extractDialog.visible = false;
|
|
getList();
|
|
};
|
|
|
|
const onExtractConfigDel = (row: any) => {
|
|
ElMessageBox.confirm(`确定要删除「${row.reportName}」的抽取配置吗?`, '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning',
|
|
})
|
|
.then(async () => {
|
|
try {
|
|
await deleteExtractConfig(Number(row.extractConfigIds));
|
|
ElMessage.success('删除成功');
|
|
getList();
|
|
} catch (_e) {
|
|
ElMessage.error('删除失败');
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
};
|
|
|
|
// ========== 按天回刷 ==========
|
|
|
|
const onDailyExtract = (row: any) => {
|
|
dailyExtractDialog.businessCode = row.businessCode;
|
|
dailyExtractDialog.reportCode = row.reportCode;
|
|
dailyExtractDialog.dateRange = [];
|
|
dailyExtractDialog.loading = false;
|
|
dailyExtractDialog.visible = true;
|
|
};
|
|
|
|
const onDailyExtractConfirm = async () => {
|
|
if (!dailyExtractDialog.dateRange || dailyExtractDialog.dateRange.length !== 2) {
|
|
ElMessage.warning('请选择日期范围');
|
|
return;
|
|
}
|
|
dailyExtractDialog.loading = true;
|
|
try {
|
|
const res = await execDailyBackfill({
|
|
businessCode: dailyExtractDialog.businessCode,
|
|
reportCode: dailyExtractDialog.reportCode,
|
|
startDate: dailyExtractDialog.dateRange[0],
|
|
endDate: dailyExtractDialog.dateRange[1],
|
|
});
|
|
if (res.data?.success === false) {
|
|
ElMessage.warning(res.data?.message || '回刷失败');
|
|
return;
|
|
}
|
|
ElMessage.success('回刷任务已提交');
|
|
dailyExtractDialog.visible = false;
|
|
} catch (_e) {
|
|
ElMessage.error('执行回刷失败');
|
|
} finally {
|
|
dailyExtractDialog.loading = false;
|
|
}
|
|
};
|
|
|
|
// ========== 初始化 ==========
|
|
|
|
onMounted(() => {
|
|
loadBusinesses();
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.biz-tabs-header {
|
|
display: flex;
|
|
align-items: stretch;
|
|
|
|
.biz-tabs {
|
|
flex: 1;
|
|
min-width: 0;
|
|
|
|
:deep(.el-tabs__header) {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
:deep(.el-tabs__content) {
|
|
display: none;
|
|
}
|
|
|
|
:deep(.el-tabs__item) {
|
|
position: relative;
|
|
height: 34px;
|
|
line-height: 34px;
|
|
padding: 0 10px;
|
|
|
|
// 关闭图标始终可见
|
|
.is-icon-close {
|
|
width: 14px !important;
|
|
overflow: visible !important;
|
|
opacity: 0.45;
|
|
transition: opacity 0.2s;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.biz-add-btn {
|
|
flex-shrink: 0;
|
|
margin-left: 12px;
|
|
height: 34px;
|
|
align-self: flex-end;
|
|
}
|
|
}
|
|
|
|
.custom-tab-label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-size: 13px;
|
|
|
|
.tab-name {
|
|
max-width: 100px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tab-edit-btn {
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
margin-left: 3px;
|
|
color: var(--el-text-color-placeholder);
|
|
transition: color 0.2s;
|
|
|
|
&:hover {
|
|
color: var(--el-color-primary);
|
|
}
|
|
}
|
|
}
|
|
|
|
</style>
|