feat(testReport): 新增测试报告分组和报告生成功能
- 添加ReportTaskState和ReportTaskGenerateState类型定义 - 扩展ReportTaskLedgerImportStage枚举,增加文件导入阶段 - 新增ReportTaskLedgerImportRequest、ReportTaskLedgerValidateAttachmentRecord等接口定义 - 添加validateReportTaskLedgerApi、importReportTaskLedgerApi等API方法 - 在操作列新增分组和生成报告按钮 - 实现ReportTaskGroupDialog组件用于监测点分组管理 - 添加分组报告下载功能和相关事件处理 - 优化报告任务详情对话框中的分组报告显示 - 更新createEmptyLedgerPreparedState函数初始化逻辑
This commit is contained in:
@@ -37,11 +37,32 @@ export const downloadReportTaskLedgerTemplateApi = (): Promise<AxiosResponse<Blo
|
||||
}) as unknown as Promise<AxiosResponse<Blob>>
|
||||
|
||||
export const validateReportTaskLedgerApi = (id: string, formData: FormData) => {
|
||||
return http.post<ReportTask.ReportTaskLedgerImportResult>(`${REPORT_TASK_BASE_URL}/${id}/ledger/validate`, formData, {
|
||||
return http.post<ReportTask.ReportTaskLedgerValidateResult>(`${REPORT_TASK_BASE_URL}/${id}/ledger/validate`, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
}
|
||||
|
||||
export const importReportTaskLedgerApi = (id: string, params: ReportTask.ReportTaskLedgerImportRequest) => {
|
||||
return http.post<ReportTask.ReportTaskLedgerImportResult>(`${REPORT_TASK_BASE_URL}/${id}/ledger/import`, params)
|
||||
}
|
||||
|
||||
export const listReportTaskPointsApi = (id: string) => {
|
||||
return http.get<ReportTask.ReportTaskPointRecord[]>(`${REPORT_TASK_BASE_URL}/${id}/point/list`)
|
||||
}
|
||||
|
||||
export const saveReportTaskGroupsApi = (id: string, params: ReportTask.ReportTaskGroupSaveRequest) => {
|
||||
return http.post<boolean>(`${REPORT_TASK_BASE_URL}/${id}/group/save`, params)
|
||||
}
|
||||
|
||||
export const listReportTaskGroupReportsApi = (id: string) => {
|
||||
return http.get<ReportTask.ReportTaskGroupReportRecord[]>(`${REPORT_TASK_BASE_URL}/${id}/group-report/list`)
|
||||
}
|
||||
|
||||
export const generateReportTaskGroupReportsApi = (id: string) => {
|
||||
return http.post<boolean>(`${REPORT_TASK_BASE_URL}/${id}/generate`)
|
||||
}
|
||||
|
||||
export const downloadReportTaskGroupReportApi = (groupReportId: string): Promise<AxiosResponse<Blob>> =>
|
||||
http.get(`${REPORT_TASK_BASE_URL}/group-report/${groupReportId}/download`, undefined, {
|
||||
responseType: 'blob'
|
||||
}) as unknown as Promise<AxiosResponse<Blob>>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
export namespace ReportTask {
|
||||
export type ReportTaskState = '01' | '02' | '03' | '04' | '05'
|
||||
export type ReportTaskGenerateState = 0 | 1 | 2
|
||||
export type ReportTaskGroupReportGenerateState = 0 | 1 | 2 | 3
|
||||
export type ReportTaskLedgerImportStage =
|
||||
| '选择文件'
|
||||
| '校验文件'
|
||||
| '文件上传'
|
||||
| '文件导入'
|
||||
| '基础资料维护'
|
||||
| '完成'
|
||||
|
||||
@@ -41,6 +44,7 @@ export namespace ReportTask {
|
||||
searchBeginTime?: string
|
||||
searchEndTime?: string
|
||||
timeRange?: string[]
|
||||
state?: ReportTaskState | string
|
||||
pageNum?: number
|
||||
pageSize?: number
|
||||
}
|
||||
@@ -65,12 +69,59 @@ export namespace ReportTask {
|
||||
checkResult?: string
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerImportRequest {
|
||||
batchId: string
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerImportStageRecord {
|
||||
stage?: ReportTaskLedgerImportStage | string | null
|
||||
success?: boolean | null
|
||||
message?: string | null
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerValidateAttachmentRecord {
|
||||
attachmentName?: string | null
|
||||
attachmentType?: string | null
|
||||
referenced?: boolean | null
|
||||
uploaded?: boolean | null
|
||||
missing?: boolean | null
|
||||
reuploadAllowed?: boolean | null
|
||||
message?: string | null
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerValidatePointRecord {
|
||||
rowNo?: number | null
|
||||
pointKey?: string | null
|
||||
substationName?: string | null
|
||||
pointName?: string | null
|
||||
complete?: boolean | null
|
||||
missingAttachmentCount?: number | null
|
||||
testDeviceNoValid?: boolean | null
|
||||
testDeviceNoMessage?: string | null
|
||||
clientUnitNameValid?: boolean | null
|
||||
clientUnitNameMessage?: string | null
|
||||
attachments?: ReportTaskLedgerValidateAttachmentRecord[] | null
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerValidateResult {
|
||||
sessionId?: string | null
|
||||
batchId?: string | null
|
||||
success?: boolean | null
|
||||
summaryFileName?: string | null
|
||||
summaryFilePresent?: boolean | null
|
||||
tempStoragePath?: string | null
|
||||
uploadedFileCount?: number | null
|
||||
pointCount?: number | null
|
||||
missingAttachmentCount?: number | null
|
||||
canContinueUpload?: boolean | null
|
||||
requiredSheets?: string[] | null
|
||||
existingSheets?: string[] | null
|
||||
missingSheets?: string[] | null
|
||||
orphanAttachmentNames?: string[] | null
|
||||
failReasons?: string[] | null
|
||||
points?: ReportTaskLedgerValidatePointRecord[] | null
|
||||
}
|
||||
|
||||
export interface ReportTaskLedgerImportSnapshotGroupRecord {
|
||||
groupNo?: number | null
|
||||
count?: number | null
|
||||
@@ -100,7 +151,9 @@ export namespace ReportTask {
|
||||
currentStage?: ReportTaskLedgerImportStage | string | null
|
||||
success?: boolean | null
|
||||
summaryFileName?: string | null
|
||||
tempStoragePath?: string | null
|
||||
totalFileCount?: number
|
||||
uploadedFileCount?: number
|
||||
pointCount?: number
|
||||
excelAttachmentCount?: number
|
||||
wordAttachmentCount?: number
|
||||
@@ -153,9 +206,13 @@ export namespace ReportTask {
|
||||
export interface ReportTaskLedgerPreparedState {
|
||||
draftId: string
|
||||
batchId: string
|
||||
validateSessionId: string
|
||||
validateResult: ReportTaskLedgerValidateResult | null
|
||||
latestImportResult: ReportTaskLedgerImportResult | null
|
||||
snapshot: ReportTaskLedgerImportSnapshot | null
|
||||
hasImported: boolean
|
||||
validatedBatchId: string
|
||||
pendingReimport: boolean
|
||||
pendingRevalidate: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,19 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="generateMessage" label="生成消息" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="generateTime" label="生成时间" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:disabled="row.generateState !== 2 || !row.id"
|
||||
:loading="downloadingGroupReportId === row.id"
|
||||
@click="emit('download-group-report', row)"
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,10 +88,12 @@ const props = defineProps<{
|
||||
groupReports: ReportTask.ReportTaskGroupReportRecord[]
|
||||
companyLabelMap: Record<string, string>
|
||||
standardLabelMap: Record<string, string>
|
||||
downloadingGroupReportId?: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:visible', value: boolean): void
|
||||
(event: 'download-group-report', value: ReportTask.ReportTaskGroupReportRecord): void
|
||||
}>()
|
||||
|
||||
const visibleProxy = computed({
|
||||
@@ -89,6 +104,7 @@ const visibleProxy = computed({
|
||||
const companyLabelMap = computed(() => props.companyLabelMap)
|
||||
const standardLabelMap = computed(() => props.standardLabelMap)
|
||||
const groupReports = computed(() => props.groupReports || [])
|
||||
const downloadingGroupReportId = computed(() => props.downloadingGroupReportId || '')
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -321,10 +321,14 @@ const logEntries = ref<Array<{ id: string; type: ReportTaskLogType; time: string
|
||||
const ledgerPreparedState = ref<ReportTask.ReportTaskLedgerPreparedState>({
|
||||
draftId: '',
|
||||
batchId: '',
|
||||
validateSessionId: '',
|
||||
validateResult: null,
|
||||
latestImportResult: null,
|
||||
snapshot: null,
|
||||
hasImported: false,
|
||||
pendingReimport: false
|
||||
validatedBatchId: '',
|
||||
pendingReimport: false,
|
||||
pendingRevalidate: false
|
||||
})
|
||||
const lastHandledSaveSuccessVersion = ref(0)
|
||||
|
||||
@@ -445,10 +449,14 @@ const resetForm = () => {
|
||||
ledgerPreparedState.value = {
|
||||
draftId: '',
|
||||
batchId: '',
|
||||
validateSessionId: '',
|
||||
validateResult: null,
|
||||
latestImportResult: null,
|
||||
snapshot: null,
|
||||
hasImported: false,
|
||||
pendingReimport: false
|
||||
validatedBatchId: '',
|
||||
pendingReimport: false,
|
||||
pendingRevalidate: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,10 +502,14 @@ const fillForm = async () => {
|
||||
ledgerPreparedState.value = {
|
||||
draftId: activeDraftId.value,
|
||||
batchId: '',
|
||||
validateSessionId: '',
|
||||
validateResult: null,
|
||||
latestImportResult: null,
|
||||
snapshot,
|
||||
hasImported: Boolean(snapshot || Number(record?.pointCount) > 0),
|
||||
pendingReimport: false
|
||||
validatedBatchId: '',
|
||||
pendingReimport: false,
|
||||
pendingRevalidate: false
|
||||
}
|
||||
|
||||
applyInitialStep(Boolean(snapshot || Number(record?.pointCount) > 0))
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<el-dialog v-model="visibleProxy" title="监测点分组" width="1120px" append-to-body destroy-on-close>
|
||||
<div v-loading="loading" class="report-task-group-dialog">
|
||||
<el-descriptions :column="4" border class="summary-descriptions">
|
||||
<el-descriptions-item label="报告编号">{{ resolveReportTaskText(record?.no) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="委托单位">{{ resolveReportTaskText(record?.clientUnitName) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="监测点数">{{ pointList.length || 0 }}</el-descriptions-item>
|
||||
<el-descriptions-item label="已分组点位">{{ groupedPointCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分组数量">{{ groupedPayload.groups.length || 0 }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-empty v-if="!loading && !pointList.length" description="暂无监测点数据,无法进行分组" :image-size="88" />
|
||||
|
||||
<template v-else>
|
||||
<el-alert
|
||||
v-if="!groupingCompleted"
|
||||
title="请为所有监测点设置大于 0 的分组号后再保存。"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="section-alert"
|
||||
/>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-title">批量分组</div>
|
||||
<div class="toolbar-actions">
|
||||
<el-input-number
|
||||
v-model="batchGroupNo"
|
||||
:min="1"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
placeholder="分组号"
|
||||
/>
|
||||
<el-button type="primary" :disabled="!selectedPointIds.length || !batchGroupNo" @click="applyBatchGroupNo">
|
||||
应用到已选
|
||||
</el-button>
|
||||
<el-button :disabled="!selectedPointIds.length" @click="clearSelectedGroups">清空已选</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="pointList"
|
||||
row-key="id"
|
||||
border
|
||||
size="small"
|
||||
max-height="460"
|
||||
class="point-table"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column type="index" label="序号" width="70" />
|
||||
<el-table-column label="分组号" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
:model-value="resolvePointGroupNo(row.id)"
|
||||
:min="1"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
@update:model-value="handlePointGroupNoChange(row.id, $event)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="substationName" label="变电站" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="pointName" label="监测点" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="monitorTime" label="监测时间" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="voltageLevel" label="电压等级" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="excelAttachmentName" label="原始文件" min-width="180" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visibleProxy = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" :disabled="loading || !groupingCompleted" @click="handleSubmit">
|
||||
保存分组
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import type { ReportTask } from '@/api/aireport/testReport/interface'
|
||||
import {
|
||||
checkReportTaskGroupingCompleted,
|
||||
normalizeReportTaskGroupSavePayload,
|
||||
resolveReportTaskText
|
||||
} from '../utils/testReport'
|
||||
|
||||
defineOptions({
|
||||
name: 'ReportTaskGroupDialog'
|
||||
})
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
loading: boolean
|
||||
saving: boolean
|
||||
record: ReportTask.ReportTaskRecord | null
|
||||
pointList: ReportTask.ReportTaskPointRecord[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:visible', value: boolean): void
|
||||
(event: 'submit', value: ReportTask.ReportTaskGroupSaveRequest): void
|
||||
}>()
|
||||
|
||||
const localPointGroupMap = ref<Record<string, number | null>>({})
|
||||
const selectedPointIds = ref<string[]>([])
|
||||
const batchGroupNo = ref<number | null>(null)
|
||||
|
||||
const visibleProxy = computed({
|
||||
get: () => props.visible,
|
||||
set: value => emit('update:visible', value)
|
||||
})
|
||||
|
||||
const initializePointGroupMap = () => {
|
||||
const nextGroupMap: Record<string, number | null> = {}
|
||||
|
||||
props.pointList.forEach(point => {
|
||||
const pointId = String(point.id || '').trim()
|
||||
if (!pointId) return
|
||||
|
||||
const groupNo = Number(point.groupNo)
|
||||
nextGroupMap[pointId] = Number.isInteger(groupNo) && groupNo > 0 ? groupNo : null
|
||||
})
|
||||
|
||||
localPointGroupMap.value = nextGroupMap
|
||||
selectedPointIds.value = []
|
||||
batchGroupNo.value = null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.visible, props.pointList],
|
||||
([visible]) => {
|
||||
if (visible) {
|
||||
initializePointGroupMap()
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
const groupedPayload = computed(() => normalizeReportTaskGroupSavePayload(props.pointList, localPointGroupMap.value))
|
||||
const groupingCompleted = computed(() => checkReportTaskGroupingCompleted(props.pointList, groupedPayload.value))
|
||||
const groupedPointCount = computed(() =>
|
||||
props.pointList.reduce((count, point) => {
|
||||
const pointId = String(point.id || '').trim()
|
||||
if (!pointId) return count
|
||||
|
||||
const groupNo = Number(localPointGroupMap.value[pointId])
|
||||
return Number.isInteger(groupNo) && groupNo > 0 ? count + 1 : count
|
||||
}, 0)
|
||||
)
|
||||
|
||||
const resolvePointGroupNo = (pointId?: string) => {
|
||||
const normalizedPointId = String(pointId || '').trim()
|
||||
if (!normalizedPointId) return null
|
||||
return localPointGroupMap.value[normalizedPointId] ?? null
|
||||
}
|
||||
|
||||
const updatePointGroupNo = (pointId: string | undefined, value: number | null | undefined) => {
|
||||
const normalizedPointId = String(pointId || '').trim()
|
||||
if (!normalizedPointId) return
|
||||
|
||||
const groupNo = Number(value)
|
||||
localPointGroupMap.value = {
|
||||
...localPointGroupMap.value,
|
||||
[normalizedPointId]: Number.isInteger(groupNo) && groupNo > 0 ? groupNo : null
|
||||
}
|
||||
}
|
||||
|
||||
const handlePointGroupNoChange = (pointId: string | undefined, value: number | null | undefined) => {
|
||||
updatePointGroupNo(pointId, value)
|
||||
}
|
||||
|
||||
const handleSelectionChange = (selection: ReportTask.ReportTaskPointRecord[]) => {
|
||||
selectedPointIds.value = selection.map(item => String(item.id || '').trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
const applyBatchGroupNo = () => {
|
||||
const groupNo = Number(batchGroupNo.value)
|
||||
if (!Number.isInteger(groupNo) || groupNo <= 0) return
|
||||
|
||||
const nextGroupMap = { ...localPointGroupMap.value }
|
||||
selectedPointIds.value.forEach(pointId => {
|
||||
nextGroupMap[pointId] = groupNo
|
||||
})
|
||||
localPointGroupMap.value = nextGroupMap
|
||||
}
|
||||
|
||||
const clearSelectedGroups = () => {
|
||||
const nextGroupMap = { ...localPointGroupMap.value }
|
||||
selectedPointIds.value.forEach(pointId => {
|
||||
nextGroupMap[pointId] = null
|
||||
})
|
||||
localPointGroupMap.value = nextGroupMap
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
emit('submit', groupedPayload.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.report-task-group-dialog {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.summary-descriptions,
|
||||
.section-alert,
|
||||
.point-table {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.toolbar-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -24,6 +24,17 @@
|
||||
</template>
|
||||
<template #operation="{ row }">
|
||||
<el-button link type="primary" :icon="View" @click="openDetailDialog(row)">详情</el-button>
|
||||
<el-button link type="primary" :disabled="!isReportTaskGeneratePending(row) || !row.pointCount" @click="openGroupDialog(row)">
|
||||
分组
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:disabled="!isReportTaskGeneratePending(row) || !row.groupCount"
|
||||
@click="handleGenerateGroupReports(row)"
|
||||
>
|
||||
生成报告
|
||||
</el-button>
|
||||
<el-button link type="primary" :icon="Edit" @click="openEditDialog(row)">编辑</el-button>
|
||||
<el-button link type="primary" :icon="Upload" @click="openAuditDialog(row)">提交审核</el-button>
|
||||
<el-button link type="danger" :icon="Delete" @click="handleDelete(row)">删除</el-button>
|
||||
@@ -50,6 +61,8 @@
|
||||
:group-reports="detailGroupReports"
|
||||
:company-label-map="companyLabelMap"
|
||||
:standard-label-map="standardLabelMap"
|
||||
:downloading-group-report-id="downloadingGroupReportId"
|
||||
@download-group-report="handleDownloadGroupReport"
|
||||
/>
|
||||
|
||||
<ReportTaskAuditDialog
|
||||
@@ -58,6 +71,15 @@
|
||||
:record="currentAuditRecord"
|
||||
@submit="handleSubmitAudit"
|
||||
/>
|
||||
|
||||
<ReportTaskGroupDialog
|
||||
v-model:visible="groupDialogVisible"
|
||||
:loading="groupDialogLoading"
|
||||
:saving="groupDialogSaving"
|
||||
:record="currentGroupRecord"
|
||||
:point-list="groupPointList"
|
||||
@submit="handleSaveGroups"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -71,10 +93,14 @@ import type { ColumnProps, ProTableInstance } from '@/components/ProTable/interf
|
||||
import {
|
||||
createReportTaskApi,
|
||||
deleteReportTasksApi,
|
||||
downloadReportTaskGroupReportApi,
|
||||
exportReportTasksApi,
|
||||
generateReportTaskGroupReportsApi,
|
||||
getReportTaskDetailApi,
|
||||
listReportTaskGroupReportsApi,
|
||||
listReportTaskPointsApi,
|
||||
listReportTasksApi,
|
||||
saveReportTaskGroupsApi,
|
||||
submitReportTaskAuditApi,
|
||||
updateReportTaskApi
|
||||
} from '@/api/aireport/testReport'
|
||||
@@ -88,6 +114,7 @@ import { useDictStore } from '@/stores/modules/dict'
|
||||
import ReportTaskAuditDialog from './components/ReportTaskAuditDialog.vue'
|
||||
import ReportTaskDetailDialog from './components/ReportTaskDetailDialog.vue'
|
||||
import ReportTaskFormDialog from './components/ReportTaskFormDialog.vue'
|
||||
import ReportTaskGroupDialog from './components/ReportTaskGroupDialog.vue'
|
||||
import {
|
||||
buildDictSelectOptions,
|
||||
buildOptionLabelMap,
|
||||
@@ -95,6 +122,7 @@ import {
|
||||
normalizeReportTaskGroupReportList,
|
||||
normalizeReportTaskListParams,
|
||||
normalizeReportTaskPage,
|
||||
normalizeReportTaskPointList,
|
||||
resolveReportTaskCreateUnitText,
|
||||
resolveReportTaskStandardText,
|
||||
resolveReportTaskText,
|
||||
@@ -110,17 +138,23 @@ const proTable = ref<ProTableInstance>()
|
||||
const formDialogVisible = ref(false)
|
||||
const detailDialogVisible = ref(false)
|
||||
const auditDialogVisible = ref(false)
|
||||
const groupDialogVisible = ref(false)
|
||||
const formSaving = ref(false)
|
||||
const formSaveSuccessVersion = ref(0)
|
||||
const detailLoading = ref(false)
|
||||
const auditSaving = ref(false)
|
||||
const groupDialogLoading = ref(false)
|
||||
const groupDialogSaving = ref(false)
|
||||
const formMode = ref<'create' | 'edit'>('create')
|
||||
const currentRecord = ref<ReportTask.ReportTaskRecord | null>(null)
|
||||
const detailRecord = ref<ReportTask.ReportTaskRecord | null>(null)
|
||||
const detailGroupReports = ref<ReportTask.ReportTaskGroupReportRecord[]>([])
|
||||
const currentAuditRecord = ref<ReportTask.ReportTaskRecord | null>(null)
|
||||
const currentGroupRecord = ref<ReportTask.ReportTaskRecord | null>(null)
|
||||
const groupPointList = ref<ReportTask.ReportTaskPointRecord[]>([])
|
||||
const clientUnitOptions = ref<Array<{ label: string; value: string }>>([])
|
||||
const reportModelOptions = ref<Array<{ label: string; value: string }>>([])
|
||||
const downloadingGroupReportId = ref('')
|
||||
|
||||
const companyOptions = computed(() => buildDictSelectOptions(dictStore.getDictData(DICT_CODES.TEST_REPORT_COMPANY)))
|
||||
const standardOptions = computed(() => buildDictSelectOptions(dictStore.getDictData(DICT_CODES.TEST_REPORT_STANDARD)))
|
||||
@@ -130,6 +164,7 @@ const requiredDictCodes = [DICT_CODES.TEST_REPORT_COMPANY, DICT_CODES.TEST_REPOR
|
||||
const currentSearchParams = computed(() =>
|
||||
normalizeReportTaskListParams((proTable.value?.searchParam || {}) as ReportTask.ReportTaskListParams)
|
||||
)
|
||||
const isReportTaskGeneratePending = (row: ReportTask.ReportTaskRecord) => Number(row.reportGenerateState ?? 0) === 0
|
||||
|
||||
const columns = reactive<ColumnProps<ReportTask.ReportTaskRecord>[]>([
|
||||
{ type: 'selection', fixed: 'left', width: 70 },
|
||||
@@ -191,7 +226,7 @@ const columns = reactive<ColumnProps<ReportTask.ReportTaskRecord>[]>([
|
||||
{ prop: 'createTime', label: '创建时间', minWidth: 170, render: ({ row }) => resolveReportTaskText(row.createTime) },
|
||||
{ prop: 'updateByName', label: '更新人', minWidth: 120, isShow: false, render: ({ row }) => resolveReportTaskText(row.updateByName || row.updateBy) },
|
||||
{ prop: 'updateTime', label: '更新时间', minWidth: 170, isShow: false, render: ({ row }) => resolveReportTaskText(row.updateTime) },
|
||||
{ prop: 'operation', label: '操作', fixed: 'right', width: 280 }
|
||||
{ prop: 'operation', label: '操作', fixed: 'right', width: 360 }
|
||||
])
|
||||
|
||||
const ensureReportTaskDictOptionsReady = async () => {
|
||||
@@ -297,6 +332,27 @@ const openEditDialog = async (row: ReportTask.ReportTaskRecord) => {
|
||||
}
|
||||
}
|
||||
|
||||
const loadDetailDialogData = async (id: string) => {
|
||||
const [detailResponse, groupReportsResponse] = await Promise.all([getReportTaskDetailApi(id), listReportTaskGroupReportsApi(id)])
|
||||
|
||||
detailRecord.value = unwrapReportTaskPayload<ReportTask.ReportTaskRecord>(detailResponse)
|
||||
detailGroupReports.value = normalizeReportTaskGroupReportList(groupReportsResponse)
|
||||
}
|
||||
|
||||
const refreshDetailDialogDataIfMatched = async (id: string) => {
|
||||
if (!detailDialogVisible.value) return
|
||||
|
||||
const currentDetailId = String(detailRecord.value?.id || '').trim()
|
||||
if (currentDetailId !== id) return
|
||||
|
||||
detailLoading.value = true
|
||||
try {
|
||||
await loadDetailDialogData(id)
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const openDetailDialog = async (row: ReportTask.ReportTaskRecord) => {
|
||||
if (!row.id) {
|
||||
ElMessage.warning('当前报告任务缺少 ID,无法查看详情')
|
||||
@@ -309,13 +365,7 @@ const openDetailDialog = async (row: ReportTask.ReportTaskRecord) => {
|
||||
detailLoading.value = true
|
||||
|
||||
try {
|
||||
const [detailResponse, groupReportsResponse] = await Promise.all([
|
||||
getReportTaskDetailApi(row.id),
|
||||
listReportTaskGroupReportsApi(row.id)
|
||||
])
|
||||
|
||||
detailRecord.value = unwrapReportTaskPayload<ReportTask.ReportTaskRecord>(detailResponse)
|
||||
detailGroupReports.value = normalizeReportTaskGroupReportList(groupReportsResponse)
|
||||
await loadDetailDialogData(row.id)
|
||||
} catch (error) {
|
||||
ElMessage.error(getReportTaskErrorMessage(error, '报告任务详情查询失败'))
|
||||
} finally {
|
||||
@@ -323,6 +373,33 @@ const openDetailDialog = async (row: ReportTask.ReportTaskRecord) => {
|
||||
}
|
||||
}
|
||||
|
||||
const openGroupDialog = async (row: ReportTask.ReportTaskRecord) => {
|
||||
if (!row.id) {
|
||||
ElMessage.warning('当前报告任务缺少 ID,无法维护分组')
|
||||
return
|
||||
}
|
||||
|
||||
if (!isReportTaskGeneratePending(row)) {
|
||||
ElMessage.warning('当前报告任务已生成过报告,不能再修改分组')
|
||||
return
|
||||
}
|
||||
|
||||
currentGroupRecord.value = row
|
||||
groupPointList.value = []
|
||||
groupDialogVisible.value = true
|
||||
groupDialogLoading.value = true
|
||||
|
||||
try {
|
||||
const response = await listReportTaskPointsApi(row.id)
|
||||
groupPointList.value = normalizeReportTaskPointList(response)
|
||||
} catch (error) {
|
||||
groupDialogVisible.value = false
|
||||
ElMessage.error(getReportTaskErrorMessage(error, '监测点列表查询失败'))
|
||||
} finally {
|
||||
groupDialogLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const openAuditDialog = (row: ReportTask.ReportTaskRecord) => {
|
||||
if (!row.id) {
|
||||
ElMessage.warning('当前报告任务缺少 ID,无法提交审核')
|
||||
@@ -368,6 +445,86 @@ const handleSubmitAudit = async (params: ReportTask.ReportTaskAuditRequest) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveGroups = async (params: ReportTask.ReportTaskGroupSaveRequest) => {
|
||||
const reportId = String(currentGroupRecord.value?.id || '').trim()
|
||||
if (!reportId) {
|
||||
ElMessage.warning('当前报告任务缺少 ID,无法保存分组')
|
||||
return
|
||||
}
|
||||
|
||||
groupDialogSaving.value = true
|
||||
try {
|
||||
await saveReportTaskGroupsApi(reportId, params)
|
||||
ElMessage.success('监测点分组保存成功')
|
||||
groupDialogVisible.value = false
|
||||
refreshReportTasks()
|
||||
await refreshDetailDialogDataIfMatched(reportId)
|
||||
} catch (error) {
|
||||
ElMessage.error(getReportTaskErrorMessage(error, '监测点分组保存失败'))
|
||||
} finally {
|
||||
groupDialogSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleGenerateGroupReports = async (row: ReportTask.ReportTaskRecord) => {
|
||||
if (!row.id) {
|
||||
ElMessage.warning('当前报告任务缺少 ID,无法生成报告')
|
||||
return
|
||||
}
|
||||
|
||||
if (!isReportTaskGeneratePending(row)) {
|
||||
ElMessage.warning('当前报告任务不是待生成状态,不能重复生成')
|
||||
return
|
||||
}
|
||||
|
||||
if (!row.groupCount) {
|
||||
ElMessage.warning('请先完成监测点分组后再生成报告')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm('将按当前分组生成所有报告,是否继续?', '生成报告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await generateReportTaskGroupReportsApi(row.id)
|
||||
ElMessage.success('报告生成任务已执行完成')
|
||||
refreshReportTasks()
|
||||
await refreshDetailDialogDataIfMatched(row.id)
|
||||
} catch (error) {
|
||||
ElMessage.error(getReportTaskErrorMessage(error, '报告生成失败'))
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownloadGroupReport = async (row: ReportTask.ReportTaskGroupReportRecord) => {
|
||||
const groupReportId = String(row.id || '').trim()
|
||||
if (!groupReportId) {
|
||||
ElMessage.warning('当前分组报告缺少 ID,无法下载')
|
||||
return
|
||||
}
|
||||
|
||||
downloadingGroupReportId.value = groupReportId
|
||||
try {
|
||||
await useDownloadWithServerFileName(
|
||||
() => downloadReportTaskGroupReportApi(groupReportId),
|
||||
row.reportFileName || row.reportName || `分组报告_${row.groupNo || ''}`,
|
||||
undefined,
|
||||
false,
|
||||
'.docx'
|
||||
)
|
||||
} catch (error) {
|
||||
ElMessage.error(getReportTaskErrorMessage(error, '分组报告下载失败'))
|
||||
} finally {
|
||||
downloadingGroupReportId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const deleteReportTasks = async (ids: string[], successMessage: string) => {
|
||||
if (!ids.length) {
|
||||
ElMessage.warning('请选择要删除的报告任务')
|
||||
|
||||
@@ -39,12 +39,14 @@ export const REPORT_TASK_FLOW_STEPS: ReportTaskFlowStepOption[] = [
|
||||
|
||||
export const createEmptyLedgerPreparedState = (): ReportTask.ReportTaskLedgerPreparedState => ({
|
||||
draftId: '',
|
||||
batchId: '',
|
||||
validateSessionId: '',
|
||||
validateResult: null,
|
||||
latestImportResult: null,
|
||||
snapshot: null,
|
||||
hasImported: false,
|
||||
validatedBatchId: '',
|
||||
pendingReimport: false,
|
||||
pendingRevalidate: false
|
||||
})
|
||||
|
||||
|
||||
@@ -145,9 +145,13 @@ export const normalizeReportTaskPointList = (
|
||||
export const normalizeReportTaskLedgerImportResult = (
|
||||
response:
|
||||
ResultData<ReportTask.ReportTaskLedgerImportResult> | ReportTask.ReportTaskLedgerImportResult | null | undefined
|
||||
| ResultData<ReportTask.ReportTaskLedgerValidateResult>
|
||||
| ReportTask.ReportTaskLedgerValidateResult
|
||||
): ReportTask.ReportTaskLedgerImportResult => {
|
||||
const payload = unwrapReportTaskPayload<ReportTask.ReportTaskLedgerImportResult | null | undefined>(
|
||||
response as ResultData<ReportTask.ReportTaskLedgerImportResult>
|
||||
const payload = unwrapReportTaskPayload<
|
||||
Partial<ReportTask.ReportTaskLedgerImportResult & ReportTask.ReportTaskLedgerValidateResult> | null | undefined
|
||||
>(
|
||||
response as ResultData<Partial<ReportTask.ReportTaskLedgerImportResult & ReportTask.ReportTaskLedgerValidateResult>>
|
||||
)
|
||||
|
||||
const stageList = Array.isArray(payload?.stages) ? payload.stages : []
|
||||
@@ -169,7 +173,7 @@ export const normalizeReportTaskLedgerImportResult = (
|
||||
clientReuseCount: payload?.clientReuseCount ?? 0,
|
||||
groupCount: payload?.groupCount ?? 0,
|
||||
failReasons: Array.isArray(payload?.failReasons) ? payload.failReasons.filter(Boolean) : [],
|
||||
stages: stageList.map(stage => ({
|
||||
stages: stageList.map((stage: ReportTask.ReportTaskLedgerImportStageRecord) => ({
|
||||
stage: stage?.stage || undefined,
|
||||
success: stage?.success ?? false,
|
||||
message: stage?.message || ''
|
||||
|
||||
Reference in New Issue
Block a user