栖息地线上接口
This commit is contained in:
parent
cb484e32e1
commit
5d3e9820c8
41
frontend/src/api/qxd/index.ts
Normal file
41
frontend/src/api/qxd/index.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import request from '@/utils/request';
|
||||
//栖息地保护工作开展情况
|
||||
export function fhGetKendoListCust(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/env/fh/GetKendoListCust',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//获取所属栖息地
|
||||
export function msstbprptGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//水温监测数据
|
||||
export function sdrvwtsGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/base/sdrvwts/GetKendoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//水文监测
|
||||
export function sdriverdaysGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-swqx-server/zq/sdriverdays/GetKendoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//主要栖息地基本信息
|
||||
export function fhGetKendoListCustom(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/env/fh/GetKendoListCustom',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
@ -1143,7 +1143,7 @@ const FhPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '所属流域',
|
||||
filed: 'baseName',
|
||||
filed: 'hbrvcdName',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1179,7 +1179,7 @@ const FhPointColumns: Array<any> = [
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
name: '保护外围长度',
|
||||
name: '保护外围长度(km)',
|
||||
filed: 'gsmqcd',
|
||||
visible: true,
|
||||
type: 'number',
|
||||
@ -1210,14 +1210,14 @@ const FhPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '保护措施',
|
||||
filed: 'prottyp',
|
||||
filed: 'bhcs',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
name: '保护方式',
|
||||
filed: 'protmthd',
|
||||
filed: 'bhfs',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1228,6 +1228,7 @@ const FhPointColumns: Array<any> = [
|
||||
visible: true,
|
||||
type: 'number',
|
||||
url: '',
|
||||
toFixed: 3,
|
||||
},
|
||||
|
||||
|
||||
@ -1257,7 +1258,7 @@ const FhZQPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '所属流域',
|
||||
filed: 'baseName',
|
||||
filed: 'hbrvcdName',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1327,7 +1328,7 @@ const FPPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '所属流域',
|
||||
filed: 'baseName',
|
||||
filed: 'hbrvcdName',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1500,7 +1501,7 @@ const FBPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '所属流域',
|
||||
filed: 'baseName',
|
||||
filed: 'hbrvcdName',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1667,7 +1668,7 @@ const VaPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '所属流域',
|
||||
filed: 'baseName',
|
||||
filed: 'hbrvcdName',
|
||||
visible: true,
|
||||
type: 'select',
|
||||
url: '',
|
||||
@ -1728,7 +1729,7 @@ const VaPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '保护方式',
|
||||
filed: 'protmthd',
|
||||
filed: 'bhfs',
|
||||
visible: true,
|
||||
type: 'input',
|
||||
url: '',
|
||||
@ -1836,7 +1837,7 @@ const VPPointColumns: Array<any> = [
|
||||
},
|
||||
{
|
||||
name: '保护方式',
|
||||
filed: 'protmthd',
|
||||
filed: 'bhfs',
|
||||
visible: true,
|
||||
type: 'input',
|
||||
url: '',
|
||||
|
||||
@ -490,7 +490,7 @@ const FHTabs: Array<any> = [
|
||||
name: '基础信息',
|
||||
key: 'basicInfo',
|
||||
type: 'basic',
|
||||
url: '/bbi/siteBipc/getSiteBasicInfo',
|
||||
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
|
||||
default: true // 默认显示
|
||||
},
|
||||
{
|
||||
@ -591,31 +591,31 @@ const FHTabs: Array<any> = [
|
||||
name: '流量监测',
|
||||
key: 'FlowMeasure',
|
||||
type: 'FlowMeasure',
|
||||
tabs: [
|
||||
{
|
||||
url: '/wmp-eng-server/eng/river/GetKendoListCust',
|
||||
name: '流量',
|
||||
type: 'monitor',
|
||||
tableUrl: '/wmp-eng-server/eng/river/GetKendoListCust',
|
||||
chartType: 'line',
|
||||
// filter: NormalStcdFilter,
|
||||
filterProps: {
|
||||
params: {
|
||||
ftype: 'WE',
|
||||
sttp: 'ZQ',
|
||||
dataDimensionType: 'hyBase',
|
||||
dataDimensionVal: 'all',
|
||||
maptype: '2'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
// tabs: [
|
||||
// {
|
||||
// url: '/wmp-eng-server/eng/river/GetKendoListCust',
|
||||
// name: '流量',
|
||||
// type: 'monitor',
|
||||
// tableUrl: '/wmp-eng-server/eng/river/GetKendoListCust',
|
||||
// chartType: 'line',
|
||||
// // filter: NormalStcdFilter,
|
||||
// filterProps: {
|
||||
// params: {
|
||||
// ftype: 'WE',
|
||||
// sttp: 'ZQ',
|
||||
// dataDimensionType: 'hyBase',
|
||||
// dataDimensionVal: 'all',
|
||||
// maptype: '2'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
},
|
||||
{
|
||||
name: '实时视频',
|
||||
key: 'videoInfo',
|
||||
type: 'video',
|
||||
url: '/video/dataStcdFrame/getVideoMonitorList'
|
||||
url: ''
|
||||
}
|
||||
// {
|
||||
// name: "全景影像",
|
||||
@ -715,7 +715,7 @@ const FLOWTabs: Array<any> = [
|
||||
name: '基础信息',
|
||||
key: 'basicInfo',
|
||||
type: 'basic',
|
||||
url: '/bbi/siteBipc/getSiteBasicInfo',
|
||||
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
|
||||
default: true // 默认显示
|
||||
},
|
||||
{
|
||||
@ -1193,7 +1193,6 @@ const WATabs: Array<any> = [
|
||||
]
|
||||
// //mway : 1-是人工 , 2-是自动 dtinType: 0-自建 1-国家 2-人工
|
||||
const handleTabs = (modaldata: any) => {
|
||||
console.log('modaldata', modaldata);
|
||||
if (!modaldata?.sttp) return;
|
||||
const sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : '';
|
||||
console.log('sttp', sttp);
|
||||
@ -1205,7 +1204,12 @@ const handleTabs = (modaldata: any) => {
|
||||
case 'FH_WQ_POINT':
|
||||
return WQFBTabs;
|
||||
case 'FH_POINT':
|
||||
if (modaldata.show) {
|
||||
return FHTabs;
|
||||
}else{
|
||||
let FHTabsTwo = FHTabs.slice(0, 1);
|
||||
return FHTabsTwo;
|
||||
}
|
||||
case 'FH_ZQ_POINT':
|
||||
return FLOWTabs;
|
||||
case 'FP_POINT':
|
||||
|
||||
@ -17,9 +17,9 @@
|
||||
<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">
|
||||
<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="''" label="全部">全部</a-select-option>
|
||||
<a-select-option :value="'0'" label="自建水质站">自建水质站</a-select-option>
|
||||
<a-select-option :value="'1'" label="国家水质站">国家水质站</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
@ -92,15 +92,12 @@
|
||||
<!-- 详情弹窗 -->
|
||||
<a-modal v-model:open="detailModalVisible" :title="`${detailData.stnm || ''} 详细信息`" width="80%" :footer="null"
|
||||
@cancel="handleDetailModalClose">
|
||||
<HJMZDTwoLays
|
||||
:tc="{
|
||||
<HJMZDTwoLays :tc="{
|
||||
stcd: detailData.stcd || '',
|
||||
startTime:detailData.tm ,
|
||||
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 }"
|
||||
/>
|
||||
}" :calculateFlag="{ calculateFlag: 0 }" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
@ -142,7 +139,7 @@ const typeOne = ref(props.typeOne || '')
|
||||
const originalMonth = ref<string>('') // 保存原始月份,用于年度切回月度时恢复
|
||||
const formState = reactive({
|
||||
dataDimensionVal: props.dataDimensionVal || '',
|
||||
dtinType: props.buildType || '',
|
||||
dtinType: props.buildType.toString() || '',
|
||||
types: props.type || 'month',
|
||||
sfdb: '',
|
||||
dateValues: props.dateValue ? (typeof props.dateValue === 'string' ? dayjs(props.dateValue, props.type === 'month' ? 'YYYY-MM' : 'YYYY') : props.dateValue) : dayjs(),
|
||||
@ -400,7 +397,17 @@ const fetchPieData = async () => {
|
||||
let data = res?.data?.data || res?.data || []
|
||||
|
||||
if (data.length === 0) {
|
||||
// 销毁图表实例
|
||||
if (pieChartInstance) {
|
||||
pieChartInstance.dispose()
|
||||
pieChartInstance = null
|
||||
}
|
||||
|
||||
// 重置相关状态
|
||||
displayTotal.value = 0
|
||||
pieCode.value = []
|
||||
showPieChart.value = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -705,11 +712,11 @@ watch(
|
||||
(newVal) => {
|
||||
// 重置表单状态
|
||||
formState.dataDimensionVal = newVal || ''
|
||||
formState.dtinType = ''
|
||||
formState.dtinType = props.buildType.toString() || ''
|
||||
formState.sfdb = ''
|
||||
formState.stnm = ''
|
||||
pieCode.value = []
|
||||
|
||||
debugger
|
||||
// 重新加载数据
|
||||
nextTick(() => {
|
||||
handleSearch()
|
||||
|
||||
@ -456,7 +456,7 @@ const getEchartsData = async () => {
|
||||
baseid.value == 'all' ? {
|
||||
"field": "dtinType",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"value":tabs.value
|
||||
} : {
|
||||
"field": "rstcd",
|
||||
"operator": "isnotnull"
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="栖息地保护工作开展情况">
|
||||
<a-spin :spinning="loading" tip="加载中...">
|
||||
<div class="facility-grid">
|
||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card"
|
||||
@click="handleFacilityClick(facility)">
|
||||
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;">
|
||||
<div class="facility-icon">
|
||||
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i>
|
||||
@ -16,48 +18,120 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</SidePanelItem>
|
||||
<!-- 弹框 -->
|
||||
<a-modal v-model:open="modalVisible" :title="'水质监测工作开展情况'" :footer="null" width="1536px" @cancel="handleCloseModal">
|
||||
<QixidiheduanjianceqingkuangEJ v-if="currentFacility" :activeKey="currentFacility.sttpCode" :tabs="facilities"
|
||||
:baseId="baseid" />
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { fhGetKendoListCust } from '@/api/qxd'
|
||||
import QixidiheduanjianceqingkuangEJ from "./qixidiheduanjianceqingkuangEJ/index.vue"
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: 'qixidibaohugongzuokaizhanQK'
|
||||
});
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
// loading状态
|
||||
const loading = ref(false);
|
||||
// 设施数据
|
||||
const facilities = ref([
|
||||
{
|
||||
name: '栖息地',
|
||||
count: 56,
|
||||
icon: 'icon iconfont icon-qixidi'
|
||||
count: 0,
|
||||
icon: 'icon iconfont icon-qixidi',
|
||||
sttpCode: 'FH'
|
||||
},
|
||||
{
|
||||
name: '水温监测',
|
||||
count: 1722,
|
||||
icon: 'icon iconfont icon-diwenshuijianhuan'
|
||||
count: 0,
|
||||
icon: 'icon iconfont icon-diwenshuijianhuan',
|
||||
sttpCode: 'WTRV'
|
||||
},
|
||||
{
|
||||
name: '水文监测',
|
||||
count: 135,
|
||||
icon: 'icon iconfont icon-shuiwen-line'
|
||||
count: 0,
|
||||
icon: 'icon iconfont icon-shuiwen-line',
|
||||
sttpCode: 'ZQ'
|
||||
},
|
||||
{
|
||||
name: '视频监控',
|
||||
count: 135,
|
||||
icon: 'icon iconfont icon-shipinjiankongshebei'
|
||||
count: 0,
|
||||
icon: 'icon iconfont icon-shipinjiankongshebei',
|
||||
sttpCode: 'VD'
|
||||
},
|
||||
|
||||
]);
|
||||
const baseid = ref('')
|
||||
// 弹框相关状态
|
||||
const modalVisible = ref(false);
|
||||
const currentFacility = ref<any>(null);
|
||||
//获取页面数据
|
||||
const getData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
baseid.value != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": baseid.value
|
||||
} : null
|
||||
].filter(Boolean)
|
||||
},
|
||||
"group": [
|
||||
{
|
||||
"dir": "asc",
|
||||
"field": "sttpCode"
|
||||
}
|
||||
],
|
||||
"groupResultFlat": true
|
||||
}
|
||||
const res = await fhGetKendoListCust(params); //适配监控-VD
|
||||
let data = res?.data?.data || res?.data || [];
|
||||
|
||||
// 根据接口返回的数据更新 facilities 的 count
|
||||
facilities.value.forEach(facility => {
|
||||
const matchedItem = data.find(item => item.sttpCode === facility.sttpCode);
|
||||
if (matchedItem) {
|
||||
facility.count = matchedItem.count_sttpCode || 0;
|
||||
} else {
|
||||
facility.count = 0;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
// 点击处理函数
|
||||
const handleFacilityClick = (facility: any) => {
|
||||
currentFacility.value = facility;
|
||||
modalVisible.value = true;
|
||||
|
||||
|
||||
};
|
||||
// 关闭弹框
|
||||
const handleCloseModal = () => {
|
||||
modalVisible.value = false;
|
||||
currentFacility.value = null;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
|
||||
getData()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<div class="shuiwenjiancegongzwo-ej-container">
|
||||
<!-- Tab切换 -->
|
||||
<a-tabs v-model:activeKey="tabIndex" @change="handleTabChange">
|
||||
<a-tab-pane v-for="tab in tabs" :key="tab.sttpCode" :tab="tab.name" />
|
||||
</a-tabs>
|
||||
<!-- 搜索表单 -->
|
||||
<div class="search-form">
|
||||
<a-space size="middle">
|
||||
<div>所属基地:</div>
|
||||
<a-select v-model:value="searchData.baseId" placeholder="请选择所属基地" style="width: 200px" show-search
|
||||
:filter-option="filterOption" :options="jiDiList" @change="handleHydropowerStationChange" />
|
||||
<div>所属栖息地:</div>
|
||||
<a-select v-model:value="searchData.fhstcd" placeholder=" " style="width: 200px" allow-clear show-search
|
||||
:filter-option="filterOption" :options="stationOptions" />
|
||||
<a-input v-model:value="searchData.stnm" placeholder="请输入电站或设施名称" style="width: 200px" allow-clear />
|
||||
|
||||
<a-button type="primary" @click="handleSearch">查询</a-button>
|
||||
<a-tooltip title="重置">
|
||||
<a-button @click="handleReset">重置</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</div>
|
||||
<!-- 列表 -->
|
||||
<BasicTable ref="tableRef" :scrollY="360" :columns="columns" :list-url="fhGetKendoListCust"
|
||||
:search-params="{ sort: sortConfig }" :transform-data="customTransform">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'ennm'">
|
||||
<a @click="handleViewDetail(record, 'dz')" class="text-link">
|
||||
{{ record.ennm }}
|
||||
</a>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a @click="handleViewDetail(record, 'qxd')" class="text-link">
|
||||
查看详情
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { msstbprptGetKendoList, fhGetKendoListCust } from '@/api/qxd'
|
||||
import BasicTable from '@/components/BasicTable/index.vue'
|
||||
import { useModelStore } from "@/store/modules/model";
|
||||
|
||||
|
||||
// ==================== Props 定义 ====================
|
||||
const props = defineProps<{
|
||||
baseId?: string
|
||||
tabs?: any[]
|
||||
activeKey?: string
|
||||
}>()
|
||||
|
||||
// ==================== 状态管理 ====================
|
||||
const tabIndex = ref(props.activeKey || 'FH')
|
||||
const searchData = ref<any>({
|
||||
baseId: props.baseId || 'all',
|
||||
fhstcd: 'all',
|
||||
stnm: null
|
||||
})
|
||||
const modelStore = useModelStore();
|
||||
const tableRef = ref()
|
||||
const stationOptions: any = ref([])
|
||||
// ==================== 基地列表数据(硬编码) ====================
|
||||
const jiDiList: any = ref([
|
||||
{
|
||||
"value": "all",
|
||||
"label": "当前全部",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "01",
|
||||
"label": "金沙江干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "02",
|
||||
"label": "雅砻江干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "03",
|
||||
"label": "大渡河干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "04",
|
||||
"label": "乌江干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "05",
|
||||
"label": "长江上游干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "10",
|
||||
"label": "湘西",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "08",
|
||||
"label": "黄河上游干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "09",
|
||||
"label": "黄河中游干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "06",
|
||||
"label": "南盘江-红水河",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "12",
|
||||
"label": "东北",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "07",
|
||||
"label": "澜沧江干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "13",
|
||||
"label": "怒江干流",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "11",
|
||||
"label": "闽浙赣",
|
||||
|
||||
},
|
||||
{
|
||||
"value": "other",
|
||||
"label": "其他",
|
||||
|
||||
}
|
||||
])
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{
|
||||
key: 'stnm',
|
||||
title: '设施名称',
|
||||
dataIndex: 'stnm',
|
||||
width: '176px'
|
||||
},
|
||||
{
|
||||
key: 'baseName',
|
||||
title: '所在基地',
|
||||
dataIndex: 'baseName',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'ennm',
|
||||
title: '所属电站',
|
||||
dataIndex: 'ennm',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'fhstnm',
|
||||
title: '所属栖息地',
|
||||
dataIndex: 'fhstnm',
|
||||
width: '176px'
|
||||
},
|
||||
{
|
||||
key: 'ststdt',
|
||||
title: '开工日期',
|
||||
dataIndex: 'ststdt',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'esstdt',
|
||||
title: '建成日期',
|
||||
dataIndex: 'esstdt',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'mway',
|
||||
title: '监测方式',
|
||||
dataIndex: 'mway',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'vlsr',
|
||||
title: '数据接入来源',
|
||||
dataIndex: 'vlsr',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'hydrodtin_type',
|
||||
title: '数据接入类型',
|
||||
dataIndex: 'hydrodtinType',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'enable',
|
||||
title: '是否启用',
|
||||
dataIndex: 'enable',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
key: 'dtin',
|
||||
title: '是否接入',
|
||||
dataIndex: 'dtin',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 100,
|
||||
align: 'center' as const,
|
||||
fixed: 'right' as const
|
||||
}
|
||||
];
|
||||
// 排序配置
|
||||
const sortConfig = computed(() => [
|
||||
{
|
||||
"field": "baseStepSort",
|
||||
"dir": "asc"
|
||||
},
|
||||
{
|
||||
"field": "rvcdStepSort",
|
||||
"dir": "asc"
|
||||
},
|
||||
{
|
||||
"field": "rstcdStepSort",
|
||||
"dir": "asc"
|
||||
}
|
||||
])
|
||||
const handleTabChange = (key: string) => {
|
||||
console.log('【Tab切换】', key)
|
||||
tabIndex.value = key
|
||||
handleSearch()
|
||||
}
|
||||
const filterOption = (input: string, option: any) => {
|
||||
// 使用 options 属性时,option 是标准对象 { label, value }
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
//所属基地发生变化
|
||||
const handleHydropowerStationChange = (value: string) => {
|
||||
console.log('【水电站选择变化】', value)
|
||||
// 清空测站选择
|
||||
searchData.value.fhstcd = 'all'
|
||||
getselectTwo()
|
||||
}
|
||||
//获取栖息地
|
||||
const getselectTwo = async () => {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": tabIndex.value
|
||||
},
|
||||
searchData.value.baseId != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": searchData.value.baseId
|
||||
} : null
|
||||
].filter(Boolean)
|
||||
},
|
||||
"select": [
|
||||
"stcd",
|
||||
"stnm"
|
||||
]
|
||||
}
|
||||
let res = await msstbprptGetKendoList(params)
|
||||
console.log('【获取栖息地】', res)
|
||||
stationOptions.value = []
|
||||
if (res?.data?.data.length > 0) {
|
||||
stationOptions.value = res.data.data.map((item: any) => {
|
||||
return {
|
||||
label: item.stnm,
|
||||
value: item.stcd
|
||||
}
|
||||
})
|
||||
}
|
||||
stationOptions.value.unshift({
|
||||
label: '当前全部',
|
||||
value: 'all'
|
||||
})
|
||||
}
|
||||
const handleSearch = () => {
|
||||
console.log('【搜索】', searchData.value)
|
||||
const filters: any[] = [
|
||||
searchData.value.baseId != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"value": "01"
|
||||
} : null,
|
||||
searchData.value.fhstcd != 'all' ? {
|
||||
"field": "fhstcd",
|
||||
"operator": "eq",
|
||||
"value": searchData.value.fhstcd
|
||||
} : null,
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "eq",
|
||||
"value": tabIndex.value
|
||||
},
|
||||
searchData.value.stnm ? {
|
||||
"logic": "or",
|
||||
"filters": [
|
||||
{
|
||||
"field": "stnm",
|
||||
"operator": "contains",
|
||||
"value": searchData.value.stnm
|
||||
},
|
||||
{
|
||||
"field": "ennm",
|
||||
"operator": "contains",
|
||||
"value": searchData.value.stnm
|
||||
}
|
||||
]
|
||||
} : null
|
||||
].filter(Boolean)
|
||||
|
||||
const filter = {
|
||||
logic: 'and',
|
||||
filters
|
||||
}
|
||||
// 刷新表格
|
||||
tableRef.value?.getList(filter)
|
||||
}
|
||||
const handleReset = () => {
|
||||
console.log('【重置】')
|
||||
searchData.value = {
|
||||
baseId: 'all',
|
||||
fhstcd: 'all',
|
||||
stnm: null
|
||||
}
|
||||
handleSearch()
|
||||
}
|
||||
// 自定义数据转换
|
||||
const customTransform = (res: any) => {
|
||||
return {
|
||||
records: res?.data?.data || [],
|
||||
total: res?.data?.total || 0
|
||||
}
|
||||
}
|
||||
// 查看详情
|
||||
const handleViewDetail = (record: any, type: any) => {
|
||||
console.log(tabIndex.value)
|
||||
debugger
|
||||
if (type == 'dz') {
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "ENG";
|
||||
modelStore.title = record.ennm + " 详情信息";
|
||||
modelStore.params.stcd = record.rstcd;
|
||||
} else {
|
||||
|
||||
if (tabIndex.value == 'FH') {
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "fh_point";
|
||||
modelStore.title = record.stnm + " 详情信息";
|
||||
modelStore.params.stcd = record.stcd;
|
||||
modelStore.params.show = false
|
||||
} else if (tabIndex.value == 'WTRV') {
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "wt_point";
|
||||
modelStore.title = record.stnm + " 详情信息";
|
||||
modelStore.params.stcd = record.stcd;
|
||||
} else if (tabIndex.value == 'ZQ') {
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "fh_zq_point";
|
||||
modelStore.title = record.stnm + " 详情信息";
|
||||
modelStore.params.stcd = record.stcd;
|
||||
} else if (tabIndex.value == 'VD') {
|
||||
// modelStore.modalVisible = true;
|
||||
// modelStore.params.sttp = "fh_zq_point";
|
||||
// modelStore.title = record.stnm + " 详情信息";
|
||||
// modelStore.params.stcd = record.stcd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// ==================== 生命周期 ====================
|
||||
onMounted(() => {
|
||||
getselectTwo()
|
||||
handleSearch()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.shuiwenjiancegongzwo-ej-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #ffffff;
|
||||
box-sizing: border-box;
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-table-wrapper) {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: #2f6b98;
|
||||
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,9 +1,9 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="主要栖息地基本信息" :select="select">
|
||||
<SidePanelItem title="主要栖息地基本信息" :select="select" @update-values="handlePanelChange1">
|
||||
<div class="table-container">
|
||||
<a-table :columns="columns" :data-source="tableData" :pagination="pagination" :scroll="{ y: 450 }"
|
||||
size="small">
|
||||
<a-table :columns="columns" :data-source="tableData" :pagination="pagination" :scroll="{ y: 420 }"
|
||||
:loading="loading" size="small" @change="handleTableChange">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<!-- 仅栖息地列需要自定义渲染 -->
|
||||
<template v-if="column.key === 'fhstnm'">
|
||||
@ -26,22 +26,91 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { fhGetKendoListCustom } from '@/api/qxd';
|
||||
import { useModelStore } from "@/store/modules/model";
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: 'qixidijchuXx'
|
||||
});
|
||||
|
||||
// ==================== 响应式变量定义 ====================
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
// ==================== 基地列表数据(硬编码) ====================
|
||||
const jiDiList: any = ref([
|
||||
{
|
||||
"value": "all",
|
||||
"label": "当前全部",
|
||||
},
|
||||
{
|
||||
"value": "01",
|
||||
"label": "金沙江干流",
|
||||
},
|
||||
{
|
||||
"value": "02",
|
||||
"label": "雅砻江干流",
|
||||
},
|
||||
{
|
||||
"value": "03",
|
||||
"label": "大渡河干流",
|
||||
},
|
||||
{
|
||||
"value": "04",
|
||||
"label": "乌江干流",
|
||||
},
|
||||
{
|
||||
"value": "05",
|
||||
"label": "长江上游干流",
|
||||
},
|
||||
{
|
||||
"value": "10",
|
||||
"label": "湘西",
|
||||
},
|
||||
{
|
||||
"value": "08",
|
||||
"label": "黄河上游干流",
|
||||
},
|
||||
{
|
||||
"value": "09",
|
||||
"label": "黄河中游干流",
|
||||
},
|
||||
{
|
||||
"value": "06",
|
||||
"label": "南盘江-红水河",
|
||||
},
|
||||
{
|
||||
"value": "12",
|
||||
"label": "东北",
|
||||
},
|
||||
{
|
||||
"value": "07",
|
||||
"label": "澜沧江干流",
|
||||
},
|
||||
{
|
||||
"value": "13",
|
||||
"label": "怒江干流",
|
||||
},
|
||||
{
|
||||
"value": "11",
|
||||
"label": "闽浙赣",
|
||||
},
|
||||
{
|
||||
"value": "other",
|
||||
"label": "其他",
|
||||
}
|
||||
])
|
||||
const select = ref({
|
||||
show: true,
|
||||
value: undefined,
|
||||
options: [],
|
||||
value: 'all',
|
||||
options: jiDiList.value,
|
||||
picker: undefined,
|
||||
format: undefined
|
||||
})
|
||||
|
||||
const baseid = ref('');
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
const modelStore = useModelStore();
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
@ -83,11 +152,16 @@ const columns = [
|
||||
]
|
||||
|
||||
// 分页配置
|
||||
const pagination = {
|
||||
const pagination = ref({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
size: 'small',
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条`,
|
||||
showSizeChanger: false
|
||||
}
|
||||
pageSizeOptions: ['10', '20', '50', '100']
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const tableData = ref(
|
||||
@ -259,12 +333,76 @@ const formatValue = (value: any): string => {
|
||||
return value === null || value === undefined || value === '' ? '-' : String(value);
|
||||
}
|
||||
|
||||
// 点击事件处理(预留功能)
|
||||
// 点击事件处理(预留功能)
|
||||
const handleHabitatClick = (record: any) => {
|
||||
console.log('点击栖息地:', record)
|
||||
// TODO: 后续实现具体功能
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "fh_point";
|
||||
modelStore.title = record.stnm + " 详情信息";
|
||||
modelStore.params.stcd = record.stcd;
|
||||
modelStore.params.show = true;
|
||||
}
|
||||
|
||||
// 分页变化处理
|
||||
const handleTableChange = (pag: any, filters: any, sorter: any) => {
|
||||
pagination.value.current = pag.current
|
||||
pagination.value.pageSize = pag.pageSize
|
||||
gettableData(baseid.value)
|
||||
}
|
||||
|
||||
const gettableData = async (basid: any) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
let params = {
|
||||
"take": pagination.value.pageSize,
|
||||
"skip": (pagination.value.current - 1) * pagination.value.pageSize,
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
basid != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": basid
|
||||
} : null,
|
||||
].filter(Boolean),
|
||||
}
|
||||
}
|
||||
let res = await fhGetKendoListCustom(params)
|
||||
|
||||
// 数据处理
|
||||
if (res?.data) {
|
||||
tableData.value = res.data.data || []
|
||||
pagination.value.total = res.data.total || 0
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
// 重置分页到第一页
|
||||
pagination.value.current = 1
|
||||
gettableData(newVal.wbsCode)
|
||||
if (newVal.wbsCode != 'all') {
|
||||
select.value.show = false
|
||||
} else {
|
||||
select.value.show = true
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
const handlePanelChange1 = async (data) => {
|
||||
if (data.select) {
|
||||
// 重置分页到第一页
|
||||
pagination.value.current = 1
|
||||
gettableData(data.select)
|
||||
}
|
||||
}
|
||||
// 页面加载时执行
|
||||
onMounted(() => {
|
||||
// 延迟初始化,确保容器已渲染
|
||||
|
||||
@ -1,24 +1,41 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="水文监测" :select="select" :scopeDate="datetimePicker" >
|
||||
<div class="chart-container">
|
||||
<SidePanelItem title="水文监测" :select="select" :scopeDate="datetimePicker" @update-values="handlePanelChange1">
|
||||
<div class="chart-wrapper">
|
||||
<a-spin :spinning="loading">
|
||||
<!-- 始终渲染图表容器,确保有固定宽高 -->
|
||||
<div ref="chartRef" class="echarts-chart"></div>
|
||||
<!-- 无数据时显示Empty,但不影响容器尺寸 -->
|
||||
<div v-if="!loading && !hasData" class="empty-overlay">
|
||||
<a-empty description="暂无数据" />
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { msstbprptGetKendoList, sdriverdaysGetKendoList } from '@/api/qxd';
|
||||
import { useModelStore } from "@/store/modules/model";
|
||||
// 定义组件名
|
||||
defineOptions({
|
||||
name: 'qixidiliuliangbianhua'
|
||||
});
|
||||
|
||||
// ==================== 选择器配置 ====================
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
const baseid = ref('')
|
||||
const modelStore = useModelStore();
|
||||
|
||||
// Loading 状态和数据状态
|
||||
const loading = ref(false);
|
||||
const hasData = ref(true); // 初始化为 true,因为 initChart 时会渲染
|
||||
|
||||
const select = ref({
|
||||
show: true,
|
||||
value: undefined,
|
||||
@ -27,7 +44,7 @@ const select = ref({
|
||||
format: undefined
|
||||
});
|
||||
// 日期选择器配置
|
||||
const datetimePicker = ref({
|
||||
const datetimePicker: any = ref({
|
||||
show: true,
|
||||
value: (() => {
|
||||
const now = new Date();
|
||||
@ -45,21 +62,8 @@ const datetimePicker = ref({
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
|
||||
// 模拟图表数据(水温监测 - 12个月)
|
||||
const echartsData = ref<any[]>([
|
||||
{ dt: '2024-01', wt: 8.5, q: 120.5, z: 45.2 },
|
||||
{ dt: '2024-02', wt: 9.2, q: 135.8, z: 46.1 },
|
||||
{ dt: '2024-03', wt: 12.8, q: 180.3, z: 47.5 },
|
||||
{ dt: '2024-04', wt: 16.3, q: 220.6, z: 48.8 },
|
||||
{ dt: '2024-05', wt: 20.5, q: 280.2, z: 50.3 },
|
||||
{ dt: '2024-06', wt: 24.8, q: 350.5, z: 52.1 },
|
||||
{ dt: '2024-07', wt: 28.3, q: 420.8, z: 53.6 },
|
||||
{ dt: '2024-08', wt: 27.5, q: 390.3, z: 52.9 },
|
||||
{ dt: '2024-09', wt: 23.2, q: 310.7, z: 51.2 },
|
||||
{ dt: '2024-10', wt: 18.6, q: 240.5, z: 49.5 },
|
||||
{ dt: '2024-11', wt: 13.4, q: 165.2, z: 47.8 },
|
||||
{ dt: '2024-12', wt: 9.8, q: 130.6, z: 46.3 }
|
||||
]);
|
||||
// 图表数据(初始为空数组)
|
||||
const echartsData = ref<any[]>([]);
|
||||
|
||||
// 图表配置引用(用于 legendselectchanged 时读取最新配置)
|
||||
const echartOptionRef = ref<EChartsOption>({});
|
||||
@ -93,7 +97,7 @@ const yAxisShowDynamic = (selected: Record<string, boolean>, options: any) => {
|
||||
// 只有一个Y轴:统一置于左侧
|
||||
if (showCount === 1) {
|
||||
options.grid = omit(options.grid, 'right');
|
||||
options.grid.left = '80px';
|
||||
options.grid.left = '60px';
|
||||
|
||||
options.yAxis = options.yAxis.map((item: any) => {
|
||||
if (item.show) {
|
||||
@ -122,7 +126,7 @@ const yAxisShowDynamic = (selected: Record<string, boolean>, options: any) => {
|
||||
if (leftIndex === 0) {
|
||||
leftIndex++;
|
||||
options.grid = omit(options.grid, 'right');
|
||||
options.grid.left = '80px';
|
||||
options.grid.left = '60px';
|
||||
|
||||
return {
|
||||
...item,
|
||||
@ -168,24 +172,27 @@ const initChart = () => {
|
||||
chartInstance.on('legendselectchanged', (params: any) => {
|
||||
const { selected } = params;
|
||||
|
||||
// 深拷贝当前配置
|
||||
const options = JSON.parse(JSON.stringify(echartOptionRef.value));
|
||||
// ✅ 方案A:手动构建新配置对象,保留所有函数引用(包括formatter)
|
||||
const currentOptions = echartOptionRef.value as any;
|
||||
|
||||
// 同步图例选中状态
|
||||
options.legend.selected = selected;
|
||||
|
||||
// 根据图例状态更新 Y 轴显隐
|
||||
const newYAxis = options.yAxis.map((item: any) => {
|
||||
const options: any = {
|
||||
...currentOptions,
|
||||
legend: {
|
||||
...currentOptions.legend,
|
||||
selected: selected
|
||||
},
|
||||
yAxis: Array.isArray(currentOptions.yAxis)
|
||||
? currentOptions.yAxis.map((item: any) => {
|
||||
let isShow = true;
|
||||
for (const key in selected) {
|
||||
if (key === item.name) {
|
||||
isShow = selected[key];
|
||||
}
|
||||
}
|
||||
return { ...item, show: isShow };
|
||||
});
|
||||
|
||||
options.yAxis = newYAxis;
|
||||
return { ...item, show: isShow }; // ✅ 保留formatter等函数
|
||||
})
|
||||
: currentOptions.yAxis
|
||||
};
|
||||
|
||||
// 触发布局调整
|
||||
yAxisShowDynamic(selected, options);
|
||||
@ -197,12 +204,13 @@ const initChart = () => {
|
||||
|
||||
// 监听数据点点击事件
|
||||
chartInstance.on('click', (params: any) => {
|
||||
console.log('点击数据点:', {
|
||||
date: params.name,
|
||||
seriesName: params.seriesName,
|
||||
value: params.value
|
||||
});
|
||||
// TODO: 可扩展为打开详情弹窗
|
||||
// ✅ 判断是否点击的是数据点(series中的点)
|
||||
if (params.componentType === 'series') {
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "fh_zq_point";
|
||||
modelStore.title = "水文监测";
|
||||
modelStore.params.stcd = select.value.value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -210,10 +218,22 @@ const initChart = () => {
|
||||
const updateChart = () => {
|
||||
if (!chartInstance) return;
|
||||
|
||||
// 单位和颜色配置(可根据实际需求从配置系统获取)
|
||||
const Color = ['#5470c6', '#91cc75', '#fac858'];
|
||||
// ✅ 计算数据统计值(用于Y轴动态范围)
|
||||
const qValues = echartsData.value.map(item => item.q).filter(v => v != null && !isNaN(v));
|
||||
const zValues = echartsData.value.map(item => item.z).filter(v => v != null && !isNaN(v));
|
||||
const vValues = echartsData.value.map(item => item.v).filter(v => v != null && !isNaN(v));
|
||||
|
||||
const _legendData = ['水温(℃)', '流量(m³/s)', '水位(m)'];
|
||||
const minQ = qValues.length > 0 ? Math.min(...qValues) : 0;
|
||||
const maxQ = qValues.length > 0 ? Math.max(...qValues) : 0;
|
||||
const minZ = zValues.length > 0 ? Math.min(...zValues) : 0;
|
||||
const maxZ = zValues.length > 0 ? Math.max(...zValues) : 0;
|
||||
const minV = vValues.length > 0 ? Math.min(...vValues) : 0;
|
||||
const maxV = vValues.length > 0 ? Math.max(...vValues) : 0;
|
||||
|
||||
// ✅ 颜色和Y轴配置
|
||||
const Color = ['#9556a4', '#56c2e3', '#78c300'];
|
||||
|
||||
const _legendData = ['流量(m³/s)', '水位(m)', '流速(m/s)'];
|
||||
|
||||
const setting: EChartsOption = {
|
||||
// Tooltip 配置
|
||||
@ -231,17 +251,20 @@ const updateChart = () => {
|
||||
const seriesName = item.seriesName ?? '';
|
||||
const regx = /\(([^()]+?)\)/;
|
||||
const unit = seriesName.match(regx);
|
||||
const finalValue = item.value !== undefined && item.value !== null ? item.value : '-';
|
||||
|
||||
if (item.value !== undefined && item.value !== null) {
|
||||
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%; display: inline-block; margin-right:10px;"></span>${item.seriesName} ${finalValue}${unit?.[1] || ''}<br/>`;
|
||||
// ✅ 保留两位小数
|
||||
const formattedValue = Number(item.value).toFixed(2);
|
||||
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%; display: inline-block; margin-right:10px;"></span>${item.seriesName} ${formattedValue}${unit?.[1] || ''}<br/>`;
|
||||
} else {
|
||||
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%; display: inline-block; margin-right:10px;"></span>${item.seriesName} -${unit?.[1] || ''}<br/>`;
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
},
|
||||
|
||||
// 颜色配置
|
||||
// ✅ 颜色配置:流量-紫色,水位-青色,流速-绿色
|
||||
color: Color,
|
||||
|
||||
// 图例配置
|
||||
@ -253,8 +276,8 @@ const updateChart = () => {
|
||||
itemGap: 15,
|
||||
// 默认只选中"水温",其他系列隐藏
|
||||
selected: {
|
||||
'水温(℃)': true,
|
||||
'流量(m³/s)': false,
|
||||
'流速(m/s)': false,
|
||||
'流量(m³/s)': true,
|
||||
'水位(m)': false
|
||||
}
|
||||
},
|
||||
@ -288,7 +311,17 @@ const updateChart = () => {
|
||||
data: echartsData.value.map(item => item.dt),
|
||||
boundaryGap: true,
|
||||
axisLabel: {
|
||||
show: true
|
||||
show: true,
|
||||
// ✅ X轴标签显示策略:最多显示5个标签,强制显示首尾
|
||||
interval: (index: number) => {
|
||||
const total = echartsData.value.length;
|
||||
if (total <= 5) return true; // 数据少于等于5个,全部显示
|
||||
if (index === 0 || index === total - 1) return true; // 首尾必显
|
||||
|
||||
// 中间标签均匀分布
|
||||
const step = Math.floor((total - 1) / 3); // 中间显示3个
|
||||
return index % step === 0;
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: true
|
||||
@ -308,14 +341,17 @@ const updateChart = () => {
|
||||
}
|
||||
},
|
||||
|
||||
// Y轴配置 - 三个独立Y轴
|
||||
// Y轴配置 - 三个独立Y轴(按期望顺序:流量、水位、流速)
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '水温(℃)',
|
||||
name: '流量(m³/s)',
|
||||
position: 'left',
|
||||
offset: 0,
|
||||
show: true,
|
||||
// ✅ 动态范围:floor(min) ~ ceil(max)+5
|
||||
min: qValues.length > 0 ? Math.floor(minQ) : undefined,
|
||||
max: qValues.length > 0 ? Math.ceil(maxQ) : undefined,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
@ -329,7 +365,7 @@ const updateChart = () => {
|
||||
axisLabel: {
|
||||
show: true,
|
||||
formatter: '{value}',
|
||||
color: '#5470c6'
|
||||
color: '#9556a4'
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
@ -339,51 +375,28 @@ const updateChart = () => {
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#5470c6',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '流量(m³/s)',
|
||||
position: 'left',
|
||||
offset: 60,
|
||||
show: false,
|
||||
splitLine: { show: false },
|
||||
axisTick: {
|
||||
show: true
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
formatter: '{value}',
|
||||
color: '#91cc75'
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#6e7079',
|
||||
width: 2
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#91cc75',
|
||||
color: '#9556a4',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '水位(m)',
|
||||
position: 'right',
|
||||
offset: 0,
|
||||
position: 'left',
|
||||
offset: 60,
|
||||
show: false,
|
||||
// ✅ 动态范围:min-0.01 ~ max+0.04
|
||||
min: zValues.length > 0 ? minZ : undefined,
|
||||
max: zValues.length > 0 ? maxZ : undefined,
|
||||
splitLine: { show: false },
|
||||
axisTick: {
|
||||
show: true
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
formatter: '{value}',
|
||||
color: '#fac858'
|
||||
// ✅ Y轴刻度保留两位小数(使用函数形式)
|
||||
formatter: (value: any) => value.toFixed(2),
|
||||
color: '#56c2e3'
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
@ -393,62 +406,94 @@ const updateChart = () => {
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#fac858',
|
||||
color: '#56c2e3',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '流速(m/s)',
|
||||
position: 'right',
|
||||
offset: 0,
|
||||
show: false,
|
||||
// ✅ 动态范围:min-0.2 ~ max+0.5
|
||||
min: vValues.length > 0 ? minV - 0.02 : undefined,
|
||||
max: vValues.length > 0 ? maxV + 0.02 : undefined,
|
||||
splitLine: { show: false },
|
||||
axisTick: {
|
||||
show: true
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
// ✅ Y轴刻度保留三位小数
|
||||
formatter: (value: any) => value.toFixed(3),
|
||||
color: '#78c300'
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#6e7079',
|
||||
width: 2
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#78c300',
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// 系列配置
|
||||
// 系列配置(按期望顺序:流量、水位、流速)
|
||||
series: [
|
||||
{
|
||||
name: '水温(℃)',
|
||||
data: echartsData.value.map(item => item.wt),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
symbolSize: 4,
|
||||
symbol: 'circle',
|
||||
itemStyle: {
|
||||
color: '#5470c6'
|
||||
},
|
||||
lineStyle: {
|
||||
width: 2.5
|
||||
},
|
||||
yAxisIndex: 0
|
||||
},
|
||||
|
||||
{
|
||||
name: '流量(m³/s)',
|
||||
data: echartsData.value.map(item => item.q),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
symbolSize: 4,
|
||||
// connectNulls: true,
|
||||
symbolSize: 3,
|
||||
symbol: 'circle',
|
||||
itemStyle: {
|
||||
color: '#91cc75'
|
||||
color: '#9556a4'
|
||||
},
|
||||
lineStyle: {
|
||||
width: 2.5
|
||||
width: 2
|
||||
},
|
||||
yAxisIndex: 1
|
||||
yAxisIndex: 0
|
||||
},
|
||||
{
|
||||
name: '水位(m)',
|
||||
data: echartsData.value.map(item => item.z),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
symbolSize: 4,
|
||||
// connectNulls: true,
|
||||
symbolSize: 3,
|
||||
symbol: 'circle',
|
||||
itemStyle: {
|
||||
color: '#fac858'
|
||||
color: '#56c2e3'
|
||||
},
|
||||
lineStyle: {
|
||||
width: 2.5
|
||||
width: 2
|
||||
},
|
||||
yAxisIndex: 1
|
||||
},
|
||||
{
|
||||
name: '流速(m/s)',
|
||||
data: echartsData.value.map(item => item.v),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
// connectNulls: true,
|
||||
symbolSize: 3,
|
||||
symbol: 'circle',
|
||||
itemStyle: {
|
||||
color: '#78c300'
|
||||
},
|
||||
lineStyle: {
|
||||
width: 2
|
||||
},
|
||||
yAxisIndex: 2
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
@ -458,11 +503,11 @@ const updateChart = () => {
|
||||
// 完全替换模式更新图表
|
||||
chartInstance.setOption(setting, true);
|
||||
|
||||
// ✅ 初始化时应用动态布局算法,确保只有水温Y轴显示
|
||||
// ✅ 初始化时应用动态布局算法,确保只有流量Y轴显示
|
||||
yAxisShowDynamic({
|
||||
'水温(℃)': true,
|
||||
'流量(m³/s)': false,
|
||||
'水位(m)': false
|
||||
'流量(m³/s)': true,
|
||||
'水位(m)': false,
|
||||
'流速(m/s)': false
|
||||
}, setting);
|
||||
|
||||
// 再次应用调整后的配置
|
||||
@ -486,18 +531,283 @@ onUnmounted(() => {
|
||||
chartInstance = null;
|
||||
}
|
||||
});
|
||||
//获取水温监测下拉框
|
||||
const getselsectData = async () => {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
baseid.value != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": baseid.value
|
||||
} : null,
|
||||
{
|
||||
"field": "fhstcd",
|
||||
"operator": "isnotnull"
|
||||
},
|
||||
{
|
||||
"logic": "or",
|
||||
"filters": [
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": "ZQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
].filter(Boolean)
|
||||
},
|
||||
"select": [
|
||||
"stcd",
|
||||
"stnm",
|
||||
"fhstcd",
|
||||
"fhstnm",
|
||||
"sttpCode"
|
||||
]
|
||||
}
|
||||
let res = await msstbprptGetKendoList(params)
|
||||
console.log(res)
|
||||
if (!res?.data?.data) {
|
||||
|
||||
select.value.value = ''
|
||||
select.value.options = []
|
||||
return
|
||||
}
|
||||
select.value.value = res.data.data[0].stcd
|
||||
select.value.options = res.data.data.map((item: any) => {
|
||||
return {
|
||||
label: item.stnm,
|
||||
value: item.stcd
|
||||
}
|
||||
})
|
||||
// debugger
|
||||
};
|
||||
const convertDateRange = (dateRange: string[]) => {
|
||||
if (!dateRange || dateRange.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
// debugger
|
||||
|
||||
const [startStr, endStr] = dateRange;
|
||||
|
||||
// 获取今天的日期(日部分)
|
||||
const today = new Date();
|
||||
const currentDay = today.getDate();
|
||||
|
||||
// 解析开始日期 YY-MM
|
||||
const [startYearStr, startMonthStr] = startStr.split('-');
|
||||
const startYear = parseInt(startYearStr);
|
||||
const startMonth = parseInt(startMonthStr);
|
||||
const fullStartYear = startYear < 100 ? 2000 + startYear : startYear;
|
||||
|
||||
// 解析结束日期 YY-MM
|
||||
const [endYearStr, endMonthStr] = endStr.split('-');
|
||||
const endYear = parseInt(endYearStr);
|
||||
const endMonth = parseInt(endMonthStr);
|
||||
const fullEndYear = endYear < 100 ? 2000 + endYear : endYear;
|
||||
|
||||
// 开始日期:基于第一个值的年月 + 今天的日期 + 00:00:00
|
||||
// 需要处理月份天数边界问题(如今天是31号,但2月只有28天)
|
||||
const startMonthLastDay = new Date(fullStartYear, startMonth, 0).getDate();
|
||||
const actualStartDay = Math.min(currentDay, startMonthLastDay);
|
||||
const startDate = `${fullStartYear}-${String(startMonth).padStart(2, '0')}-${String(actualStartDay).padStart(2, '0')} 00:00:00`;
|
||||
|
||||
// 结束日期:基于第二个值的年月 + 今天的日期 + 23:59:59
|
||||
// 同样需要处理月份天数边界问题
|
||||
const endMonthLastDay = new Date(fullEndYear, endMonth, 0).getDate();
|
||||
const actualEndDay = Math.min(currentDay, endMonthLastDay);
|
||||
const endDate = `${fullEndYear}-${String(endMonth).padStart(2, '0')}-${String(actualEndDay).padStart(2, '0')} 23:59:59`;
|
||||
|
||||
return {
|
||||
startDate,
|
||||
endDate
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载图表数据
|
||||
* @param startDate 开始日期 (格式: YYYY-MM-DD HH:mm:ss)
|
||||
* @param endDate 结束日期 (格式: YYYY-MM-DD HH:mm:ss)
|
||||
* @param stcd 测站代码
|
||||
*/
|
||||
const getChartData = async (startDate: string, endDate: string, stcd: string) => {
|
||||
try {
|
||||
console.log('=== 开始加载图表数据 ===');
|
||||
console.log('请求参数:', { startDate, endDate, stcd });
|
||||
|
||||
// 设置 loading 状态
|
||||
loading.value = true;
|
||||
hasData.value = false;
|
||||
|
||||
const params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "DT",
|
||||
"operator": "gte",
|
||||
"value": startDate
|
||||
},
|
||||
{
|
||||
"field": "DT",
|
||||
"operator": "lte",
|
||||
"value": endDate
|
||||
},
|
||||
{
|
||||
"field": "stcd",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": stcd
|
||||
}
|
||||
]
|
||||
},
|
||||
"sort": [
|
||||
{
|
||||
"field": "dt",
|
||||
"dir": "asc"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 调用实际的API获取数据
|
||||
const res = await sdriverdaysGetKendoList(params);
|
||||
console.log('API返回结果:', res);
|
||||
|
||||
let data = res?.data?.data || [];
|
||||
console.log('原始数据条数:', data.length);
|
||||
|
||||
// 处理空数据情况
|
||||
if (!data || data.length === 0) {
|
||||
echartsData.value = [];
|
||||
hasData.value = false;
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.warn('未查询到水文数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ 数据预处理:验证字段存在性并转换类型
|
||||
const processedData = data
|
||||
.map(item => {
|
||||
// 验证必要字段
|
||||
if (!item.dt || typeof item.dt !== 'string') {
|
||||
console.warn('无效的日期数据:', item);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确保数值类型
|
||||
const q = typeof item.q === 'number' ? item.q : parseFloat(item.q);
|
||||
const z = typeof item.z === 'number' ? item.z : parseFloat(item.z);
|
||||
const v = typeof item.v === 'number' ? item.v : parseFloat(item.v);
|
||||
|
||||
if (isNaN(q) || isNaN(z) || isNaN(v)) {
|
||||
console.warn('无效的水文数据:', item);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
dt: item.dt.split(' ')[0], // 提取日期部分 "2026-05-03"
|
||||
v: v, // 确保数值类型
|
||||
q: q,
|
||||
z: z
|
||||
};
|
||||
})
|
||||
.filter(Boolean); // 过滤掉无效数据
|
||||
|
||||
console.log('处理后数据条数:', processedData.length);
|
||||
console.log('处理后数据示例:', processedData[0]);
|
||||
|
||||
// ✅ 更新响应式数据
|
||||
echartsData.value = processedData;
|
||||
|
||||
// 判断是否有数据
|
||||
hasData.value = echartsData.value.length > 0;
|
||||
console.log('hasData 设置为:', hasData.value);
|
||||
|
||||
// ✅ 刷新图表(确保DOM更新后执行)
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.log('图表已更新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取图表数据失败:', error);
|
||||
hasData.value = false;
|
||||
} finally {
|
||||
// 关闭 loading 状态
|
||||
await nextTick();
|
||||
console.log('关闭 loading 状态');
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePanelChange1 = async (data) => {
|
||||
console.log('=== 用户交互触发 ===');
|
||||
console.log('当前所有控件状态:', data);
|
||||
// scopeDate: ['26-05', '26-06']
|
||||
// select: "0836000011"
|
||||
if (data.scopeDate && data.scopeDate.length > 0 && data.select) {
|
||||
console.log('参数验证通过,开始加载数据');
|
||||
// 转换日期格式并加载数据
|
||||
const dateRange = convertDateRange(data.scopeDate);
|
||||
if (dateRange) {
|
||||
console.log('日期转换结果:', dateRange);
|
||||
await getChartData(dateRange.startDate, dateRange.endDate, data.select);
|
||||
} else {
|
||||
console.error('日期转换失败');
|
||||
}
|
||||
} else {
|
||||
loading.value = false;
|
||||
hasData.value = false;
|
||||
// 清空图表数据
|
||||
echartsData.value = [];
|
||||
// 更新图表显示空状态
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.warn('参数不完整:', {
|
||||
scopeDate: data.scopeDate,
|
||||
select: data.select
|
||||
});
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
getselsectData()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart-container {
|
||||
.chart-wrapper {
|
||||
width: 100%;
|
||||
height: 231px;
|
||||
min-height: 231px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
/* 为empty-overlay提供定位上下文 */
|
||||
|
||||
.echarts-chart {
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
min-width: 100%;
|
||||
min-height: 231px;
|
||||
}
|
||||
|
||||
.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);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,26 +1,42 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="水温监测" :select="select" :scopeDate="datetimePicker">
|
||||
<SidePanelItem title="水温监测" :select="select" :scopeDate="datetimePicker" @update-values="handlePanelChange1">
|
||||
<div class="chart-wrapper">
|
||||
<a-spin :spinning="loading">
|
||||
<!-- 始终渲染图表容器,确保有固定宽高 -->
|
||||
<div ref="chartRef" class="water-temp-chart"></div>
|
||||
<!-- 无数据时显示Empty,但不影响容器尺寸 -->
|
||||
<div v-if="!loading && !hasData" class="empty-overlay">
|
||||
<a-empty description="暂无数据" />
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { msstbprptGetKendoList, sdrvwtsGetKendoList } from '@/api/qxd';
|
||||
import { useModelStore } from "@/store/modules/model";
|
||||
// 定义组件名
|
||||
defineOptions({
|
||||
name: 'qixidishuiwenbianhua'
|
||||
});
|
||||
|
||||
// ==================== 响应式变量定义 ====================
|
||||
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
// 图表容器引用
|
||||
const chartRef = ref<HTMLDivElement>();
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
const baseid = ref('')
|
||||
|
||||
// Loading 状态和数据状态
|
||||
const loading = ref(false);
|
||||
const hasData = ref(true); // 初始化为 true,因为 initChart 时会渲染
|
||||
|
||||
// 选择器配置
|
||||
const select = ref({
|
||||
@ -32,7 +48,7 @@ const select = ref({
|
||||
});
|
||||
|
||||
// 日期选择器配置
|
||||
const datetimePicker = ref({
|
||||
const datetimePicker: any = ref({
|
||||
show: true,
|
||||
value: (() => {
|
||||
const now = new Date();
|
||||
@ -48,7 +64,7 @@ const datetimePicker = ref({
|
||||
|
||||
// 图表数据
|
||||
const echartsData = ref<any[]>([]);
|
||||
|
||||
const modelStore = useModelStore();
|
||||
// 单位配置
|
||||
const unita = ref('℃');
|
||||
|
||||
@ -96,6 +112,9 @@ const initChart = () => {
|
||||
// 创建新实例
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
|
||||
// 绑定数据点点击事件
|
||||
chartInstance.on('click', handleDataPointClick);
|
||||
|
||||
// 更新图表
|
||||
updateChart();
|
||||
|
||||
@ -111,6 +130,9 @@ const updateChart = () => {
|
||||
|
||||
const _legendData = [`水温(${unita.value})`];
|
||||
|
||||
// 处理空数据情况
|
||||
const hasData = echartsData.value && echartsData.value.length > 0;
|
||||
|
||||
const option: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
@ -128,7 +150,10 @@ const updateChart = () => {
|
||||
const seriesName = item.seriesName ?? '';
|
||||
let regx = /\(([^()]+?)\)/;
|
||||
let unit = seriesName.match(regx);
|
||||
const finalValue = item.value !== undefined && item.value !== null ? item.value : '-';
|
||||
// 数据保留一位小数
|
||||
const finalValue = item.value !== undefined && item.value !== null
|
||||
? Number(item.value).toFixed(1)
|
||||
: '-';
|
||||
|
||||
if (item.value !== undefined && item.value !== null) {
|
||||
res += `<span style="background: ${item.color}; height:10px; width: 10px; border-radius: 50%;display: inline-block;margin-right:10px;"></span> ${item.seriesName} ${finalValue}${unit?.[1] || ''} <br/>`;
|
||||
@ -150,15 +175,15 @@ const updateChart = () => {
|
||||
color: Color,
|
||||
legend: {
|
||||
data: _legendData,
|
||||
top: 10,
|
||||
top: 0,
|
||||
left: 'center',
|
||||
selectedMode: 'multiple'
|
||||
},
|
||||
grid: {
|
||||
top: 45,
|
||||
left: '10%',
|
||||
right: '10px',
|
||||
bottom: '10%',
|
||||
top: 25,
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
dataZoom: {
|
||||
@ -171,6 +196,26 @@ const updateChart = () => {
|
||||
type: 'category',
|
||||
data: echartsData.value?.map((item: any) => item.dt) || [],
|
||||
boundaryGap: true,
|
||||
// X轴标签配置 - 最多显示4个标签,强制显示第一个
|
||||
axisLabel: {
|
||||
show: true,
|
||||
rotate: 0, // 不倾斜
|
||||
interval: (index: number, value: string): boolean => {
|
||||
const total = echartsData.value?.length || 0;
|
||||
if (total <= 4) return true; // 数据少于4条,全部显示
|
||||
|
||||
// 强制显示第一个
|
||||
if (index === 0) return true;
|
||||
|
||||
// 其余均匀分布3个标签(总共4个)
|
||||
const step = Math.floor((total - 1) / 3);
|
||||
return index % step === 0 && index < total;
|
||||
},
|
||||
formatter: function (value: string) {
|
||||
// 显示完整日期 "YYYY-MM-DD" 格式
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// X轴网格线(垂直方向)
|
||||
splitLine: {
|
||||
show: true,
|
||||
@ -191,11 +236,27 @@ const updateChart = () => {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: _legendData[0],
|
||||
// 确保显示刻度和标签
|
||||
// 移除 name,避免与 legend 重复,在刻度上显示单位
|
||||
name: _legendData[0], // 显示 "水温(℃)"
|
||||
nameLocation: 'end', // 显示在 Y 轴顶部
|
||||
nameGap: 8, // 与轴线距离 20px
|
||||
nameTextStyle: {
|
||||
color: '#333333',
|
||||
fontSize: 12,
|
||||
|
||||
},
|
||||
// 计算 Y 轴范围:最小值向下取整,最大值向上取整
|
||||
min: hasData && echartsData.value.length > 0
|
||||
? Math.floor(Math.min(...echartsData.value.map(item => item.wt)))
|
||||
: undefined,
|
||||
max: hasData && echartsData.value.length > 0
|
||||
? Math.ceil(Math.max(...echartsData.value.map(item => item.wt)))
|
||||
: undefined,
|
||||
// 确保显示刻度和标签,保持整数
|
||||
axisLabel: {
|
||||
show: true,
|
||||
color: '#333' // 刻度标签颜色
|
||||
color: '#333',
|
||||
formatter: (value: number) => `${Math.round(value)} ℃` // 取整并显示单位
|
||||
},
|
||||
axisTick: {
|
||||
show: true
|
||||
@ -203,33 +264,34 @@ const updateChart = () => {
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#333' // Y轴轴线颜色,与刻度标签一致
|
||||
color: '#333'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid' // 虚线改为实线
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
splitNumber: 3
|
||||
// 确保 Y 轴刻度为整数
|
||||
minInterval: 1,
|
||||
maxInterval: 1
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: _legendData[0],
|
||||
data: echartsData.value?.map((item: any) => item.wt) || [],
|
||||
data: hasData ? (echartsData.value?.map((item: any) => item.wt) || []) : [],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
symbolSize: 4,
|
||||
lineStyle: {
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 使用完全替换模式更新配置
|
||||
chartInstance.setOption(option, true);
|
||||
};
|
||||
@ -243,6 +305,35 @@ const handleResize = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理数据点点击事件
|
||||
*/
|
||||
const handleDataPointClick = (params: any) => {
|
||||
console.log('=== 数据点点击事件 ===');
|
||||
console.log('点击参数:', params);
|
||||
|
||||
if (!params || !params.dataIndex) {
|
||||
console.warn('无效的数据点点击');
|
||||
return;
|
||||
}
|
||||
|
||||
const dataIndex = params.dataIndex;
|
||||
const dataItem = echartsData.value[dataIndex];
|
||||
|
||||
if (dataItem) {
|
||||
console.log('点击的数据:', {
|
||||
日期: dataItem.dt,
|
||||
水温: dataItem.wt,
|
||||
测站代码: dataItem.stcd,
|
||||
索引: dataIndex
|
||||
});
|
||||
modelStore.modalVisible = true;
|
||||
modelStore.params.sttp = "wt_point";
|
||||
modelStore.title = '水温监测';
|
||||
modelStore.params.stcd = dataItem.stcd;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载模拟数据
|
||||
*/
|
||||
@ -259,6 +350,255 @@ const loadData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载图表数据
|
||||
* @param startDate 开始日期 (格式: YYYY-MM-DD HH:mm:ss)
|
||||
* @param endDate 结束日期 (格式: YYYY-MM-DD HH:mm:ss)
|
||||
* @param stcd 测站代码
|
||||
*/
|
||||
const getChartData = async (startDate: string, endDate: string, stcd: string) => {
|
||||
try {
|
||||
console.log('=== 开始加载图表数据 ===');
|
||||
console.log('请求参数:', { startDate, endDate, stcd });
|
||||
|
||||
// 设置 loading 状态
|
||||
loading.value = true;
|
||||
hasData.value = false;
|
||||
|
||||
// TODO: 实现API调用逻辑
|
||||
// 参考选中的代码结构,构建请求参数
|
||||
const params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "DT",
|
||||
"operator": "gte",
|
||||
"value": startDate // 例如: "2026-05-01 00:00:00"
|
||||
},
|
||||
{
|
||||
"field": "DT",
|
||||
"operator": "lte",
|
||||
"value": endDate // 例如: "2026-06-30 23:59:59"
|
||||
},
|
||||
{
|
||||
"field": "STCD",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": stcd
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// 调用实际的API获取数据
|
||||
const res = await sdrvwtsGetKendoList(params);
|
||||
console.log('API返回结果:', res);
|
||||
|
||||
let data = res?.data?.data || [];
|
||||
console.log('原始数据条数:', data.length);
|
||||
|
||||
// 处理空数据情况
|
||||
if (!data || data.length === 0) {
|
||||
echartsData.value = [];
|
||||
hasData.value = false;
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.warn('未查询到水温数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换数据格式:提取日期部分用于X轴显示,并进行数据验证和类型转换
|
||||
echartsData.value = data
|
||||
.map(item => {
|
||||
// 验证必要字段
|
||||
if (!item.dt || typeof item.dt !== 'string') {
|
||||
console.warn('无效的日期数据:', item);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确保 wt 是数值类型
|
||||
const wt = typeof item.wt === 'number' ? item.wt : parseFloat(item.wt);
|
||||
if (isNaN(wt)) {
|
||||
console.warn('无效的水温数据:', item);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
dt: item.dt.substring(0, 10), // 提取 "2026-05-02" 格式
|
||||
wt: wt, // 确保是 number 类型
|
||||
stcd: item.stcd || stcd // 保留 stcd 字段,如果 API 返回中没有则使用传入的 stcd
|
||||
};
|
||||
})
|
||||
.filter(Boolean); // 过滤掉无效数据
|
||||
|
||||
console.log('转换后的图表数据:', echartsData.value);
|
||||
console.log('数据类型检查:', {
|
||||
第一条数据: echartsData.value[0],
|
||||
dt类型: typeof echartsData.value[0]?.dt,
|
||||
wt类型: typeof echartsData.value[0]?.wt,
|
||||
wt값: echartsData.value[0]?.wt
|
||||
});
|
||||
|
||||
// 判断是否有数据
|
||||
hasData.value = echartsData.value.length > 0;
|
||||
console.log('hasData 设置为:', hasData.value);
|
||||
|
||||
// 数据加载完成后更新图表
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.log('✅ 图表数据加载完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取图表数据失败:', error);
|
||||
hasData.value = false;
|
||||
} finally {
|
||||
// 关闭 loading 状态
|
||||
await nextTick();
|
||||
console.log('关闭 loading 状态');
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 将 YY-MM 格式转换为完整的日期时间范围
|
||||
* @param dateRange ['26-05', '26-06'] 格式的数组
|
||||
* @returns { startDate: string, endDate: string } 格式化后的日期范围
|
||||
*/
|
||||
const convertDateRange = (dateRange: string[]) => {
|
||||
if (!dateRange || dateRange.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
// debugger
|
||||
|
||||
const [startStr, endStr] = dateRange;
|
||||
|
||||
// 获取今天的日期(日部分)
|
||||
const today = new Date();
|
||||
const currentDay = today.getDate();
|
||||
|
||||
// 解析开始日期 YY-MM
|
||||
const [startYearStr, startMonthStr] = startStr.split('-');
|
||||
const startYear = parseInt(startYearStr);
|
||||
const startMonth = parseInt(startMonthStr);
|
||||
const fullStartYear = startYear < 100 ? 2000 + startYear : startYear;
|
||||
|
||||
// 解析结束日期 YY-MM
|
||||
const [endYearStr, endMonthStr] = endStr.split('-');
|
||||
const endYear = parseInt(endYearStr);
|
||||
const endMonth = parseInt(endMonthStr);
|
||||
const fullEndYear = endYear < 100 ? 2000 + endYear : endYear;
|
||||
|
||||
// 开始日期:基于第一个值的年月 + 今天的日期 + 00:00:00
|
||||
// 需要处理月份天数边界问题(如今天是31号,但2月只有28天)
|
||||
const startMonthLastDay = new Date(fullStartYear, startMonth, 0).getDate();
|
||||
const actualStartDay = Math.min(currentDay, startMonthLastDay);
|
||||
const startDate = `${fullStartYear}-${String(startMonth).padStart(2, '0')}-${String(actualStartDay).padStart(2, '0')} 00:00:00`;
|
||||
|
||||
// 结束日期:基于第二个值的年月 + 今天的日期 + 23:59:59
|
||||
// 同样需要处理月份天数边界问题
|
||||
const endMonthLastDay = new Date(fullEndYear, endMonth, 0).getDate();
|
||||
const actualEndDay = Math.min(currentDay, endMonthLastDay);
|
||||
const endDate = `${fullEndYear}-${String(endMonth).padStart(2, '0')}-${String(actualEndDay).padStart(2, '0')} 23:59:59`;
|
||||
|
||||
return {
|
||||
startDate,
|
||||
endDate
|
||||
};
|
||||
};
|
||||
|
||||
const handlePanelChange1 = async (data) => {
|
||||
console.log('=== 用户交互触发 ===');
|
||||
console.log('当前所有控件状态:', data);
|
||||
// scopeDate: ['26-05', '26-06']
|
||||
// select: "0836000011"
|
||||
if (data.scopeDate && data.scopeDate.length > 0 && data.select) {
|
||||
console.log('参数验证通过,开始加载数据');
|
||||
// 转换日期格式并加载数据
|
||||
const dateRange = convertDateRange(data.scopeDate);
|
||||
if (dateRange) {
|
||||
console.log('日期转换结果:', dateRange);
|
||||
await getChartData(dateRange.startDate, dateRange.endDate, data.select);
|
||||
} else {
|
||||
console.error('日期转换失败');
|
||||
}
|
||||
} else {
|
||||
loading.value = false;
|
||||
hasData.value = false;
|
||||
// 清空图表数据
|
||||
echartsData.value = [];
|
||||
// 更新图表显示空状态
|
||||
await nextTick();
|
||||
updateChart();
|
||||
console.warn('参数不完整:', {
|
||||
scopeDate: data.scopeDate,
|
||||
select: data.select
|
||||
});
|
||||
}
|
||||
}
|
||||
//获取水温监测下拉框
|
||||
const getselsectData = async () => {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
baseid.value != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": baseid.value
|
||||
} : null,
|
||||
{
|
||||
"field": "fhstcd",
|
||||
"operator": "isnotnull"
|
||||
},
|
||||
{
|
||||
"logic": "or",
|
||||
"filters": [
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": "WTRV"
|
||||
}
|
||||
]
|
||||
}
|
||||
].filter(Boolean)
|
||||
},
|
||||
"select": [
|
||||
"stcd",
|
||||
"stnm",
|
||||
"fhstcd",
|
||||
"fhstnm",
|
||||
"sttpCode"
|
||||
]
|
||||
}
|
||||
let res = await msstbprptGetKendoList(params)
|
||||
console.log(res)
|
||||
if (!res?.data?.data) {
|
||||
|
||||
select.value.value = ''
|
||||
select.value.options = []
|
||||
return
|
||||
}
|
||||
select.value.value = res.data.data[0].stcd
|
||||
select.value.options = res.data.data.map((item: any) => {
|
||||
return {
|
||||
label: item.stnm,
|
||||
value: item.stcd
|
||||
}
|
||||
})
|
||||
// debugger
|
||||
};
|
||||
////
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
getselsectData()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
// ==================== 生命周期钩子 ====================
|
||||
|
||||
// 页面加载时执行
|
||||
@ -271,7 +611,9 @@ onMounted(() => {
|
||||
const rect = chartRef.value.getBoundingClientRect();
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
initChart();
|
||||
loadData();
|
||||
// 注释掉模拟数据加载,等待用户交互后加载真实数据
|
||||
// loadData();
|
||||
console.log('✅ 图表初始化完成,等待用户交互加载数据');
|
||||
} else {
|
||||
console.warn('图表容器尺寸为0,启动重试机制');
|
||||
// 指数退避重试
|
||||
@ -284,7 +626,8 @@ onMounted(() => {
|
||||
const newRect = chartRef.value?.getBoundingClientRect();
|
||||
if (newRect && newRect.width > 0 && newRect.height > 0) {
|
||||
initChart();
|
||||
loadData();
|
||||
// loadData();
|
||||
console.log('✅ 图表初始化完成(重试成功)');
|
||||
} else {
|
||||
retryInit();
|
||||
}
|
||||
@ -307,6 +650,8 @@ onUnmounted(() => {
|
||||
|
||||
// 销毁图表实例
|
||||
if (chartInstance) {
|
||||
// 解绑数据点点击事件
|
||||
chartInstance.off('click', handleDataPointClick);
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
@ -314,9 +659,31 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.water-temp-chart {
|
||||
.chart-wrapper {
|
||||
width: 100%;
|
||||
height: 231px;
|
||||
min-height: 231px;
|
||||
position: relative;
|
||||
/* 为empty-overlay提供定位上下文 */
|
||||
|
||||
.water-temp-chart {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
min-width: 100%;
|
||||
min-height: 231px;
|
||||
}
|
||||
|
||||
.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);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -13,10 +13,12 @@ export const useModelStore = defineStore('model', () => {
|
||||
sttp: string;
|
||||
stcd: any;
|
||||
date: any;
|
||||
show: any;
|
||||
}>({
|
||||
sttp: 'eng',
|
||||
stcd: '',
|
||||
date: '',
|
||||
show: true
|
||||
});
|
||||
return {
|
||||
params,
|
||||
|
||||
@ -24,7 +24,9 @@ service.interceptors.request.use(
|
||||
config.url.includes('/wmp-env-server') ||
|
||||
config.url.includes('/wmp-sys-server') ||
|
||||
config.url.includes('/wmp-eng-server') ||
|
||||
config.url.includes('/dec-modules-usm-springcloud-starter')
|
||||
config.url.includes('/dec-modules-usm-springcloud-starter') ||
|
||||
config.url.includes('/wmp-swqx-server')
|
||||
|
||||
) {
|
||||
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
||||
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
||||
|
||||
@ -148,7 +148,7 @@ const showMapModal17 = () => {
|
||||
<a-button @click="showMapModal1">打开水温弹窗</a-button>
|
||||
<!-- <a-button @click="showMapModal2">打开水质弹窗</a-button> -->
|
||||
<!-- <a-button @click="showMapModal3">打开栖息地弹窗</a-button> -->
|
||||
<!-- <a-button @click="showMapModal4">打开栖息地流量弹窗</a-button> -->
|
||||
<a-button @click="showMapModal4">打开栖息地流量弹窗</a-button>
|
||||
<!-- <a-button @click="showMapModal5">打开过鱼设施弹窗</a-button> -->
|
||||
<!-- <a-button @click="showMapModal6">打开鱼类增殖站弹窗</a-button> -->
|
||||
<!-- <a-button @click="showMapModal7">打开动物救助站弹窗</a-button> -->
|
||||
|
||||
@ -94,7 +94,18 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
||||
new RegExp('^/api/dec-modules-usm-springcloud-starter'),
|
||||
'/api/dec-modules-usm-springcloud-starter'
|
||||
)
|
||||
},
|
||||
'/api/wmp-swqx-server/': {
|
||||
target: 'https://211.99.26.225:12122',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
rewrite: path =>
|
||||
path.replace(
|
||||
new RegExp('^/api/dec-modules-usm-springcloud-starter'),
|
||||
'/api/dec-modules-usm-springcloud-starter'
|
||||
)
|
||||
}
|
||||
// /
|
||||
}
|
||||
},
|
||||
build: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user