栖息地线上接口

This commit is contained in:
王兴凯 2026-06-03 17:17:51 +08:00
commit bbfea93b20
14 changed files with 1622 additions and 241 deletions

View 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
});
}

View File

@ -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: '',

View File

@ -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':
return FHTabs;
if (modaldata.show) {
return FHTabs;
}else{
let FHTabsTwo = FHTabs.slice(0, 1);
return FHTabsTwo;
}
case 'FH_ZQ_POINT':
return FLOWTabs;
case 'FP_POINT':

View File

@ -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="{
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 }"
/>
<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 }" />
</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
}
@ -546,7 +553,7 @@ const initPieChart = (data: any[]) => {
kong.value = false
const selectedKeys = Object.keys(params.selected).filter(key => params.selected[key])
const allFalse = Object.values(params.selected).every(value => value === false)
//
if (allFalse) {
// 0
@ -557,7 +564,7 @@ const initPieChart = (data: any[]) => {
.filter(item => selectedKeys.includes(item.name))
.reduce((sum, item) => sum + item.value, 0)
}
// title
pieChartInstance.setOption({
title: [
@ -566,7 +573,7 @@ const initPieChart = (data: any[]) => {
}
]
})
const selectedCodes = data
.filter(item => selectedKeys.includes(item.name))
.map(item => item.keyData)
@ -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()
@ -873,7 +880,7 @@ defineExpose({
.search-form {
background: #fff;
border-radius: 4px;
padding: 0px 0px 16px 0px;
padding: 0px 0px 16px 0px;
:deep(.ant-space) {
display: flex;

View File

@ -456,7 +456,7 @@ const getEchartsData = async () => {
baseid.value == 'all' ? {
"field": "dtinType",
"operator": "eq",
"value": 0
"value":tabs.value
} : {
"field": "rstcd",
"operator": "isnotnull"

View File

@ -1,63 +1,137 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="栖息地保护工作开展情况">
<div class="facility-grid">
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
<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>
<a-spin :spinning="loading" tip="加载中...">
<div class="facility-grid">
<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>
</div>
</div>
<div class="facility-info">
<div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count
}}</span><span></span></div>
</div>
</div>
<div class="facility-info">
<div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count
}}</span><span></span></div>
</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 }
);

View File

@ -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>

View File

@ -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(() => {
//

View File

@ -1,24 +1,41 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="水文监测" :select="select" :scopeDate="datetimePicker" >
<div class="chart-container">
<div ref="chartRef" class="echarts-chart"></div>
<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));
// Aformatter
const currentOptions = echartOptionRef.value as any;
//
options.legend.selected = selected;
// Y
const newYAxis = options.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;
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 }; // 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,
// X5
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
// 31228
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>

View File

@ -1,26 +1,42 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="水温监测" :select="select" :scopeDate="datetimePicker">
<div ref="chartRef" class="water-temp-chart"></div>
<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;
// 34
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
// 31228
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>

View File

@ -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,

View File

@ -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';

View File

@ -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> -->

View File

@ -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: {