2026-06-01 08:37:38 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="environmental-quality-container">
|
|
|
|
|
|
<!-- 搜索区域 -->
|
|
|
|
|
|
<a-form ref="formRef" :model="formState" layout="inline" class="search-form">
|
|
|
|
|
|
<a-space wrap>
|
|
|
|
|
|
<a-form-item label="所属基地" name="dataDimensionVal">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-select v-model:value="formState.dataDimensionVal" placeholder="请选择" style="width: 120px"
|
|
|
|
|
|
show-search :filter-option="filterBaseOption" option-filter-prop="label"
|
|
|
|
|
|
@change="handleBaseChange">
|
|
|
|
|
|
<a-select-option v-for="item in baseList" :key="item.baseid" :value="item.baseid"
|
|
|
|
|
|
:label="item.basename">
|
2026-06-01 08:37:38 +08:00
|
|
|
|
{{ item.basename }}
|
|
|
|
|
|
</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-form-item v-if="typeOne == 'all'" label="测站类型" name="dtinType">
|
|
|
|
|
|
<a-select v-model:value="formState.dtinType" placeholder="请选择" style="width: 120px" show-search
|
|
|
|
|
|
:filter-option="filterOption" option-filter-prop="label">
|
2026-06-03 17:10:34 +08:00
|
|
|
|
<a-select-option :value="''" label="全部">全部</a-select-option>
|
|
|
|
|
|
<a-select-option :value="'0'" label="自建水质站">自建水质站</a-select-option>
|
|
|
|
|
|
<a-select-option :value="'1'" label="国家水质站">国家水质站</a-select-option>
|
2026-06-01 08:37:38 +08:00
|
|
|
|
</a-select>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="时间维度" name="types">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-select v-model:value="formState.types" placeholder="请选择" style="width: 80px" show-search
|
|
|
|
|
|
:filter-option="filterOption" option-filter-prop="label">
|
2026-06-01 08:37:38 +08:00
|
|
|
|
<a-select-option value="year" label="年度">年度</a-select-option>
|
|
|
|
|
|
<a-select-option value="month" label="月度">月度</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="达标状态" name="sfdb">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-select v-model:value="formState.sfdb" placeholder="请选择" style="width: 100px" show-search
|
|
|
|
|
|
:filter-option="filterOption" option-filter-prop="label">
|
2026-06-01 08:37:38 +08:00
|
|
|
|
<a-select-option value="" label="全部">全部</a-select-option>
|
|
|
|
|
|
<a-select-option value="0" label="不达标">不达标</a-select-option>
|
|
|
|
|
|
<a-select-option value="1" label="达标">达标</a-select-option>
|
|
|
|
|
|
<a-select-option value="2" label="无目标等级/无数据">无目标等级/无数据</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="时间" name="dateValues">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-date-picker v-model:value="formState.dateValues"
|
|
|
|
|
|
:format="formState.types === 'month' ? 'YYYY-MM' : 'YYYY'" :picker="formState.types"
|
|
|
|
|
|
placeholder="请选择月份" style="width: 140px" :disabled-date="disabledMonthDate" />
|
|
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="断面名称" name="stnm">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-input v-model:value="formState.stnm" placeholder="请输入断面名称" style="width: 200px" allow-clear />
|
2026-06-01 08:37:38 +08:00
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item>
|
|
|
|
|
|
<a-space>
|
|
|
|
|
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
|
|
|
|
|
<a-button @click="handleReset">重置</a-button>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</a-form>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 图表和表格布局区域 -->
|
|
|
|
|
|
<div class="content-layout">
|
|
|
|
|
|
<!-- 左侧饼图区域 -->
|
|
|
|
|
|
<div class="chart-section">
|
|
|
|
|
|
<a-spin :spinning="pieLoading" tip="加载中...">
|
|
|
|
|
|
<div ref="pieChartRef" class="pie-chart-container"></div>
|
|
|
|
|
|
<div v-if="!showPieChart && !pieLoading" class="empty-overlay">
|
|
|
|
|
|
<a-empty description="暂无数据" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-spin>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧表格区域 -->
|
|
|
|
|
|
<div class="table-section">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<BasicTable ref="tableRef" :scrollY="360" :columns="columns" :list-url="wqGetKendoList"
|
|
|
|
|
|
:search-params="{ sort: sortConfig }" :transform-data="customTransform">
|
2026-06-01 08:37:38 +08:00
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
|
<!-- 操作列 -->
|
|
|
|
|
|
<template v-if="column.key === 'action'">
|
|
|
|
|
|
<a @click="handleViewDetail(record)" class="text-link">
|
|
|
|
|
|
查看详情
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</BasicTable>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 详情弹窗 -->
|
2026-06-02 14:52:44 +08:00
|
|
|
|
<a-modal v-model:open="detailModalVisible" :title="`${detailData.stnm || ''} 详细信息`" width="80%" :footer="null"
|
|
|
|
|
|
@cancel="handleDetailModalClose">
|
2026-06-03 17:10:34 +08:00
|
|
|
|
<HJMZDTwoLays :tc="{
|
|
|
|
|
|
stcd: detailData.stcd || '',
|
|
|
|
|
|
startTime: detailData.tm,
|
|
|
|
|
|
endTime: (typeof detailData.tm === 'string' ? detailData.tm.split(' ')[0] : dayjs(detailData.tm).format('YYYY-MM-DD')) + ' 23:59:59',
|
|
|
|
|
|
sfdb: formState.sfdb || ''
|
|
|
|
|
|
}" :calculateFlag="{ calculateFlag: 0 }" />
|
2026-06-01 08:37:38 +08:00
|
|
|
|
</a-modal>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-06-02 14:52:44 +08:00
|
|
|
|
import { ref, reactive, computed, onMounted, onBeforeUnmount, watch, nextTick, h } from 'vue'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
import { message } from 'ant-design-vue'
|
|
|
|
|
|
import * as echarts from 'echarts'
|
|
|
|
|
|
import dayjs, { Dayjs } from 'dayjs'
|
2026-06-02 14:52:44 +08:00
|
|
|
|
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
import BasicTable from '@/components/BasicTable/index.vue'
|
2026-06-02 14:52:44 +08:00
|
|
|
|
import { wqGetKendoList } from '@/api/sz'
|
|
|
|
|
|
import HJMZDTwoLays from "./HJMZDTwoLays.vue"
|
|
|
|
|
|
|
|
|
|
|
|
// 注册 dayjs 插件
|
|
|
|
|
|
dayjs.extend(isSameOrAfter)
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
// Props 定义
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
|
datas?: Array<{ baseid: string; basename: string }> // 基地列表
|
2026-06-02 14:52:44 +08:00
|
|
|
|
type?: string // 时间维度
|
2026-06-01 08:37:38 +08:00
|
|
|
|
modalData?: string // 模态框数据
|
|
|
|
|
|
dateValue?: string | Dayjs // 日期值
|
|
|
|
|
|
dataDimensionVal?: string // 数据维度值
|
|
|
|
|
|
buildType?: string | number // 建设类型
|
2026-06-02 14:52:44 +08:00
|
|
|
|
typeOne: string //区分基地和站点
|
|
|
|
|
|
baseid: string
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
|
|
// Refs
|
|
|
|
|
|
const formRef = ref()
|
|
|
|
|
|
const tableRef = ref()
|
|
|
|
|
|
const pieChartRef = ref<HTMLElement | null>(null)
|
|
|
|
|
|
let pieChartInstance: echarts.ECharts | null = null
|
|
|
|
|
|
|
|
|
|
|
|
// State
|
2026-06-02 14:52:44 +08:00
|
|
|
|
const baseid = ref(props.baseid || '')
|
|
|
|
|
|
const typeOne = ref(props.typeOne || '')
|
|
|
|
|
|
const originalMonth = ref<string>('') // 保存原始月份,用于年度切回月度时恢复
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const formState = reactive({
|
|
|
|
|
|
dataDimensionVal: props.dataDimensionVal || '',
|
2026-06-03 17:10:34 +08:00
|
|
|
|
dtinType: props.buildType.toString() || '',
|
2026-06-01 08:37:38 +08:00
|
|
|
|
types: props.type || 'month',
|
|
|
|
|
|
sfdb: '',
|
|
|
|
|
|
dateValues: props.dateValue ? (typeof props.dateValue === 'string' ? dayjs(props.dateValue, props.type === 'month' ? 'YYYY-MM' : 'YYYY') : props.dateValue) : dayjs(),
|
|
|
|
|
|
stnm: ''
|
|
|
|
|
|
})
|
2026-06-02 14:52:44 +08:00
|
|
|
|
const kong = ref(true)
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const baseList = computed(() => props.datas || [])
|
|
|
|
|
|
const pieLoading = ref(false)
|
|
|
|
|
|
const showPieChart = ref(true)
|
|
|
|
|
|
const pieCode = ref<string[]>([]) // 饼图选中的代码,用于过滤表格
|
2026-06-02 14:52:44 +08:00
|
|
|
|
const displayTotal = ref<number>(0) // 饼图中心显示的总数(动态更新)
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 弹窗相关
|
|
|
|
|
|
const detailModalVisible = ref(false)
|
|
|
|
|
|
const detailData = ref<any>({})
|
|
|
|
|
|
const mapModalVisible = ref(false)
|
|
|
|
|
|
const mapModalData = ref<any>({})
|
|
|
|
|
|
|
|
|
|
|
|
// 排序配置
|
|
|
|
|
|
const sortConfig = computed(() => [
|
|
|
|
|
|
{ field: 'rstcdStepSort', dir: 'asc' },
|
|
|
|
|
|
{ field: 'stnm', dir: 'asc' },
|
|
|
|
|
|
{ field: 'tm', dir: 'desc' }
|
|
|
|
|
|
])
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 自定义数据转换
|
|
|
|
|
|
const customTransform = (res: any) => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
records: res?.data?.data || [],
|
|
|
|
|
|
total: res?.data?.total || 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 计算断面名称合并信息
|
|
|
|
|
|
const getStnmMergeInfo = (records: any[]) => {
|
|
|
|
|
|
if (!records || records.length === 0) return {}
|
|
|
|
|
|
|
|
|
|
|
|
const mergeInfo: Record<number, { rowSpan: number }> = {}
|
|
|
|
|
|
let i = 0
|
|
|
|
|
|
|
|
|
|
|
|
while (i < records.length) {
|
|
|
|
|
|
const currentStnm = records[i].stnm
|
|
|
|
|
|
let rowSpan = 1
|
|
|
|
|
|
|
|
|
|
|
|
// 查找后续相同断面名称的行
|
|
|
|
|
|
let j = i + 1
|
|
|
|
|
|
while (j < records.length && records[j].stnm === currentStnm) {
|
|
|
|
|
|
rowSpan++
|
|
|
|
|
|
j++
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置第一行的 rowSpan
|
|
|
|
|
|
mergeInfo[i] = { rowSpan }
|
|
|
|
|
|
|
|
|
|
|
|
// 设置后续行的 rowSpan 为 0(隐藏)
|
|
|
|
|
|
for (let k = i + 1; k < j; k++) {
|
|
|
|
|
|
mergeInfo[k] = { rowSpan: 0 }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
i = j
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return mergeInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
// 表格列定义
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '日期',
|
|
|
|
|
|
dataIndex: 'tm',
|
|
|
|
|
|
key: 'tm',
|
|
|
|
|
|
width: 120,
|
|
|
|
|
|
customRender: ({ record }: any) => {
|
|
|
|
|
|
const date = record.tm
|
|
|
|
|
|
if (!date) return '-'
|
|
|
|
|
|
if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
|
|
|
|
return date
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeof date === 'string' && date.includes(' ')) {
|
|
|
|
|
|
return date.split(' ')[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
return date
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '断面名称',
|
|
|
|
|
|
dataIndex: 'stnm',
|
|
|
|
|
|
key: 'stnm',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
width: 180,
|
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
|
customCell: (record: any, rowIndex: number) => {
|
|
|
|
|
|
const tableData = tableRef.value?.tableData || []
|
|
|
|
|
|
const mergeInfo = getStnmMergeInfo(tableData)
|
|
|
|
|
|
return mergeInfo[rowIndex] || { rowSpan: 1 }
|
|
|
|
|
|
}
|
2026-06-01 08:37:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '测站类型',
|
|
|
|
|
|
dataIndex: 'sttypeName',
|
|
|
|
|
|
key: 'sttypeName',
|
|
|
|
|
|
width: 120
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '达标状态',
|
|
|
|
|
|
dataIndex: 'sfdbName',
|
|
|
|
|
|
key: 'sfdbName',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
width: 120,
|
|
|
|
|
|
customRender: ({ record }: any) => {
|
|
|
|
|
|
const sfdb = record.sfdbName
|
|
|
|
|
|
let color = '#000000'
|
|
|
|
|
|
|
|
|
|
|
|
if (sfdb === '达标') {
|
|
|
|
|
|
color = '#008000' // 达标 - 绿色
|
|
|
|
|
|
} else if (sfdb === '不达标') {
|
|
|
|
|
|
color = '#FF0000' // 不达标 - 红色
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return h('span', { style: { color } }, record.sfdbName || '-')
|
|
|
|
|
|
}
|
2026-06-01 08:37:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '水质要求',
|
|
|
|
|
|
dataIndex: 'wwqtgName',
|
|
|
|
|
|
key: 'wwqtgName',
|
|
|
|
|
|
width: 120
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '当前水质',
|
|
|
|
|
|
dataIndex: 'wqGrdName',
|
|
|
|
|
|
key: 'wqGrdName',
|
|
|
|
|
|
width: 120
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '去年同期水质',
|
|
|
|
|
|
dataIndex: 'beforeWqGrdName',
|
|
|
|
|
|
key: 'beforeWqGrdName',
|
|
|
|
|
|
width: 150
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
|
|
|
|
|
key: 'action',
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
fixed: 'right'
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用未来月份
|
|
|
|
|
|
const disabledMonthDate = (current: Dayjs) => {
|
|
|
|
|
|
if (!current) return false
|
|
|
|
|
|
const now = dayjs()
|
|
|
|
|
|
return current.isAfter(now, 'month')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 基地选择器搜索过滤函数
|
|
|
|
|
|
const filterBaseOption = (input: string, option: any) => {
|
|
|
|
|
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通用下拉框搜索过滤函数
|
|
|
|
|
|
const filterOption = (input: string, option: any) => {
|
|
|
|
|
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取饼图数据
|
|
|
|
|
|
const fetchPieData = async () => {
|
|
|
|
|
|
pieLoading.value = true
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 计算时间参数
|
|
|
|
|
|
const timeFormat = formState.types === 'month' ? 'YYYY-MM' : 'YYYY'
|
|
|
|
|
|
const startTime = formState.dateValues ? formState.dateValues.format(timeFormat) : ''
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
if (!startTime || !formState.dataDimensionVal) {
|
|
|
|
|
|
showPieChart.value = false
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建请求参数
|
|
|
|
|
|
const filters: any[] = [
|
2026-06-02 14:52:44 +08:00
|
|
|
|
formState.dataDimensionVal != 'all' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'baseId',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
value: typeOne.value == 'all' ? formState.dataDimensionVal : baseid.value
|
|
|
|
|
|
} : null,
|
2026-06-01 08:37:38 +08:00
|
|
|
|
formState.types === 'month' ? {
|
|
|
|
|
|
field: 'drMonth',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: startTime
|
|
|
|
|
|
} : {
|
|
|
|
|
|
field: 'drYear',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: startTime
|
|
|
|
|
|
},
|
2026-06-02 14:52:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
field: 'TYPE',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: 'DAY'
|
|
|
|
|
|
},
|
|
|
|
|
|
typeOne.value != 'all' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'rstcd',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.dataDimensionVal
|
|
|
|
|
|
} : null,
|
2026-06-02 14:52:44 +08:00
|
|
|
|
pieCode.value.length > 0 ? {
|
|
|
|
|
|
field: 'sfdb',
|
|
|
|
|
|
operator: 'in',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: pieCode.value
|
|
|
|
|
|
} : (formState.sfdb ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'sfdb',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.sfdb
|
2026-06-02 14:52:44 +08:00
|
|
|
|
} : null),
|
2026-06-01 08:37:38 +08:00
|
|
|
|
formState.stnm ? {
|
|
|
|
|
|
field: 'stnm',
|
|
|
|
|
|
operator: 'contains',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.stnm
|
|
|
|
|
|
} : null,
|
2026-06-02 14:52:44 +08:00
|
|
|
|
typeOne.value == 'all' && formState.dtinType != '' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'dtinType',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.dtinType
|
|
|
|
|
|
} : null
|
|
|
|
|
|
].filter(Boolean)
|
|
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
filter: {
|
|
|
|
|
|
logic: 'and',
|
|
|
|
|
|
filters
|
2026-06-02 14:52:44 +08:00
|
|
|
|
},
|
|
|
|
|
|
group: [
|
|
|
|
|
|
{
|
|
|
|
|
|
"dir": "des",
|
|
|
|
|
|
"field": "sfdb"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用API获取饼图数据
|
|
|
|
|
|
const res = await wqGetKendoList(params)
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
let data = res?.data?.data || res?.data || []
|
|
|
|
|
|
|
|
|
|
|
|
if (data.length === 0) {
|
2026-06-03 17:10:34 +08:00
|
|
|
|
// 销毁图表实例
|
|
|
|
|
|
if (pieChartInstance) {
|
|
|
|
|
|
pieChartInstance.dispose()
|
|
|
|
|
|
pieChartInstance = null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重置相关状态
|
|
|
|
|
|
displayTotal.value = 0
|
|
|
|
|
|
pieCode.value = []
|
2026-06-01 08:37:38 +08:00
|
|
|
|
showPieChart.value = false
|
2026-06-03 17:10:34 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 转换数据格式 - 为每个数据项设置对应颜色
|
|
|
|
|
|
const dataSource = data.map((item: any) => {
|
|
|
|
|
|
const name = item.keyName || 'null'
|
|
|
|
|
|
// 根据名称设置颜色:达标-绿色,不达标-红色,其他-灰色
|
|
|
|
|
|
let color = '#d9d9d9'
|
|
|
|
|
|
if (name === '达标') {
|
|
|
|
|
|
color = '#52c41a' // 绿色
|
|
|
|
|
|
} else if (name === '不达标') {
|
|
|
|
|
|
color = '#ff4d4f' // 红色
|
|
|
|
|
|
}
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
return {
|
|
|
|
|
|
name: name,
|
|
|
|
|
|
value: item.count,
|
|
|
|
|
|
key: item.keyName === '达标' ? 'DB_STATUS_1' : item.keyName === '不达标' ? 'DB_STATUS_0' : 'CURNODATA',
|
|
|
|
|
|
keyData: item?.key,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: color
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 使用所有数据项,包括"无数据"
|
|
|
|
|
|
const filteredDataSource = dataSource
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
if (filteredDataSource.length === 0) {
|
|
|
|
|
|
showPieChart.value = false
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
showPieChart.value = true
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
// 初始化或更新饼图
|
|
|
|
|
|
await nextTick()
|
|
|
|
|
|
initPieChart(filteredDataSource)
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取饼图数据失败:', error)
|
|
|
|
|
|
message.error('获取饼图数据失败')
|
|
|
|
|
|
showPieChart.value = false
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
pieLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化饼图
|
|
|
|
|
|
const initPieChart = (data: any[]) => {
|
|
|
|
|
|
if (!pieChartRef.value) return
|
|
|
|
|
|
|
|
|
|
|
|
// 如果实例已存在,先销毁
|
|
|
|
|
|
if (pieChartInstance) {
|
|
|
|
|
|
pieChartInstance.dispose()
|
|
|
|
|
|
pieChartInstance = null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pieChartInstance = echarts.init(pieChartRef.value)
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 计算总数并初始化 displayTotal
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const total = data.reduce((sum, item) => sum + item.value, 0)
|
2026-06-02 14:52:44 +08:00
|
|
|
|
displayTotal.value = total
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
formatter: '{b}: {c} 次 ({d}%)'
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
right: '10%',
|
|
|
|
|
|
top: '10%',
|
|
|
|
|
|
data: data.map(item => item.name)
|
|
|
|
|
|
},
|
|
|
|
|
|
title: [
|
|
|
|
|
|
{
|
2026-06-02 14:52:44 +08:00
|
|
|
|
text: displayTotal.value.toString(),
|
|
|
|
|
|
left: '39%',
|
|
|
|
|
|
top: '38%',
|
2026-06-01 08:37:38 +08:00
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 20,
|
|
|
|
|
|
fontWeight: 'bold',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
color: '#2f6b98'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
text: '监测总次数',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
left: '39%',
|
|
|
|
|
|
top: '44%',
|
2026-06-01 08:37:38 +08:00
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
textStyle: {
|
2026-06-02 14:52:44 +08:00
|
|
|
|
fontSize: 13,
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontWeight: '500'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
text: '(次)',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
left: '39%',
|
|
|
|
|
|
top: '49%',
|
2026-06-01 08:37:38 +08:00
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
textStyle: {
|
2026-06-02 14:52:44 +08:00
|
|
|
|
fontSize: 13,
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontWeight: '500'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '断面总数量',
|
|
|
|
|
|
type: 'pie',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
radius: ['25%', '35%'],
|
|
|
|
|
|
center: ['40%', '45%'],
|
2026-06-01 08:37:38 +08:00
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
borderRadius: 10,
|
|
|
|
|
|
borderColor: '#fff',
|
|
|
|
|
|
borderWidth: 2
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
2026-06-02 14:52:44 +08:00
|
|
|
|
formatter: '{b}'
|
2026-06-01 08:37:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
emphasis: {
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
fontWeight: 'bold'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data: data
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
pieChartInstance.setOption(option)
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 绑定点击事件 - 过滤表格数据
|
|
|
|
|
|
pieChartInstance.on('legendselectchanged', (params: any) => {
|
2026-06-02 14:52:44 +08:00
|
|
|
|
kong.value = false
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const selectedKeys = Object.keys(params.selected).filter(key => params.selected[key])
|
|
|
|
|
|
const allFalse = Object.values(params.selected).every(value => value === false)
|
2026-06-03 17:10:34 +08:00
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 动态计算当前显示的总数
|
|
|
|
|
|
if (allFalse) {
|
|
|
|
|
|
// 所有图例都取消选中,显示 0
|
|
|
|
|
|
displayTotal.value = 0
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 只统计被选中图例的数量总和
|
|
|
|
|
|
displayTotal.value = data
|
|
|
|
|
|
.filter(item => selectedKeys.includes(item.name))
|
|
|
|
|
|
.reduce((sum, item) => sum + item.value, 0)
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
2026-06-03 17:10:34 +08:00
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 局部更新 title 文本
|
|
|
|
|
|
pieChartInstance.setOption({
|
|
|
|
|
|
title: [
|
|
|
|
|
|
{
|
|
|
|
|
|
text: displayTotal.value.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
})
|
2026-06-03 17:10:34 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const selectedCodes = data
|
|
|
|
|
|
.filter(item => selectedKeys.includes(item.name))
|
|
|
|
|
|
.map(item => item.keyData)
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
pieCode.value = allFalse ? ['5'] : selectedCodes
|
|
|
|
|
|
// 刷新表格
|
|
|
|
|
|
handleSearch()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 基地变化处理
|
|
|
|
|
|
const handleBaseChange = () => {
|
|
|
|
|
|
formState.stnm = ''
|
|
|
|
|
|
handleSearch()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询处理
|
|
|
|
|
|
const handleSearch = () => {
|
|
|
|
|
|
const timeFormat = formState.types === 'month' ? 'YYYY-MM' : 'YYYY'
|
|
|
|
|
|
const startTime = formState.dateValues ? formState.dateValues.format(timeFormat) : ''
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// console.log( typeOne.value )
|
|
|
|
|
|
// console.log( formState.dtinType )
|
|
|
|
|
|
// console.log(typeOne.value == 'all' && formState.dtinType !='')
|
|
|
|
|
|
// debugger
|
2026-06-01 08:37:38 +08:00
|
|
|
|
const filters: any[] = [
|
2026-06-02 14:52:44 +08:00
|
|
|
|
formState.dataDimensionVal != 'all' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'baseId',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
2026-06-02 14:52:44 +08:00
|
|
|
|
value: typeOne.value == 'all' ? formState.dataDimensionVal : baseid.value
|
|
|
|
|
|
} : null,
|
2026-06-01 08:37:38 +08:00
|
|
|
|
formState.types === 'month' ? {
|
|
|
|
|
|
field: 'drMonth',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: startTime
|
|
|
|
|
|
} : {
|
|
|
|
|
|
field: 'drYear',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: startTime
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2026-06-02 14:52:44 +08:00
|
|
|
|
field: 'TYPE',
|
2026-06-01 08:37:38 +08:00
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: 'DAY'
|
|
|
|
|
|
},
|
2026-06-02 14:52:44 +08:00
|
|
|
|
typeOne.value != 'all' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'rstcd',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.dataDimensionVal
|
|
|
|
|
|
} : null,
|
|
|
|
|
|
pieCode.value.length > 0 ? {
|
|
|
|
|
|
field: 'sfdb',
|
|
|
|
|
|
operator: 'in',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: pieCode.value
|
|
|
|
|
|
} : (formState.sfdb ? {
|
|
|
|
|
|
field: 'sfdb',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.sfdb
|
|
|
|
|
|
} : null),
|
|
|
|
|
|
formState.stnm ? {
|
|
|
|
|
|
field: 'stnm',
|
|
|
|
|
|
operator: 'contains',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.stnm
|
|
|
|
|
|
} : null,
|
2026-06-02 14:52:44 +08:00
|
|
|
|
typeOne.value == 'all' && formState.dtinType != '' ? {
|
2026-06-01 08:37:38 +08:00
|
|
|
|
field: 'dtinType',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: formState.dtinType
|
|
|
|
|
|
} : null
|
|
|
|
|
|
].filter(Boolean)
|
|
|
|
|
|
|
|
|
|
|
|
const filter = {
|
|
|
|
|
|
logic: 'and',
|
|
|
|
|
|
filters
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新表格
|
|
|
|
|
|
tableRef.value?.getList(filter)
|
2026-06-02 14:52:44 +08:00
|
|
|
|
if (kong.value) {
|
|
|
|
|
|
// debugger
|
|
|
|
|
|
fetchPieData()
|
|
|
|
|
|
}
|
|
|
|
|
|
kong.value = true
|
|
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重置处理
|
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
|
formState.dataDimensionVal = props.dataDimensionVal || ''
|
|
|
|
|
|
formState.dtinType = ''
|
|
|
|
|
|
formState.types = props.type || 'month'
|
|
|
|
|
|
formState.sfdb = ''
|
|
|
|
|
|
formState.dateValues = dayjs()
|
|
|
|
|
|
formState.stnm = ''
|
|
|
|
|
|
pieCode.value = []
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
handleSearch()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查看详情
|
|
|
|
|
|
const handleViewDetail = (record: any) => {
|
|
|
|
|
|
detailData.value = { ...record }
|
|
|
|
|
|
detailModalVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 详情弹窗关闭
|
|
|
|
|
|
const handleDetailModalClose = () => {
|
|
|
|
|
|
detailModalVisible.value = false
|
|
|
|
|
|
detailData.value = {}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 地图弹窗关闭
|
|
|
|
|
|
const handleMapModalClose = () => {
|
|
|
|
|
|
mapModalVisible.value = false
|
|
|
|
|
|
mapModalData.value = {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 监听日期变化
|
2026-06-01 08:37:38 +08:00
|
|
|
|
watch(
|
2026-06-02 14:52:44 +08:00
|
|
|
|
() => formState.dateValues,
|
2026-06-01 08:37:38 +08:00
|
|
|
|
() => {
|
|
|
|
|
|
handleSearch()
|
2026-06-02 14:52:44 +08:00
|
|
|
|
}
|
2026-06-01 08:37:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-06-02 14:52:44 +08:00
|
|
|
|
// 监听 props.dataDimensionVal 变化,重置表单状态并重新加载数据
|
2026-06-01 08:37:38 +08:00
|
|
|
|
watch(
|
2026-06-02 14:52:44 +08:00
|
|
|
|
() => props.dataDimensionVal,
|
|
|
|
|
|
(newVal) => {
|
|
|
|
|
|
// 重置表单状态
|
|
|
|
|
|
formState.dataDimensionVal = newVal || ''
|
2026-06-03 17:10:34 +08:00
|
|
|
|
formState.dtinType = props.buildType.toString() || ''
|
2026-06-02 14:52:44 +08:00
|
|
|
|
formState.sfdb = ''
|
|
|
|
|
|
formState.stnm = ''
|
|
|
|
|
|
pieCode.value = []
|
|
|
|
|
|
// 重新加载数据
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
handleSearch()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听 props.type 变化,同步更新时间维度和日期格式
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.type,
|
|
|
|
|
|
(newType) => {
|
|
|
|
|
|
if (!newType || newType === formState.types) return
|
|
|
|
|
|
|
|
|
|
|
|
// 转换日期格式以匹配新的时间维度
|
|
|
|
|
|
const currentValue: any = formState.dateValues
|
|
|
|
|
|
if (currentValue) {
|
|
|
|
|
|
if (newType === 'year') {
|
|
|
|
|
|
// 切换到年度模式:保存当前月份
|
|
|
|
|
|
if (typeof currentValue.year === 'function') {
|
|
|
|
|
|
// dayjs 对象,保存月份
|
|
|
|
|
|
originalMonth.value = String(currentValue.month() + 1).padStart(2, '0')
|
|
|
|
|
|
const year = currentValue.year()
|
|
|
|
|
|
formState.dateValues = dayjs(String(year), 'YYYY')
|
|
|
|
|
|
} else if (typeof currentValue === 'string') {
|
|
|
|
|
|
// 字符串,提取并保存月份
|
|
|
|
|
|
const monthMatch = currentValue.match(/^(\d{4})-(\d{2})/)
|
|
|
|
|
|
if (monthMatch) {
|
|
|
|
|
|
originalMonth.value = monthMatch[2]
|
|
|
|
|
|
formState.dateValues = dayjs(monthMatch[1], 'YYYY')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const yearMatch = currentValue.match(/^(\d{4})/)
|
|
|
|
|
|
if (yearMatch) {
|
|
|
|
|
|
formState.dateValues = dayjs(yearMatch[1], 'YYYY')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (newType === 'month') {
|
|
|
|
|
|
// 切换到月度模式:恢复原来保存的月份
|
|
|
|
|
|
const monthToUse = originalMonth.value || '01'
|
|
|
|
|
|
if (typeof currentValue.year === 'function') {
|
|
|
|
|
|
const year = currentValue.year()
|
|
|
|
|
|
formState.dateValues = dayjs(`${year}-${monthToUse}`, 'YYYY-MM')
|
|
|
|
|
|
} else if (typeof currentValue === 'string') {
|
|
|
|
|
|
const yearMatch = currentValue.match(/^(\d{4})/)
|
|
|
|
|
|
if (yearMatch) {
|
|
|
|
|
|
formState.dateValues = dayjs(`${yearMatch[1]}-${monthToUse}`, 'YYYY-MM')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新时间维度
|
|
|
|
|
|
formState.types = newType
|
|
|
|
|
|
|
|
|
|
|
|
// 重新加载数据
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
handleSearch()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听 props.typeOne 变化,同步更新本地 state
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.typeOne,
|
|
|
|
|
|
(newVal) => {
|
|
|
|
|
|
typeOne.value = newVal
|
|
|
|
|
|
// debugger
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听 props.baseid 变化,同步更新本地 state
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.baseid,
|
|
|
|
|
|
(newVal) => {
|
|
|
|
|
|
baseid.value = newVal || ''
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听时间维度变化,自动转换日期格式
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => formState.types,
|
|
|
|
|
|
(newType, oldType) => {
|
|
|
|
|
|
if (!formState.dateValues || newType === oldType) return
|
|
|
|
|
|
// debugger
|
|
|
|
|
|
const currentValue: any = formState.dateValues
|
|
|
|
|
|
|
|
|
|
|
|
if (newType === 'year') {
|
|
|
|
|
|
// 从月度切换到年度:保存当前月份
|
|
|
|
|
|
if (currentValue && typeof currentValue.year === 'function') {
|
|
|
|
|
|
// dayjs 对象,保存月份
|
|
|
|
|
|
originalMonth.value = String(currentValue.month() + 1).padStart(2, '0')
|
|
|
|
|
|
const year = currentValue.year()
|
|
|
|
|
|
formState.dateValues = dayjs(String(year), 'YYYY')
|
|
|
|
|
|
} else if (typeof currentValue === 'string') {
|
|
|
|
|
|
// 字符串,提取并保存月份
|
|
|
|
|
|
const monthMatch = currentValue.match(/^(\d{4})-(\d{2})/)
|
|
|
|
|
|
if (monthMatch) {
|
|
|
|
|
|
originalMonth.value = monthMatch[2]
|
|
|
|
|
|
formState.dateValues = dayjs(monthMatch[1], 'YYYY')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const yearMatch = currentValue.match(/^(\d{4})/)
|
|
|
|
|
|
if (yearMatch) {
|
|
|
|
|
|
formState.dateValues = dayjs(yearMatch[1], 'YYYY')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (newType === 'month') {
|
|
|
|
|
|
// 从年度切换到月度:恢复原来保存的月份
|
|
|
|
|
|
const monthToUse = originalMonth.value || '01'
|
|
|
|
|
|
if (currentValue && typeof currentValue.year === 'function') {
|
|
|
|
|
|
const year = currentValue.year()
|
|
|
|
|
|
formState.dateValues = dayjs(`${year}-${monthToUse}`, 'YYYY-MM')
|
|
|
|
|
|
} else if (typeof currentValue === 'string') {
|
|
|
|
|
|
const yearMatch = currentValue.match(/^(\d{4})/)
|
|
|
|
|
|
if (yearMatch) {
|
|
|
|
|
|
formState.dateValues = dayjs(`${yearMatch[1]}-${monthToUse}`, 'YYYY-MM')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 日期格式转换后,重新获取数据
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
handleSearch()
|
|
|
|
|
|
})
|
2026-06-01 08:37:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
await nextTick()
|
|
|
|
|
|
handleSearch()
|
2026-06-02 14:52:44 +08:00
|
|
|
|
|
2026-06-01 08:37:38 +08:00
|
|
|
|
// 监听窗口resize
|
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
|
pieChartInstance?.resize()
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
|
pieChartInstance?.dispose()
|
|
|
|
|
|
pieChartInstance = null
|
|
|
|
|
|
window.removeEventListener('resize', () => {
|
|
|
|
|
|
pieChartInstance?.resize()
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 暴露方法给父组件
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
handleSearch
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.environmental-quality-container {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
|
|
|
|
.search-form {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 4px;
|
2026-06-03 17:10:34 +08:00
|
|
|
|
padding: 0px 0px 16px 0px;
|
2026-06-01 08:37:38 +08:00
|
|
|
|
|
|
|
|
|
|
:deep(.ant-space) {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-form-item) {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-layout {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.chart-section {
|
|
|
|
|
|
width: 35%;
|
|
|
|
|
|
min-width: 300px;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
.pie-chart-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 482px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-overlay {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.table-section {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.text-link {
|
|
|
|
|
|
color: #2f6b98;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
color: #40a9ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-content {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
max-height: 600px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
|
|
|
|
|
|
pre {
|
|
|
|
|
|
background: #f5f5f5;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-spin-nested-loading) {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-spin-container) {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
2026-06-02 14:52:44 +08:00
|
|
|
|
</style>
|