|
|
@@ -0,0 +1,232 @@
|
|
|
+<template>
|
|
|
+ <div class="report-log-query-page">
|
|
|
+ <a-card :bordered="false">
|
|
|
+ <a-row :gutter="[12, 12]" align="middle">
|
|
|
+ <a-col :xs="24" :md="6">
|
|
|
+ <a-select
|
|
|
+ v-model:value="query.type"
|
|
|
+ :options="typeOptions"
|
|
|
+ placeholder="文件类别"
|
|
|
+ allow-clear
|
|
|
+ class="full-control"
|
|
|
+ />
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :md="6">
|
|
|
+ <a-select
|
|
|
+ v-model:value="query.channel"
|
|
|
+ :options="channelOptions"
|
|
|
+ placeholder="上传通道"
|
|
|
+ allow-clear
|
|
|
+ class="full-control"
|
|
|
+ />
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :md="6">
|
|
|
+ <a-date-picker
|
|
|
+ v-model:value="query.queryDate"
|
|
|
+ format="YYYY-MM-DD"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ placeholder="查询时间"
|
|
|
+ class="full-control"
|
|
|
+ />
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :md="6">
|
|
|
+ <a-space>
|
|
|
+ <a-button type="primary" :loading="loading" @click="handleQuery">查询</a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-card>
|
|
|
+
|
|
|
+ <a-card :bordered="false" class="content-card">
|
|
|
+ <a-table
|
|
|
+ :columns="columns"
|
|
|
+ :data-source="rows"
|
|
|
+ :loading="loading"
|
|
|
+ :pagination="pagination"
|
|
|
+ row-key="id"
|
|
|
+ size="middle"
|
|
|
+ @change="handleTableChange"
|
|
|
+ >
|
|
|
+ <template #bodyCell="{ column, record }">
|
|
|
+ <template v-if="column.dataIndex === 'type'">
|
|
|
+ {{ typeLabelMap[record.type] || record.type }}
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.dataIndex === 'status'">
|
|
|
+ <a-tag :color="statusColorMap[record.status] || 'default'">
|
|
|
+ {{ statusLabelMap[record.status] ?? record.status }}
|
|
|
+ </a-tag>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.dataIndex === 'contentPath'">
|
|
|
+ {{ fileName(record) }}
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.key === 'action'">
|
|
|
+ <a-button
|
|
|
+ type="link"
|
|
|
+ size="small"
|
|
|
+ :disabled="!record.contentPath"
|
|
|
+ @click="handleViewFile(record)"
|
|
|
+ >查看文件</a-button>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </a-card>
|
|
|
+
|
|
|
+ <a-modal
|
|
|
+ v-model:open="fileModalVisible"
|
|
|
+ title="文件内容"
|
|
|
+ :footer="null"
|
|
|
+ width="720px"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <a-spin :spinning="fileLoading">
|
|
|
+ <pre class="file-content">{{ fileContent }}</pre>
|
|
|
+ </a-spin>
|
|
|
+ </a-modal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="ReportLogQuery">
|
|
|
+import {onMounted, reactive, ref} from 'vue';
|
|
|
+import {message} from 'ant-design-vue';
|
|
|
+import dayjs from 'dayjs';
|
|
|
+import {getReportLogFileContent, listReportLog} from '@/api/fileupload/reportLog';
|
|
|
+
|
|
|
+const loading = ref(false);
|
|
|
+const rows = ref([]);
|
|
|
+const pagination = reactive({
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0,
|
|
|
+ showSizeChanger: true,
|
|
|
+ showTotal: (total) => `共 ${total} 条`
|
|
|
+});
|
|
|
+
|
|
|
+const query = reactive({
|
|
|
+ type: undefined,
|
|
|
+ channel: undefined,
|
|
|
+ queryDate: dayjs().format('YYYY-MM-DD')
|
|
|
+});
|
|
|
+
|
|
|
+const typeOptions = [
|
|
|
+ {label: '超短期功率预报', value: 'supershort'},
|
|
|
+ {label: '短期功率预报', value: 'short'},
|
|
|
+ {label: '中期功率预报', value: 'medium'}
|
|
|
+];
|
|
|
+
|
|
|
+const channelOptions = [
|
|
|
+ {label: 'IEC104', value: 1},
|
|
|
+ {label: 'XML文件', value: 2},
|
|
|
+ {label: 'FTP', value: 3},
|
|
|
+ {label: 'MQTT', value: 4}
|
|
|
+];
|
|
|
+
|
|
|
+const typeLabelMap = {
|
|
|
+ supershort: '超短期功率预报',
|
|
|
+ short: '短期功率预报',
|
|
|
+ medium: '中期功率预报'
|
|
|
+};
|
|
|
+
|
|
|
+const statusLabelMap = {
|
|
|
+ 0: '待发送',
|
|
|
+ 1: '上报成功',
|
|
|
+ 2: '上报失败',
|
|
|
+ 3: '超时'
|
|
|
+};
|
|
|
+
|
|
|
+const statusColorMap = {
|
|
|
+ 0: 'default',
|
|
|
+ 1: 'success',
|
|
|
+ 2: 'error',
|
|
|
+ 3: 'warning'
|
|
|
+};
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ {title: '场站名称', dataIndex: 'stationName', width: 180},
|
|
|
+ {title: '上报文件类型', dataIndex: 'type', width: 140},
|
|
|
+ {title: '计划上报时间', dataIndex: 'estReportTime', width: 170},
|
|
|
+ {title: '实际上报时间', dataIndex: 'reportTime', width: 170},
|
|
|
+ {title: '状态', dataIndex: 'status', width: 100},
|
|
|
+ {title: '文件名称', dataIndex: 'contentPath', width: 240, ellipsis: true},
|
|
|
+ {title: '操作', key: 'action', width: 100, fixed: 'right'}
|
|
|
+];
|
|
|
+
|
|
|
+const fileName = (record) => {
|
|
|
+ if (!record.contentPath) return '';
|
|
|
+ const parts = record.contentPath.split(/[\\/]/);
|
|
|
+ return parts[parts.length - 1];
|
|
|
+};
|
|
|
+
|
|
|
+const fetchList = async (pageNum, pageSize) => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await listReportLog({
|
|
|
+ pageNum,
|
|
|
+ pageSize,
|
|
|
+ type: query.type,
|
|
|
+ channel: query.channel,
|
|
|
+ queryDate: query.queryDate
|
|
|
+ });
|
|
|
+ rows.value = res.rows || [];
|
|
|
+ pagination.total = res.total || 0;
|
|
|
+ pagination.current = pageNum;
|
|
|
+ pagination.pageSize = pageSize;
|
|
|
+ } catch (e) {
|
|
|
+ // request.js 已统一提示错误
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleQuery = () => {
|
|
|
+ fetchList(1, pagination.pageSize);
|
|
|
+};
|
|
|
+
|
|
|
+const handleTableChange = (pag) => {
|
|
|
+ fetchList(pag.current, pag.pageSize);
|
|
|
+};
|
|
|
+
|
|
|
+const fileModalVisible = ref(false);
|
|
|
+const fileLoading = ref(false);
|
|
|
+const fileContent = ref('');
|
|
|
+
|
|
|
+const handleViewFile = async (record) => {
|
|
|
+ fileModalVisible.value = true;
|
|
|
+ fileLoading.value = true;
|
|
|
+ fileContent.value = '';
|
|
|
+ try {
|
|
|
+ const res = await getReportLogFileContent(record.id);
|
|
|
+ fileContent.value = res.content ?? '';
|
|
|
+ } catch (e) {
|
|
|
+ // request.js 已统一提示错误
|
|
|
+ } finally {
|
|
|
+ fileLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchList(1, pagination.pageSize);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.report-log-query-page {
|
|
|
+ padding: 16px;
|
|
|
+}
|
|
|
+.full-control {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.content-card {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+.file-content {
|
|
|
+ max-height: 600px;
|
|
|
+ overflow: auto;
|
|
|
+ margin: 0;
|
|
|
+ padding: 12px;
|
|
|
+ background: #f5f5f5;
|
|
|
+ border-radius: 4px;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-all;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+</style>
|