添加栖息地弹框,修改批复文件显示多个
This commit is contained in:
parent
cc8c1e0647
commit
34502b7ed2
@ -1,6 +1,12 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { LoginData, TokenResult, VerifyCode } from './types';
|
import { LoginData, TokenResult, VerifyCode } from './types';
|
||||||
|
export function getAccessToken() {
|
||||||
|
return request({
|
||||||
|
url: '/register/accessToken',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -52,8 +58,11 @@ export function registerUser(data: any): AxiosPromise<any> {
|
|||||||
*/
|
*/
|
||||||
export function getBasinList(): AxiosPromise<any[]> {
|
export function getBasinList(): AxiosPromise<any[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/env/rvcd/regDropdown',
|
url: '/register/dropdown/rvcd',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
'register-token': localStorage.getItem('register-token') || ''
|
||||||
|
}
|
||||||
// params: baseid ? { baseid } : {}
|
// params: baseid ? { baseid } : {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -63,9 +72,12 @@ export function getBasinList(): AxiosPromise<any[]> {
|
|||||||
*/
|
*/
|
||||||
export function getGroupList(): AxiosPromise<any[]> {
|
export function getGroupList(): AxiosPromise<any[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/env/hycd/regDropdown',
|
url: '/register/dropdown/hycd',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params:{lx:1}
|
params: { lx: 1 },
|
||||||
|
headers: {
|
||||||
|
'register-token': localStorage.getItem('register-token') || ''
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,20 +86,26 @@ export function getGroupList(): AxiosPromise<any[]> {
|
|||||||
*/
|
*/
|
||||||
export function getCompanyList(): AxiosPromise<any[]> {
|
export function getCompanyList(): AxiosPromise<any[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/env/hycd/regDropdown',
|
url: '/register/dropdown/hycd',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { lx:2 }
|
params: { lx: 2 },
|
||||||
|
headers: {
|
||||||
|
'register-token': localStorage.getItem('register-token') || ''
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据流域获取电站列表
|
* 根据流域获取电站列表
|
||||||
*/
|
*/
|
||||||
export function getStationList(params:any): AxiosPromise<any[]> {
|
export function getStationList(params: any): AxiosPromise<any[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/env/engInfo/regDropdown',
|
url: '/register/dropdown/engInfo',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: params
|
data: params,
|
||||||
|
headers: {
|
||||||
|
'register-token': localStorage.getItem('register-token') || ''
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +128,11 @@ export function sendSmsCode(phone: string, type = 1): AxiosPromise<any> {
|
|||||||
* @param code 验证码
|
* @param code 验证码
|
||||||
* @param type 验证码类型:1-注册 2-找回密码
|
* @param type 验证码类型:1-注册 2-找回密码
|
||||||
*/
|
*/
|
||||||
export function verifySmsCode(phone: string, code: string, type = 1): AxiosPromise<any> {
|
export function verifySmsCode(
|
||||||
|
phone: string,
|
||||||
|
code: string,
|
||||||
|
type = 1
|
||||||
|
): AxiosPromise<any> {
|
||||||
return request({
|
return request({
|
||||||
url: '/sms/verifyCode',
|
url: '/sms/verifyCode',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -123,7 +145,10 @@ export function verifySmsCode(phone: string, code: string, type = 1): AxiosPromi
|
|||||||
* @param phone 手机号
|
* @param phone 手机号
|
||||||
* @param code 验证码
|
* @param code 验证码
|
||||||
*/
|
*/
|
||||||
export function smsLoginApi(phone: string, code: string): AxiosPromise<TokenResult> {
|
export function smsLoginApi(
|
||||||
|
phone: string,
|
||||||
|
code: string
|
||||||
|
): AxiosPromise<TokenResult> {
|
||||||
return request({
|
return request({
|
||||||
url: '/sms/login',
|
url: '/sms/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -137,7 +162,11 @@ export function smsLoginApi(phone: string, code: string): AxiosPromise<TokenResu
|
|||||||
* @param code 验证码
|
* @param code 验证码
|
||||||
* @param password 新密码
|
* @param password 新密码
|
||||||
*/
|
*/
|
||||||
export function resetPassword(phone: string, code: string, password: string): AxiosPromise<any> {
|
export function resetPassword(
|
||||||
|
phone: string,
|
||||||
|
code: string,
|
||||||
|
password: string
|
||||||
|
): AxiosPromise<any> {
|
||||||
return request({
|
return request({
|
||||||
url: '/sms/resetPassword',
|
url: '/sms/resetPassword',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|||||||
@ -62,10 +62,33 @@ export function getMonitorData(data: any) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// 监测数据 水温查询 栖息地
|
||||||
|
|
||||||
|
export function getMonitorDataWt(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/wt/msstbprpt/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function getMonitorDataWq(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/wq/msstbprpt/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function getMonitorDataZq(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/zq/msstbprpt/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
// 监测数据 - 水温
|
// 监测数据 - 水温
|
||||||
export function getMonitorDataWaterTemp(data: any) {
|
export function getMonitorDataWaterTemp(data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/api/wmp-env-server/sw/alongDetail/qgc/GetKendoListCust',
|
url: '/wt/alongDetail/qgc/GetKendoListCust',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@ -73,7 +96,7 @@ export function getMonitorDataWaterTemp(data: any) {
|
|||||||
// 监测数据 - 水温 - 查询显示 综合/等温
|
// 监测数据 - 水温 - 查询显示 综合/等温
|
||||||
export function getMonitorDataWaterTempPowerStation(params: any) {
|
export function getMonitorDataWaterTempPowerStation(params: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/api/wmp-env-server/sw/wtrv/getIoWtrvFlag',
|
url: '/wt/wtrv/getIoWtrvFlag',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
@ -81,7 +104,7 @@ export function getMonitorDataWaterTempPowerStation(params: any) {
|
|||||||
// 监测数据 - 水温 - 、综合分析导出数据
|
// 监测数据 - 水温 - 、综合分析导出数据
|
||||||
export function exportMonitorDataWaterTempPowerStation(params: any) {
|
export function exportMonitorDataWaterTempPowerStation(params: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/api/wmp-env-server/sw/alongDetail/qgc/GetKendoListCust',
|
url: '/wt/alongDetail/qgc/GetKendoListCust',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params,
|
params,
|
||||||
responseType: 'blob'
|
responseType: 'blob'
|
||||||
@ -91,32 +114,55 @@ export function exportMonitorDataWaterTempPowerStation(params: any) {
|
|||||||
// 监测数据 - 水温 - 查询是否显示 等温水深
|
// 监测数据 - 水温 - 查询是否显示 等温水深
|
||||||
export function getMonitorDataWaterTempPowerStation2(params: any) {
|
export function getMonitorDataWaterTempPowerStation2(params: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/api/wmp-env-server/sw/alongDetail/qgc/stcdCheck2',
|
url: '/wt/alongDetail/qgc/stcdCheck2',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 监测数据 - 垂向水温
|
// 监测数据 - 垂向水温
|
||||||
|
|
||||||
export function getMonitorDataWaterTempVertical(data: any) {
|
export function getMonitorDataWaterTempVertical(data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/api/wmp-env-server/sw/cxDetail/GetKendoListCust',
|
url: '/wt/cxDetail/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 监测数据 - 水质 判断是否显示综合分析
|
||||||
|
export function getMonitorDataWaterQuality(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/wq/vmsstbprpt/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 监测数据 - 水质 - 获取水质参数
|
||||||
|
export function getMonitorDataWaterQualityDetail(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/wq/stbprp/GetStbprpYsByStcd',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 监测数据 - 水质 - 获取水质数据
|
||||||
|
export function getMonitorDataWaterQualityList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/wq/data/noAuth/GetKendoListCust',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 生态流量 - 限制范围查询 - 日
|
// 生态流量 - 限制范围查询 - 日
|
||||||
export function getEngLimitDay(data: any) {
|
export function getMonitorDataWaterTempVerticalDay(data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/eq/interval/qgc/day/GetKendoListCust',
|
url: '/eq/data/day/GetKendoListCust',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 生态流量 - 限制范围查询 - 月
|
// 生态流量 - 限制范围查询 - 小时
|
||||||
export function getEngLimit(data: any) {
|
export function getMonitorDataWaterTempVerticalHour(data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/eq/interval/qgc/month/GetKendoListCust',
|
url: '/eq/data/GetKendoListCust',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -143,13 +143,29 @@ const loadApprovalData = () => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
queryPostUrlList(props.url, params).then(res => {
|
queryPostUrlList(props.url, params).then(res => {
|
||||||
const data = res.data?.data || [];
|
const data = res.data?.data || [];
|
||||||
const fileArray = data.map((item: any) => ({
|
if (data[0].flid == null) {
|
||||||
id: item.flpath.split('?')[1] || '',
|
const fileArray = data.map((item: any) => ({
|
||||||
name: item.approvalFileNo || item.approvalFileTitle,
|
id: item.flpath.split('?')[1] || '',
|
||||||
url: item.flpath || ''
|
name: item.approvalFileNo || item.approvalFileTitle,
|
||||||
}));
|
url: item.flpath || ''
|
||||||
hasLoaded.value = true;
|
}));
|
||||||
updateFileList(fileArray);
|
hasLoaded.value = true;
|
||||||
|
updateFileList(fileArray);
|
||||||
|
} else {
|
||||||
|
getIdUrl({
|
||||||
|
id: data[0].flid
|
||||||
|
}).then(res1 => {
|
||||||
|
const data = res1?.data || {};
|
||||||
|
const fileArray = Object.keys(data).map(key => ({
|
||||||
|
id: key,
|
||||||
|
name: data[key].name,
|
||||||
|
url: data[key].fullpath
|
||||||
|
}));
|
||||||
|
loading.value = false;
|
||||||
|
hasLoaded.value = true;
|
||||||
|
updateFileList(fileArray);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,15 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-right" v-if="item.visible">
|
<div class="col-right" v-if="item.visible">
|
||||||
<a-tooltip :title="!isEdit ? item.vlsr : ''">
|
<a-tooltip
|
||||||
|
:title="
|
||||||
|
!isEdit
|
||||||
|
? item.vlsr || String(item.value).length > 10
|
||||||
|
? item.value
|
||||||
|
: ''
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
>
|
||||||
<span v-if="!isEdit && item.filed != ''">{{
|
<span v-if="!isEdit && item.filed != ''">{{
|
||||||
item.value || '-'
|
item.value || '-'
|
||||||
}}</span>
|
}}</span>
|
||||||
@ -250,6 +258,10 @@ const columnsConfig = ref([
|
|||||||
{
|
{
|
||||||
type: 'DW_1',
|
type: 'DW_1',
|
||||||
columns: DwOnePointColumns
|
columns: DwOnePointColumns
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'ZQ',
|
||||||
|
columns: FhZQPointColumns
|
||||||
}
|
}
|
||||||
|
|
||||||
//DW_1
|
//DW_1
|
||||||
|
|||||||
@ -45,9 +45,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 底部图表区 -->
|
<!-- 底部图表区 -->
|
||||||
<div class="bottom-section">
|
<div class="bottom-section">
|
||||||
<a-spin :spinning="isChartLoading" tip="加载中...">
|
<a-spin v-show="hasData" :spinning="isChartLoading" tip="加载中...">
|
||||||
<div class="chart-wrapper" ref="chartRef"></div>
|
<div class="chart-wrapper" ref="chartRef"></div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
|
<a-empty
|
||||||
|
v-show="!hasData && !isChartLoading"
|
||||||
|
description="暂无数据"
|
||||||
|
class="empty-wrapper h-full flex items-center justify-center"
|
||||||
|
style="flex-direction: column"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -55,7 +61,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, computed, watch, onUnmounted, nextTick } from 'vue';
|
import { ref, onMounted, computed, watch, onUnmounted, nextTick } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import { getEngLimit, getEngLimitDay } from '@/api/mapModal';
|
import {
|
||||||
|
getMonitorDataWaterTempVerticalDay,
|
||||||
|
getMonitorDataWaterTempVerticalHour
|
||||||
|
} from '@/api/mapModal';
|
||||||
import { useModelStore } from '@/store/modules/model';
|
import { useModelStore } from '@/store/modules/model';
|
||||||
import { DateSetting } from '@/utils/enumeration';
|
import { DateSetting } from '@/utils/enumeration';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@ -74,6 +83,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const hasLoaded = ref<boolean>(false); // 是否加载完成
|
const hasLoaded = ref<boolean>(false); // 是否加载完成
|
||||||
const isChartLoading = ref<boolean>(false);
|
const isChartLoading = ref<boolean>(false);
|
||||||
|
const hasData = ref<boolean>(true); // 是否有数据
|
||||||
const unqualifiedCount = ref<number>(0);
|
const unqualifiedCount = ref<number>(0);
|
||||||
const complianceRate = ref<string>('');
|
const complianceRate = ref<string>('');
|
||||||
const limitInfo = ref<string>('');
|
const limitInfo = ref<string>('');
|
||||||
@ -131,7 +141,7 @@ const fetchLimitInfo = async () => {
|
|||||||
const stcd = modelStore.params.stcd;
|
const stcd = modelStore.params.stcd;
|
||||||
const { startTime, endTime } = getDateRange();
|
const { startTime, endTime } = getDateRange();
|
||||||
|
|
||||||
const res = await getEngLimit({
|
const res = await getMonitorDataWaterTempVerticalHour({
|
||||||
filter: {
|
filter: {
|
||||||
logic: 'and',
|
logic: 'and',
|
||||||
filters: [
|
filters: [
|
||||||
@ -165,7 +175,7 @@ const fetchDayData = async () => {
|
|||||||
const stcd = modelStore.params.stcd;
|
const stcd = modelStore.params.stcd;
|
||||||
const { startTime, endTime } = getDateRange();
|
const { startTime, endTime } = getDateRange();
|
||||||
|
|
||||||
const res = await getEngLimitDay({
|
const res = await getMonitorDataWaterTempVerticalDay({
|
||||||
filter: {
|
filter: {
|
||||||
logic: 'and',
|
logic: 'and',
|
||||||
filters: [
|
filters: [
|
||||||
@ -206,27 +216,6 @@ const fetchDayData = async () => {
|
|||||||
const chartRef = ref<HTMLDivElement | null>(null);
|
const chartRef = ref<HTMLDivElement | null>(null);
|
||||||
let chartInstance: echarts.ECharts | null = null;
|
let chartInstance: echarts.ECharts | null = null;
|
||||||
|
|
||||||
// 生成模拟数据
|
|
||||||
const getMockData = () => {
|
|
||||||
const now = dayjs();
|
|
||||||
const data: any[] = [];
|
|
||||||
const count = timeType.value === 'hour' ? 48 : 30; // 小时显示48条,日显示30条
|
|
||||||
for (let i = count - 1; i >= 0; i--) {
|
|
||||||
const tm =
|
|
||||||
timeType.value === 'hour'
|
|
||||||
? now.subtract(i, 'hour').format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
: now.subtract(i, 'day').format('YYYY-MM-DD HH:mm:ss');
|
|
||||||
data.push({
|
|
||||||
tm,
|
|
||||||
qi: Math.round(Math.random() * 100 + 150), // 入库流量 150-250
|
|
||||||
qec: Math.round(Math.random() * 50 + 100), // 生态流量 100-150
|
|
||||||
qecLimit: 145, // 生态流量限值固定
|
|
||||||
qecSameLastYear: Math.round(Math.random() * 60 + 90) // 去年同期生态流量 90-150
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更新图表
|
// 更新图表
|
||||||
const updateChart = (data: any[]) => {
|
const updateChart = (data: any[]) => {
|
||||||
if (!chartInstance) return;
|
if (!chartInstance) return;
|
||||||
@ -241,18 +230,22 @@ const updateChart = (data: any[]) => {
|
|||||||
(a, b) => new Date(a.tm).getTime() - new Date(b.tm).getTime()
|
(a, b) => new Date(a.tm).getTime() - new Date(b.tm).getTime()
|
||||||
);
|
);
|
||||||
|
|
||||||
const xAxisData = sorted.map(item => dayjs(item.tm).format('MM-DD HH:mm'));
|
const xAxisData = sorted.map(item =>
|
||||||
|
dayjs(timeType.value === 'hour' ? item.tm : item.dt).format(
|
||||||
|
timeType.value === 'hour' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD'
|
||||||
|
)
|
||||||
|
);
|
||||||
const qiData = sorted.map(item => item.qi);
|
const qiData = sorted.map(item => item.qi);
|
||||||
const qecData = sorted.map(item => item.qec);
|
const qecData = sorted.map(item => item.qec);
|
||||||
const qecLimitData = sorted.map(item => item.qecLimit);
|
const qecLimitData = sorted.map(item => item.qecLimit);
|
||||||
const qecSameLastYearData = sorted.map(item => item.qecSameLastYear);
|
const beforeQecData = sorted.map(item => item.beforeQec);
|
||||||
|
|
||||||
// 计算 Y 轴最大值
|
// 计算 Y 轴最大值
|
||||||
const flowValues = [
|
const flowValues = [
|
||||||
...qiData,
|
...qiData,
|
||||||
...qecData,
|
...qecData,
|
||||||
...qecLimitData,
|
...qecLimitData,
|
||||||
...qecSameLastYearData
|
...beforeQecData
|
||||||
].filter(v => v !== null && v !== undefined);
|
].filter(v => v !== null && v !== undefined);
|
||||||
const flowMax = flowValues.length > 0 ? Math.max(...flowValues) : 200;
|
const flowMax = flowValues.length > 0 ? Math.max(...flowValues) : 200;
|
||||||
const flowYMax = Math.ceil(flowMax * 1.1);
|
const flowYMax = Math.ceil(flowMax * 1.1);
|
||||||
@ -267,9 +260,19 @@ const updateChart = (data: any[]) => {
|
|||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
if (!params || params.length === 0) return '';
|
if (!params || params.length === 0) return '';
|
||||||
const dataIndex = params[0].dataIndex;
|
const dataIndex = params[0].dataIndex;
|
||||||
const fullTime = sorted[dataIndex]?.tm
|
console.log(sorted[dataIndex]);
|
||||||
? dayjs(sorted[dataIndex].tm).format('YYYY-MM-DD HH:mm:ss')
|
const fullTime =
|
||||||
: '';
|
timeType.value === 'hour'
|
||||||
|
? sorted[dataIndex]?.tm
|
||||||
|
: sorted[dataIndex]?.dt
|
||||||
|
? dayjs(
|
||||||
|
timeType.value === 'hour'
|
||||||
|
? sorted[dataIndex].tm
|
||||||
|
: sorted[dataIndex].dt
|
||||||
|
).format(
|
||||||
|
timeType.value === 'hour' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD'
|
||||||
|
)
|
||||||
|
: '';
|
||||||
let html = `<div style="font-size:16px;margin-bottom:8px;">${fullTime}</div>`;
|
let html = `<div style="font-size:16px;margin-bottom:8px;">${fullTime}</div>`;
|
||||||
// 系列名称对应的格式化规则
|
// 系列名称对应的格式化规则
|
||||||
const formatRules: Record<
|
const formatRules: Record<
|
||||||
@ -369,7 +372,7 @@ const updateChart = (data: any[]) => {
|
|||||||
{
|
{
|
||||||
name: '去年同期生态流量',
|
name: '去年同期生态流量',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: qecSameLastYearData,
|
data: beforeQecData,
|
||||||
smooth: true,
|
smooth: true,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
symbolSize: 4,
|
symbolSize: 4,
|
||||||
@ -405,7 +408,9 @@ const initChart = () => {
|
|||||||
if (chartInstance) {
|
if (chartInstance) {
|
||||||
chartInstance.dispose();
|
chartInstance.dispose();
|
||||||
}
|
}
|
||||||
chartInstance = echarts.init(chartRef.value);
|
nextTick(() => {
|
||||||
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
@ -422,22 +427,45 @@ const destroyChart = () => {
|
|||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', handleResize);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 请求图表数据(预留接口调用)
|
// 请求图表数据
|
||||||
const fetchChartData = async () => {
|
const fetchChartData = async () => {
|
||||||
isChartLoading.value = true;
|
isChartLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// TODO: 替换为实际接口调用
|
const stcd = modelStore.params.stcd;
|
||||||
// const stcd = modelStore.params.stcd;
|
const { startTime, endTime } = getDateRange();
|
||||||
// const { startTime, endTime } = getDateRange();
|
|
||||||
// const res = await getEngChartList({ ... });
|
|
||||||
// updateChart(res?.data?.data || []);
|
|
||||||
|
|
||||||
// 模拟 2 秒 loading
|
const apiFn =
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
timeType.value === 'day'
|
||||||
|
? getMonitorDataWaterTempVerticalDay
|
||||||
|
: getMonitorDataWaterTempVerticalHour;
|
||||||
|
|
||||||
// 使用模拟数据
|
const res = await apiFn({
|
||||||
const mockData = getMockData();
|
filter: {
|
||||||
updateChart(mockData);
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{ field: 'stcd', operator: 'eq', dataType: 'string', value: stcd },
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'gte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: startTime
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'lte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: endTime
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
sort: [{ field: 'tm', dir: 'asc' }]
|
||||||
|
});
|
||||||
|
|
||||||
|
const rawData = res?.data?.data || [];
|
||||||
|
hasData.value = rawData.length > 0;
|
||||||
|
if (hasData.value) {
|
||||||
|
updateChart(rawData);
|
||||||
|
}
|
||||||
hasLoaded.value = true;
|
hasLoaded.value = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取图表数据失败:', error);
|
console.error('获取图表数据失败:', error);
|
||||||
@ -448,6 +476,7 @@ const fetchChartData = async () => {
|
|||||||
|
|
||||||
// 查询按钮
|
// 查询按钮
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
|
hasData.value = true;
|
||||||
fetchLimitInfo();
|
fetchLimitInfo();
|
||||||
fetchDayData();
|
fetchDayData();
|
||||||
fetchChartData();
|
fetchChartData();
|
||||||
@ -456,6 +485,8 @@ const handleQuery = () => {
|
|||||||
// 监听 timeType 切换时重置日期范围
|
// 监听 timeType 切换时重置日期范围
|
||||||
watch(timeType, () => {
|
watch(timeType, () => {
|
||||||
dateRange.value = initDateRange();
|
dateRange.value = initDateRange();
|
||||||
|
hasData.value = true;
|
||||||
|
fetchChartData();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@ -466,10 +497,8 @@ watch(
|
|||||||
fetchDayData();
|
fetchDayData();
|
||||||
// 初始化图表
|
// 初始化图表
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
initChart();
|
||||||
initChart();
|
fetchChartData();
|
||||||
fetchChartData();
|
|
||||||
}, 2000);
|
|
||||||
});
|
});
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
}
|
}
|
||||||
@ -477,7 +506,9 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {});
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
destroyChart();
|
destroyChart();
|
||||||
|
|||||||
626
frontend/src/components/MapModal/components/FlowMeasure.vue
Normal file
626
frontend/src/components/MapModal/components/FlowMeasure.vue
Normal file
@ -0,0 +1,626 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flow-measure">
|
||||||
|
<a-tabs v-model:activeKey="activeTabKey">
|
||||||
|
<a-tab-pane v-for="tab in tabsList" :key="tab.key" :tab="tab.name" />
|
||||||
|
<template #rightExtra>
|
||||||
|
<div class="search-bar">
|
||||||
|
<a-range-picker
|
||||||
|
v-model:value="dateRange"
|
||||||
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
:show-time="showTimeConfig"
|
||||||
|
:allowClear="false"
|
||||||
|
:presets="DateSetting.RangeButton.month1"
|
||||||
|
:disabled-date="disabledDate"
|
||||||
|
/>
|
||||||
|
<a-button type="primary" class="search-btn" @click="handleSearch">
|
||||||
|
查询
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-tabs>
|
||||||
|
|
||||||
|
<a-spin :spinning="isLoading" tip="加载中...">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="content-body">
|
||||||
|
<div class="chart-wrapper">
|
||||||
|
<div ref="chartRef" class="chart-container"></div>
|
||||||
|
<a-empty
|
||||||
|
v-if="!chartData || chartData.length === 0"
|
||||||
|
description="暂无数据"
|
||||||
|
class="chart-empty"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<BasicTable
|
||||||
|
:scrollY="480"
|
||||||
|
:scrollX="tableScrollX"
|
||||||
|
:columns="tableColumns"
|
||||||
|
:data="tableData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
|
||||||
|
<!-- 视频播放弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:open="videoModalVisible"
|
||||||
|
:title="videoModalTitle"
|
||||||
|
:width="800"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<div class="video-container">
|
||||||
|
<video
|
||||||
|
v-if="currentVideoUrl"
|
||||||
|
:src="currentVideoUrl"
|
||||||
|
controls
|
||||||
|
autoplay
|
||||||
|
class="video-player"
|
||||||
|
/>
|
||||||
|
<a-empty v-else description="暂无视频" />
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
nextTick,
|
||||||
|
h,
|
||||||
|
computed
|
||||||
|
} from 'vue';
|
||||||
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { queryPostUrlList } from '@/api/mapModal';
|
||||||
|
import { useModelStore } from '@/store/modules/model';
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue';
|
||||||
|
import { DateSetting } from '@/utils/enumeration';
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isActive: { type: Boolean, default: false },
|
||||||
|
url: { type: String, default: '' },
|
||||||
|
code: { type: String, default: '' },
|
||||||
|
stcd: { type: String, default: '' }
|
||||||
|
});
|
||||||
|
|
||||||
|
const isQxdMode = computed(() => props.code === 'qxd.tabs.lcjs');
|
||||||
|
|
||||||
|
const hasLoaded = ref(false);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const tableData = ref<any[]>([]);
|
||||||
|
const chartData = ref<any[]>([]);
|
||||||
|
const chartRef = ref<HTMLElement>();
|
||||||
|
let chartInstance: echarts.ECharts | null = null;
|
||||||
|
|
||||||
|
// 视频弹窗
|
||||||
|
const videoModalVisible = ref(false);
|
||||||
|
const videoModalTitle = ref('');
|
||||||
|
const currentVideoUrl = ref('');
|
||||||
|
|
||||||
|
const tabsList = [{ name: '流量监测', key: 'flowMeasure' }];
|
||||||
|
const activeTabKey = ref('flowMeasure');
|
||||||
|
|
||||||
|
// 时间选择器配置
|
||||||
|
const showTimeConfig = {
|
||||||
|
format: 'HH:mm',
|
||||||
|
hourStep: 1,
|
||||||
|
minuteStep: 5,
|
||||||
|
secondStep: 60
|
||||||
|
};
|
||||||
|
const disabledDate = (current: Dayjs) =>
|
||||||
|
current && current.isAfter(dayjs(), 'day');
|
||||||
|
|
||||||
|
const initDateRange = (): [Dayjs, Dayjs] => {
|
||||||
|
return [dayjs().subtract(7, 'day'), dayjs()];
|
||||||
|
};
|
||||||
|
const dateRange = ref<[Dayjs, Dayjs] | undefined>(initDateRange());
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const tableColumns = [
|
||||||
|
{
|
||||||
|
title: '时间',
|
||||||
|
dataIndex: 'tm',
|
||||||
|
width: 180,
|
||||||
|
fixed: 'left',
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
text ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水位(m)',
|
||||||
|
dataIndex: 'z',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
text !== undefined && text !== null ? Number(text).toFixed(2) : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '流量(m³/s)',
|
||||||
|
dataIndex: 'q',
|
||||||
|
width: 130,
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
text !== undefined && text !== null ? Number(text).toFixed(1) : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '流速(m³/s)',
|
||||||
|
dataIndex: 'v',
|
||||||
|
width: 130,
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
text !== undefined && text !== null ? Number(text).toFixed(2) : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水位视频',
|
||||||
|
dataIndex: 'rzVideoPath',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (!record.rzVideoPath) return '-';
|
||||||
|
return h(
|
||||||
|
'a-button',
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => playVideo(record.rzVideoPath, '水位视频')
|
||||||
|
},
|
||||||
|
'-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '流速视频',
|
||||||
|
dataIndex: 'speedVideoPath',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (!record.speedVideoPath) return '-';
|
||||||
|
return h(
|
||||||
|
'a-button',
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => playVideo(record.speedVideoPath, '流速视频')
|
||||||
|
},
|
||||||
|
'-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const tableScrollX = tableColumns.reduce((s, c) => s + (c.width || 100), 0);
|
||||||
|
|
||||||
|
// 播放视频
|
||||||
|
const playVideo = (videoUrl: string, title: string) => {
|
||||||
|
currentVideoUrl.value = videoUrl;
|
||||||
|
videoModalTitle.value = title;
|
||||||
|
videoModalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = () => {
|
||||||
|
if (!chartRef.value) return;
|
||||||
|
if (chartInstance) chartInstance.dispose();
|
||||||
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
updateChart(chartData.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
|
const updateChart = (data: any[]) => {
|
||||||
|
if (!chartInstance) return;
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
chartInstance.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted = [...data].sort(
|
||||||
|
(a, b) => new Date(a.tm).getTime() - new Date(b.tm).getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
const xAxisData = sorted.map(item => {
|
||||||
|
const hm = dayjs(item.tm).format('HH:mm');
|
||||||
|
if (hm === '00:00') {
|
||||||
|
const date = dayjs(item.tm).format('MM-DD');
|
||||||
|
return `${hm}\n${date}`;
|
||||||
|
}
|
||||||
|
return hm;
|
||||||
|
});
|
||||||
|
|
||||||
|
const zData = sorted.map(item => item.z);
|
||||||
|
const qData = sorted.map(item => item.q);
|
||||||
|
const vData = sorted.map(item => item.v);
|
||||||
|
|
||||||
|
const waterValues = zData.filter(v => v !== null && v !== undefined);
|
||||||
|
const waterMin = waterValues.length > 0 ? Math.min(...waterValues) : 0;
|
||||||
|
const waterMax = waterValues.length > 0 ? Math.max(...waterValues) : 10;
|
||||||
|
|
||||||
|
const flowValues = [...qData, ...vData].filter(
|
||||||
|
v => v !== null && v !== undefined
|
||||||
|
);
|
||||||
|
const flowMin = flowValues.length > 0 ? Math.min(...flowValues) : 0;
|
||||||
|
const flowMax = flowValues.length > 0 ? Math.max(...flowValues) : 10;
|
||||||
|
|
||||||
|
const formatRules: Record<
|
||||||
|
string,
|
||||||
|
{ format: (v: number) => string; unit: string }
|
||||||
|
> = {
|
||||||
|
水位: { format: v => v.toFixed(2), unit: '(m)' },
|
||||||
|
流量: { format: v => String(Math.round(v)), unit: '(m³/s)' },
|
||||||
|
流速: { format: v => v.toFixed(2), unit: '(m³/s)' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(50, 50, 50, 0.9)',
|
||||||
|
textStyle: { color: '#fff', fontSize: 12 },
|
||||||
|
axisPointer: { type: 'cross' },
|
||||||
|
formatter: (params: any) => {
|
||||||
|
if (!params || params.length === 0) return '';
|
||||||
|
const dataIndex = params[0].dataIndex;
|
||||||
|
const fullTime = sorted[dataIndex]?.tm
|
||||||
|
? dayjs(sorted[dataIndex].tm).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
: '';
|
||||||
|
let html = `<div style="font-size:16px;margin-bottom:8px;">${fullTime}</div>`;
|
||||||
|
params.forEach((param: any) => {
|
||||||
|
if (param.value == null) return;
|
||||||
|
const rule = Object.entries(formatRules).find(([key]) =>
|
||||||
|
param.seriesName.includes(key)
|
||||||
|
);
|
||||||
|
const displayValue = rule
|
||||||
|
? rule[1].format(Number(param.value))
|
||||||
|
: param.value;
|
||||||
|
const unit = rule ? rule[1].unit : '';
|
||||||
|
html += `
|
||||||
|
<div style="display:flex;align-items:center;justify-content:space-between;margin:4px 0;">
|
||||||
|
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${param.color};margin-right:8px;"></span>
|
||||||
|
<span style="flex:1;font-size:14px;text-align:left;margin-right:6px;">${param.seriesName}: </span>
|
||||||
|
<span style="font-size:14px;min-width:60px;text-align:right;"><strong>${displayValue}</strong> ${unit}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
top: 10,
|
||||||
|
data: ['水位', '流量', '流速'],
|
||||||
|
textStyle: { fontSize: 12 },
|
||||||
|
selected: {
|
||||||
|
水位: true,
|
||||||
|
流量: true,
|
||||||
|
流速: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 60,
|
||||||
|
right: 100,
|
||||||
|
top: 80,
|
||||||
|
bottom: 60
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xAxisData,
|
||||||
|
axisLine: { lineStyle: { color: '#000000' } },
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLabel: { fontSize: 12 },
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: '#bfbfbf', type: 'solid' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
name: '水位(m)',
|
||||||
|
type: 'value',
|
||||||
|
position: 'left',
|
||||||
|
axisLine: { show: true, lineStyle: { color: '#56C2E3' } },
|
||||||
|
axisLabel: { color: '#56C2E3' },
|
||||||
|
nameTextStyle: { color: '#56C2E3' },
|
||||||
|
alignTicks: true,
|
||||||
|
scale: true,
|
||||||
|
splitNumber: 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '流量(m³/s)',
|
||||||
|
type: 'value',
|
||||||
|
position: 'right',
|
||||||
|
axisLine: { show: true, lineStyle: { color: '#9556A4' } },
|
||||||
|
axisLabel: { color: '#9556A4' },
|
||||||
|
nameTextStyle: { color: '#9556A4' },
|
||||||
|
alignTicks: true,
|
||||||
|
scale: true,
|
||||||
|
splitNumber: 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '流速(m³/s)',
|
||||||
|
type: 'value',
|
||||||
|
position: 'right',
|
||||||
|
axisLine: { show: true, lineStyle: { color: '#78C300' } },
|
||||||
|
axisLabel: { color: '#78C300' },
|
||||||
|
nameTextStyle: { color: '#78C300' },
|
||||||
|
alignTicks: true,
|
||||||
|
scale: true,
|
||||||
|
splitNumber: 9,
|
||||||
|
offset: 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '水位',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 0,
|
||||||
|
data: zData,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4,
|
||||||
|
lineStyle: { color: '#56C2E3', width: 2 },
|
||||||
|
itemStyle: { color: '#56C2E3' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '流量',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1,
|
||||||
|
data: qData,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4,
|
||||||
|
lineStyle: { color: '#9556A4', width: 2 },
|
||||||
|
itemStyle: { color: '#9556A4' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '流速',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 2,
|
||||||
|
data: vData,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4,
|
||||||
|
lineStyle: { color: '#78C300', width: 2 },
|
||||||
|
itemStyle: { color: '#78C300' }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
xAxisIndex: [0],
|
||||||
|
throttle: 50,
|
||||||
|
start: 0,
|
||||||
|
end: 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
saveAsImage: { title: '保存为图片', type: 'png', pixelRatio: 2 }
|
||||||
|
},
|
||||||
|
right: 20,
|
||||||
|
top: 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chartInstance.setOption(option, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 数据请求
|
||||||
|
const fetchData = async () => {
|
||||||
|
if (!dateRange.value) return;
|
||||||
|
|
||||||
|
// qxd模式必须有stcd才能请求
|
||||||
|
if (isQxdMode.value && !props.stcd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 确定使用的stcd:qxd模式使用props.stcd,否则使用modelStore.params.stcd
|
||||||
|
const currentStcd = isQxdMode.value ? props.stcd : modelStore.params.stcd;
|
||||||
|
|
||||||
|
const filterParams = {
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
field: 'stcd',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: currentStcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'gte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: dateRange.value[0].format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'lte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: dateRange.value[1].format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
sort: [{ field: 'tm', dir: 'asc' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// qxd模式使用getMonitorDataZq,非qxd模式使用queryPostUrlList
|
||||||
|
let rawData;
|
||||||
|
if (isQxdMode.value) {
|
||||||
|
const { getMonitorDataZq } = await import('@/api/mapModal');
|
||||||
|
const res = await getMonitorDataZq(filterParams);
|
||||||
|
rawData = res?.data?.data || res?.data?.records || [];
|
||||||
|
} else {
|
||||||
|
const res = await queryPostUrlList(props.url, filterParams);
|
||||||
|
rawData = res?.data?.data || res?.data?.records || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData.value = [...rawData].reverse();
|
||||||
|
chartData.value = rawData;
|
||||||
|
nextTick(() => updateChart(rawData));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取数据失败:', error);
|
||||||
|
tableData.value = [];
|
||||||
|
chartData.value = [];
|
||||||
|
if (chartInstance) chartInstance.clear();
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => fetchData();
|
||||||
|
|
||||||
|
const initData = () => {
|
||||||
|
if (hasLoaded.value) return;
|
||||||
|
nextTick(() => initChart());
|
||||||
|
fetchData();
|
||||||
|
hasLoaded.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.isActive,
|
||||||
|
active => {
|
||||||
|
if (active && !hasLoaded.value) initData();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => modelStore.params.stcd,
|
||||||
|
(newStcd, oldStcd) => {
|
||||||
|
// 非qxd模式才监听store的stcd变化
|
||||||
|
if (!isQxdMode.value && newStcd && newStcd !== oldStcd) fetchData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// qxd模式下监听props.stcd变化
|
||||||
|
watch(
|
||||||
|
() => props.stcd,
|
||||||
|
(newStcd, oldStcd) => {
|
||||||
|
if (isQxdMode.value && newStcd && newStcd !== oldStcd) {
|
||||||
|
hasLoaded.value = false;
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let resizeObserver: ResizeObserver | null = null;
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.isActive,
|
||||||
|
active => {
|
||||||
|
if (active && chartRef.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
}, 200);
|
||||||
|
if (!resizeObserver) {
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
});
|
||||||
|
resizeObserver.observe(chartRef.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose();
|
||||||
|
chartInstance = null;
|
||||||
|
}
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
resizeObserver = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.flow-measure {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 600px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
:deep(.ant-tabs-nav) {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.content-body {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
height: 600px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-empty {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 500px;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-left: 1px solid #dcdfe6;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 400px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.video-player {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 600px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -321,7 +321,7 @@ const updateChart = (selectedRows: any[]) => {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
formatter: function (value) {
|
formatter: function (value) {
|
||||||
return value + '℃';
|
return value.toFixed(1) + '℃';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
splitLine: { show: true }
|
splitLine: { show: true }
|
||||||
@ -349,6 +349,13 @@ const updateChart = (selectedRows: any[]) => {
|
|||||||
},
|
},
|
||||||
right: 20,
|
right: 20,
|
||||||
top: 10
|
top: 10
|
||||||
|
},
|
||||||
|
dataZoom: {
|
||||||
|
type: 'inside',
|
||||||
|
xAxisIndex: [0],
|
||||||
|
throttle: 50,
|
||||||
|
start: 0,
|
||||||
|
end: 100
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
778
frontend/src/components/MapModal/components/WaterQuality.vue
Normal file
778
frontend/src/components/MapModal/components/WaterQuality.vue
Normal file
@ -0,0 +1,778 @@
|
|||||||
|
<template>
|
||||||
|
<div class="water-quality">
|
||||||
|
<a-tabs v-model:activeKey="activeTabKey">
|
||||||
|
<a-tab-pane v-for="tab in tabsList" :key="tab.key" :tab="tab.name" />
|
||||||
|
<template #rightExtra>
|
||||||
|
<div class="search-bar">
|
||||||
|
<a-range-picker
|
||||||
|
v-model:value="dateRange"
|
||||||
|
format="YYYY-MM-DD HH"
|
||||||
|
:show-time="showTimeConfig"
|
||||||
|
:allowClear="false"
|
||||||
|
:presets="DateSetting.RangeButton.hour"
|
||||||
|
:disabled-date="disabledDate"
|
||||||
|
/>
|
||||||
|
<a-button type="primary" class="search-btn" @click="handleSearch">
|
||||||
|
查询
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
v-if="isSummaryMode"
|
||||||
|
class="search-btn"
|
||||||
|
@click="handleExport"
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-tabs>
|
||||||
|
|
||||||
|
<div class="tab-checkbox">
|
||||||
|
<a-checkbox-group
|
||||||
|
v-model:value="selectedColumns"
|
||||||
|
name="checkboxgroup"
|
||||||
|
:options="filteredCheckBoxOptions"
|
||||||
|
class="checkbox-group"
|
||||||
|
@change="handleCheckboxChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-spin :spinning="isLoading" tip="加载中...">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="content-body">
|
||||||
|
<div class="chart-wrapper">
|
||||||
|
<div ref="chartRef" class="chart-container"></div>
|
||||||
|
<a-empty
|
||||||
|
v-if="!chartData || chartData.length === 0"
|
||||||
|
description="暂无数据"
|
||||||
|
class="chart-empty"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<BasicTable
|
||||||
|
:scrollY="480"
|
||||||
|
:scrollX="tableScrollX"
|
||||||
|
:columns="currentColumns"
|
||||||
|
:data="tableData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
computed,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
nextTick
|
||||||
|
} from 'vue';
|
||||||
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import {
|
||||||
|
getMonitorDataWaterQuality,
|
||||||
|
getMonitorDataWaterQualityDetail,
|
||||||
|
getMonitorDataWaterQualityList
|
||||||
|
} from '@/api/mapModal';
|
||||||
|
import { useModelStore } from '@/store/modules/model';
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue';
|
||||||
|
import { DateSetting } from '@/utils/enumeration';
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isActive: { type: Boolean, default: false },
|
||||||
|
code: { type: String, default: '' },
|
||||||
|
stcd: { type: String, default: '' }
|
||||||
|
});
|
||||||
|
|
||||||
|
const isQxdMode = computed(() => props.code === 'qxd.tabs.szjc');
|
||||||
|
|
||||||
|
const hasLoaded = ref(false);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const tableData = ref<any[]>([]);
|
||||||
|
const chartData = ref<any[]>([]);
|
||||||
|
const chartRef = ref<HTMLElement>();
|
||||||
|
let chartInstance: echarts.ECharts | null = null;
|
||||||
|
|
||||||
|
const tabsList = [{ name: '水质', key: 'szjc.tabs.jcsj' }];
|
||||||
|
const activeTabKey = ref('szjc.tabs.jcsj');
|
||||||
|
|
||||||
|
// 时间选择器配置
|
||||||
|
const showTimeConfig = {
|
||||||
|
format: 'HH',
|
||||||
|
hourStep: 1,
|
||||||
|
minuteStep: 5,
|
||||||
|
secondStep: 60
|
||||||
|
};
|
||||||
|
const disabledDate = (current: Dayjs) =>
|
||||||
|
current && current.isAfter(dayjs(), 'day');
|
||||||
|
|
||||||
|
const initDateRange = (): [Dayjs, Dayjs] => {
|
||||||
|
const startDate = dayjs().subtract(7, 'day').startOf('day');
|
||||||
|
return [startDate, dayjs()];
|
||||||
|
};
|
||||||
|
const dateRange = ref<[Dayjs, Dayjs] | undefined>(initDateRange());
|
||||||
|
|
||||||
|
// ==================== Checkbox 配置 ====================
|
||||||
|
const selectedColumns = ref<any[]>([]);
|
||||||
|
const checkBoxOptions = [{ label: '综合分析', value: 'summary' }];
|
||||||
|
const showSummaryCheckbox = ref(false);
|
||||||
|
|
||||||
|
const isDataEmpty = computed(() => {
|
||||||
|
const data = Array.isArray(chartData.value) ? chartData.value : [];
|
||||||
|
return data.length === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredCheckBoxOptions = computed(() => {
|
||||||
|
if (isDataEmpty.value) return [];
|
||||||
|
|
||||||
|
const available = checkBoxOptions.filter(opt => {
|
||||||
|
if (opt.value === 'summary' && !showSummaryCheckbox.value) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return available;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSummaryMode = computed(() => selectedColumns.value.includes('summary'));
|
||||||
|
|
||||||
|
const handleCheckboxChange = (values: any[]) => {
|
||||||
|
selectedColumns.value = values;
|
||||||
|
if (values.length === 0) {
|
||||||
|
selectedColumns.value = [];
|
||||||
|
}
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 动态参数(用于图表和表格) ====================
|
||||||
|
const qualityParams = ref<any[]>([]); // enable==1 的参数
|
||||||
|
const allDetailParams = ref<any[]>([]); // 所有参数(用于表格列判断)
|
||||||
|
const visibleSeriesNames = ref<string[]>([]); // 当前图表显示的series名称(最多2个)
|
||||||
|
|
||||||
|
// 解析showControl获取unit
|
||||||
|
const parseUnit = (showControl: string) => {
|
||||||
|
if (!showControl) return '';
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(showControl);
|
||||||
|
return config.unit || '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 表格列配置 ====================
|
||||||
|
// 固定左侧列
|
||||||
|
const fixedColumns = [
|
||||||
|
{
|
||||||
|
title: '时间',
|
||||||
|
dataIndex: 'tm',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 160,
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
text ? dayjs(text).format('YYYY-MM-DD HH:mm') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水质要求',
|
||||||
|
dataIndex: 'wwqtgName',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水质等级',
|
||||||
|
dataIndex: 'wqgrdName',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '是否达标',
|
||||||
|
dataIndex: 'sfdb',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ text }: any) => {
|
||||||
|
const isUnqualified = text == 0; // 0是不达标,1是达标
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
style: { color: isUnqualified ? 'red' : 'inherit' }
|
||||||
|
},
|
||||||
|
children: text == 0 ? '不达标' : text == 1 ? '达标' : '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// 动态水质参数列,根据接口返回生成
|
||||||
|
const fixedQualityColumns = computed(() => {
|
||||||
|
const columns = allDetailParams.value.map((p: any) => {
|
||||||
|
const unit = parseUnit(p.showControl);
|
||||||
|
const title = unit ? `${p.ysShowName}(${unit})` : p.ysShowName;
|
||||||
|
const dataIndex = p.ys.toLowerCase();
|
||||||
|
const isEnabled = p.enable == 1;
|
||||||
|
|
||||||
|
// 宽度判断:默认100,超过5个字140,超过6个字160
|
||||||
|
const titleLen = title.length;
|
||||||
|
let width = 100;
|
||||||
|
if (titleLen > 6) {
|
||||||
|
width = 160;
|
||||||
|
} else if (titleLen > 5) {
|
||||||
|
width = 140;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldUpper = p.ys.toUpperCase(); // max/min 中的字段是大写
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
dataIndex,
|
||||||
|
enabled: isEnabled,
|
||||||
|
width,
|
||||||
|
customRender: ({ text, record }: any) => {
|
||||||
|
if (!isEnabled) return '-'; // enable=0 显示-
|
||||||
|
if (text === undefined || text === null || text === '') return '-';
|
||||||
|
const num = Number(text);
|
||||||
|
if (isNaN(num)) return '-';
|
||||||
|
|
||||||
|
// 判断是否超出 max/min(max/min 从 record 中取)
|
||||||
|
const maxList = record?.max;
|
||||||
|
const minList = record?.min;
|
||||||
|
let isOutOfRange = false;
|
||||||
|
|
||||||
|
if (Array.isArray(maxList) && maxList.length > 0) {
|
||||||
|
const maxItem = maxList.find((m: any) => m[fieldUpper] !== undefined);
|
||||||
|
if (maxItem && num > maxItem[fieldUpper]) {
|
||||||
|
isOutOfRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(minList) && minList.length > 0) {
|
||||||
|
const minItem = minList.find((m: any) => m[fieldUpper] !== undefined);
|
||||||
|
if (minItem && num < minItem[fieldUpper]) {
|
||||||
|
isOutOfRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
style: { color: isOutOfRange ? 'red' : 'inherit' }
|
||||||
|
},
|
||||||
|
children: num
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 综合分析模式下添加出库流量列
|
||||||
|
if (isSummaryMode.value) {
|
||||||
|
columns.push({
|
||||||
|
title: '出库流量(m³/s)',
|
||||||
|
dataIndex: 'qo',
|
||||||
|
width: 140,
|
||||||
|
customRender: ({ text }: any) => {
|
||||||
|
if (text === undefined || text === null || text === '') return '-';
|
||||||
|
const num = Number(text);
|
||||||
|
return isNaN(num) ? '-' : num;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
});
|
||||||
|
|
||||||
|
const swjcColumns = computed(() => {
|
||||||
|
return [...fixedColumns, ...fixedQualityColumns.value];
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentColumns = swjcColumns;
|
||||||
|
|
||||||
|
const tableScrollX = computed(() => {
|
||||||
|
const columns = currentColumns.value;
|
||||||
|
const totalWidth = columns.reduce(
|
||||||
|
(sum: number, col: any) => sum + (col.width || 120),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
return totalWidth > 600 ? totalWidth : undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ==================== 图表 ====================
|
||||||
|
function shouldStagger(width: number, dataLen: number) {
|
||||||
|
return dataLen > Math.floor(width / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAxisLabelConfig(chartWidth: number, xAxisData: string[]) {
|
||||||
|
const needStagger = shouldStagger(chartWidth, xAxisData.length);
|
||||||
|
return {
|
||||||
|
fontSize: 12,
|
||||||
|
interval: 'auto',
|
||||||
|
formatter: (value: string, index: number) => {
|
||||||
|
const [date, time] = value.split(' ');
|
||||||
|
if (needStagger) {
|
||||||
|
return index % 2 === 0 ? `${date}\n${time}\n ` : ` \n${date}\n${time}`;
|
||||||
|
}
|
||||||
|
return `${date}\n${time}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateChart = (data: any[], enabledParams: any[]) => {
|
||||||
|
if (!chartInstance) return;
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
chartInstance.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted = [...data].sort(
|
||||||
|
(a, b) => new Date(a.tm).getTime() - new Date(b.tm).getTime()
|
||||||
|
);
|
||||||
|
const xAxisData = sorted.map(item =>
|
||||||
|
dayjs(item.tm).format('YYYY-MM-DD HH:mm')
|
||||||
|
);
|
||||||
|
const width = chartRef.value?.clientWidth || 0;
|
||||||
|
const axisLabelConfig = getAxisLabelConfig(width, xAxisData);
|
||||||
|
|
||||||
|
// 生成所有series(从接口获取所有参数)
|
||||||
|
const allSeries = enabledParams.map((param: any, index: number) => {
|
||||||
|
const showControl = param.showControl || '{}';
|
||||||
|
let lineColor = '';
|
||||||
|
let unit = '';
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(showControl);
|
||||||
|
lineColor = config.lineColor || '';
|
||||||
|
unit = config.unit || '';
|
||||||
|
} catch {
|
||||||
|
// 解析失败使用默认颜色
|
||||||
|
}
|
||||||
|
console.log(param);
|
||||||
|
const dataIndex = param.ys.toLowerCase();
|
||||||
|
const legendName = param.ysShowName; // legend不显示unit
|
||||||
|
const yAxisName = unit ? `${param.ysShowName}\n${unit}` : param.ysShowName; // Y轴显示名称+unit
|
||||||
|
const color = lineColor;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: legendName,
|
||||||
|
ysShowName: param.ysShowName,
|
||||||
|
unit,
|
||||||
|
yAxisName,
|
||||||
|
type: 'line',
|
||||||
|
data: sorted.map(item => item[dataIndex]),
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: { color: color, width: 2 },
|
||||||
|
itemStyle: { color: color }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 综合分析模式下添加出库流量series(默认不选中)
|
||||||
|
if (isSummaryMode.value) {
|
||||||
|
allSeries.push({
|
||||||
|
name: '出库流量',
|
||||||
|
ysShowName: '出库流量',
|
||||||
|
unit: 'm³/s',
|
||||||
|
yAxisName: '出库流量\nm³/s',
|
||||||
|
type: 'line',
|
||||||
|
data: sorted.map(item => item.qo),
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: { color: '#4B79AB', width: 2 },
|
||||||
|
itemStyle: { color: '#4B79AB' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const legendData = allSeries.map((s: any) => s.name);
|
||||||
|
|
||||||
|
// 初始化可见series:默认只选中溶解氧
|
||||||
|
if (visibleSeriesNames.value.length === 0) {
|
||||||
|
const defaultName = '溶解氧';
|
||||||
|
if (legendData.includes(defaultName)) {
|
||||||
|
visibleSeriesNames.value = [defaultName];
|
||||||
|
} else if (legendData.length > 0) {
|
||||||
|
visibleSeriesNames.value = [legendData[0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// series 包含所有数据,通过 legend selected 控制显示
|
||||||
|
const series = allSeries;
|
||||||
|
|
||||||
|
// 构建Y轴配置(最多两个,基于 visibleSeriesNames)
|
||||||
|
const yAxisConfig: any[] = [];
|
||||||
|
const visibleSeriesList = series.filter((s: any) =>
|
||||||
|
visibleSeriesNames.value.includes(s.name)
|
||||||
|
);
|
||||||
|
console.log(visibleSeriesList[0]);
|
||||||
|
|
||||||
|
if (visibleSeriesList.length >= 1) {
|
||||||
|
yAxisConfig.push({
|
||||||
|
name: visibleSeriesList[0].yAxisName,
|
||||||
|
// nameLocation: 'middle',
|
||||||
|
// nameGap: 30,
|
||||||
|
type: 'value',
|
||||||
|
position: 'left',
|
||||||
|
// axisLine: { lineStyle: { color: visibleSeriesList[0].itemStyle.color } },
|
||||||
|
scale: true,
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: '#bfbfbf', type: 'solid' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 给所有series设置yAxisIndex
|
||||||
|
series.forEach((s: any) => {
|
||||||
|
s.yAxisIndex = visibleSeriesNames.value.includes(s.name) ? 0 : 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (visibleSeriesList.length >= 2) {
|
||||||
|
yAxisConfig.push({
|
||||||
|
name: visibleSeriesList[1].yAxisName,
|
||||||
|
// nameLocation: 'middle',
|
||||||
|
// nameGap: 35,
|
||||||
|
type: 'value',
|
||||||
|
position: 'right',
|
||||||
|
// axisLine: { lineStyle: { color: visibleSeriesList[1].itemStyle.color } },
|
||||||
|
scale: true,
|
||||||
|
splitLine: { show: false }
|
||||||
|
});
|
||||||
|
visibleSeriesList[0].yAxisIndex = 0;
|
||||||
|
visibleSeriesList[1].yAxisIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建legend selected状态
|
||||||
|
const legendSelected = legendData.reduce((acc: any, name) => {
|
||||||
|
acc[name] = visibleSeriesNames.value.includes(name);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const option: any = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(50,50,50,0.9)',
|
||||||
|
textStyle: { color: '#fff', fontSize: 12 },
|
||||||
|
axisPointer: { type: 'cross' },
|
||||||
|
formatter: (params: any) => {
|
||||||
|
if (!params?.length) return '';
|
||||||
|
const idx = params[0].dataIndex;
|
||||||
|
const fullTime = sorted[idx]?.tm
|
||||||
|
? dayjs(sorted[idx].tm).format('YYYY-MM-DD HH:mm')
|
||||||
|
: '';
|
||||||
|
let html = `<div style="font-size:16px;margin-bottom:8px;">${fullTime}</div>`;
|
||||||
|
params.forEach((p: any) => {
|
||||||
|
const v = p.value != null ? Number(p.value).toFixed(2) : '-';
|
||||||
|
html += `<div style="display:flex;align-items:center;justify-content:space-between;margin:4px 0;"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${p.color};margin-right:8px;"></span><span style="flex:1;font-size:14px;">${p.seriesName}: </span><span style="font-size:14px;min-width:60px;text-align:right;"><strong>${v}</strong></span></div>`;
|
||||||
|
});
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
width: '80%',
|
||||||
|
right: 60,
|
||||||
|
top: 10,
|
||||||
|
data: legendData,
|
||||||
|
textStyle: { fontSize: 12 },
|
||||||
|
selected: legendSelected
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 60,
|
||||||
|
right: series.length >= 2 ? 60 : 40,
|
||||||
|
top: 80,
|
||||||
|
bottom: 80
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xAxisData,
|
||||||
|
axisLine: { lineStyle: { color: '#000000' } },
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLabel: axisLabelConfig,
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: '#bfbfbf', type: 'solid' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: yAxisConfig.length === 1 ? yAxisConfig[0] : yAxisConfig,
|
||||||
|
series,
|
||||||
|
dataZoom: [
|
||||||
|
{ type: 'inside', xAxisIndex: [0], throttle: 50, start: 0, end: 100 }
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
saveAsImage: { title: '保存为图片', type: 'png', pixelRatio: 2 }
|
||||||
|
},
|
||||||
|
right: 20,
|
||||||
|
top: 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chartInstance.setOption(option, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定legend切换事件(只绑定一次)
|
||||||
|
const bindLegendEvent = () => {
|
||||||
|
if (!chartInstance) return;
|
||||||
|
chartInstance.off('legendselectchanged');
|
||||||
|
chartInstance.on('legendselectchanged', (params: any) => {
|
||||||
|
const selected = params.selected;
|
||||||
|
const name = params.name;
|
||||||
|
const wasSelected = selected[name]; // echarts already updated internal state
|
||||||
|
|
||||||
|
if (wasSelected) {
|
||||||
|
// 用户点击了选中(从取消变为选中)
|
||||||
|
const prevVisible = [...visibleSeriesNames.value];
|
||||||
|
if (prevVisible.length >= 2) {
|
||||||
|
// 已有2个选中,取消第一个,保留第二个和新点击的
|
||||||
|
visibleSeriesNames.value = [prevVisible[1], name];
|
||||||
|
} else {
|
||||||
|
visibleSeriesNames.value = [...new Set([...prevVisible, name])];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 用户点击了取消选中
|
||||||
|
visibleSeriesNames.value = visibleSeriesNames.value.filter(
|
||||||
|
n => n !== name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新渲染图表(使用allDetailParams包含所有参数)
|
||||||
|
updateChart(chartData.value, allDetailParams.value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 数据请求 ====================
|
||||||
|
const fetchData = async () => {
|
||||||
|
if (!dateRange.value) return;
|
||||||
|
|
||||||
|
// qxd模式必须有stcd才能请求
|
||||||
|
if (isQxdMode.value && !props.stcd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
// 确定使用的stcd:qxd模式使用props.stcd,否则使用modelStore.params.stcd
|
||||||
|
const currentStcd = isQxdMode.value ? props.stcd : modelStore.params.stcd;
|
||||||
|
|
||||||
|
const filterParams = {
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
field: 'stcd',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: currentStcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'gte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: dateRange.value[0].format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tm',
|
||||||
|
operator: 'lte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: dateRange.value[1].format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
sort: [{ field: 'tm', dir: 'asc' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 并发请求三个接口
|
||||||
|
const [qualityRes, detailRes, listRes] = await Promise.all([
|
||||||
|
getMonitorDataWaterQuality(filterParams),
|
||||||
|
getMonitorDataWaterQualityDetail({
|
||||||
|
stcd: currentStcd,
|
||||||
|
tbCode: 'WQ_R',
|
||||||
|
startTime: dateRange.value[0].format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
endTime: dateRange.value[1].format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}),
|
||||||
|
getMonitorDataWaterQualityList(filterParams)
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 判断是否显示综合分析(只有当data不为null且不为空数组时才显示)
|
||||||
|
const qualityData = qualityRes?.data?.data || qualityRes?.data?.records;
|
||||||
|
showSummaryCheckbox.value = !!qualityData && qualityData.length > 0;
|
||||||
|
|
||||||
|
// 处理detail数据
|
||||||
|
const detailData = detailRes?.data?.data || detailRes?.data || [];
|
||||||
|
allDetailParams.value = detailData; // 所有参数用于表格列判断
|
||||||
|
qualityParams.value = detailData.filter((item: any) => item.enable == 1); // enable==1用于图表
|
||||||
|
|
||||||
|
// 重置可见series(因为参数可能变化)
|
||||||
|
visibleSeriesNames.value = [];
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const listData = listRes?.data?.data || listRes?.data?.records || [];
|
||||||
|
|
||||||
|
tableData.value = [...listData].reverse();
|
||||||
|
chartData.value = listData;
|
||||||
|
nextTick(() => updateChart(listData, allDetailParams.value));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取水质数据失败:', error);
|
||||||
|
tableData.value = [];
|
||||||
|
chartData.value = [];
|
||||||
|
qualityParams.value = [];
|
||||||
|
if (chartInstance) chartInstance.clear();
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => fetchData();
|
||||||
|
const handleExport = () => {
|
||||||
|
/* 导出逻辑 */
|
||||||
|
};
|
||||||
|
|
||||||
|
const initData = () => {
|
||||||
|
if (hasLoaded.value) return;
|
||||||
|
nextTick(() => {
|
||||||
|
if (chartRef.value && !chartInstance)
|
||||||
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
// 延迟绑定事件,确保chart已经渲染完成
|
||||||
|
nextTick(() => {
|
||||||
|
bindLegendEvent();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fetchData();
|
||||||
|
hasLoaded.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.isActive,
|
||||||
|
active => {
|
||||||
|
if (active && !hasLoaded.value) initData();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => modelStore.params.stcd,
|
||||||
|
(newStcd, oldStcd) => {
|
||||||
|
// 非qxd模式才监听store的stcd变化
|
||||||
|
if (!isQxdMode.value && newStcd && newStcd !== oldStcd) fetchData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// qxd模式下监听props.stcd变化
|
||||||
|
watch(
|
||||||
|
() => props.stcd,
|
||||||
|
(newStcd, oldStcd) => {
|
||||||
|
if (isQxdMode.value && newStcd && newStcd !== oldStcd) {
|
||||||
|
hasLoaded.value = false;
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// ResizeObserver
|
||||||
|
let resizeObserver: ResizeObserver | null = null;
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.isActive,
|
||||||
|
active => {
|
||||||
|
if (active && chartRef.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
}, 200);
|
||||||
|
if (!resizeObserver) {
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
});
|
||||||
|
resizeObserver.observe(chartRef.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
if (chartInstance) chartInstance.resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose();
|
||||||
|
chartInstance = null;
|
||||||
|
}
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
resizeObserver = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.water-quality {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 600px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
:deep(.ant-tabs-nav) {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-checkbox {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
left: 30%;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.content-body {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
height: 600px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-empty {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 500px;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-left: 1px solid #dcdfe6;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
|
|
||||||
<div class="tab-checkbox" v-if="activeTabKey === 'swjc.tabs.jcsj'">
|
<div class="tab-checkbox">
|
||||||
<a-checkbox-group
|
<a-checkbox-group
|
||||||
v-model:value="selectedColumns"
|
v-model:value="selectedColumns"
|
||||||
name="checkboxgroup"
|
name="checkboxgroup"
|
||||||
@ -105,6 +105,7 @@ import dayjs, { Dayjs } from 'dayjs';
|
|||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import { Tooltip } from 'ant-design-vue';
|
import { Tooltip } from 'ant-design-vue';
|
||||||
import {
|
import {
|
||||||
|
// getMonitorDataWaterTempList,
|
||||||
getMonitorDataWaterTemp,
|
getMonitorDataWaterTemp,
|
||||||
getMonitorDataWaterTempPowerStation,
|
getMonitorDataWaterTempPowerStation,
|
||||||
getMonitorDataWaterTempPowerStation2
|
getMonitorDataWaterTempPowerStation2
|
||||||
@ -117,7 +118,9 @@ import { InfoCircleOutlined } from '@ant-design/icons-vue';
|
|||||||
const modelStore = useModelStore();
|
const modelStore = useModelStore();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isActive: { type: Boolean, default: false }
|
code: { type: String, default: '' },
|
||||||
|
isActive: { type: Boolean, default: false },
|
||||||
|
stcd: { type: String, default: '' }
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasLoaded = ref(false);
|
const hasLoaded = ref(false);
|
||||||
@ -503,6 +506,7 @@ const updateChart = (data: any[]) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
width: '80%',
|
||||||
type: 'scroll',
|
type: 'scroll',
|
||||||
top: 10,
|
top: 10,
|
||||||
data: ['水温'],
|
data: ['水温'],
|
||||||
@ -685,6 +689,8 @@ const updateChart = (data: any[]) => {
|
|||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
type: 'scroll',
|
type: 'scroll',
|
||||||
|
width: '80%',
|
||||||
|
right: 60,
|
||||||
top: 10,
|
top: 10,
|
||||||
data: [
|
data: [
|
||||||
'出库水温',
|
'出库水温',
|
||||||
@ -809,10 +815,21 @@ const updateChart = (data: any[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ==================== 数据请求 ====================
|
// ==================== 数据请求 ====================
|
||||||
|
const isQxdMode = computed(() => props.code === 'qxd.tabs.jcsj');
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
if (!dateRange.value) return;
|
if (!dateRange.value) return;
|
||||||
|
|
||||||
|
// qxd模式必须有stcd才能请求
|
||||||
|
if (isQxdMode.value && !props.stcd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
// 确定使用的stcd:qxd模式使用props.stcd,否则使用modelStore.params.stcd
|
||||||
|
const currentStcd = isQxdMode.value ? props.stcd : modelStore.params.stcd;
|
||||||
|
|
||||||
const filterParams = {
|
const filterParams = {
|
||||||
filter: {
|
filter: {
|
||||||
logic: 'and',
|
logic: 'and',
|
||||||
@ -821,7 +838,7 @@ const fetchData = async () => {
|
|||||||
field: 'stcd',
|
field: 'stcd',
|
||||||
operator: 'eq',
|
operator: 'eq',
|
||||||
dataType: 'string',
|
dataType: 'string',
|
||||||
value: modelStore.params.stcd
|
value: currentStcd
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'tm',
|
field: 'tm',
|
||||||
@ -840,22 +857,35 @@ const fetchData = async () => {
|
|||||||
sort: [{ field: 'tm', dir: 'asc' }]
|
sort: [{ field: 'tm', dir: 'asc' }]
|
||||||
};
|
};
|
||||||
|
|
||||||
const [mainRes, powerStationRes, powerStationRes2] = await Promise.all([
|
// qxd模式只调用getMonitorDataWaterTemp
|
||||||
getMonitorDataWaterTemp(filterParams),
|
if (isQxdMode.value) {
|
||||||
getMonitorDataWaterTempPowerStation({ stcd: modelStore.params.stcd }),
|
const mainRes = await getMonitorDataWaterTemp(filterParams);
|
||||||
getMonitorDataWaterTempPowerStation2({ stcd: modelStore.params.stcd })
|
const mainData = mainRes?.data?.data || mainRes?.data?.records || [];
|
||||||
]);
|
showSummaryCheckbox.value = false;
|
||||||
|
showDeepCheckbox.value = false;
|
||||||
|
selectedColumns.value = [];
|
||||||
|
tableData.value = [...mainData].reverse();
|
||||||
|
chartData.value = mainData;
|
||||||
|
nextTick(() => updateChart(mainData));
|
||||||
|
} else {
|
||||||
|
// 原有模式
|
||||||
|
const [mainRes, powerStationRes, powerStationRes2] = await Promise.all([
|
||||||
|
getMonitorDataWaterTemp(filterParams),
|
||||||
|
getMonitorDataWaterTempPowerStation({ stcd: currentStcd }),
|
||||||
|
getMonitorDataWaterTempPowerStation2({ stcd: currentStcd })
|
||||||
|
]);
|
||||||
|
|
||||||
const mainData = mainRes?.data?.data || mainRes?.data?.records || [];
|
const mainData = mainRes?.data?.data || mainRes?.data?.records || [];
|
||||||
showSummaryCheckbox.value = !!powerStationRes?.data?.ioWtrv;
|
showSummaryCheckbox.value = !!powerStationRes?.data?.ioWtrv;
|
||||||
const powerStation2Data =
|
const powerStation2Data =
|
||||||
powerStationRes2?.data?.data || powerStationRes2?.data || null;
|
powerStationRes2?.data?.data || powerStationRes2?.data || null;
|
||||||
showDeepCheckbox.value =
|
showDeepCheckbox.value =
|
||||||
!!powerStationRes?.data?.hasRstcdWtvt && powerStation2Data !== null;
|
!!powerStationRes?.data?.hasRstcdWtvt && powerStation2Data !== null;
|
||||||
|
|
||||||
tableData.value = [...mainData].reverse();
|
tableData.value = [...mainData].reverse();
|
||||||
chartData.value = mainData;
|
chartData.value = mainData;
|
||||||
nextTick(() => updateChart(mainData));
|
nextTick(() => updateChart(mainData));
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取数据失败:', error);
|
console.error('获取数据失败:', error);
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
@ -892,7 +922,19 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
() => modelStore.params.stcd,
|
() => modelStore.params.stcd,
|
||||||
(newStcd, oldStcd) => {
|
(newStcd, oldStcd) => {
|
||||||
if (newStcd && newStcd !== oldStcd) fetchData();
|
// 非qxd模式才监听store的stcd变化
|
||||||
|
if (!isQxdMode.value && newStcd && newStcd !== oldStcd) fetchData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// qxd模式下监听props.stcd变化
|
||||||
|
watch(
|
||||||
|
() => props.stcd,
|
||||||
|
(newStcd, oldStcd) => {
|
||||||
|
if (isQxdMode.value && newStcd && newStcd !== oldStcd) {
|
||||||
|
hasLoaded.value = false;
|
||||||
|
initData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
<a-empty
|
<a-empty
|
||||||
v-if="!loading && videoList.length === 0"
|
v-if="!loading && videoList.length === 0"
|
||||||
description="暂无数据"
|
description="暂无数据"
|
||||||
|
class="flex align-center justify-center h-[530px] flex-col"
|
||||||
/>
|
/>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
@ -27,7 +28,11 @@
|
|||||||
<!-- 中间视频区域 55% -->
|
<!-- 中间视频区域 55% -->
|
||||||
<a-col flex="55%" class="center-panel">
|
<a-col flex="55%" class="center-panel">
|
||||||
<!-- 视频宫格 -->
|
<!-- 视频宫格 -->
|
||||||
<div class="video-grid" :class="`layout-${viewLayout}`">
|
<div
|
||||||
|
class="video-grid"
|
||||||
|
:class="`layout-${viewLayout}`"
|
||||||
|
v-show="videoList.length > 0"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="index in parseInt(viewLayout)"
|
v-for="index in parseInt(viewLayout)"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -42,6 +47,11 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<a-empty
|
||||||
|
v-show="videoList.length === 0"
|
||||||
|
description="暂无数据"
|
||||||
|
class="h-full flex align-center justify-center flex-col"
|
||||||
|
/>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<!-- 右侧录像列表 30% -->
|
<!-- 右侧录像列表 30% -->
|
||||||
@ -80,7 +90,9 @@
|
|||||||
<div class="record-list">
|
<div class="record-list">
|
||||||
<a-spin :spinning="recordLoading">
|
<a-spin :spinning="recordLoading">
|
||||||
<div v-if="paginatedRecords.length === 0" class="empty-record">
|
<div v-if="paginatedRecords.length === 0" class="empty-record">
|
||||||
<a-empty />
|
<a-empty
|
||||||
|
class="h-[410px] flex align-center justify-center flex-col"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="record-grid">
|
<div v-else class="record-grid">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -12,11 +12,14 @@
|
|||||||
<!-- 问题:
|
<!-- 问题:
|
||||||
1.基础信息图片展示是什么逻辑
|
1.基础信息图片展示是什么逻辑
|
||||||
2. 电站专题展示逻辑
|
2. 电站专题展示逻辑
|
||||||
3. 实时视频回放 少接口
|
3. 实时视频回放 少接口✅️
|
||||||
4. 预警提示 少接口
|
4. 预警提示 少接口
|
||||||
5. 生态流量 达标率查询不对
|
5. 生态流量 达标率查询不对(✅️)
|
||||||
6. 鱼类适应性繁殖同期对比NAN (王)
|
6. 鱼类适应性繁殖同期对比NAN (王)
|
||||||
7. 出库水温 综合分析 导出没做
|
7. 出库水温 综合分析 导出没做
|
||||||
|
8. 栖息地-流量监测 没有水位视频和流量视频 字段没数据
|
||||||
|
9. 栖息地 水温、水质、流量没有数据没法测
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<div v-if="modelStore.showStcdSelector" class="stcd-selector-wrapper">
|
<div v-if="modelStore.showStcdSelector" class="stcd-selector-wrapper">
|
||||||
<a-select
|
<a-select
|
||||||
@ -33,7 +36,7 @@
|
|||||||
<a-tabs :active-key="currentActiveKey" @change="onTabChange">
|
<a-tabs :active-key="currentActiveKey" @change="onTabChange">
|
||||||
<a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.name">
|
<a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.name">
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<template #rightExtra>
|
<template #rightExtra v-if="anchor.sttp == 'ENG' || anchor.sttp == 'eng'">
|
||||||
<a-tooltip :title="!isEngConfig ? '' : '该电站无专题配置'">
|
<a-tooltip :title="!isEngConfig ? '' : '该电站无专题配置'">
|
||||||
<a-button type="primary" :disabled="isEngConfig">
|
<a-button type="primary" :disabled="isEngConfig">
|
||||||
<i class="icon iconfont icon-topic mr-[5px]"></i>
|
<i class="icon iconfont icon-topic mr-[5px]"></i>
|
||||||
@ -45,6 +48,16 @@
|
|||||||
<!-- 内容区域 - 使用动态组件 + keep-alive 实现按需加载和缓存 -->
|
<!-- 内容区域 - 使用动态组件 + keep-alive 实现按需加载和缓存 -->
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<div class="content-wrapper" v-show="isQxdMode(currentActiveKey)">
|
||||||
|
测站:
|
||||||
|
<a-select
|
||||||
|
v-model:value="currentQxdSelectedStcd"
|
||||||
|
:options="qxdStationOptions"
|
||||||
|
style="width: 200px; margin-bottom: 12px"
|
||||||
|
placeholder="请选择站点"
|
||||||
|
@change="handleQxdStationChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<!-- 基本信息 -->
|
<!-- 基本信息 -->
|
||||||
<BasicInfo
|
<BasicInfo
|
||||||
v-show="currentActiveKey === 'basicInfo'"
|
v-show="currentActiveKey === 'basicInfo'"
|
||||||
@ -71,12 +84,41 @@
|
|||||||
<WaterTemperature
|
<WaterTemperature
|
||||||
v-show="currentActiveKey === 'WaterTemperature'"
|
v-show="currentActiveKey === 'WaterTemperature'"
|
||||||
:is-active="currentActiveKey === 'WaterTemperature'"
|
:is-active="currentActiveKey === 'WaterTemperature'"
|
||||||
|
:code="getTabCode('WaterTemperature')"
|
||||||
|
:stcd="
|
||||||
|
getTabCode('WaterTemperature') == 'qxd.tabs.jcsj'
|
||||||
|
? qxdSelectedStcd
|
||||||
|
: ''
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<!-- 监测数据 - 垂向水温 -->
|
<!-- 监测数据 - 垂向水温 -->
|
||||||
<VerticalWaterTemperature
|
<VerticalWaterTemperature
|
||||||
v-show="currentActiveKey === 'VerticalWaterTemperature'"
|
v-show="currentActiveKey === 'VerticalWaterTemperature'"
|
||||||
:is-active="currentActiveKey === 'VerticalWaterTemperature'"
|
:is-active="currentActiveKey === 'VerticalWaterTemperature'"
|
||||||
/>
|
/>
|
||||||
|
<!-- 监测数据 - 水质 -->
|
||||||
|
<WaterQuality
|
||||||
|
v-show="currentActiveKey === 'WaterQuality'"
|
||||||
|
:is-active="currentActiveKey === 'WaterQuality'"
|
||||||
|
:code="getTabCode('WaterQuality')"
|
||||||
|
:stcd="
|
||||||
|
getTabCode('WaterQuality') == 'qxd.tabs.szjc'
|
||||||
|
? qxdSelectedStcdWq
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<!-- 流量监测 -->
|
||||||
|
<FlowMeasure
|
||||||
|
v-show="currentActiveKey === 'FlowMeasure'"
|
||||||
|
:is-active="currentActiveKey === 'FlowMeasure'"
|
||||||
|
:url="getTabUrl('FlowMeasure')"
|
||||||
|
:code="getTabCode('FlowMeasure')"
|
||||||
|
:stcd="
|
||||||
|
getTabCode('FlowMeasure') == 'qxd.tabs.lcjs'
|
||||||
|
? qxdSelectedStcdZq
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
/>
|
||||||
<!-- 预警提示 -->
|
<!-- 预警提示 -->
|
||||||
<EarlyWarningAlert
|
<EarlyWarningAlert
|
||||||
v-show="currentActiveKey === 'tableTabs'"
|
v-show="currentActiveKey === 'tableTabs'"
|
||||||
@ -123,17 +165,160 @@ import PanoramaInfo from './components/PanoramaInfo.vue'; // 全景影像
|
|||||||
import MonitorInfo from './components/MonitorInfo.vue'; // 电站运行过程线
|
import MonitorInfo from './components/MonitorInfo.vue'; // 电站运行过程线
|
||||||
import WaterTemperature from './components/WaterTemperature.vue'; // 水温
|
import WaterTemperature from './components/WaterTemperature.vue'; // 水温
|
||||||
import VerticalWaterTemperature from './components/VerticalWaterTemperature.vue'; // 垂向水温
|
import VerticalWaterTemperature from './components/VerticalWaterTemperature.vue'; // 垂向水温
|
||||||
|
import WaterQuality from './components/WaterQuality.vue'; // 水质
|
||||||
import EarlyWarningAlert from './components/EarlyWarningAlert.vue'; // 预警提示
|
import EarlyWarningAlert from './components/EarlyWarningAlert.vue'; // 预警提示
|
||||||
|
import FlowMeasure from './components/FlowMeasure.vue'; // 流量监测
|
||||||
import EcologicalFlow from './components/EcologicalFlow.vue'; // 生态流量
|
import EcologicalFlow from './components/EcologicalFlow.vue'; // 生态流量
|
||||||
import Attachment from './components/Attachment.vue'; // 查看报告/批复文件
|
import Attachment from './components/Attachment.vue'; // 查看报告/批复文件
|
||||||
import WaterTemperatureRep from './components/WaterTemperatureRep.vue'; // 水温对比数据
|
import WaterTemperatureRep from './components/WaterTemperatureRep.vue'; // 水温对比数据
|
||||||
import { useModelStore } from '@/store/modules/model';
|
import { useModelStore } from '@/store/modules/model';
|
||||||
import { handleTabs } from './setting.config';
|
import { handleTabs } from './setting.config';
|
||||||
|
import {
|
||||||
|
getMonitorDataWt,
|
||||||
|
getMonitorDataWq,
|
||||||
|
getMonitorDataZq
|
||||||
|
} from '@/api/mapModal';
|
||||||
|
|
||||||
const modelStore = useModelStore();
|
const modelStore = useModelStore();
|
||||||
const tabsConfig = ref([]);
|
const tabsConfig = ref([]);
|
||||||
// 判断是否显示电站专题配置
|
// 判断是否显示电站专题配置
|
||||||
const isEngConfig = ref(true);
|
const isEngConfig = ref(true);
|
||||||
|
|
||||||
|
// ==================== qxd 栖息地模式相关 ====================
|
||||||
|
// qxd模式配置映射
|
||||||
|
const qxdConfigMap: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
sttpCode: string;
|
||||||
|
apiFn: (data: any) => Promise<any>;
|
||||||
|
selectProp: string;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
'qxd.tabs.jcsj': {
|
||||||
|
// 水温
|
||||||
|
sttpCode: 'WTRV',
|
||||||
|
apiFn: getMonitorDataWt,
|
||||||
|
selectProp: 'qxdSelectedStcd'
|
||||||
|
},
|
||||||
|
'qxd.tabs.szjc': {
|
||||||
|
// 水质
|
||||||
|
sttpCode: 'WQ',
|
||||||
|
apiFn: getMonitorDataWq,
|
||||||
|
selectProp: 'qxdSelectedStcdWq'
|
||||||
|
},
|
||||||
|
'qxd.tabs.lcjs': {
|
||||||
|
// 流量监测
|
||||||
|
sttpCode: 'ZQ',
|
||||||
|
apiFn: getMonitorDataZq,
|
||||||
|
selectProp: 'qxdSelectedStcdZq'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 各模式的站点选项和选中值
|
||||||
|
const qxdStationOptions = ref<{ label: string; value: string }[]>([]);
|
||||||
|
const qxdSelectedStcd = ref<string>('');
|
||||||
|
const qxdSelectedStcdWq = ref<string>('');
|
||||||
|
const qxdSelectedStcdZq = ref<string>('');
|
||||||
|
const qxdLoadedCodes = ref<Set<string>>(new Set());
|
||||||
|
|
||||||
|
// 获取当前tab对应的qxd配置
|
||||||
|
const getCurrentQxdConfig = (tabKey: string) => {
|
||||||
|
const code = getTabCode(tabKey);
|
||||||
|
return code && qxdConfigMap[code] ? qxdConfigMap[code] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取选中的stcd
|
||||||
|
const getQxdSelectedStcd = (tabKey: string) => {
|
||||||
|
const config = getCurrentQxdConfig(tabKey);
|
||||||
|
if (!config) return '';
|
||||||
|
switch (config.selectProp) {
|
||||||
|
case 'qxdSelectedStcd':
|
||||||
|
return qxdSelectedStcd.value;
|
||||||
|
case 'qxdSelectedStcdWq':
|
||||||
|
return qxdSelectedStcdWq.value;
|
||||||
|
case 'qxdSelectedStcdZq':
|
||||||
|
return qxdSelectedStcdZq.value;
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置选中的stcd
|
||||||
|
const setQxdSelectedStcd = (tabKey: string, value: string) => {
|
||||||
|
const config = getCurrentQxdConfig(tabKey);
|
||||||
|
if (!config) return;
|
||||||
|
switch (config.selectProp) {
|
||||||
|
case 'qxdSelectedStcd':
|
||||||
|
qxdSelectedStcd.value = value;
|
||||||
|
break;
|
||||||
|
case 'qxdSelectedStcdWq':
|
||||||
|
qxdSelectedStcdWq.value = value;
|
||||||
|
break;
|
||||||
|
case 'qxdSelectedStcdZq':
|
||||||
|
qxdSelectedStcdZq.value = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载栖息地站点列表
|
||||||
|
const loadQxdStationList = async (tabKey: string) => {
|
||||||
|
const code = getTabCode(tabKey);
|
||||||
|
if (!code || !qxdConfigMap[code]) return;
|
||||||
|
if (qxdLoadedCodes.value.has(code)) return;
|
||||||
|
|
||||||
|
const config = qxdConfigMap[code];
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
field: 'fhstcd',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: modelStore.params.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sttpCode',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: config.sttpCode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
select: ['stcd', 'stnm']
|
||||||
|
};
|
||||||
|
const res = await config.apiFn(params);
|
||||||
|
const stations = res?.data?.data || res?.data?.records || [];
|
||||||
|
if (stations.length > 0) {
|
||||||
|
qxdStationOptions.value = stations.map((item: any) => ({
|
||||||
|
label: item.stnm,
|
||||||
|
value: item.stcd
|
||||||
|
}));
|
||||||
|
setQxdSelectedStcd(tabKey, stations[0].stcd);
|
||||||
|
}
|
||||||
|
qxdLoadedCodes.value.add(code);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`获取站点列表失败(${code}):`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取当前激活tab对应的选中stcd (支持v-model双向绑定)
|
||||||
|
const currentQxdSelectedStcd = computed({
|
||||||
|
get: () => getQxdSelectedStcd(currentActiveKey.value),
|
||||||
|
set: (val: string) => setQxdSelectedStcd(currentActiveKey.value, val)
|
||||||
|
});
|
||||||
|
|
||||||
|
// 判断是否是qxd模式
|
||||||
|
const isQxdMode = (tabKey: string) => {
|
||||||
|
const code = getTabCode(tabKey);
|
||||||
|
return code && qxdConfigMap[code] ? true : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理栖息地站点切换
|
||||||
|
const handleQxdStationChange = () => {
|
||||||
|
// 站点切换后,子组件会通过 watch stcd 自动刷新
|
||||||
|
};
|
||||||
// import MapView from './components/MapView.vue';
|
// import MapView from './components/MapView.vue';
|
||||||
// import SurroundingInfo from './components/SurroundingInfo.vue';
|
// import SurroundingInfo from './components/SurroundingInfo.vue';
|
||||||
|
|
||||||
@ -176,6 +361,7 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
// 内部维护的 activeKey
|
// 内部维护的 activeKey
|
||||||
const currentActiveKey = ref<string>('');
|
const currentActiveKey = ref<string>('');
|
||||||
|
const anchor = ref<string>('');
|
||||||
|
|
||||||
// 监听外部传入的 activeKey 变化,同步到内部状态
|
// 监听外部传入的 activeKey 变化,同步到内部状态
|
||||||
watch(
|
watch(
|
||||||
@ -192,12 +378,29 @@ watch(
|
|||||||
newVal => {
|
newVal => {
|
||||||
if (!newVal || Object.keys(newVal).length === 0) return;
|
if (!newVal || Object.keys(newVal).length === 0) return;
|
||||||
console.log(newVal);
|
console.log(newVal);
|
||||||
tabsConfig.value = handleTabs(newVal);
|
anchor.value = newVal;
|
||||||
|
let params = newVal;
|
||||||
|
if (['VD', 'WTRV', 'ZQ', 'WQ'].includes(params?.sttpCode)) {
|
||||||
|
params.sttp = params.sttpCode;
|
||||||
|
}
|
||||||
|
tabsConfig.value = handleTabs({ ...params });
|
||||||
let value = tabsConfig.value.find((item: any) => item.default);
|
let value = tabsConfig.value.find((item: any) => item.default);
|
||||||
currentActiveKey.value = value?.key;
|
currentActiveKey.value = value?.key;
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ deep: true, immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 监听 tab 切换,如果是 qxd 模式,加载站点列表
|
||||||
|
watch(
|
||||||
|
() => currentActiveKey.value,
|
||||||
|
activeKey => {
|
||||||
|
const code = getTabCode(activeKey);
|
||||||
|
if (code && qxdConfigMap[code]) {
|
||||||
|
loadQxdStationList(activeKey);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
// 监听内部 tab 切换
|
// 监听内部 tab 切换
|
||||||
const onTabChange = (key: string) => {
|
const onTabChange = (key: string) => {
|
||||||
currentActiveKey.value = key;
|
currentActiveKey.value = key;
|
||||||
@ -213,6 +416,12 @@ const handleClose = () => {
|
|||||||
// 清理状态,避免影响下次打开
|
// 清理状态,避免影响下次打开
|
||||||
modelStore.showStcdSelector = false;
|
modelStore.showStcdSelector = false;
|
||||||
modelStore.stcdOptions = [];
|
modelStore.stcdOptions = [];
|
||||||
|
// 清理qxd模式状态
|
||||||
|
qxdStationOptions.value = [];
|
||||||
|
qxdSelectedStcd.value = '';
|
||||||
|
qxdSelectedStcdWq.value = '';
|
||||||
|
qxdSelectedStcdZq.value = '';
|
||||||
|
qxdLoadedCodes.value = new Set();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 为了方便模板中使用,将 props.data 暴露给模板
|
// 为了方便模板中使用,将 props.data 暴露给模板
|
||||||
|
|||||||
@ -320,11 +320,10 @@ const FPTabs: Array<any> =
|
|||||||
// code: 'gyss.tabs.sssp'
|
// code: 'gyss.tabs.sssp'
|
||||||
// }
|
// }
|
||||||
{
|
{
|
||||||
name: '监测数据',
|
name: '在线监测数据',
|
||||||
key: 'FishFacilityMonitorData', //Normal
|
key: 'FishFacilityMonitorData', //Normal
|
||||||
type: 'FishFacilityMonitorData', //Normal
|
type: 'FishFacilityMonitorData', //Normal
|
||||||
code: 'gyss.tabs.jcsj',
|
code: 'gyss.tabs.jcsj'
|
||||||
default: true // 默认显示
|
|
||||||
// tabs: [
|
// tabs: [
|
||||||
// {
|
// {
|
||||||
// name: '',
|
// name: '',
|
||||||
@ -340,7 +339,8 @@ const FPTabs: Array<any> =
|
|||||||
name: '运行情况',
|
name: '运行情况',
|
||||||
key: 'FishFacilityRunState', //Normal1
|
key: 'FishFacilityRunState', //Normal1
|
||||||
type: 'FishFacilityRunState', //Normal
|
type: 'FishFacilityRunState', //Normal
|
||||||
code: 'gyss.tabs.yxqk'
|
code: 'gyss.tabs.yxqk',
|
||||||
|
default: true // 默认显示
|
||||||
// tabs: [
|
// tabs: [
|
||||||
// {
|
// {
|
||||||
// name: '',
|
// name: '',
|
||||||
@ -504,119 +504,20 @@ const FHTabs: Array<any> = [
|
|||||||
name: '水温监测',
|
name: '水温监测',
|
||||||
key: 'WaterTemperature',
|
key: 'WaterTemperature',
|
||||||
type: 'WaterTemperature',
|
type: 'WaterTemperature',
|
||||||
tabs: [
|
code: 'qxd.tabs.jcsj'
|
||||||
{
|
|
||||||
url: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
|
|
||||||
name: '水温',
|
|
||||||
type: 'WaterTemperature',
|
|
||||||
tableUrl: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
|
|
||||||
chartType: 'line',
|
|
||||||
// filter: NormalStcdFilter,
|
|
||||||
filterProps: {
|
|
||||||
params: {
|
|
||||||
ftype: 'WE',
|
|
||||||
sttp: 'WT', //WT
|
|
||||||
dataDimensionType: 'hyBase',
|
|
||||||
dataDimensionVal: 'all'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '水质监测',
|
name: '水质监测',
|
||||||
key: 'WaterQuality',
|
key: 'WaterQuality',
|
||||||
type: 'WaterQuality',
|
type: 'WaterQuality',
|
||||||
tabs: [
|
code: 'qxd.tabs.szjc'
|
||||||
{
|
|
||||||
url: '/wmp-env-server/env/wq/data/GetKendoListCust',
|
|
||||||
name: '水质',
|
|
||||||
type: 'monitor',
|
|
||||||
key: 'WaterQuality',
|
|
||||||
tableUrl: '/wmp-env-server/env/wq/data/GetKendoListCust',
|
|
||||||
chartType: 'lines',
|
|
||||||
// chartEvent: {
|
|
||||||
// legendselectchanged: (object: any, instance: any) => {
|
|
||||||
// const selected = object.selected
|
|
||||||
// const options = instance.getOption()
|
|
||||||
// if (options.grid instanceof Array) {
|
|
||||||
// options.grid = options.grid[0]
|
|
||||||
// }
|
|
||||||
// if (selected != undefined && options) {
|
|
||||||
// let yAxis: any = options.yAxis
|
|
||||||
// yAxis.map((item: any, index: number) => {
|
|
||||||
// item.show = false
|
|
||||||
// for (let i in selected) {
|
|
||||||
// if (selected[i] == true && item.name.indexOf(i) !== -1) {
|
|
||||||
// item.show = true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// options.legend && (options.legend.selected = selected)
|
|
||||||
// let offset = 30
|
|
||||||
// let padding = 60
|
|
||||||
// if (options.yAxis && options.yAxis instanceof Array && options.grid && !(options.grid instanceof Array)) {
|
|
||||||
// let showYAxis = yAxis.filter((x: any) => {
|
|
||||||
// return x.show
|
|
||||||
// })
|
|
||||||
// showYAxis.map((yAxis: any, index: number) => {
|
|
||||||
// yAxis.position = index % 2 === 0 ? "left" : "right"
|
|
||||||
// yAxis.offset = padding * Math.floor(index / 2)
|
|
||||||
// if (index >= 4) {
|
|
||||||
// yAxis.offset = padding * Math.floor(2 / 2)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// if (showYAxis.length % 2 === 0) {
|
|
||||||
// options.grid.left = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
|
|
||||||
// options.grid.right = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
|
|
||||||
// } else {
|
|
||||||
// const left = showYAxis.filter((x: any) => x.position === "left")
|
|
||||||
// const right = showYAxis.filter((x: any) => x.position === "right")
|
|
||||||
// const left_start = left.length ? 0 : 60
|
|
||||||
// const right_start = left.length ? 0 : 60
|
|
||||||
// options.grid.left = left_start + padding * (left.length >= 2 ? 2 : left.length)
|
|
||||||
// options.grid.right = right_start + padding * (right.length >= 2 ? 2 : right.length)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// instance.setOption(options, false, true)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// filter: NormalStcdFilter,
|
|
||||||
filterProps: {
|
|
||||||
params: {
|
|
||||||
ftype: 'WE',
|
|
||||||
sttp: 'WQ',
|
|
||||||
dataDimensionType: 'hyBase',
|
|
||||||
dataDimensionVal: 'all'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '流量监测',
|
name: '流量监测',
|
||||||
key: 'FlowMeasure',
|
key: 'FlowMeasure',
|
||||||
type: 'FlowMeasure'
|
type: 'FlowMeasure',
|
||||||
// tabs: [
|
code: 'qxd.tabs.lcjs',
|
||||||
// {
|
url: '/zq/river/GetKendoListCust'
|
||||||
// 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: '实时视频',
|
name: '实时视频',
|
||||||
@ -624,43 +525,22 @@ const FHTabs: Array<any> = [
|
|||||||
type: 'video',
|
type: 'video',
|
||||||
url: ''
|
url: ''
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// name: "全景影像",
|
|
||||||
// key: "panoramaInfo",
|
|
||||||
// type: "panorama"
|
|
||||||
// }
|
|
||||||
];
|
];
|
||||||
// const ZQTabs: Array<any> = [
|
const ZQTabs: Array<any> = [
|
||||||
// {
|
{
|
||||||
// name: '基础信息',
|
name: '基础信息',
|
||||||
// key: 'basicInfo',
|
key: 'basicInfo',
|
||||||
// type: 'basic',
|
type: 'basic',
|
||||||
// url: '/bbi/siteBipc/getSiteBasicInfo'
|
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
|
||||||
// },
|
default: true // 默认显示
|
||||||
// {
|
},
|
||||||
// name: '流量监测',
|
{
|
||||||
// key: 'FlowMeasure',
|
name: '流量监测',
|
||||||
// type: 'FlowMeasure',
|
key: 'FlowMeasure',
|
||||||
// tabs: [
|
type: 'FlowMeasure',
|
||||||
// {
|
url: '/zq/river/GetKendoListCust'
|
||||||
// url: '/wmp-swqx-server/zq/river/GetKendoListCust',
|
}
|
||||||
// name: '流量',
|
];
|
||||||
// type: 'monitor',
|
|
||||||
// tableUrl: '/wmp-swqx-server/zq/river/GetKendoListCust',
|
|
||||||
// chartType: 'line',
|
|
||||||
// filterProps: {
|
|
||||||
// params: {
|
|
||||||
// ftype: 'FHT',
|
|
||||||
// sttp: 'ZQ',
|
|
||||||
// dataDimensionType: 'hyBase',
|
|
||||||
// dataDimensionVal: 'all',
|
|
||||||
// maptype: '2'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
|
|
||||||
// //水质监测站 √
|
// //水质监测站 √
|
||||||
const WQFBTabs: Array<any> = [
|
const WQFBTabs: Array<any> = [
|
||||||
@ -1212,8 +1092,8 @@ const handleTabs = (modaldata: any) => {
|
|||||||
} else {
|
} else {
|
||||||
return ENGTabs;
|
return ENGTabs;
|
||||||
}
|
}
|
||||||
case 'WT':
|
case 'WT': // 水温
|
||||||
case 'WTRV':
|
case 'WTRV': // 垂向水温
|
||||||
if (modaldata.enfc == '1') {
|
if (modaldata.enfc == '1') {
|
||||||
return WTTabs1;
|
return WTTabs1;
|
||||||
} else {
|
} else {
|
||||||
@ -1340,8 +1220,8 @@ const handleTabs = (modaldata: any) => {
|
|||||||
} else {
|
} else {
|
||||||
return FPTabs;
|
return FPTabs;
|
||||||
}
|
}
|
||||||
// case 'ZQ':
|
case 'ZQ': // 流量检测站
|
||||||
// return ZQTabs
|
return ZQTabs;
|
||||||
// case 'FB':
|
// case 'FB':
|
||||||
// if (modaldata.bldstt == '1' || modaldata.bldstt == '0') {
|
// if (modaldata.bldstt == '1' || modaldata.bldstt == '0') {
|
||||||
// return FBTabs1
|
// return FBTabs1
|
||||||
|
|||||||
@ -146,9 +146,12 @@ export class MapOl implements MapInterface {
|
|||||||
this.map.on('click', evt => {
|
this.map.on('click', evt => {
|
||||||
this.popupManager.showPopup(undefined, undefined);
|
this.popupManager.showPopup(undefined, undefined);
|
||||||
this.popupManager.handleMapClick(evt.pixel, detectedFeature => {
|
this.popupManager.handleMapClick(evt.pixel, detectedFeature => {
|
||||||
|
console.log(detectedFeature);
|
||||||
modelStore.modalVisible = true;
|
modelStore.modalVisible = true;
|
||||||
modelStore.params = detectedFeature.values_;
|
modelStore.params = detectedFeature.values_;
|
||||||
modelStore.title = detectedFeature.values_.titleName + ' 详情信息';
|
modelStore.title =
|
||||||
|
detectedFeature.values_.titleName ||
|
||||||
|
detectedFeature.values_.stnm + ' 详情信息';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -187,10 +187,11 @@ const handleControllerClick = (item: any) => {
|
|||||||
switch (item.key) {
|
switch (item.key) {
|
||||||
case 'fullScreen':
|
case 'fullScreen':
|
||||||
isFullScreen.value = !isFullScreen.value;
|
isFullScreen.value = !isFullScreen.value;
|
||||||
|
map.flyTopanto([92.39728, 29.24587], 14);
|
||||||
// console.log(mapClass.hasLayer('eng_point'));
|
// console.log(mapClass.hasLayer('eng_point'));
|
||||||
// map.jdPanelControlShowAndHidden("01", false);
|
// map.jdPanelControlShowAndHidden("01", false);
|
||||||
map.mdLayerTreeShowOrHidden('eng_point', false);
|
// map.mdLayerTreeShowOrHidden('eng_point', false);
|
||||||
map.mdLayerTreeShowOrHidden('wq_countryWq_point', true);
|
// map.mdLayerTreeShowOrHidden('wq_countryWq_point', true);
|
||||||
// map.controlBaseLayerTreeShowAndHidden(
|
// map.controlBaseLayerTreeShowAndHidden(
|
||||||
// 'eng_point',
|
// 'eng_point',
|
||||||
// 'eng_point',
|
// 'eng_point',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,6 @@ service.interceptors.request.use(
|
|||||||
config.url.includes('/wmp-eng-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.url.includes('/wmp-swqx-server')
|
||||||
|
|
||||||
) {
|
) {
|
||||||
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
||||||
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
||||||
@ -34,7 +33,7 @@ service.interceptors.request.use(
|
|||||||
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
|
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
|
||||||
|
|
||||||
config.headers.authorization =
|
config.headers.authorization =
|
||||||
'bearer 7894f05d-7204-4117-bda5-8d2f850ae463';
|
'bearer f6ce5036-cefe-487b-b731-b6d7b8922e0f';
|
||||||
config.baseURL = '/';
|
config.baseURL = '/';
|
||||||
} else {
|
} else {
|
||||||
const user = useUserStoreHook();
|
const user = useUserStoreHook();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user