水温监测右侧弹框接口对接
This commit is contained in:
parent
42bd4c66a0
commit
ca83d4be94
@ -1,7 +1,65 @@
|
||||
import request from '@/utils/request';
|
||||
export function getKendoListCust(data: any) {
|
||||
return request({
|
||||
url: '/sw/alongList/qgc/GetKendoListCust',
|
||||
url: '/api/wmp-env-server/sw/alongList/qgc/GetKendoListCust',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//获取水温下拉框
|
||||
export function wbsbGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/wbsb/GetKendoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取垂向水温变化树形站点数据
|
||||
* @param data 请求参数
|
||||
* @returns Promise
|
||||
*/
|
||||
export function getChuiXiangShuiWenTreeStcd(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/base/sdrvwts/default/treeStcd',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取垂向水温变化列表数据(按月份聚合)
|
||||
* @param data 请求参数 { filter, sort }
|
||||
* @returns Promise
|
||||
*/
|
||||
export function getCxswList(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/sw/dzCxList/GetKendoListCust',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//获取出入库水温下拉选则树
|
||||
export function getVmsstbprpt(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//出入库水温图表数据
|
||||
//
|
||||
export function inOutOneGetKendoListCust(data: any) {
|
||||
return request({
|
||||
url: '/api/wmp-env-server/sw/inOutOne/GetKendoListCust',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
//水温监测工作开展情况
|
||||
export function baseEvnmAutoMonitorGetKendoListCust(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
|
||||
@ -33,25 +33,45 @@
|
||||
<img v-else src="@/assets/components/arrow-down.png" alt="">
|
||||
</div>
|
||||
<div v-if="moreSelect.show">
|
||||
<a-tree-select v-model:value="moreSelectValue" show-search
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="Please select"
|
||||
allow-clear tree-default-expand-all :tree-data="moreSelect.options"
|
||||
tree-node-filter-prop="label">
|
||||
<a-tree-select v-model:value="moreSelectValue" show-search :size="'small'" style="width: 110px"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto',minWidth: '180px' }" placeholder=" "
|
||||
:tree-data="processedMoreSelectOptions"
|
||||
:field-names="{ label: 'title', value: 'value', children: 'children' }"
|
||||
tree-node-filter-prop="label"
|
||||
:expanded-keys="expandedKeys"
|
||||
popup-class-name="no-wrap-tree-select"
|
||||
@select="handleTreeSelect"
|
||||
@expand="handleTreeExpand"
|
||||
@dropdownVisibleChange="handleDropdownVisibleChange">
|
||||
</a-tree-select>
|
||||
</div>
|
||||
<div v-if="datetimePicker.show">
|
||||
<!-- 添加 locale 属性来设置语言 -->
|
||||
<a-date-picker v-model:value="datetimeValue" show-time
|
||||
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '120px' }"
|
||||
<a-date-picker
|
||||
v-model:value="datetimeValue"
|
||||
show-time
|
||||
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '130px' }"
|
||||
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
|
||||
:picker="datetimePicker.picker" placeholder=" " @change="handleDateTimeChange"
|
||||
:size="'small'" />
|
||||
:picker="datetimePicker.picker"
|
||||
:allowClear="false"
|
||||
placeholder=" "
|
||||
@change="handleDateTimeChange"
|
||||
:size="'small'"
|
||||
:disabledDate="createDisabledDateFn(datetimePicker.picker)"
|
||||
:disabledTime="disabledTimeForSinglePicker" />
|
||||
<!-- 修改为 locale 变量 -->
|
||||
</div>
|
||||
<div v-if="scopeDate.show" class="title_scopeDate">
|
||||
<a-range-picker v-model:value="scopeDateValue" :picker="scopeDate.picker"
|
||||
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '150px' : '') }"
|
||||
:format="scopeDate.format" :range-separator="' 至 '" :size="'small'" />
|
||||
<a-range-picker
|
||||
v-model:value="scopeDateValue"
|
||||
:picker="scopeDate.picker"
|
||||
:allowClear="false"
|
||||
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '180px' : '') }"
|
||||
:format="scopeDate.format"
|
||||
:range-separator="' 至 '"
|
||||
:size="'small'"
|
||||
:presets="computedScopeDatePresets"
|
||||
:disabledDate="createDisabledDateFn(scopeDate.picker)" />
|
||||
</div>
|
||||
<div v-if="tabs.show" class="typeOne">
|
||||
<div @click="handleTabClick('one')" :class="tabsValue == 'one' ? 'typezhong' : ''">图片</div>
|
||||
@ -66,7 +86,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, watch, computed } from 'vue';
|
||||
import {
|
||||
QuestionCircleOutlined,
|
||||
InfoCircleOutlined
|
||||
@ -169,10 +189,10 @@ const props = defineProps({
|
||||
})
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['tab-change']);
|
||||
const emit = defineEmits(['tab-change', 'update-values']);
|
||||
const isExpand = ref(true);
|
||||
const selectValue = ref(props.select.value)
|
||||
const moreSelectValue = ref(props.select.value)
|
||||
const moreSelectValue = ref(props.moreSelect.value)
|
||||
const datetimeValue = ref<Dayjs | null>(props.datetimePicker.value ? dayjs(props.datetimePicker.value) : null);
|
||||
const scopeDateValue = ref<[Dayjs, Dayjs] | undefined>(
|
||||
props.scopeDate.value && Array.isArray(props.scopeDate.value)
|
||||
@ -180,21 +200,338 @@ const scopeDateValue = ref<[Dayjs, Dayjs] | undefined>(
|
||||
: undefined
|
||||
);
|
||||
const tabsValue = ref(props.tabs.value)
|
||||
|
||||
// 树选择器展开状态管理
|
||||
const expandedKeys = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* 创建针对不同 picker 类型的日期禁用函数
|
||||
* @param pickerType - 选择器类型: year | month | quarter | week | date
|
||||
* @returns disabledDate 回调函数
|
||||
*/
|
||||
const createDisabledDateFn = (pickerType: string) => {
|
||||
return (current: Dayjs) => {
|
||||
if (!current) return false
|
||||
|
||||
const now = dayjs()
|
||||
|
||||
switch (pickerType) {
|
||||
case 'year':
|
||||
// 年份选择器:禁用 > 当前年份
|
||||
return current.year() > now.year()
|
||||
|
||||
case 'month':
|
||||
// 月份选择器:禁用 > 当前年月
|
||||
return current.isAfter(now, 'month')
|
||||
|
||||
case 'quarter':
|
||||
// 季度选择器:禁用 > 当前季度
|
||||
return current.isAfter(now, 'quarter')
|
||||
|
||||
case 'week':
|
||||
// 周选择器:禁用 > 当前周
|
||||
return current.isAfter(now, 'week')
|
||||
|
||||
case 'date':
|
||||
default:
|
||||
// 日期选择器:禁用 > 当前日期
|
||||
return current.isAfter(now, 'day')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单日期选择器的时间禁用函数(针对 show-time)
|
||||
* 精确限制到当前时刻的时分秒
|
||||
*/
|
||||
const disabledTimeForSinglePicker = () => {
|
||||
// 只在 datetimePicker 显示且为 date 类型时生效
|
||||
if (!props.datetimePicker.show || props.datetimePicker.picker !== 'date') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const now = dayjs()
|
||||
const selectedDate = datetimeValue.value
|
||||
|
||||
// 如果未选择日期,或选择的不是今天,则不限制时间
|
||||
if (!selectedDate || !selectedDate.isSame(now, 'day')) {
|
||||
return {}
|
||||
}
|
||||
|
||||
// 辅助函数:生成从 start 到 end-1 的数组
|
||||
const range = (start: number, end: number) => {
|
||||
const result: number[] = []
|
||||
for (let i = start; i < end; i++) {
|
||||
result.push(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
return {
|
||||
// 禁用当前小时之后的所有小时
|
||||
disabledHours: () => {
|
||||
return range(now.hour() + 1, 24)
|
||||
},
|
||||
|
||||
// 禁用当前分钟之后的所有分钟(仅在当前小时)
|
||||
disabledMinutes: (selectedHour: number) => {
|
||||
if (selectedHour === now.hour()) {
|
||||
return range(now.minute() + 1, 60)
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
// 禁用当前秒数之后的所有秒数(仅在当前小时和分钟)
|
||||
disabledSeconds: (selectedHour: number, selectedMinute: number) => {
|
||||
if (selectedHour === now.hour() && selectedMinute === now.minute()) {
|
||||
return range(now.second() + 1, 60)
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // 定义 locale 变量
|
||||
// const locale = zhCN;
|
||||
|
||||
// console.log(locale, "zhCN");
|
||||
|
||||
/**
|
||||
* 递归处理树数据,为父节点添加 selectable: false
|
||||
* @param data 原始树数据
|
||||
* @returns 处理后的树数据
|
||||
*/
|
||||
const processTreeData = (data: any[]): any[] => {
|
||||
if (!data || !Array.isArray(data)) return [];
|
||||
|
||||
return data.map(item => {
|
||||
const newItem = { ...item };
|
||||
|
||||
// 如果有子项,标记为不可选中
|
||||
if (newItem.children && newItem.children.length > 0) {
|
||||
newItem.selectable = false;
|
||||
// 递归处理子项
|
||||
newItem.children = processTreeData(newItem.children);
|
||||
} else {
|
||||
// 叶子节点默认可选中(显式声明更清晰)
|
||||
newItem.selectable = true;
|
||||
}
|
||||
|
||||
return newItem;
|
||||
});
|
||||
};
|
||||
|
||||
// 计算属性:处理后的树数据
|
||||
const processedMoreSelectOptions = computed(() => {
|
||||
return processTreeData(props.moreSelect.options || []);
|
||||
});
|
||||
|
||||
/**
|
||||
* 计算属性:根据 picker 类型动态生成快捷日期选项
|
||||
*/
|
||||
const computedScopeDatePresets = computed(() => {
|
||||
const now = dayjs();
|
||||
const presets: Array<{ label: string; value: [Dayjs, Dayjs] }> = [];
|
||||
|
||||
// 根据 picker 类型生成对应的快捷选项
|
||||
switch (props.scopeDate.picker) {
|
||||
case 'year':
|
||||
// 年份选择器:只显示今年
|
||||
presets.push({
|
||||
label: '今年',
|
||||
value: [now.startOf('year'), now]
|
||||
});
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
// 月份选择器:显示今天、昨天、最近七天、最近一个月、最近三个月、今年
|
||||
presets.push(
|
||||
{
|
||||
label: '今天',
|
||||
value: [now.startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '昨天',
|
||||
value: [now.subtract(1, 'day').startOf('day'), now.subtract(1, 'day').endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近七天',
|
||||
value: [now.subtract(6, 'day').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近一个月',
|
||||
value: [now.subtract(1, 'month').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近三个月',
|
||||
value: [now.subtract(3, 'month').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '今年',
|
||||
value: [now.startOf('year'), now.endOf('day')]
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case 'quarter':
|
||||
// 季度选择器:显示最近一季度、今年
|
||||
presets.push(
|
||||
{
|
||||
label: '最近一季度',
|
||||
value: [now.subtract(1, 'quarter').startOf('quarter'), now.endOf('quarter')]
|
||||
},
|
||||
{
|
||||
label: '今年',
|
||||
value: [now.startOf('year'), now.endOf('quarter')]
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
// 周选择器:显示本周、上周、最近四周
|
||||
presets.push(
|
||||
{
|
||||
label: '本周',
|
||||
value: [now.startOf('week'), now.endOf('week')]
|
||||
},
|
||||
{
|
||||
label: '上周',
|
||||
value: [now.subtract(1, 'week').startOf('week'), now.subtract(1, 'week').endOf('week')]
|
||||
},
|
||||
{
|
||||
label: '最近四周',
|
||||
value: [now.subtract(3, 'week').startOf('week'), now.endOf('week')]
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
default:
|
||||
// 日期选择器:显示所有常用选项
|
||||
presets.push(
|
||||
{
|
||||
label: '今天',
|
||||
value: [now.startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '昨天',
|
||||
value: [now.subtract(1, 'day').startOf('day'), now.subtract(1, 'day').endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近七天',
|
||||
value: [now.subtract(6, 'day').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近一个月',
|
||||
value: [now.subtract(1, 'month').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '最近三个月',
|
||||
value: [now.subtract(3, 'month').startOf('day'), now.endOf('day')]
|
||||
},
|
||||
{
|
||||
label: '今年',
|
||||
value: [now.startOf('year'), now.endOf('day')]
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return presets;
|
||||
});
|
||||
|
||||
/**
|
||||
* 处理树节点选择事件
|
||||
* 由于父节点已设置 selectable: false,这里只会接收到叶子节点
|
||||
* @param selectedKeys 选中的键值(可能是字符串或数组)
|
||||
* @param info 节点信息对象(本身就是节点,不是包含 node 的对象)
|
||||
*/
|
||||
const handleTreeSelect = (selectedKeys: string | string[], info: any) => {
|
||||
// selectedKeys 可能是字符串(单选模式)或数组(多选模式)
|
||||
let selectedValue: string;
|
||||
|
||||
if (typeof selectedKeys === 'string') {
|
||||
// 单选模式:selectedKeys 直接就是字符串
|
||||
selectedValue = selectedKeys;
|
||||
} else if (Array.isArray(selectedKeys)) {
|
||||
// 多选模式:取第一个元素
|
||||
selectedValue = selectedKeys[0];
|
||||
} else {
|
||||
// 兜底:尝试从 info 中获取
|
||||
selectedValue = info?.value || '';
|
||||
}
|
||||
|
||||
moreSelectValue.value = selectedValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理树节点展开/收起事件
|
||||
* @param keys 展开的节点键值数组
|
||||
*/
|
||||
const handleTreeExpand = (keys: string[]) => {
|
||||
expandedKeys.value = keys;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查找节点的父节点路径
|
||||
* @param treeData 树数据
|
||||
* @param targetValue 目标节点的值
|
||||
* @returns 父节点值的数组(从根到直接父节点)
|
||||
*/
|
||||
const findParentKeys = (treeData: any[], targetValue: string): string[] => {
|
||||
const parentKeys: string[] = [];
|
||||
|
||||
const search = (nodes: any[], target: string, parents: string[]): boolean => {
|
||||
for (const node of nodes) {
|
||||
if (node.value === target) {
|
||||
// 找到目标节点,记录所有父节点
|
||||
parentKeys.push(...parents);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.children && node.children.length > 0) {
|
||||
// 递归搜索子节点,将当前节点加入父节点列表
|
||||
if (search(node.children, target, [...parents, node.value])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
search(treeData, targetValue, []);
|
||||
return parentKeys;
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理下拉框显示/隐藏变化事件
|
||||
* 当下拉框打开且有选中值时,自动展开该节点的所有父节点
|
||||
* @param visible 下拉框是否可见
|
||||
*/
|
||||
const handleDropdownVisibleChange = (visible: boolean) => {
|
||||
if (visible && moreSelectValue.value && processedMoreSelectOptions.value.length > 0) {
|
||||
// 查找选中节点的所有父节点
|
||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, moreSelectValue.value);
|
||||
|
||||
if (parentKeys.length > 0) {
|
||||
// 合并现有的展开节点和父节点,去重
|
||||
const mergedKeys = Array.from(new Set([...expandedKeys.value, ...parentKeys]));
|
||||
expandedKeys.value = mergedKeys;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 下拉选择框事件处理
|
||||
const handleChange = (value: string) => {
|
||||
console.log(`selected ${value}`);
|
||||
// Handle change
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
console.log('blur');
|
||||
// Handle blur
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
console.log('focus');
|
||||
// Handle focus
|
||||
};
|
||||
|
||||
const filterOption = (input: string, option?: { value: string }) => {
|
||||
@ -209,7 +546,7 @@ const getPopupContainer = (trigger: HTMLElement) => {
|
||||
|
||||
//时间选择框事件处理
|
||||
const handleDateTimeChange = (date: any | null, dateString: string) => {
|
||||
console.log('Selected DateTime:', date, dateString);
|
||||
// Handle date time change
|
||||
};
|
||||
|
||||
const handleTabClick = (value: string) => {
|
||||
@ -220,9 +557,137 @@ const handleTabClick = (value: string) => {
|
||||
tabLabel: value === 'one' ? '图片' : '视频'
|
||||
});
|
||||
};
|
||||
|
||||
// 统一收集并发送所有控件的值
|
||||
const emitAllValues = () => {
|
||||
const payload: any = {
|
||||
select: selectValue.value,
|
||||
moreSelect: moreSelectValue.value,
|
||||
tabs: tabsValue.value,
|
||||
};
|
||||
|
||||
// 处理单个时间选择器
|
||||
if (datetimeValue.value) {
|
||||
// 使用传入的 format,如果没有则根据 picker 类型设置默认格式
|
||||
const format = props.datetimePicker.format || getDefaultFormat(props.datetimePicker.picker);
|
||||
payload.datetime = datetimeValue.value.format(format);
|
||||
} else {
|
||||
payload.datetime = null;
|
||||
}
|
||||
|
||||
// 处理时间范围选择器
|
||||
if (scopeDateValue.value && Array.isArray(scopeDateValue.value)) {
|
||||
// 使用传入的 format,如果没有则根据 picker 类型设置默认格式
|
||||
const format = props.scopeDate.format || getDefaultFormat(props.scopeDate.picker);
|
||||
payload.scopeDate = scopeDateValue.value.map(d => d ? d.format(format) : null);
|
||||
} else {
|
||||
payload.scopeDate = [];
|
||||
}
|
||||
|
||||
emit('update-values', payload);
|
||||
};
|
||||
|
||||
// 根据 picker 类型获取默认格式
|
||||
const getDefaultFormat = (picker: string): string => {
|
||||
switch (picker) {
|
||||
case 'year':
|
||||
return 'YYYY';
|
||||
case 'month':
|
||||
return 'YYYY-MM';
|
||||
case 'quarter':
|
||||
return 'YYYY-[Q]Q';
|
||||
case 'week':
|
||||
return 'YYYY-wo';
|
||||
case 'date':
|
||||
default:
|
||||
return 'YYYY-MM-DD';
|
||||
}
|
||||
};
|
||||
|
||||
// 监听各个变量的变化
|
||||
watch([selectValue, moreSelectValue, datetimeValue, scopeDateValue, tabsValue], () => {
|
||||
emitAllValues();
|
||||
});
|
||||
|
||||
// 监听 props 变化,实现父子组件数据同步
|
||||
watch(
|
||||
() => props.select.value,
|
||||
(newVal) => {
|
||||
if (newVal !== selectValue.value) {
|
||||
selectValue.value = newVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.moreSelect.value,
|
||||
(newVal) => {
|
||||
if (newVal !== moreSelectValue.value) {
|
||||
moreSelectValue.value = newVal;
|
||||
|
||||
// 如果有新值且树数据已加载,自动展开其父节点
|
||||
if (newVal && processedMoreSelectOptions.value.length > 0) {
|
||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, newVal);
|
||||
if (parentKeys.length > 0) {
|
||||
expandedKeys.value = Array.from(new Set([...expandedKeys.value, ...parentKeys]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.datetimePicker.value,
|
||||
(newVal) => {
|
||||
const newDayjs = newVal ? dayjs(newVal) : null;
|
||||
if (!datetimeValue.value || !newDayjs || !datetimeValue.value.isSame(newDayjs)) {
|
||||
datetimeValue.value = newDayjs;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.scopeDate.value,
|
||||
(newVal) => {
|
||||
if (newVal && Array.isArray(newVal) && newVal.length === 2) {
|
||||
const newRange: [Dayjs, Dayjs] = [dayjs(newVal[0]), dayjs(newVal[1])];
|
||||
const currentRange = scopeDateValue.value;
|
||||
|
||||
// 检查是否需要更新(避免不必要的触发)
|
||||
if (!currentRange ||
|
||||
!currentRange[0].isSame(newRange[0]) ||
|
||||
!currentRange[1].isSame(newRange[1])) {
|
||||
scopeDateValue.value = newRange;
|
||||
}
|
||||
} else {
|
||||
if (scopeDateValue.value) {
|
||||
scopeDateValue.value = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.tabs.value,
|
||||
(newVal) => {
|
||||
if (newVal !== tabsValue.value) {
|
||||
tabsValue.value = newVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 页面加载时执行的逻辑
|
||||
onMounted(() => {
|
||||
console.log(props.select);
|
||||
// 初始化时发送一次默认值
|
||||
emitAllValues();
|
||||
|
||||
// 如果 tree-select 有默认值,预先展开其父节点
|
||||
if (moreSelectValue.value && processedMoreSelectOptions.value.length > 0) {
|
||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, moreSelectValue.value);
|
||||
if (parentKeys.length > 0) {
|
||||
expandedKeys.value = parentKeys;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,150 +1,429 @@
|
||||
<!-- 垂向水温变化图 -->
|
||||
<template>
|
||||
<SidePanelItem title="垂向水温变化">
|
||||
<SidePanelItem title="垂向水温变化" :moreSelect="select" :datetimePicker="datetimePicker"
|
||||
@update-values="handlePanelChange1">
|
||||
<div class="chart-wrapper">
|
||||
<!-- 图例与翻页控制 -->
|
||||
<div class="chart-header">
|
||||
<div class="legend-container">
|
||||
<div
|
||||
v-for="item in currentLegendItems"
|
||||
:key="item.name"
|
||||
class="legend-item"
|
||||
:class="{ inactive: legendInactiveSet.has(item.name) }"
|
||||
@click="toggleLegend(item.name)"
|
||||
>
|
||||
<span class="legend-dot" :style="{ backgroundColor: legendInactiveSet.has(item.name) ? '#ccc' : item.color }"></span>
|
||||
<span class="legend-text" :style="{ color: legendInactiveSet.has(item.name) ? '#ccc' : '#333' }">{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<span class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">◀</span>
|
||||
<span class="page-info">{{ currentPage }}/{{ totalPages }}</span>
|
||||
<span class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">▶</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图表容器 -->
|
||||
<div ref="chartRef" class="chart-container"></div>
|
||||
<a-spin :spinning="loading" tip="加载中...">
|
||||
<div v-show="showemit && !loading" ref="chartRef" class="chart-container"></div>
|
||||
<div v-show="!showemit && !loading" class="chart-container">
|
||||
<a-empty />
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import type { ECharts } from 'echarts';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { getChuiXiangShuiWenTreeStcd, getCxswList } from "@/api/sw";
|
||||
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
const baseid = ref('');
|
||||
|
||||
// 定义组件名
|
||||
defineOptions({
|
||||
name: 'chuixiangshuiwenChangeMod'
|
||||
});
|
||||
|
||||
// ==================== 加载状态与显示控制 ====================
|
||||
const showemit = ref(false); // 控制图表是否显示
|
||||
const loading = ref(false); // 控制加载状态
|
||||
|
||||
// ==================== 工具函数 ====================
|
||||
|
||||
/**
|
||||
* 智能刻度计算函数
|
||||
*/
|
||||
function chartMax(
|
||||
targetTickCount: number,
|
||||
max: number,
|
||||
min: number,
|
||||
round: boolean = true,
|
||||
base: number = 0
|
||||
): { min: number; max: number; scale: number } {
|
||||
const range = max - min;
|
||||
|
||||
if (range === 0) {
|
||||
const expandedMax = max * 1.1;
|
||||
const expandedMin = min * 0.9;
|
||||
return {
|
||||
min: expandedMin,
|
||||
max: expandedMax,
|
||||
scale: (expandedMax - expandedMin) / targetTickCount
|
||||
};
|
||||
}
|
||||
|
||||
let idealScale = range / targetTickCount;
|
||||
const magnitude = Math.pow(10, Math.floor(Math.log10(idealScale)));
|
||||
const normalized = idealScale / magnitude;
|
||||
|
||||
let friendlyScale: number;
|
||||
if (normalized < 1.5) {
|
||||
friendlyScale = 1 * magnitude;
|
||||
} else if (normalized < 3) {
|
||||
friendlyScale = 2 * magnitude;
|
||||
} else if (normalized < 7) {
|
||||
friendlyScale = 5 * magnitude;
|
||||
} else {
|
||||
friendlyScale = 10 * magnitude;
|
||||
}
|
||||
|
||||
let newMin = Math.floor(min / friendlyScale) * friendlyScale;
|
||||
let newMax = Math.ceil(max / friendlyScale) * friendlyScale;
|
||||
|
||||
if (newMin > min) newMin -= friendlyScale;
|
||||
if (newMax < max) newMax += friendlyScale;
|
||||
|
||||
if (round) {
|
||||
newMin = Math.round(newMin);
|
||||
newMax = Math.round(newMax);
|
||||
friendlyScale = Math.round(friendlyScale);
|
||||
}
|
||||
|
||||
return {
|
||||
min: newMin,
|
||||
max: newMax,
|
||||
scale: friendlyScale
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组最大值
|
||||
*/
|
||||
function arrMax(arr: number[]): number {
|
||||
return Math.max(...arr.filter(v => v !== null && v !== undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组最小值
|
||||
*/
|
||||
function arrMin(arr: number[]): number {
|
||||
return Math.min(...arr.filter(v => v !== null && v !== undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 API 返回的 aggregates 数据转换为图表数据格式
|
||||
*/
|
||||
function transformAggregatesToChartData(aggregates: Record<string, any[]>): Array<{
|
||||
name: string;
|
||||
dataXy: Array<[number, number]>;
|
||||
}> {
|
||||
const result: Array<{ name: string; dataXy: Array<[number, number]> }> = [];
|
||||
|
||||
for (let month = 1; month <= 12; month++) {
|
||||
const key = month.toString();
|
||||
const monthData = aggregates[key];
|
||||
|
||||
// ✅ 不跳过空月份,而是创建空数组(与 React 版本保持一致)
|
||||
if (!monthData || monthData.length === 0) {
|
||||
result.push({
|
||||
name: `${month}月`,
|
||||
dataXy: [] // 空数组,ECharts 会显示为断开
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// 转换数据格式:{ wthg, vwt } → [vwt, wthg]
|
||||
const dataXy: Array<[number, number]> = monthData.map((item: any) => [
|
||||
parseFloat(item.vwt), // 温度
|
||||
parseInt(item.wthg) // 深度/高程
|
||||
]);
|
||||
|
||||
result.push({
|
||||
name: `${month}月`,
|
||||
dataXy
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前年月生成颜色和图例显隐状态
|
||||
*/
|
||||
function generateColorsAndVisibility(
|
||||
dataLength: number, // ⚠️ 现在固定传入 12
|
||||
sDate: string | number
|
||||
): {
|
||||
colors: string[];
|
||||
selected: Record<string, boolean>;
|
||||
} {
|
||||
const baseColors = [
|
||||
'#6ca4f7', '#78c300', '#9556a4', '#df91ab',
|
||||
'#7399c6', '#dbb629', '#56c2e3', '#f56a06',
|
||||
'#cdba75', '#76523b', '#df75b6', '#00a050'
|
||||
];
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
const currentMonth = new Date().getMonth() + 1;
|
||||
const selectedYear = typeof sDate === 'string' ? parseInt(sDate) : sDate;
|
||||
|
||||
const colors: string[] = [];
|
||||
const selected: Record<string, boolean> = {};
|
||||
|
||||
// ✅ 修改:固定循环 12 次,而非 dataLength
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const monthName = `${i + 1}月`;
|
||||
|
||||
if (selectedYear < currentYear) {
|
||||
// 历史年份:所有月份正常显示
|
||||
colors.push(baseColors[i]);
|
||||
selected[monthName] = true;
|
||||
} else {
|
||||
// 当前年份:未来月份灰色且隐藏
|
||||
if (i + 1 < currentMonth) {
|
||||
colors.push(baseColors[i]);
|
||||
selected[monthName] = true;
|
||||
} else {
|
||||
colors.push('#D3D3D3');
|
||||
selected[monthName] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { colors, selected };
|
||||
}
|
||||
|
||||
// ==================== 原有逻辑保持不变 ====================
|
||||
|
||||
const getCurrentHourTime = () => {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
return `${year}`;
|
||||
};
|
||||
|
||||
const getCurrentHourTimeTwo = () => {
|
||||
const now = new Date();
|
||||
const endTime = new Date(now);
|
||||
endTime.setHours(endTime.getHours() - 1);
|
||||
endTime.setMinutes(0);
|
||||
endTime.setSeconds(0);
|
||||
endTime.setMilliseconds(0);
|
||||
|
||||
const startTime = new Date(endTime);
|
||||
startTime.setMonth(startTime.getMonth() - 1);
|
||||
|
||||
const formatDateTime = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
console.log('开始时间:', formatDateTime(startTime));
|
||||
console.log('结束时间:', formatDateTime(endTime));
|
||||
return [formatDateTime(startTime), formatDateTime(endTime)];
|
||||
};
|
||||
|
||||
const select = ref({
|
||||
show: true,
|
||||
value: '',
|
||||
options: [],
|
||||
picker: undefined,
|
||||
format: undefined,
|
||||
});
|
||||
|
||||
const datetimePicker = ref({
|
||||
show: true,
|
||||
value: computed(() => getCurrentHourTime()),
|
||||
format: "YYYY",
|
||||
picker: "year" as const,
|
||||
options: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取站点下拉选项数据
|
||||
*/
|
||||
const selectOptions = async () => {
|
||||
loading.value = true; // 开始加载站点数据
|
||||
|
||||
try {
|
||||
let filters = [
|
||||
{
|
||||
"field": "mway",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"field": "tm",
|
||||
"operator": "gte",
|
||||
"dataType": "date",
|
||||
"value": getCurrentHourTimeTwo()[0]
|
||||
},
|
||||
{
|
||||
"field": "tm",
|
||||
"operator": "lte",
|
||||
"dataType": "date",
|
||||
"value": getCurrentHourTimeTwo()[1]
|
||||
}
|
||||
];
|
||||
|
||||
if (baseid.value && baseid.value !== 'all') {
|
||||
filters.push({
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": baseid.value
|
||||
});
|
||||
}
|
||||
|
||||
let filter = {
|
||||
"logic": "and",
|
||||
"filters": filters
|
||||
};
|
||||
|
||||
let sort = baseid.value && baseid.value !== 'all' ? [
|
||||
{
|
||||
"field": "rstcdStepSort",
|
||||
"dir": "asc"
|
||||
}
|
||||
] : [
|
||||
{
|
||||
"field": "baseId",
|
||||
"dir": "asc"
|
||||
},
|
||||
{
|
||||
"field": "rstcdStepSort",
|
||||
"dir": "asc"
|
||||
}
|
||||
];
|
||||
|
||||
const data = { filter, sort };
|
||||
const res = await getChuiXiangShuiWenTreeStcd(data);
|
||||
let dataOne = res?.data?.data || res.data
|
||||
|
||||
if (dataOne.length > 0) {
|
||||
const treeData = dataOne.map(item => {
|
||||
return {
|
||||
title: item.ennm,
|
||||
value: item.rstcd,
|
||||
selectable: false,
|
||||
children: (item.stcdVo || []).map(child => ({
|
||||
title: child.stnm,
|
||||
value: child.stcd
|
||||
}))
|
||||
};
|
||||
});
|
||||
if (baseid.value == 'all') {
|
||||
select.value.value = '008640203800001014'
|
||||
select.value.options = treeData;
|
||||
} else {
|
||||
select.value.value = treeData[0].children[0].value
|
||||
select.value.options = treeData;
|
||||
}
|
||||
} else {
|
||||
select.value.options = []
|
||||
select.value.value = ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取站点数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false; // 关闭loading
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 新增图表相关状态 ====================
|
||||
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chartInstance: ECharts | null = null;
|
||||
|
||||
// 月份配置
|
||||
const ITEMS_PER_PAGE = 5; // 每页显示5个月份
|
||||
const currentPage = ref(1);
|
||||
// 图表数据
|
||||
const chartData = ref<Array<{ name: string; dataXy: Array<[number, number]> }>>([]);
|
||||
|
||||
// 图例 inactive 状态集合
|
||||
const legendInactiveSet = ref<Set<string>>(new Set());
|
||||
// Y轴类型(1=水深,2=高程)
|
||||
const type = ref(1);
|
||||
|
||||
// 12个月份的颜色配置(与设计稿一致)
|
||||
const monthColors: Record<string, string> = {
|
||||
'1月': '#5B9BD5',
|
||||
'2月': '#70AD47',
|
||||
'3月': '#7030A0',
|
||||
'4月': '#ED7D31',
|
||||
'5月': '#A5A5A5',
|
||||
'6月': '#FFC000',
|
||||
'7月': '#4472C4',
|
||||
'8月': '#548235',
|
||||
'9月': '#6F35A0',
|
||||
'10月': '#C55A11',
|
||||
'11月': '#8497B0',
|
||||
'12月': '#7F7F7F'
|
||||
// 颜色和图例状态
|
||||
const colors = ref<string[]>([]);
|
||||
const selected = ref<Record<string, boolean>>({});
|
||||
|
||||
// 加载状态
|
||||
const dataLoading = ref(false);
|
||||
|
||||
// ==================== 数据获取逻辑 ====================
|
||||
|
||||
const fetchChartData = async (stcd: string, year: string | number) => {
|
||||
if (loading.value) return; // 防止重复请求
|
||||
loading.value = true; // 开始请求前设置loading
|
||||
|
||||
try {
|
||||
const params = {
|
||||
filter: {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{
|
||||
field: "year",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: String(year)
|
||||
},
|
||||
{
|
||||
field: "stcd",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: stcd
|
||||
}
|
||||
]
|
||||
},
|
||||
sort: [
|
||||
{
|
||||
field: "depth",
|
||||
dir: "asc"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 生成12个月份的图例数据
|
||||
const allLegendItems = ref(
|
||||
Object.keys(monthColors).map(month => ({
|
||||
name: month,
|
||||
color: monthColors[month]
|
||||
}))
|
||||
const res = await getCxswList(params);
|
||||
const aggregates = res?.data?.aggregates;
|
||||
|
||||
if (aggregates) {
|
||||
// 转换数据
|
||||
chartData.value = transformAggregatesToChartData(aggregates);
|
||||
|
||||
// ✅ 修改:传入固定值 12,而非 chartData.value.length
|
||||
const { colors: newColors, selected: newSelected } = generateColorsAndVisibility(
|
||||
12, // ⚠️ 固定传入 12
|
||||
year
|
||||
);
|
||||
colors.value = newColors;
|
||||
selected.value = newSelected;
|
||||
|
||||
// 计算总页数
|
||||
const totalPages = computed(() => {
|
||||
return Math.ceil(allLegendItems.value.length / ITEMS_PER_PAGE);
|
||||
});
|
||||
|
||||
// 当前页的图例项
|
||||
const currentLegendItems = computed(() => {
|
||||
const start = (currentPage.value - 1) * ITEMS_PER_PAGE;
|
||||
const end = start + ITEMS_PER_PAGE;
|
||||
return allLegendItems.value.slice(start, end);
|
||||
});
|
||||
|
||||
// 静态数据 - 深度数组
|
||||
const depths = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
|
||||
|
||||
// 生成月份数据(模拟真实水温变化特征)
|
||||
const generateMonthData = (monthIndex: number) => {
|
||||
const baseSurfaceTemp = 2 + monthIndex * 2.2;
|
||||
const deepWaterTemp = 3.5 + monthIndex * 0.3;
|
||||
|
||||
return depths.map((depth, index) => {
|
||||
let temp;
|
||||
|
||||
if (depth <= 10) {
|
||||
temp = baseSurfaceTemp - depth * 0.15 + Math.sin(index * 0.8) * 0.5;
|
||||
} else if (depth <= 40) {
|
||||
const middleFactor = (depth - 10) / 30;
|
||||
temp = baseSurfaceTemp - 1.5 - middleFactor * (baseSurfaceTemp - deepWaterTemp) * 0.6;
|
||||
// 根据数据长度决定showemit
|
||||
if (chartData.value.length > 0 && chartData.value.some(item => item.dataXy.length > 0)) {
|
||||
showemit.value = true; // 有数据则显示图表
|
||||
} else {
|
||||
temp = deepWaterTemp + Math.sin(index * 0.3) * 0.2;
|
||||
showemit.value = false; // 无数据显示空状态
|
||||
}
|
||||
|
||||
return Math.max(0, Math.round(temp * 100) / 100);
|
||||
});
|
||||
};
|
||||
|
||||
// 生成所有月份的静态数据,格式为 [温度, 深度] 的二维数组
|
||||
const monthData = ref(
|
||||
Array.from({ length: 12 }, (_, i) => ({
|
||||
month: `${i + 1}月`,
|
||||
data: generateMonthData(i).map((temp, idx) => [temp, depths[idx]]) // [温度, 深度]
|
||||
}))
|
||||
);
|
||||
|
||||
// 切换图例显示/隐藏
|
||||
const toggleLegend = (name: string) => {
|
||||
if (legendInactiveSet.value.has(name)) {
|
||||
legendInactiveSet.value.delete(name);
|
||||
// 更新图表
|
||||
await nextTick();
|
||||
updateChart();
|
||||
} else {
|
||||
legendInactiveSet.value.add(name);
|
||||
chartData.value = [];
|
||||
colors.value = [];
|
||||
selected.value = {};
|
||||
showemit.value = false; // 无数据显示空状态
|
||||
}
|
||||
updateChart();
|
||||
};
|
||||
|
||||
// 上一页
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
updateChart();
|
||||
} catch (error) {
|
||||
// console.error('获取图表数据失败:', error);
|
||||
chartData.value = [];
|
||||
showemit.value = false; // 出错也显示空状态
|
||||
} finally {
|
||||
loading.value = false; // 无论成功失败都关闭loading
|
||||
}
|
||||
};
|
||||
|
||||
// 下一页
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
updateChart();
|
||||
}
|
||||
};
|
||||
// ==================== 图表初始化和更新 ====================
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartRef.value) return;
|
||||
|
||||
@ -155,186 +434,207 @@ const initChart = () => {
|
||||
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
updateChart();
|
||||
|
||||
// 绑定图例点击事件 (如果需要与ECharts内部状态同步,虽然这里主要用自定义图例)
|
||||
// chartInstance.on('legendselectchanged', (params: any) => { ... });
|
||||
};
|
||||
|
||||
// 更新图表
|
||||
const updateChart = () => {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const option = {
|
||||
// ===== 数据预处理 =====
|
||||
const xData: number[] = [];
|
||||
const yData: any[] = [];
|
||||
const legend: string[] = [];
|
||||
|
||||
chartData.value.forEach((item) => {
|
||||
if (item.dataXy.length > 0) {
|
||||
xData.push(item.dataXy[0][0]);
|
||||
}
|
||||
|
||||
legend.push(item.name);
|
||||
|
||||
yData.push({
|
||||
name: item.name,
|
||||
data: item.dataXy,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
symbolSize: 2
|
||||
});
|
||||
});
|
||||
|
||||
// ===== 坐标轴范围计算 =====
|
||||
const maxy1 = arrMax(xData);
|
||||
const miny1 = arrMin(xData);
|
||||
|
||||
const y1 = chartMax(
|
||||
5,
|
||||
miny1 === maxy1 ? maxy1 * 1.1 : maxy1,
|
||||
miny1 === maxy1 ? miny1 * 0.9 : miny1,
|
||||
true,
|
||||
0
|
||||
);
|
||||
|
||||
// ✅ X 轴固定从 0 开始
|
||||
const curMin = 0;
|
||||
|
||||
// ===== 构建图表配置 =====
|
||||
const option: any = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
borderColor: '#ccc',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#333',
|
||||
fontSize: 12
|
||||
},
|
||||
show: true,
|
||||
formatter: (params: any) => {
|
||||
if (!params || !params.seriesName) return '';
|
||||
|
||||
const temperature = params.data[0]; // 温度值
|
||||
const depth = params.data[1]; // 深度值
|
||||
const temperature = params.data[0];
|
||||
const depth = params.data[1];
|
||||
|
||||
return `<div style="font-weight:bold;margin-bottom:8px;">${params.seriesName}</div>
|
||||
<div>水温(°C):${temperature}</div>
|
||||
<div>深度(m):${depth}</div>`;
|
||||
return `<span>${params.seriesName}</span><br />
|
||||
<span>水温(℃):${temperature}</span><br />
|
||||
<span>深度(m):${depth}</span>`;
|
||||
}
|
||||
},
|
||||
color: colors.value,
|
||||
grid: {
|
||||
right: '15%',
|
||||
bottom: '10%'
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
data: allLegendItems.value.map(item => ({
|
||||
name: item.name,
|
||||
icon: 'circle'
|
||||
})),
|
||||
selected: allLegendItems.value.reduce((acc, item) => {
|
||||
acc[item.name] = !legendInactiveSet.value.has(item.name);
|
||||
return acc;
|
||||
}, {} as Record<string, boolean>),
|
||||
// 隐藏ECharts默认图例,使用自定义图例
|
||||
top: -9999
|
||||
type: 'scroll',
|
||||
data: legend,
|
||||
selected: selected.value,
|
||||
textStyle: {
|
||||
align: 'middle' as const
|
||||
},
|
||||
grid: {
|
||||
left: '70px',
|
||||
right: '100px',
|
||||
bottom: '60px',
|
||||
top: '30px'
|
||||
top: '1%',
|
||||
left: 'center' as const
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
position: 'top',
|
||||
name: '水温(°C)',
|
||||
nameLocation: 'end',
|
||||
nameGap: 20,
|
||||
nameTextStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12,
|
||||
align: 'right',
|
||||
verticalAlign: 'top'
|
||||
},
|
||||
min: 0,
|
||||
max: 8,
|
||||
interval: null,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#d0d0d0',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
type: 'value' as const,
|
||||
boundaryGap: false,
|
||||
position: 'top' as const,
|
||||
nameLocation: 'end' as const,
|
||||
axisTick: {
|
||||
show: true,
|
||||
length: 4,
|
||||
inside: false,
|
||||
lineStyle: {
|
||||
color: '#d0d0d0'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontSize: 11,
|
||||
margin: 6,
|
||||
formatter: (value: number) => {
|
||||
const showTicks = [0, 3, 6, 8];
|
||||
if (showTicks.includes(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
show: true
|
||||
},
|
||||
interval: y1.scale,
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
position: 'left',
|
||||
inverse: true,
|
||||
type: 'value' as const,
|
||||
name: type.value === 2 ? '高程(m)' : '水深(m)',
|
||||
min: 0,
|
||||
max: 80,
|
||||
interval: 20,
|
||||
name: '水深(m)',
|
||||
nameLocation: 'end',
|
||||
nameGap: 25,
|
||||
nameRotate: 0,
|
||||
nameTextStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12,
|
||||
align: 'center',
|
||||
verticalAlign: 'top'
|
||||
scale: false, // ✅ 新增:确保 Y 轴从 0 开始,防止自动调整
|
||||
nameGap: type.value === 2 ? 22 : 10,
|
||||
inverse: type.value !== 2
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#d0d0d0',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: true,
|
||||
length: 3,
|
||||
inside: false,
|
||||
lineStyle: {
|
||||
color: '#d0d0d0'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontSize: 11,
|
||||
inside: false,
|
||||
margin: 8
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#e5e5e5',
|
||||
type: 'dashed',
|
||||
width: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
series: monthData.value.map((monthItem: any) => ({
|
||||
name: monthItem.month,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 2,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: monthColors[monthItem.month]
|
||||
},
|
||||
itemStyle: {
|
||||
color: monthColors[monthItem.month]
|
||||
},
|
||||
data: monthItem.data.map((item: any) => [item[0], item[1]]),
|
||||
connectNulls: false
|
||||
}))
|
||||
dataZoom: [{ type: 'inside' as const }],
|
||||
series: yData
|
||||
};
|
||||
|
||||
option.xAxis.min = curMin;
|
||||
|
||||
chartInstance.setOption(option, { notMerge: true });
|
||||
};
|
||||
|
||||
// 组件挂载时初始化
|
||||
const handleChartClick = (params: any) => {
|
||||
if (!params || !params.seriesName) return;
|
||||
|
||||
const matchMonth = params.seriesName.match(/\d+/);
|
||||
const monthNum = matchMonth ? parseInt(matchMonth[0]) : 1;
|
||||
|
||||
const year = typeof datetimePicker.value.value === 'string'
|
||||
? parseInt(datetimePicker.value.value)
|
||||
: datetimePicker.value.value;
|
||||
|
||||
const startTime = `${year}-${String(monthNum).padStart(2, '0')}-01 00:00:00`;
|
||||
const lastDay = new Date(year, monthNum, 0).getDate();
|
||||
const endTime = `${year}-${String(monthNum).padStart(2, '0')}-${lastDay} 23:59:59`;
|
||||
|
||||
const currentStcd = select.value.value;
|
||||
let currentStnm = '';
|
||||
|
||||
select.value.options.forEach((station: any) => {
|
||||
station.children?.forEach((child: any) => {
|
||||
if (child.value === currentStcd) {
|
||||
currentStnm = child.title;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
import('@/store/modules/model').then(({ useModelStore }) => {
|
||||
import('@/components/MapModal/setting.config').then(({ handleTabs }) => {
|
||||
const modelStore = useModelStore();
|
||||
|
||||
modelStore.params = {
|
||||
sttp: 'WT',
|
||||
stcd: currentStcd,
|
||||
titleName: currentStnm,
|
||||
enfc: '1',
|
||||
timeRange: [startTime, endTime]
|
||||
} as any;
|
||||
|
||||
modelStore.title = currentStnm ? `${currentStnm} 详情信息` : '详情信息';
|
||||
modelStore.tabList = handleTabs(modelStore.params);
|
||||
modelStore.modalVisible = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== 生命周期和监听 ====================
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', () => {
|
||||
chartInstance?.resize();
|
||||
});
|
||||
});
|
||||
|
||||
// 组件卸载时清理
|
||||
onBeforeUnmount(() => {
|
||||
chartInstance?.dispose();
|
||||
window.removeEventListener('resize', () => {
|
||||
chartInstance?.resize();
|
||||
});
|
||||
});
|
||||
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
async (newVal) => {
|
||||
if (!newVal || !newVal.wbsCode) {
|
||||
return;
|
||||
}
|
||||
baseid.value = newVal.wbsCode;
|
||||
await selectOptions();
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
// // 监听测站和年份变化,触发数据加载
|
||||
// watch(
|
||||
// () => [select.value.value, datetimePicker.value.value],
|
||||
// async ([newStcd, newYear]) => {
|
||||
// if (newStcd && newYear) {
|
||||
// await fetchChartData(newStcd, newYear);
|
||||
// }
|
||||
// },
|
||||
// { deep: true }
|
||||
// );
|
||||
|
||||
const handlePanelChange1 = (data: any) => {
|
||||
console.log('当前所有控件状态:', data);
|
||||
if (data.moreSelect && data.datetime) {
|
||||
fetchChartData(data.moreSelect, data.datetime)
|
||||
} else {
|
||||
showemit.value = true
|
||||
chartData.value = [];
|
||||
colors.value = [];
|
||||
selected.value = {};
|
||||
showemit.value = false;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -345,80 +645,16 @@ onBeforeUnmount(() => {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.legend-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.legend-item.inactive {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.legend-text {
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-btn {
|
||||
cursor: pointer;
|
||||
padding: 2px 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.page-btn:hover:not(.disabled) {
|
||||
border-color: #1890ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.page-btn.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
min-height: 252px !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.ant-spin-nested-loading) {
|
||||
height: 252px !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,227 +1,280 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<!--
|
||||
出入库水温图表组件
|
||||
功能:展示水库入库水温和出库水温的时序变化曲线
|
||||
数据来源:inOutOneGetKendoListCust接口
|
||||
特性:支持月份选择、站点筛选、数据缩放、空值断开显示
|
||||
-->
|
||||
<template>
|
||||
<SidePanelItem title="出入库水温">
|
||||
<div ref="chartContainer" class="chart-container"></div>
|
||||
<SidePanelItem title="出入库水温" :moreSelect="select" :scopeDate="scopeDate" @update-values="handlePanelChange1">
|
||||
<!-- ECharts图表容器 -->
|
||||
<a-spin :spinning="loading" tip="加载中...">
|
||||
<div v-show="showemit && !loading" ref="chartContainer" class="chart-container"></div>
|
||||
<div v-show="!showemit && !loading" class="chart-container">
|
||||
<a-empty />
|
||||
</div>
|
||||
</a-spin>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import dayjs from 'dayjs';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
import { getVmsstbprpt, inOutOneGetKendoListCust } from '@/api/sw';
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
|
||||
// ==================== 组件基础配置 ====================
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: 'churukushuiwenMod'
|
||||
});
|
||||
|
||||
const chartContainer = ref<HTMLDivElement | null>(null);
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
// ==================== 状态管理初始化 ====================
|
||||
const JidiSelectEventStore = useJidiSelectEventStore(); // 基地选择事件Store
|
||||
|
||||
// 页面加载时执行的逻辑
|
||||
onMounted(() => {
|
||||
// 延迟初始化,确保 DOM 渲染完成
|
||||
setTimeout(() => {
|
||||
if (chartContainer.value) {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
}
|
||||
}, 100);
|
||||
// ==================== DOM引用与图表实例 ====================
|
||||
const chartContainer = ref<HTMLDivElement | null>(null); // 图表容器DOM引用
|
||||
let chartInstance: echarts.ECharts | null = null; // ECharts实例
|
||||
const currentMonth = new Date().toISOString().slice(0, 7); // 当前月份(格式: YYYY-MM)
|
||||
const chartDataLoaded = ref(false); // 数据加载状态标志,防止重复请求
|
||||
|
||||
// ==================== 加载状态与显示控制 ====================
|
||||
const showemit = ref(false); // 控制图表是否显示
|
||||
const loading = ref(false); // 控制加载状态
|
||||
|
||||
// ==================== 下拉框配置(站点选择) ====================
|
||||
const select = ref({
|
||||
show: true, // 是否显示下拉框
|
||||
value: '', // 当前选中值(站点编码)
|
||||
options: [], // 下拉选项列表
|
||||
picker: undefined, // 选择器类型(未使用)
|
||||
format: undefined, // 格式化字符串(未使用)
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
window.removeEventListener('resize', handleResize);
|
||||
// ==================== 日期范围选择器配置 ====================
|
||||
const scopeDate = ref({
|
||||
show: true, // 是否显示日期选择器
|
||||
value: [currentMonth, currentMonth] as any, // 默认选中当前月份范围(使用 as any 绕过类型检查)
|
||||
format: "YYYY-MM", // 显示格式
|
||||
picker: "month" as const, // 选择器类型:月份选择
|
||||
options: [], // 可选日期范围(未使用)
|
||||
});
|
||||
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
// ==================== 业务变量 ====================
|
||||
const baseid = ref(''); // 当前选中的基地ID
|
||||
|
||||
const initChart = () => {
|
||||
if (!chartContainer.value) return;
|
||||
|
||||
// 检查容器实际高度,如果为 0 则延迟重试
|
||||
const containerHeight = chartContainer.value.offsetHeight;
|
||||
if (containerHeight === 0) {
|
||||
setTimeout(() => initChart(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
chartInstance = echarts.init(chartContainer.value);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(50, 50, 50, 0.9)',
|
||||
borderColor: 'transparent',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
lineStyle: {
|
||||
color: 'rgba(91, 143, 249, 0.15)',
|
||||
width: 30,
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
formatter: function(params: any) {
|
||||
if (!params || params.length === 0) return '';
|
||||
const date = params[0].name;
|
||||
let result = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 14px;">${date}</div>`;
|
||||
params.forEach((item: any) => {
|
||||
result += `<div style="display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 14px;">
|
||||
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color};"></span>
|
||||
<span>${item.seriesName}</span>
|
||||
<span style="font-weight: bold; margin-left: auto;">${item.value}°C</span>
|
||||
</div>`;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: '水温(°C)',
|
||||
left: 17,
|
||||
top: 13,
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#000000',
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['入库水温', '出库水温'],
|
||||
top: 13,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemGap: 20,
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#000000'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '10%',
|
||||
right: '5%',
|
||||
top: '15%',
|
||||
bottom: '18%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['2026-04-01', '2026-04-02', '2026-04-03', '2026-04-04', '2026-04-05', '2026-04-06', '2026-04-07'],
|
||||
boundaryGap: true,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#000000'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#000000',
|
||||
fontSize: 13,
|
||||
margin: 10,
|
||||
interval: 2
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#bfbfbf',
|
||||
type: 'solid'
|
||||
}
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
// ==================== 基地列表数据(硬编码) ====================
|
||||
const jiDiList: any = ref([
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
minValueSpan: 2,
|
||||
zoomOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
moveOnMouseWheel: false,
|
||||
zoomLock: false,
|
||||
throttle: 50
|
||||
}
|
||||
],
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 5.2,
|
||||
max: 5.9,
|
||||
interval: 0.1,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#000000',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#000000',
|
||||
width: 1
|
||||
},
|
||||
length: 4
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#000000',
|
||||
fontSize: 12,
|
||||
formatter: '{value}'
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#bfbfbf',
|
||||
type: 'solid'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '入库水温',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: '#4b79ab'
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#4b79ab'
|
||||
},
|
||||
data: [5.4, 5.3, 5.6, 5.4, 5.5, 5.6, 5.6]
|
||||
"baseid": "all",
|
||||
"basename": "当前全部",
|
||||
"id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
|
||||
},
|
||||
{
|
||||
name: '出库水温',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: '#78c300'
|
||||
"baseid": "01",
|
||||
"basename": "金沙江干流",
|
||||
"id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#78c300'
|
||||
{
|
||||
"baseid": "02",
|
||||
"basename": "雅砻江干流",
|
||||
"id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
|
||||
},
|
||||
data: [5.8, 5.8, 5.8, 5.8, 5.8, 5.8, 5.8]
|
||||
{
|
||||
"baseid": "03",
|
||||
"basename": "大渡河干流",
|
||||
"id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
|
||||
},
|
||||
{
|
||||
"baseid": "04",
|
||||
"basename": "乌江干流",
|
||||
"id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
|
||||
},
|
||||
{
|
||||
"baseid": "05",
|
||||
"basename": "长江上游干流",
|
||||
"id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
|
||||
},
|
||||
{
|
||||
"baseid": "10",
|
||||
"basename": "湘西",
|
||||
"id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
|
||||
},
|
||||
{
|
||||
"baseid": "08",
|
||||
"basename": "黄河上游干流",
|
||||
"id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
|
||||
},
|
||||
{
|
||||
"baseid": "09",
|
||||
"basename": "黄河中游干流",
|
||||
"id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
|
||||
},
|
||||
{
|
||||
"baseid": "06",
|
||||
"basename": "南盘江-红水河",
|
||||
"id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
|
||||
},
|
||||
{
|
||||
"baseid": "12",
|
||||
"basename": "东北",
|
||||
"id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
|
||||
},
|
||||
{
|
||||
"baseid": "07",
|
||||
"basename": "澜沧江干流",
|
||||
"id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
|
||||
},
|
||||
{
|
||||
"baseid": "13",
|
||||
"basename": "怒江干流",
|
||||
"id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
|
||||
},
|
||||
{
|
||||
"baseid": "11",
|
||||
"basename": "闽浙赣",
|
||||
"id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
|
||||
},
|
||||
{
|
||||
"baseid": "other",
|
||||
"basename": "其他",
|
||||
"id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
|
||||
}
|
||||
])
|
||||
|
||||
// ==================== 数据处理函数 ====================
|
||||
|
||||
/**
|
||||
* 转换图表数据格式
|
||||
* 将后端返回的扁平数据结构转换为ECharts所需的双线数据格式
|
||||
* @param rawData - 原始数据数组,包含tm(时间)、dwtp(类型:IWT/DWT)、wt(水温)字段
|
||||
* @returns 包含日期数组、入库水温数组、出库水温数组的对象
|
||||
*/
|
||||
function transformChartData(rawData: any[]) {
|
||||
// 1. 提取所有唯一日期并排序
|
||||
const dateSet = new Set<string>()
|
||||
rawData.forEach(item => {
|
||||
const date = item.tm?.split(' ')[0] // "2026-04-01 00:00:00" -> "2026-04-01"
|
||||
if (date) dateSet.add(date)
|
||||
})
|
||||
const dates = Array.from(dateSet).sort()
|
||||
|
||||
// 2. 构建两条线的数据(入库水温和出库水温)
|
||||
const iwtData: (number | null)[] = [] // 入库水温(Inlet Water Temperature)
|
||||
const dwtData: (number | null)[] = [] // 出库水温(Discharge Water Temperature)
|
||||
|
||||
dates.forEach(date => {
|
||||
// 查找该日期的入库水温(dwtp='IWT')
|
||||
const iwtItem = rawData.find(item =>
|
||||
item.tm?.startsWith(date) && item.dwtp === 'IWT'
|
||||
)
|
||||
// 保留一位小数,缺失则填null(曲线断开)
|
||||
iwtData.push(iwtItem ? Number(iwtItem.wt.toFixed(1)) : null)
|
||||
|
||||
// 查找该日期的出库水温(dwtp='DWT')
|
||||
const dwtItem = rawData.find(item =>
|
||||
item.tm?.startsWith(date) && item.dwtp === 'DWT'
|
||||
)
|
||||
// 保留一位小数,缺失则填null(曲线断开)
|
||||
dwtData.push(dwtItem ? Number(dwtItem.wt.toFixed(1)) : null)
|
||||
})
|
||||
|
||||
return { dates, iwtData, dwtData }
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算Y轴显示范围
|
||||
* 基于数据最小值和最大值,上下各扩展0.2的缓冲空间
|
||||
* @param data - 水温数据数组(可能包含null值)
|
||||
* @returns Y轴的最小值和最大值对象
|
||||
*/
|
||||
function calculateYAxisRange(data: (number | null)[]) {
|
||||
// 过滤出有效数值
|
||||
const validValues = data.filter(v => v !== null) as number[]
|
||||
if (validValues.length === 0) return { min: 0, max: 10 } // 无数据时返回默认范围
|
||||
|
||||
const min = Math.min(...validValues)
|
||||
const max = Math.max(...validValues)
|
||||
|
||||
// 上下各扩展0.2,避免曲线贴边
|
||||
return {
|
||||
min: Number((min - 0.2).toFixed(1)), // 最小值减0.2
|
||||
max: Number((max + 0.2).toFixed(1)) // 最大值加0.2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算X轴刻度间隔
|
||||
* 确保最多显示4个刻度标签,避免标签重叠
|
||||
* @param dateCount - 日期总数
|
||||
* @returns X轴刻度间隔值(interval属性)
|
||||
*/
|
||||
function calculateXAxisInterval(dateCount: number): number {
|
||||
if (dateCount <= 4) return 0 // 数据点≤4时,显示所有刻度
|
||||
return Math.ceil(dateCount / 4) - 1 // 动态计算间隔,保证最多4个刻度
|
||||
}
|
||||
const paramsOne = ref({
|
||||
value: '',
|
||||
tm: [currentMonth, currentMonth]
|
||||
})
|
||||
/**
|
||||
* 获取图表数据
|
||||
* 调用后端接口获取出入库水温数据,并触发图表更新
|
||||
*/
|
||||
async function fetchChartData() {
|
||||
if (loading.value) return; // 防止重复请求
|
||||
|
||||
loading.value = true; // 开始请求前设置loading
|
||||
|
||||
try {
|
||||
// 动态计算时间范围(考虑不同月份的实际天数)
|
||||
const startDate = paramsOne.value.tm[0] + '-01 00:00:00';
|
||||
const endDate = dayjs(paramsOne.value.tm[1]).endOf('month').format('YYYY-MM-DD') + ' 23:59:59';
|
||||
|
||||
// 构建查询参数(固定参数,后续可扩展为动态)
|
||||
const params = {
|
||||
filter: {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{
|
||||
// OR逻辑:查询入库或出库水温
|
||||
logic: "or",
|
||||
filters: [
|
||||
{ field: "engDwtCode", operator: "eq", value: paramsOne.value.value }, // 出库站点编码
|
||||
{ field: "engIwtCode", operator: "eq", value: paramsOne.value.value } // 入库站点编码
|
||||
]
|
||||
};
|
||||
},
|
||||
// 时间范围过滤
|
||||
{ field: "dt", operator: "gte", dataType: "date", value: startDate },
|
||||
{ field: "dt", operator: "lte", dataType: "date", value: endDate }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
chartInstance.setOption(option);
|
||||
// 调用API获取数据
|
||||
const res = await inOutOneGetKendoListCust(params)
|
||||
const rawData = res?.data?.data || []
|
||||
|
||||
console.log('原始数据:', rawData)
|
||||
|
||||
// 根据数据长度决定showemit
|
||||
if (rawData.length > 0) {
|
||||
showemit.value = true; // 有数据则显示图表
|
||||
|
||||
// 转换数据格式
|
||||
const { dates, iwtData, dwtData } = transformChartData(rawData)
|
||||
|
||||
console.log('转换后的数据:', { dates, iwtData, dwtData })
|
||||
|
||||
// 数据就绪后初始化或更新图表
|
||||
setTimeout(() => {
|
||||
if (!chartInstance) {
|
||||
initChartWithData(dates, iwtData, dwtData); // 带数据初始化
|
||||
} else {
|
||||
updateChart(dates, iwtData, dwtData, 0); // 已有实例则更新
|
||||
}
|
||||
|
||||
// 强制重绘,确保图表尺寸正确适配容器
|
||||
setTimeout(() => {
|
||||
@ -229,12 +282,455 @@ const initChart = () => {
|
||||
chartInstance.resize();
|
||||
}
|
||||
}, 50);
|
||||
}, 50);
|
||||
|
||||
} else {
|
||||
showemit.value = false; // 无数据显示空状态
|
||||
}
|
||||
|
||||
chartDataLoaded.value = true; // 标记数据已加载
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取图表数据失败:', error);
|
||||
showemit.value = false; // 出错也显示空状态
|
||||
chartDataLoaded.value = true; // 即使失败也标记为已加载,避免重复请求
|
||||
} finally {
|
||||
loading.value = false; // 无论成功失败都关闭loading
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带数据初始化图表
|
||||
* @param dates - 日期数组
|
||||
* @param iwtData - 入库水温数据
|
||||
* @param dwtData - 出库水温数据
|
||||
*/
|
||||
const initChartWithData = (dates: string[], iwtData: (number | null)[], dwtData: (number | null)[]) => {
|
||||
if (!chartContainer.value) return;
|
||||
|
||||
const containerHeight = chartContainer.value.offsetHeight;
|
||||
if (containerHeight === 0) {
|
||||
setTimeout(() => initChartWithData(dates, iwtData, dwtData), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
chartInstance = echarts.init(chartContainer.value);
|
||||
updateChart(dates, iwtData, dwtData, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新图表配置
|
||||
* 根据处理后的数据动态生成ECharts配置项
|
||||
* @param dates - 日期数组(X轴数据)
|
||||
* @param iwtData - 入库水温数据数组
|
||||
* @param dwtData - 出库水温数据数组
|
||||
* @param yAxisMax - 废弃参数,保留以兼容旧代码
|
||||
*/
|
||||
function updateChart(dates: string[], iwtData: (number | null)[], dwtData: (number | null)[], yAxisMax: number) {
|
||||
if (!chartInstance) {
|
||||
console.warn('图表实例未初始化')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// ==================== 动态计算坐标轴范围 ====================
|
||||
const xAxisInterval = calculateXAxisInterval(dates.length) // X轴刻度间隔
|
||||
const { min: yAxisMin, max: yAxisMaxValue } = calculateYAxisRange([...iwtData, ...dwtData]) // Y轴范围
|
||||
|
||||
console.log('X轴间隔:', xAxisInterval, 'Y轴范围:', { min: yAxisMin, max: yAxisMaxValue })
|
||||
|
||||
// ==================== ECharts配置项 ====================
|
||||
const option = {
|
||||
// 提示框配置
|
||||
tooltip: {
|
||||
trigger: 'axis', // 触发类型:坐标轴触发
|
||||
backgroundColor: 'rgba(50, 50, 50, 0.9)', // 背景色
|
||||
borderColor: 'transparent', // 边框透明
|
||||
textStyle: {
|
||||
color: '#fff', // 文字颜色
|
||||
fontSize: 14 // 字体大小
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'line', // 指示器类型:直线
|
||||
lineStyle: {
|
||||
color: 'rgba(91, 143, 249, 0.15)', // 指示线颜色
|
||||
width: 30, // 指示线宽度
|
||||
type: 'solid' // 线型:实线
|
||||
}
|
||||
},
|
||||
// 自定义提示框内容
|
||||
formatter: function (params: any) {
|
||||
if (!params || params.length === 0) return '';
|
||||
const date = params[0].name; // 获取日期
|
||||
let result = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 14px;">${date}</div>`;
|
||||
params.forEach((item: any) => {
|
||||
// 空值显示'-',符合项目规范
|
||||
const value = item.value !== null && item.value !== undefined ? `${item.value}°C` : '-'
|
||||
result += `<div style="display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 14px;">
|
||||
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color};"></span>
|
||||
<span>${item.seriesName}</span>
|
||||
<span style="font-weight: bold; margin-left: auto;">${value}</span>
|
||||
</div>`;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
// 标题配置
|
||||
title: {
|
||||
text: '水温(°C)', // 标题文本
|
||||
left: 17, // 左侧位置
|
||||
top: 13, // 顶部位置
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#000000',
|
||||
fontWeight: 'normal'
|
||||
}
|
||||
},
|
||||
|
||||
// 图例配置
|
||||
legend: {
|
||||
data: ['入库水温', '出库水温'], // 图例项
|
||||
top: 13, // 顶部对齐
|
||||
left: 'center', // 水平居中
|
||||
itemWidth: 10, // 图例图标宽度
|
||||
itemHeight: 10, // 图例图标高度
|
||||
itemGap: 20, // 图例间距
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#000000'
|
||||
}
|
||||
},
|
||||
|
||||
// 网格配置(图表区域边距)
|
||||
grid: {
|
||||
left: '10%',
|
||||
right: '5%',
|
||||
top: '15%',
|
||||
bottom: '10%'
|
||||
},
|
||||
|
||||
// X轴配置
|
||||
xAxis: {
|
||||
type: 'category', // 类目轴
|
||||
data: dates, // 日期数据
|
||||
boundaryGap: true, // 两侧留白
|
||||
interval: xAxisInterval, // 动态刻度间隔,最多显示4个标签
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#000000' // 轴线颜色
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false // 隐藏刻度线
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#000000', // 标签颜色
|
||||
fontSize: 13, // 字体大小
|
||||
margin: 10 // 标签与轴线距离
|
||||
},
|
||||
splitLine: {
|
||||
show: true, // 显示分割线
|
||||
lineStyle: {
|
||||
color: '#bfbfbf', // 分割线颜色
|
||||
type: 'solid' // 实线
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 数据缩放配置(鼠标滚轮缩放)
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside', // 内置型数据区域缩放
|
||||
start: 0, // 起始位置0%
|
||||
end: 100, // 结束位置100%
|
||||
minValueSpan: 2, // 最小显示2个数据点
|
||||
zoomOnMouseWheel: true, // 允许滚轮缩放
|
||||
moveOnMouseMove: true, // 允许鼠标拖拽平移
|
||||
moveOnMouseWheel: false, // 滚轮不触发平移
|
||||
zoomLock: false, // 不锁定缩放比例
|
||||
throttle: 50 // 节流50ms
|
||||
}
|
||||
],
|
||||
|
||||
// Y轴配置
|
||||
yAxis: {
|
||||
type: 'value', // 数值轴
|
||||
min: yAxisMin, // 动态最小值(数据最小值-0.2)
|
||||
max: yAxisMaxValue, // 动态最大值(数据最大值+0.2)
|
||||
scale: true, // 自适应缩放,不强制从0开始
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#000000',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: true, // 显示刻度线
|
||||
lineStyle: {
|
||||
color: '#000000',
|
||||
width: 1
|
||||
},
|
||||
length: 4 // 刻度线长度
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#000000',
|
||||
fontSize: 12,
|
||||
formatter: '{value}' // 标签格式
|
||||
},
|
||||
splitLine: {
|
||||
show: true, // 显示网格线
|
||||
lineStyle: {
|
||||
color: '#bfbfbf',
|
||||
type: 'solid'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 系列数据配置(两条折线)
|
||||
series: [
|
||||
{
|
||||
name: '入库水温', // 系列名称
|
||||
type: 'line', // 图表类型:折线图
|
||||
smooth: true, // 平滑曲线
|
||||
symbol: 'circle', // 数据点形状:圆形
|
||||
symbolSize: 4, // 数据点大小
|
||||
connectNulls: true, // 关键:不连接空值,实现曲线断开效果
|
||||
lineStyle: {
|
||||
width: 2, // 线宽
|
||||
color: '#4b79ab' // 线条颜色:蓝色
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#4b79ab' // 数据点颜色
|
||||
},
|
||||
data: iwtData // 入库水温数据
|
||||
},
|
||||
{
|
||||
name: '出库水温', // 系列名称
|
||||
type: 'line', // 图表类型:折线图
|
||||
smooth: true, // 平滑曲线
|
||||
symbol: 'circle', // 数据点形状:圆形
|
||||
symbolSize: 4, // 数据点大小
|
||||
connectNulls: true, // 不连接空值,实现断开效果
|
||||
lineStyle: {
|
||||
width: 2, // 线宽
|
||||
color: '#78c300' // 线条颜色:绿色
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#78c300' // 数据点颜色
|
||||
},
|
||||
data: dwtData // 出库水温数据
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 应用配置到图表实例
|
||||
chartInstance.setOption(option, true); // true表示完全替换配置
|
||||
console.log('图表更新成功')
|
||||
|
||||
// 强制重绘,确保图表尺寸正确适配容器
|
||||
setTimeout(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize(); // 重新计算图表尺寸
|
||||
}
|
||||
}, 50);
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新图表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 生命周期钩子 ====================
|
||||
|
||||
/**
|
||||
* 组件挂载时执行
|
||||
* 初始化图表并获取数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
// 延迟100ms初始化,确保DOM渲染完成
|
||||
setTimeout(() => {
|
||||
if (chartContainer.value) {
|
||||
// fetchChartData(); // 先获取真实数据
|
||||
window.addEventListener('resize', handleResize); // 监听窗口大小变化
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
/**
|
||||
* 组件卸载时执行
|
||||
* 清理资源,防止内存泄漏
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose(); // 销毁图表实例
|
||||
chartInstance = null;
|
||||
}
|
||||
window.removeEventListener('resize', handleResize); // 移除事件监听
|
||||
});
|
||||
|
||||
/**
|
||||
* 窗口大小变化处理函数
|
||||
* 自适应调整图表尺寸
|
||||
*/
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize(); // 重新计算图表尺寸
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 事件处理函数 ====================
|
||||
|
||||
/**
|
||||
* SidePanelItem面板变化回调
|
||||
* 处理下拉框和日期选择器的值变化
|
||||
* @param data - 包含moreSelect(下拉框值)和datetime(日期范围)的对象
|
||||
*/
|
||||
const handlePanelChange1 = (data: any) => {
|
||||
// console.log('当前所有控件状态:', data);
|
||||
// debugger
|
||||
// TODO: 后续可扩展联动逻辑
|
||||
if (data.moreSelect) {
|
||||
paramsOne.value.value = data.moreSelect;
|
||||
}
|
||||
paramsOne.value.tm = data.scopeDate
|
||||
fetchChartData()
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取站点下拉选项数据
|
||||
* 根据选中的基地ID查询对应的站点列表
|
||||
*/
|
||||
const getselsectData = async () => {
|
||||
loading.value = true; // 开始加载站点数据
|
||||
|
||||
try {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
// 如果baseid不是'all',则添加基地过滤条件
|
||||
baseid.value != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": baseid.value
|
||||
} : null,
|
||||
// 站点类型过滤:只查询ENG类型站点
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "contains",
|
||||
"dataType": "string",
|
||||
"value": "ENG"
|
||||
},
|
||||
// 只查询有效站点(dtin=1)
|
||||
{
|
||||
"field": "dtin",
|
||||
"operator": "eq",
|
||||
"dataType": "string",
|
||||
"value": 1
|
||||
}
|
||||
].filter(Boolean) // 过滤掉null值
|
||||
},
|
||||
"sort": [
|
||||
// 如果是'all',按基地排序;否则不排序
|
||||
baseid.value == 'all' ? {
|
||||
"field": "baseStepSort",
|
||||
"dir": "asc"
|
||||
} : null,
|
||||
{
|
||||
"field": "rvcdStepSort",
|
||||
"dir": "asc"
|
||||
},
|
||||
{
|
||||
"field": "siteStepSort",
|
||||
"dir": "asc"
|
||||
}
|
||||
].filter(Boolean), // 过滤掉null值
|
||||
"select": [
|
||||
"stcd", // 站点编码
|
||||
"stnm", // 站点名称
|
||||
"lgtd", // 经度
|
||||
"lttd", // 纬度
|
||||
"siteStepSort", // 站点排序
|
||||
"baseId", // 基地ID
|
||||
"baseName" // 基地名称
|
||||
]
|
||||
}
|
||||
|
||||
// 调用API获取站点数据
|
||||
const res = await getVmsstbprpt(params)
|
||||
console.log('res', res)
|
||||
const data = res?.data?.data || res?.data
|
||||
const obj: any = {}
|
||||
|
||||
if (data) {
|
||||
// 将扁平数据转换为树形结构(按基地分组)
|
||||
data.map((e) => {
|
||||
if (obj[e.baseId]) {
|
||||
// 如果基地已存在,添加子节点
|
||||
obj[e.baseId] = { ...obj[e.baseId], children: [...obj[e.baseId].children, { ...e, value: e.stcd, title: e.stnm }] }
|
||||
} else {
|
||||
// 创建新的基地节点
|
||||
obj[e.baseId] = { value: e.baseId, title: e.baseName, selectable: false, key: e.baseId, children: [{ ...e, value: e.stcd, title: e.stnm }] }
|
||||
}
|
||||
})
|
||||
|
||||
// 转换为数组并按jiDiList顺序排序
|
||||
let treeData: any = []
|
||||
const dataMapNameArr: any = Object.entries(obj).map(([, v]) => v)
|
||||
treeData = dataMapNameArr?.sort((a: any, b: any) => {
|
||||
const indexA = jiDiList.value.findIndex(item => item.baseid === a.value);
|
||||
const indexB = jiDiList.value.findIndex(item => item.baseid === b.value);
|
||||
return indexA - indexB;
|
||||
})
|
||||
console.log('treeData', treeData)
|
||||
|
||||
// 更新下拉框选项
|
||||
select.value.options = treeData
|
||||
|
||||
// 设置默认选中值
|
||||
if (baseid.value == 'all') {
|
||||
select.value.value = '008640203800000001' // 默认选中第一个站点
|
||||
} else {
|
||||
select.value.value = treeData?.[0]?.children[0]?.value // 选中当前基地的第一个站点
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取站点数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false; // 关闭loading
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Watch监听器 ====================
|
||||
|
||||
/**
|
||||
* 监听基地选择变化
|
||||
* 当用户切换基地时,重新加载站点下拉选项
|
||||
*/
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem, // 监听Store中的选中项
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode; // 更新基地ID
|
||||
getselsectData() // 重新获取站点数据
|
||||
},
|
||||
{ deep: true, immediate: true } // 深度监听,立即执行
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 图表容器样式 */
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 252px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* 固定高度252px */
|
||||
}
|
||||
:deep(.ant-spin-nested-loading ){
|
||||
height: 252px !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,43 +1,40 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="水温监测工作开展情况">
|
||||
<a-spin :spinning="loading" tip="加载中...">
|
||||
<div class="facility-grid">
|
||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
||||
<div
|
||||
style="
|
||||
<div style="
|
||||
width: 60px;
|
||||
height: 62px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
">
|
||||
<div class="facility-icon">
|
||||
<i
|
||||
style="color: #fff"
|
||||
:class="facility.icon"
|
||||
type="icon-shengtailiuliang2"
|
||||
></i>
|
||||
<i style="color: #fff" :class="facility.icon" type="icon-shengtailiuliang2"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="facility-info">
|
||||
<div class="facility-name">{{ facility.name }}</div>
|
||||
<div style="font-size: 16px">
|
||||
<span class="facility-count">{{ facility.count }}</span
|
||||
><span>个</span>
|
||||
<span class="facility-count">{{ facility.count }}</span><span>个</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
||||
import { getKendoListCust } from "@/api/sw";
|
||||
import { getKendoListCust, baseEvnmAutoMonitorGetKendoListCust } from "@/api/sw";
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: "shuiwenjiancegongzuokaizhangqingkuang",
|
||||
@ -47,34 +44,72 @@ defineOptions({
|
||||
const facilities = ref([
|
||||
{
|
||||
name: "表层水温",
|
||||
count: 145,
|
||||
count: 0,
|
||||
icon: "icon iconfont icon-shuizhijiancezhan",
|
||||
},
|
||||
{
|
||||
name: "垂向水温",
|
||||
count: 24,
|
||||
count: 0,
|
||||
icon: "icon iconfont icon-diwenshuijianhuan",
|
||||
},
|
||||
]);
|
||||
|
||||
// Loading 状态
|
||||
const loading = ref(false);
|
||||
|
||||
const init = async () => {
|
||||
// 防重复请求
|
||||
if (loading.value) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
filter: {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{ field: "rvcd", operator: "eq", dataType: "string", value: "SJLY1U" },
|
||||
{ field: "tm", operator: "gte", dataType: "date", value: "2026-04-17 00:00:00" },
|
||||
{ field: "tm", operator: "lte", dataType: "date", value: "2026-05-17 23:00:00" },
|
||||
],
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "showIds",
|
||||
"operator": "in",
|
||||
"value": [
|
||||
"26",
|
||||
"27"
|
||||
]
|
||||
},
|
||||
sort: [{ field: "sort", dir: "asc" }],
|
||||
};
|
||||
await getKendoListCust(params);
|
||||
baseid.value != 'all' ? {
|
||||
"field": "baseId",
|
||||
"operator": "eq",
|
||||
"value": baseid.value
|
||||
}:null
|
||||
].filter(Boolean)
|
||||
}
|
||||
}
|
||||
let res = await baseEvnmAutoMonitorGetKendoListCust(params);
|
||||
console.log(res);
|
||||
let data = res.data.data || res.data
|
||||
data.forEach((item: any, index: any) => {
|
||||
facilities.value[index].count = item.cnt
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取水温监测数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时执行的逻辑
|
||||
onMounted(() => {
|
||||
// init();
|
||||
init();
|
||||
});
|
||||
|
||||
const baseid = ref("")
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
init();
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,47 +1,139 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem
|
||||
title="沿程水温变化"
|
||||
:prompt="prompts"
|
||||
:select="select"
|
||||
:datetimePicker="datetimePicker"
|
||||
>
|
||||
<div ref="chartRef" class="chart-container"></div>
|
||||
<SidePanelItem title="沿程水温变化" :prompt="prompts" :moreSelect="select" :datetimePicker="datetimePicker"
|
||||
@update-values="handlePanelChange1">
|
||||
<a-spin :spinning="loading" tip="加载中..." >
|
||||
<div v-show="showemit && !loading" ref="chartRef" class="chart-container"></div>
|
||||
<div v-show="!showemit && !loading" class="chart-container"> <a-empty /></div>
|
||||
</a-spin>
|
||||
</SidePanelItem>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||
import { ref, onMounted, onBeforeUnmount, watch, computed } from "vue";
|
||||
import * as echarts from "echarts";
|
||||
import type { ECharts } from "echarts";
|
||||
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
||||
import { getKendoListCust } from "@/api/sw";
|
||||
import { getKendoListCust, wbsbGetKendoList } from "@/api/sw";
|
||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||
import { da } from "element-plus/es/locale/index.mjs";
|
||||
import { f } from "vue-router/dist/router-CWoNjPRp.mjs";
|
||||
|
||||
|
||||
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: "yanchengshuiwenChangeMod",
|
||||
});
|
||||
// 选择器配置
|
||||
const select = ref({
|
||||
// 改为动态获取当前时间
|
||||
const getCurrentHourTime = () => {
|
||||
const now = new Date();
|
||||
// 减去一小时
|
||||
now.setHours(now.getHours() - 1);
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hour = String(now.getHours()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hour}`;
|
||||
};
|
||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||
const baseid: any = ref(null);
|
||||
const paramsOne = {
|
||||
rvcd: '',
|
||||
tm: []
|
||||
}
|
||||
const dataOne = ref('')
|
||||
// 使用 computed 使 prompts 响应 dataOne.value 的变化
|
||||
const prompts = computed(() => ({
|
||||
show: true,
|
||||
value: undefined,
|
||||
options: [],
|
||||
picker: undefined,
|
||||
format: undefined,
|
||||
});
|
||||
|
||||
// 日期选择器配置
|
||||
const datetimePicker = ref({
|
||||
show: true,
|
||||
value: "2026-05-15 15",
|
||||
format: "YYYY-MM-DD HH",
|
||||
picker: "date" as const,
|
||||
options: [],
|
||||
});
|
||||
const prompts = ref({
|
||||
show: true,
|
||||
value: "注:最新数据时间为2026-04-08 23",
|
||||
});
|
||||
value: `注:最新数据时间为${dataOne.value || getCurrentHourTime()}`,
|
||||
}));
|
||||
const jiDiList: any = ref([
|
||||
{
|
||||
"baseid": "all",
|
||||
"basename": "当前全部",
|
||||
"id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
|
||||
},
|
||||
{
|
||||
"baseid": "01",
|
||||
"basename": "金沙江干流",
|
||||
"id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
|
||||
},
|
||||
{
|
||||
"baseid": "02",
|
||||
"basename": "雅砻江干流",
|
||||
"id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
|
||||
},
|
||||
{
|
||||
"baseid": "03",
|
||||
"basename": "大渡河干流",
|
||||
"id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
|
||||
},
|
||||
{
|
||||
"baseid": "04",
|
||||
"basename": "乌江干流",
|
||||
"id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
|
||||
},
|
||||
{
|
||||
"baseid": "05",
|
||||
"basename": "长江上游干流",
|
||||
"id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
|
||||
},
|
||||
{
|
||||
"baseid": "10",
|
||||
"basename": "湘西",
|
||||
"id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
|
||||
},
|
||||
{
|
||||
"baseid": "08",
|
||||
"basename": "黄河上游干流",
|
||||
"id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
|
||||
},
|
||||
{
|
||||
"baseid": "09",
|
||||
"basename": "黄河中游干流",
|
||||
"id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
|
||||
},
|
||||
{
|
||||
"baseid": "06",
|
||||
"basename": "南盘江-红水河",
|
||||
"id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
|
||||
},
|
||||
{
|
||||
"baseid": "12",
|
||||
"basename": "东北",
|
||||
"id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
|
||||
},
|
||||
{
|
||||
"baseid": "07",
|
||||
"basename": "澜沧江干流",
|
||||
"id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
|
||||
},
|
||||
{
|
||||
"baseid": "13",
|
||||
"basename": "怒江干流",
|
||||
"id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
|
||||
},
|
||||
{
|
||||
"baseid": "11",
|
||||
"basename": "闽浙赣",
|
||||
"id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
|
||||
},
|
||||
{
|
||||
"baseid": "other",
|
||||
"basename": "其他",
|
||||
"id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
|
||||
}
|
||||
])
|
||||
const showemit = ref(false)
|
||||
const loading = ref(false)
|
||||
// const selectOptions: any = ref([])
|
||||
const optionsFmt = (options: any) =>
|
||||
options.map((item: any) => ({
|
||||
label: item.wbsName,
|
||||
value: item.wbsCode
|
||||
}))
|
||||
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chartInstance: ECharts | null = null;
|
||||
@ -52,9 +144,25 @@ const stationNames = ref([]);
|
||||
// 静态数据 - 水温值 (°C),班多无数据设为 null
|
||||
const waterTemperatures = ref([]);
|
||||
|
||||
// 静态时间数据
|
||||
const currentTime = "2026-04-08 23";
|
||||
// 使用 computed 使 currentTime 响应 dataOne.value 的变化
|
||||
const currentTime = computed(() => dataOne.value || getCurrentHourTime());
|
||||
// 选择器配置
|
||||
const select = ref({
|
||||
show: true,
|
||||
value: '',
|
||||
options: [],
|
||||
picker: undefined,
|
||||
format: undefined,
|
||||
});
|
||||
|
||||
// 日期选择器配置
|
||||
const datetimePicker = ref({
|
||||
show: true,
|
||||
value: computed(() => getCurrentHourTime()),
|
||||
format: "YYYY-MM-DD HH",
|
||||
picker: "date" as const,
|
||||
options: [],
|
||||
});
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartRef.value) return;
|
||||
@ -72,6 +180,16 @@ const initChart = () => {
|
||||
fontWeight: "normal",
|
||||
},
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
zoomOnMouseWheel: true,
|
||||
moveOnMouseMove: true,
|
||||
filterMode: 'filter'
|
||||
}
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
formatter: (params: any) => {
|
||||
@ -79,7 +197,7 @@ const initChart = () => {
|
||||
const data = params[0];
|
||||
// 过滤掉 null 值的数据点
|
||||
if (data.value !== null && data.value !== undefined) {
|
||||
return `${currentTime}<br/>${data.name}:${data.value}°C`;
|
||||
return `${currentTime.value}<br/>${data.name}:${data.value}°C`;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
@ -199,24 +317,38 @@ const handleResize = () => {
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
if (loading.value) return; // 防止重复请求
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const params = {
|
||||
filter: {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{ field: "rvcd", operator: "eq", dataType: "string", value: "SJLY1U" },
|
||||
{ field: "tm", operator: "gte", dataType: "date", value: "2026-04-17 00:00:00" },
|
||||
{ field: "tm", operator: "lte", dataType: "date", value: "2026-05-17 23:00:00" },
|
||||
{ field: "rvcd", operator: "eq", dataType: "string", value: paramsOne.rvcd },
|
||||
{ field: "tm", operator: "gte", dataType: "date", value: paramsOne.tm[0] },
|
||||
{ field: "tm", operator: "lte", dataType: "date", value: paramsOne.tm[1] },
|
||||
],
|
||||
},
|
||||
sort: [{ field: "sort", dir: "asc" }],
|
||||
};
|
||||
|
||||
let res = await getKendoListCust(params);
|
||||
stationNames.value = res.data.data
|
||||
let data = res.data.data || res.data
|
||||
|
||||
if(data.length > 0){
|
||||
showemit.value = true
|
||||
}else{
|
||||
showemit.value = false
|
||||
}
|
||||
|
||||
stationNames.value = data
|
||||
.filter((item: any) => item.sttp == "1")
|
||||
.map((item: any) => item.stnm);
|
||||
console.log(stationNames.value);
|
||||
|
||||
waterTemperatures.value = res.data.data
|
||||
waterTemperatures.value = data
|
||||
.filter((item: any) => item.sttp == "2")
|
||||
.map((item: any) => item.temperature);
|
||||
// waterTemperatures.value = res.data.data.map((item: any) => item.temperature);
|
||||
@ -244,13 +376,191 @@ const init = async () => {
|
||||
chartInstance?.resize();
|
||||
}, 100);
|
||||
}, 50);
|
||||
} catch (error) {
|
||||
console.error('数据加载失败:', error);
|
||||
showemit.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
//获取选择器配置参数
|
||||
const getSelectConfig = async () => {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
let obj: any = {}
|
||||
if (baseid.value === 'all') {
|
||||
obj = { rstcdStepSort: 'asc', siteStepSort: 'asc' }
|
||||
} else {
|
||||
obj = { siteStepSort: 'asc' }
|
||||
}
|
||||
const filters = [
|
||||
{
|
||||
field: 'wbsType',
|
||||
operator: 'eq',
|
||||
value: 'PSB_RVCD'
|
||||
}
|
||||
]
|
||||
if (baseid.value && baseid.value !== 'all') {
|
||||
filters.push({
|
||||
field: 'objId',
|
||||
operator: 'eq', // contains
|
||||
value: baseid.value
|
||||
})
|
||||
}
|
||||
let data: any = {
|
||||
filter: {
|
||||
logic: 'and',
|
||||
filters
|
||||
}
|
||||
// select: ['WBS_CODE', 'WBS_NAME']
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
data.sort = [obj]
|
||||
} else {
|
||||
data = {
|
||||
...data,
|
||||
group: [
|
||||
{ dir: 'asc', field: 'orderIndex' },
|
||||
{ dir: 'asc', field: 'wbsCode' },
|
||||
{ dir: 'asc', field: 'wbsName' },
|
||||
{ dir: 'asc', field: 'objid' },
|
||||
],
|
||||
groupResultFlat: true
|
||||
}
|
||||
}
|
||||
let res = await wbsbGetKendoList(data)
|
||||
let dataOne = res?.data?.data || res?.data
|
||||
|
||||
if (dataOne.length > 0) {
|
||||
let dataMapNameMap: any = {}
|
||||
let jiDiListMap: any = {}
|
||||
jiDiList.value.forEach((item: any) => {
|
||||
jiDiListMap[item.baseid] = item.basename
|
||||
})
|
||||
|
||||
dataOne.map((item: any, index: number) => {
|
||||
const { stcd, stnm, objId } = item
|
||||
if (dataMapNameMap[objId]) {
|
||||
dataMapNameMap[objId].push({ ...item, baseName: jiDiListMap[objId], baseId: objId })
|
||||
} else {
|
||||
dataMapNameMap[objId] = [{ ...item, baseName: jiDiListMap[objId], baseId: objId }]
|
||||
}
|
||||
return { label: item.wbsName, value: item.wbsCode, baseId: objId, baseName: jiDiListMap[objId] }
|
||||
})
|
||||
// debugger
|
||||
let dataMapNameArr: any = []
|
||||
|
||||
Object.keys(dataMapNameMap).forEach((item: any) => {
|
||||
dataMapNameArr.push({
|
||||
title: dataMapNameMap[item]?.[0]?.baseName,
|
||||
value: item,
|
||||
selectable: false,
|
||||
// baseId:dataMapNameMap[item]?.[0]?.baseId,
|
||||
children: dataMapNameMap[item].map((item2: any) => {
|
||||
return {
|
||||
title: item2.wbsName,
|
||||
value: item2.wbsCode
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
dataMapNameArr = dataMapNameArr.sort((a: any, b: any) => {
|
||||
const indexA = jiDiList.value.findIndex(item => item.baseid === a.value);
|
||||
const indexB = jiDiList.value.findIndex(item => item.baseid === b.value);
|
||||
return indexA - indexB;
|
||||
})
|
||||
select.value.options = filterSelectOptions(dataMapNameArr)
|
||||
if (baseid.value === 'all') {
|
||||
select.value.value = 'SJLY1U'
|
||||
} else if (filterSelectOptions(dataMapNameArr)[0]?.children) {
|
||||
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value
|
||||
} else if (filterSelectOptions(dataMapNameArr)[0]?.value) {
|
||||
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.value
|
||||
} else {
|
||||
select.value.value = ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('选择器配置加载失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const filterSelectOptions = (selectOptions: any) => {
|
||||
if (selectOptions?.length === 1 && selectOptions?.[0]?.children?.length === 1) {
|
||||
return [{ ...selectOptions?.[0]?.children?.[0], isLeaf: true }]
|
||||
} else if (selectOptions.length) {
|
||||
return selectOptions.map((e) => {
|
||||
if (e?.children?.length > 1) {
|
||||
return { ...e, isLeaf: false, selectable: true, children: e.children.map((item) => ({ ...item, isLeaf: true })) }
|
||||
} else {
|
||||
return { ...e.children[0], isLeaf: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
return []
|
||||
}
|
||||
//监听子组件的数据变化
|
||||
const handlePanelChange1 = (data) => {
|
||||
console.log('当前所有控件状态:', data);
|
||||
if (data.moreSelect) {
|
||||
paramsOne.rvcd = data.moreSelect
|
||||
}
|
||||
|
||||
if (data.datetime) {
|
||||
dataOne.value = data.datetime
|
||||
const datetime = data.datetime;
|
||||
|
||||
// 解析日期和时间
|
||||
const [datePart, hourPart] = datetime.split(' ');
|
||||
const [year, month, day] = datePart.split('-').map(Number);
|
||||
|
||||
// 创建当前时间的 Date 对象
|
||||
const currentDate = new Date(year, month - 1, day, parseInt(hourPart), 0, 0);
|
||||
|
||||
// 创建一个月前的 Date 对象
|
||||
const previousDate = new Date(year, month - 2, day, 0, 0, 0);
|
||||
|
||||
// 格式化函数:将 Date 对象转为 "YYYY-MM-DD HH:mm:ss" 格式
|
||||
function formatDate(date) {
|
||||
const y = date.getFullYear();
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const d = String(date.getDate()).padStart(2, '0');
|
||||
const h = String(date.getHours()).padStart(2, '0');
|
||||
const min = String(date.getMinutes()).padStart(2, '0');
|
||||
const s = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${y}-${m}-${d} ${h}:${min}:${s}`;
|
||||
}
|
||||
|
||||
// 生成结果数组
|
||||
const result = [
|
||||
formatDate(currentDate), // "2026-05-15 15:00:00"
|
||||
formatDate(previousDate) // "2026-04-15 00:00:00"
|
||||
];
|
||||
paramsOne.tm = result
|
||||
console.log(paramsOne.tm, 'paramsOne.tm')
|
||||
}
|
||||
if (paramsOne.rvcd || paramsOne.tm.length > 0) {
|
||||
init();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
watch(
|
||||
() => JidiSelectEventStore.selectedItem,
|
||||
(newVal) => {
|
||||
baseid.value = newVal.wbsCode;
|
||||
getSelectConfig()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
// 页面加载时执行的逻辑
|
||||
onMounted(() => {
|
||||
// 延迟初始化,确保 DOM 渲染完成
|
||||
init();
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
});
|
||||
|
||||
@ -265,5 +575,11 @@ onBeforeUnmount(() => {
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 252px ;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
:deep(.ant-spin-nested-loading ){
|
||||
height: 252px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -19,14 +19,14 @@ service.interceptors.request.use(
|
||||
`Expected 'config' and 'config.headers' not to be undefined`
|
||||
);
|
||||
}
|
||||
if (config.url.includes('/dec-lygk-base-server')) {
|
||||
if (config.url.includes('/dec-lygk-base-server') || config.url.includes('/wmp-env-server')) {
|
||||
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
||||
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
||||
config.headers._platformid = '31e6d13f-c359-4a19-8e67-b6f868f2401b';
|
||||
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
|
||||
|
||||
config.headers.authorization =
|
||||
'bearer f96d0008-f77f-497a-b05d-82cded9ccd89';
|
||||
'bearer e5445e2e-798c-4cfe-9cfe-0926e606c85c';
|
||||
config.baseURL = '/';
|
||||
} else {
|
||||
const user = useUserStoreHook();
|
||||
|
||||
@ -54,6 +54,16 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
||||
new RegExp('^/api/dec-lygk-base-server'),
|
||||
'/api/dec-lygk-base-server'
|
||||
)
|
||||
},
|
||||
'/api/wmp-env-server': {
|
||||
target: 'https://211.99.26.225:12122',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
rewrite: path =>
|
||||
path.replace(
|
||||
new RegExp('^/api/wmp-env-server'),
|
||||
'/api/wmp-env-server'
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user