模块完善

This commit is contained in:
王兴凯 2026-05-15 18:08:29 +08:00
parent cd59030f07
commit e3022c2db6
12 changed files with 2218 additions and 417 deletions

View File

@ -10,6 +10,7 @@ VITE_APP_BASE_API = '/dev-api'
# VITE_APP_BASE_URL = 'http://localhost:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# 汤伟
VITE_APP_BASE_URL = 'http://10.84.121.21:8093'

View File

@ -0,0 +1,62 @@
import request from '@/utils/request';
/**
* Kendo
* @param params
* @param sortConfig
*/
export function getKendoList(params: any, sortConfig?: any[]) {
return request({
url: '/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
method: 'post',
data: {
filters: params,
sorts: sortConfig || []
}
});
}
/**
* Kendo
* @param params
* @param sortConfig
*/
export function getKendoListCust(params: any, sortConfig?: any[]) {
return request({
url: '/dec-lygk-base-server/base/vmsstbprpt/GetKendoListCust',
method: 'post',
data: {
filters: params,
sorts: sortConfig || []
}
});
}
/**
* other
* @param filters
* @param sorts
* @param needTotal
* @param fields
* @param defaultSort
*/
export function getIntroduce(
filters: any[],
sorts?: any[],
needTotal?: boolean,
fields?: string[],
defaultSort?: any
) {
return request({
url: '/dec-lygk-base-server/base/introduce/getIntroduce',
method: 'post',
data: {
logic: 'and',
filters: filters,
sorts: sorts || [],
needTotal: needTotal || false,
fields: fields || [],
defaultSort: defaultSort
}
});
}

View File

@ -15,6 +15,12 @@
<InfoCircleOutlined />
</a-tooltip>
</span>
<span v-if="iconmap.show" class="title_icon">
<a-tooltip placement="top" :title="iconmap.value"
:get-popup-container="getPopupContainer">
<span :class="iconmap.icon"></span>
</a-tooltip>
</span>
</div>
<div class="title_right">
<div v-if="select.show">
@ -36,7 +42,7 @@
<div v-if="datetimePicker.show">
<!-- 添加 locale 属性来设置语言 -->
<a-date-picker v-model:value="datetimeValue" show-time
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '' }"
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '120px' }"
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
:picker="datetimePicker.picker" placeholder=" " @change="handleDateTimeChange"
:size="'small'" />
@ -73,6 +79,7 @@ import dayjs, { Dayjs } from 'dayjs';
interface PromptConfig {
show: boolean;
value: string;
icon?: string;
}
interface SelectConfig {
@ -112,6 +119,14 @@ const props = defineProps({
value: '',
})
},
iconmap: {//
type: Object as () => PromptConfig,
default: () => ({
show: false,
value: '',
icon:'iconfont icon-time',
})
},
select: { //
type: Object as () => SelectConfig,
default: () => ({

View File

@ -13,24 +13,13 @@ import { ref, onMounted, watch } from "vue";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getBaseKenWbsbdoList } from "@/api/home";
import { getBaseWbsb } from "@/api/home";
const JidiSelectEventStore = useJidiSelectEventStore();
// 便
defineOptions({
name: "jidiInfoMod",
});
const title_text = ref("");
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
console.log(newVal);
if (newVal.name == "当前全部") {
}
initText();
},
{ deep: true }
);
const initText = () => {
const params = {
filter: {
@ -46,15 +35,26 @@ const initText = () => {
],
},
};
getBaseKenWbsbdoList(params).then((res) => {
getBaseWbsb(params).then((res) => {
console.log(res);
title_text.value = res.data.data[0].introduce;
// debugger
});
};
const title_text = ref("");
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
initText();
},
{ deep: true, immediate: true }
);
//
onMounted(() => {
initText();
console.log(JidiSelectEventStore.selectedItem);
});
</script>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
// ==================== ====================
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import * as echarts from 'echarts'
import type { EChartsOption } from 'echarts'
import type { ColumnsType } from 'ant-design-vue/es/table/interface'
@ -8,9 +8,12 @@ import { DownloadOutlined } from '@ant-design/icons-vue'
import BasicSearch from '@/components/BasicSearch/index.vue'
import BasicTable from '@/components/BasicTable/index.vue'
import { message } from 'ant-design-vue'
// TODO:
// import { ModalTabs } from '@/components/MapModal/modalTabs'
// import { handleTabs, modalTabSetting } from '@/components/MapModal/setting.config'
import { useModelStore } from '@/store/modules/model'
import { handleTabs } from '@/components/MapModal/setting.config'
import { getKendoList, getKendoListCust, getIntroduce } from '@/api/shuidiankaifa'
// ==================== ====================
const USE_MOCK_DATA = true // 使 false
// ==================== Props ====================
const props = defineProps<{
@ -57,6 +60,9 @@ interface ModalData {
// ==================== ====================
// modelStore MapModal
const modelStore = useModelStore()
//
const qid = ref<string>('')
const jiDiList = ref<any[]>([])
@ -78,11 +84,12 @@ const pieCode = ref<string[]>([])
const pikData = ref<PieDataItem[]>([])
const chartRef = ref<HTMLElement | null>(null)
const chartInstance = ref<any>(null)
const chartInitialized = ref<boolean>(false) //
const dataLoading = ref<boolean>(false)
//
const mapModal = ref<boolean>(false)
const modalData = ref<ModalData>({ sttp: '', stcd: '', titleName: '' })
// MapModal
// const mapModal = ref<boolean>(false)
// const modalData = ref<ModalData>({ sttp: '', stcd: '', titleName: '' })
//
const unit = computed(() => getUnitConfigByCode('Other', 'ZJRL').unit)
@ -99,46 +106,70 @@ const tableRef = ref<any>(null)
* 获取Tab统计数据
*/
async function fetchTabData(params: any): Promise<TabItem[]> {
// TODO: API
// const res = await shuiDianKaifaZhuangKung.GetKendoList(params, sortConfig)
console.log('【模拟】获取Tab数据参数:', params)
console.log('【API】获取Tab数据参数:', params)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => {
setTimeout(() => {
// seriesName ttpwr
const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name
// GetKendoList
const mockResponse = [
resolve([
{
key: '2',
items: [{
SUM_TTPWR: 1069300000, // kW
COUNT_ENGID: 150
}]
col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
key: 'build',
unit: useTtpwrFilter ? unit.value : '座',
value: '已建',
count: useTtpwrFilter ? 4568.50 : 120
},
{
key: '1',
items: [{
SUM_TTPWR: 331000000,
COUNT_ENGID: 80
}]
col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
key: 'building',
unit: useTtpwrFilter ? unit.value : '座',
value: '在建',
count: useTtpwrFilter ? 2345.30 : 85
},
{
key: '0',
items: [{
SUM_TTPWR: 179000000,
COUNT_ENGID: 30
}]
col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
key: 'noBuild',
unit: useTtpwrFilter ? unit.value : '座',
value: '未建',
count: useTtpwrFilter ? 1230.20 : 60
}
])
}, 300)
})
}
]
// React
// API
try {
const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name
//
const aggregates = [{ field: 'ttpwr', aggregate: 'sum' }]
const sortConfig = useTtpwrFilter
? [{ dir: 'desc', field: 'bldsttCcode', aggregates }]
: [{ dir: 'desc', field: 'bldsttCcode' }]
// API
const res = await getKendoList(
useTtpwrFilter
? { ...params, ttpwr: [{ field: 'ttpwr', operator: 'isnotnull' }] }
: params,
sortConfig
)
if (!res?.data || !Array.isArray(res.data)) {
console.warn('【API】Tab数据返回格式异常:', res)
return []
}
// React
let list: TabItem[] = []
const result = mockResponse.reduce((acc: any, cur: any) => {
res.data.reduce((acc: any, cur: any) => {
if (cur.key === '0') {
list.push({
col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
@ -167,120 +198,109 @@ async function fetchTabData(params: any): Promise<TabItem[]> {
return list
}, [])
resolve(result)
}, 500)
})
console.log('【API】Tab数据处理结果:', list)
return list
} catch (error) {
console.error('【API】获取Tab数据失败:', error)
message.error('获取Tab数据失败')
return []
}
}
/**
* 获取饼图分组数据完整实现React版本的复杂逻辑
*/
async function fetchPieData(params: any): Promise<PieDataItem[]> {
// TODO: API
console.log('【模拟】获取饼图数据,参数:', params)
console.log('【API】获取饼图数据参数:', params)
console.log('【API】USE_MOCK_DATA:', USE_MOCK_DATA, 'qid.value:', qid.value)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => {
setTimeout(() => {
const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name
// GetKendoList
let mockResponse: any[]
console.log('【模拟数据】生成饼图数据useTtpwrFilter:', useTtpwrFilter, 'qid.value:', qid.value)
let mockData: PieDataItem[]
if (qid.value === 'all') {
// baseId
mockResponse = [
{
key: 'cj',
items: [{
key: 'cj_base',
items: [{
BASENAME: '长江流域',
SUM_TTPWR: 456800000, // kW
COUNT_BASEID: 120
}]
}]
},
{
key: 'hh',
items: [{
key: 'hh_base',
items: [{
BASENAME: '黄河流域',
SUM_TTPWR: 234500000,
COUNT_BASEID: 85
}]
}]
},
{
key: 'zj',
items: [{
key: 'zj_base',
items: [{
BASENAME: '珠江流域',
SUM_TTPWR: 123000000,
COUNT_BASEID: 60
}]
}]
}
//
mockData = [
{ key: 'cj', name: '长江流域', value: useTtpwrFilter ? 4568.50 : 120, unit: '', dataDimensionRecursive: 'true' },
{ key: 'hh', name: '黄河流域', value: useTtpwrFilter ? 2345.30 : 85, unit: '', dataDimensionRecursive: 'true' },
{ key: 'zj', name: '珠江流域', value: useTtpwrFilter ? 1230.20 : 60, unit: '', dataDimensionRecursive: 'true' },
{ key: 'hh2', name: '淮河流域', value: useTtpwrFilter ? 890.10 : 45, unit: '', dataDimensionRecursive: 'true' },
{ key: 'hj', name: '海河流域', value: useTtpwrFilter ? 567.80 : 30, unit: '', dataDimensionRecursive: 'true' }
]
console.log('【模拟数据】全基地模式,生成 5 条数据')
} else if (qid.value === 'other') {
// other
mockResponse = [
{
key: 'river1',
items: [{
HBRVCDNAME: '长江干流',
SUM_TTPWR: 89000000,
COUNT_BLDSTTCCODE: 25
}]
},
{
key: 'river2',
items: [{
HBRVCDNAME: '黄河干流',
SUM_TTPWR: 56000000,
COUNT_BLDSTTCCODE: 18
}]
},
{
key: 'river3',
items: [{
HBRVCDNAME: '珠江干流',
SUM_TTPWR: 34000000,
COUNT_BLDSTTCCODE: 12
}]
}
// other
mockData = [
{ key: 'river1', name: '长江干流', value: useTtpwrFilter ? 890.50 : 25, unit: '', dataDimensionRecursive: 'true', index: 1 },
{ key: 'river2', name: '黄河干流', value: useTtpwrFilter ? 567.30 : 18, unit: '', dataDimensionRecursive: 'true', index: 2 },
{ key: 'river3', name: '珠江干流', value: useTtpwrFilter ? 345.20 : 12, unit: '', dataDimensionRecursive: 'true', index: 3 }
]
console.log('【模拟数据】other 模式,生成 3 条数据')
} else {
// hbrvcd
mockResponse = [
{
items: [{
key: 'cjgl',
items: [{
HBRVCDNAME: '长江干流',
SUM_TTPWR: 456800000,
COUNT_BLDSTTCCODE: 50
}]
}]
},
{
items: [{
key: 'hhgl',
items: [{
HBRVCDNAME: '黄河干流',
SUM_TTPWR: 234500000,
COUNT_BLDSTTCCODE: 35
}]
}]
}
//
mockData = [
{ key: 'cjgl', name: '长江干流', value: useTtpwrFilter ? 2345.60 : 50, unit: '', dataDimensionRecursive: 'true' },
{ key: 'cjzl', name: '长江支流', value: useTtpwrFilter ? 1234.50 : 35, unit: '', dataDimensionRecursive: 'true' },
{ key: 'cjxz', name: '长江下游', value: useTtpwrFilter ? 987.40 : 25, unit: '', dataDimensionRecursive: 'true' }
]
console.log('【模拟数据】单基地模式,生成 3 条数据')
}
// ReactflatMap
let list = mockResponse.flatMap((item: any) => {
console.log('【模拟数据】✅ 饼图数据生成成功:', mockData.length, '条')
console.log('【模拟数据】数据详情:', mockData)
resolve(mockData)
}, 300)
})
}
// API
try {
const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name
//
const aggregates = [{ field: 'ttpwr', aggregate: 'sum' }]
const sortConfig = [
qid.value === 'all' || qid.value === 'other' ? null : { dir: 'asc', field: 'rvcdStepSort' },
qid.value === 'all' ? { dir: 'asc', field: 'baseStepSort' } : null,
{
dir: 'asc',
field: qid.value === 'all' ? 'baseId' : 'hbrvcd'
},
{
dir: 'desc',
field: qid.value === 'all' ? 'baseName' : 'hbrvcdName'
},
{
dir: 'desc',
field: 'bldsttCcode',
aggregates
}
].filter(Boolean)
// API
const res = await getKendoList(
useTtpwrFilter
? { ...params, ttpwr: [{ field: 'ttpwr', operator: 'isnotnull' }] }
: params,
sortConfig as any[]
)
if (!res?.data || !Array.isArray(res.data)) {
console.warn('【API】饼图数据返回格式异常:', res)
return []
}
// ReactflatMap
let list = res.data.flatMap((item: any) => {
let arr: PieDataItem[] = []
// qid
@ -319,16 +339,20 @@ async function fetchPieData(params: any): Promise<PieDataItem[]> {
// other getIntroduce
if (qid.value === 'other' && list.length > 0) {
// getIntroduce
const introRes = [
{ wbsCode: 'river1', orderIndex: 1 },
{ wbsCode: 'river2', orderIndex: 2 },
{ wbsCode: 'river3', orderIndex: 3 }
]
const introRes = await getIntroduce(
[
{ field: 'wbsType', operator: 'eq', value: 'PSB_RVCD' },
{ field: 'objId', operator: 'eq', value: 'other' },
{ field: 'orderIndex', operator: 'isnotnull' }
],
[{ field: 'orderIndex', dir: 'asc' }],
false,
['wbsCode', 'wbsName', 'orderIndex']
)
if (introRes?.length && list?.length) {
if (introRes?.data?.length && list?.length) {
list = list.map((el: any) => {
const found = introRes.find((item: any) => el?.key === item?.wbsCode)
const found = introRes.data.find((item: any) => el?.key === item?.wbsCode)
return {
...el,
index: found?.orderIndex
@ -337,9 +361,13 @@ async function fetchPieData(params: any): Promise<PieDataItem[]> {
}
}
resolve(list)
}, 500)
})
console.log('【API】饼图数据处理结果:', list)
return list
} catch (error) {
console.error('【API】获取饼图数据失败:', error)
message.error('获取饼图数据失败')
return []
}
}
/**
@ -364,42 +392,40 @@ async function fetchIntroduce(params: any): Promise<any[]> {
/**
* 表格数据请求函数
*/
async function fetchTableData(params: any): Promise<{ records: any[], total: number }> {
// TODO: API
// const url = qid.value === 'all'
// ? '/dec-lygk-base-server/base/vmsstbprpt/GetKendoListCust'
// : '/dec-lygk-base-server/base/vmsstbprpt/GetKendoList'
console.log('【模拟】获取表格数据,参数:', params)
async function fetchTableData(params: any): Promise<any> {
console.log('【API】获取表格数据参数:', params)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => {
setTimeout(() => {
//
const buildStatus = params.bldsttCcode
const hbrvcdFilter = params.hbrvcd?.value || []
const hbrvcdFilter = Array.isArray(params.hbrvcd)
? params.hbrvcd[0]?.value || []
: []
//
const stationTemplates = [
{ name: '三峡', river: 'cjgl', baseName: '长江基地', province: '湖北省' },
{ name: '葛洲坝', river: 'cjgl', baseName: '长江基地', province: '湖北省' },
{ name: '向家坝', river: 'cjgl', baseName: '长江基地', province: '四川省' },
{ name: '溪洛渡', river: 'cjgl', baseName: '长江基地', province: '云南省' },
{ name: '白鹤滩', river: 'cjgl', baseName: '长江基地', province: '四川省' },
{ name: '乌东德', river: 'cjgl', baseName: '长江基地', province: '云南省' },
{ name: '小浪底', river: 'hhgl', baseName: '黄河基地', province: '河南省' },
{ name: '刘家峡', river: 'hhgl', baseName: '黄河基地', province: '甘肃省' },
{ name: '龙羊峡', river: 'hhgl', baseName: '黄河基地', province: '青海省' },
{ name: '拉西瓦', river: 'hhgl', baseName: '黄河基地', province: '青海省' },
{ name: '天生桥', river: 'zjgl', baseName: '珠江基地', province: '贵州省' },
{ name: '岩滩', river: 'zjgl', baseName: '珠江基地', province: '广西区' },
{ name: '大化', river: 'zjgl', baseName: '珠江基地', province: '广西区' },
{ name: '响洪甸', river: 'hhgl', baseName: '淮河基地', province: '安徽省' },
{ name: '梅山', river: 'hhgl', baseName: '淮河基地', province: '安徽省' },
{ name: '潘家口', river: 'hjgl', baseName: '海河基地', province: '河北省' },
{ name: '大黑汀', river: 'hjgl', baseName: '海河基地', province: '河北省' },
{ name: '丰满', river: 'sjgl', baseName: '松花江基地', province: '吉林省' },
{ name: '白山', river: 'sjgl', baseName: '松花江基地', province: '吉林省' },
{ name: '水丰', river: 'ljgl', baseName: '辽河基地', province: '辽宁省' }
{ name: '三峡', river: 'cjgl', baseName: '长江流域', province: '湖北省' },
{ name: '葛洲坝', river: 'cjgl', baseName: '长江流域', province: '湖北省' },
{ name: '向家坝', river: 'cjgl', baseName: '长江流域', province: '四川省' },
{ name: '溪洛渡', river: 'cjgl', baseName: '长江流域', province: '云南省' },
{ name: '白鹤滩', river: 'cjgl', baseName: '长江流域', province: '四川省' },
{ name: '乌东德', river: 'cjgl', baseName: '长江流域', province: '云南省' },
{ name: '小浪底', river: 'hhgl', baseName: '黄河流域', province: '河南省' },
{ name: '刘家峡', river: 'hhgl', baseName: '黄河流域', province: '甘肃省' },
{ name: '龙羊峡', river: 'hhgl', baseName: '黄河流域', province: '青海省' },
{ name: '拉西瓦', river: 'hhgl', baseName: '黄河流域', province: '青海省' },
{ name: '天生桥', river: 'zjgl', baseName: '珠江流域', province: '贵州省' },
{ name: '岩滩', river: 'zjgl', baseName: '珠江流域', province: '广西区' },
{ name: '大化', river: 'zjgl', baseName: '珠江流域', province: '广西区' },
{ name: '响洪甸', river: 'hhgl2', baseName: '淮河流域', province: '安徽省' },
{ name: '梅山', river: 'hhgl2', baseName: '淮河流域', province: '安徽省' },
{ name: '潘家口', river: 'hjgl', baseName: '海河流域', province: '河北省' },
{ name: '大黑汀', river: 'hjgl', baseName: '海河流域', province: '河北省' },
{ name: '丰满', river: 'sjgl', baseName: '松花江流域', province: '吉林省' },
{ name: '白山', river: 'sjgl', baseName: '松花江流域', province: '吉林省' },
{ name: '水丰', river: 'ljgl', baseName: '辽河流域', province: '辽宁省' }
]
//
@ -412,7 +438,13 @@ async function fetchTableData(params: any): Promise<{ records: any[], total: num
//
if (filteredStations.length === 0) {
resolve({ records: [], total: 0 })
// BasicTable { data: { records: [], total: 0 } }
resolve({
data: {
records: [],
total: 0
}
})
return
}
@ -479,21 +511,61 @@ async function fetchTableData(params: any): Promise<{ records: any[], total: num
}
})
console.log('【调试】模拟表格数据:', {
records: mockRecords.length,
total: mockRecords.length,
firstRecord: mockRecords[0]
})
// BasicTable { data: { records: [], total: 0 } }
resolve({
data: {
records: mockRecords,
total: mockRecords.length
}
})
}, 600)
}, 400)
})
}
// API
try {
// qid 使
const url = qid.value === 'all'
? '/dec-lygk-base-server/base/vmsstbprpt/GetKendoListCust'
: '/dec-lygk-base-server/base/vmsstbprpt/GetKendoList'
const apiFunc = qid.value === 'all' ? getKendoListCust : getKendoList
// API
const res = await apiFunc(params, [])
// { data: { records: [], total: 0 } }
return {
data: {
records: res?.data?.records || res?.data?.items || [],
total: res?.data?.total || 0
}
}
} catch (error) {
console.error('【API】获取表格数据失败:', error)
message.error('获取表格数据失败')
return {
data: {
records: [],
total: 0
}
}
}
}
// ==================== ====================
/**
* 单位转换函数待完善
* 单位转换函数
*/
function transUnit(value: number, from: string, to: string): number {
// TODO:
//
// kWkW
if (from === 'Other' && to === 'ZJRL') {
return value / 10000 // kW kW
@ -523,20 +595,15 @@ function handleExport() {
}
}
/**
* 处理弹窗关闭
*/
function handleModalCancel() {
mapModal.value = false
modalData.value = { sttp: '', stcd: '', titleName: '' }
}
// ==================== ECharts ====================
/**
* 计算饼图配置增强版支持themeecList自定义颜色
*/
const chartSetting = computed<EChartsOption>(() => {
console.log('【chartSetting】计算饼图配置pieData.value 长度:', pieData.value.length)
console.log('【chartSetting】pieData.value 内容:', pieData.value)
const total = pieData.value.reduce((acc, item) => acc + item.value, 0).toFixed(2)
const flag = props.seriesName === '数量(座)'
@ -544,6 +611,8 @@ const chartSetting = computed<EChartsOption>(() => {
const dddd = flag ? '电站数量' : '装机容量'
const cccc = flag ? ' (座)' : ` (${unit.value})`
console.log('【chartSetting】配置信息:', { total, bbbb, dddd, cccc, seriesDataLength: pieData.value.length })
// themeecList React
const colors = pieData.value.map((item: any, index: any) => {
if (props.themeecList && props.themeecList.length > 0) {
@ -623,14 +692,78 @@ const chartSetting = computed<EChartsOption>(() => {
* 初始化图表
*/
function initChart() {
if (!chartRef.value) return
console.log('【图表初始化】尝试初始化chartRef.value:', chartRef.value)
console.log('【图表初始化】当前 pieData.value 长度:', pieData.value.length)
if (!chartRef.value) {
console.warn('【图表初始化】容器未就绪,延迟重试')
setTimeout(initChart, 200)
return
}
//
const rect = chartRef.value.getBoundingClientRect()
const containerWidth = chartRef.value.offsetWidth
const containerHeight = chartRef.value.offsetHeight
console.log('【图表初始化】容器信息:', {
offsetWidth: containerWidth,
offsetHeight: containerHeight,
getBoundingClientRect: {
width: rect.width,
height: rect.height,
top: rect.top,
left: rect.left
},
display: window.getComputedStyle(chartRef.value).display,
visibility: window.getComputedStyle(chartRef.value).visibility,
parentDisplay: window.getComputedStyle(chartRef.value.parentElement).display
})
//
chartRef.value.style.border = '3px solid red'
chartRef.value.style.background = 'rgba(255, 0, 0, 0.1)'
if (containerWidth === 0 || containerHeight === 0) {
console.error('【图表初始化】❌ 容器尺寸为0无法初始化')
console.log('【图表初始化】⏰ 200ms 后重试...')
setTimeout(initChart, 200)
return
}
console.log('【图表初始化】✅ 容器尺寸正常,开始初始化 ECharts')
// 使541px × 412px
chartInstance.value = echarts.init(chartRef.value, null, {
width: 541,
height: 412
})
console.log('【图表初始化】ECharts 实例创建成功')
//
chartInstance.value.on('legendselectchanged', handleLegendSelectChanged)
//
chartInstance.value.on('click', handlePieClick)
// updateChart
if (pieData.value.length > 0) {
console.log('【图表初始化】✅ 数据已就绪,渲染图表')
updateChart()
// resize
setTimeout(() => {
chartInstance.value?.resize()
console.log('【图表初始化】✅ resize 完成')
console.log('【图表初始化】图表数据:', pieData.value.length, '条')
chartInitialized.value = true
}, 100)
} else {
console.log('【图表初始化】⏰ 数据未就绪,标记为已初始化,等待 watch 触发更新')
//
chartInitialized.value = true
}
}
/**
@ -771,12 +904,17 @@ const columns: ColumnsType = [
* 处理表格行点击打开详情弹窗
*/
function handleRowClick(record: any) {
modalData.value = {
// 使 MapModal
modelStore.params = {
sttp: 'ENG',
stcd: record.stcd,
titleName: record.stnm
}
mapModal.value = true
} as any // store
modelStore.title = record.stnm ? `${record.stnm} 详情信息` : '详情信息'
modelStore.tabList = handleTabs(modelStore.params)
modelStore.modalVisible = true
console.log('【打开详情弹窗】参数:', modelStore.params)
}
// ==================== ====================
@ -959,7 +1097,12 @@ watch(
watch(
[tabKey, tabCol, stnm, qid],
async () => {
if (!tabKey.value || !tabCol.value) return
console.log('【Watch触发】tabKey:', tabKey.value, 'tabCol:', tabCol.value, 'stnm:', stnm.value, 'qid:', qid.value)
if (!tabKey.value || !tabCol.value) {
console.log('【Watch触发】跳过tabKey 或 tabCol 为空')
return
}
dataLoading.value = true
try {
@ -979,8 +1122,12 @@ watch(
delete params.stnmContains
}
console.log('【Watch触发】调用 fetchPieData参数:', params)
const result = await fetchPieData(params)
console.log('【Watch触发】✅ fetchPieData 返回结果:', result.length, '条')
console.log('【Watch触发】数据内容:', result)
// other
if (qid.value === 'other' && result.length > 0) {
const introRes = await fetchIntroduce({
@ -1003,11 +1150,33 @@ watch(
}
}
console.log('【Watch触发】更新 pieData数据量:', result.length)
pikData.value = result
pieData.value = result
pieCode.value = []
console.log('【Watch触发】pieData.value 更新后的值:', pieData.value)
// DOM
await nextTick()
//
if (!chartInitialized.value) {
console.log('【Watch触发】图表未初始化开始初始化图表')
//
setTimeout(() => {
initChart()
}, 200)
} else {
//
console.log('【Watch触发】图表已初始化更新数据')
updateChart()
chartInstance.value?.resize()
console.log('【图表更新】数据变化,重新渲染')
}
} catch (error) {
console.error('获取饼图数据失败:', error)
console.error('【API】获取饼图数据失败:', error)
message.error('获取饼图数据失败')
} finally {
dataLoading.value = false
@ -1038,10 +1207,32 @@ onMounted(() => {
qid.value = 'all'
}
initChart()
// onMounted
// watch
console.log('【生命周期】onMounted 触发,等待数据加载后初始化图表')
window.addEventListener('resize', handleResize)
})
// Tab Tab
watch(tabIndex, async (newTab, oldTab) => {
console.log('【Tab切换】从', oldTab, '切换到', newTab)
// DOM
await nextTick()
setTimeout(() => {
if (chartInstance.value && chartInitialized.value) {
console.log('【Tab切换】重新调整图表尺寸')
chartInstance.value.resize()
updateChart()
} else if (!chartInitialized.value) {
console.log('【Tab切换】图表未初始化等待数据加载后初始化')
// watch([tabKey, tabCol...])
}
}, 300)
})
onUnmounted(() => {
chartInstance.value?.dispose()
window.removeEventListener('resize', handleResize)
@ -1108,36 +1299,8 @@ onUnmounted(() => {
</a-tab-pane>
</a-tabs>
<!-- 详情弹窗 -->
<a-modal
v-if="mapModal && modalData.sttp"
:open="mapModal"
:title="modalData.titleName ? `${modalData.titleName} 详情信息` : '详情信息'"
:width="1200"
:footer="null"
:maskClosable="false"
class="tabsModal"
style="padding-bottom: 0"
@cancel="handleModalCancel"
>
<!-- TODO: 集成ModalTabs组件 -->
<!-- <ModalTabs v-if="modalData" :tabs="handleTabs(modalData)" :params="modalData" /> -->
<!-- 临时替代方案 -->
<div class="modal-content">
<a-descriptions bordered :column="2">
<a-descriptions-item label="电站编码">
{{ modalData.stcd }}
</a-descriptions-item>
<a-descriptions-item label="电站类型">
{{ modalData.sttp }}
</a-descriptions-item>
</a-descriptions>
<p style="margin-top: 16px; color: #999;">
TODO: 请确认 ModalTabs 组件路径后启用上方注释代码
</p>
</div>
</a-modal>
<!-- 详情弹窗已改用全局 MapModal 组件 AppMain.vue 中统一管理 -->
<!-- 无需在此处添加 a-modal点击表格行会自动触发 modelStore.modalVisible -->
</div>
</template>

View File

@ -1,7 +1,7 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水质变化" :datetimePicker="datetimePicker">
<SidePanelItem title="沿程水质变化" :iconmap="iconmap" :datetimePicker="datetimePicker">
<div class="chart-container" ref="chartRef"></div>
</SidePanelItem>
</template>
@ -17,7 +17,11 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
defineOptions({
name: 'waterQuality'
});
const iconmap = ref({
show: true,
value: '注最新数据时间为2026-05-14 2300',
icon: 'iconfont icon-time',
});
// ==================== ====================
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;

View File

@ -1,6 +1,6 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水温变化" :prompt="prompts">
<SidePanelItem title="沿程水温变化" :prompt="prompts" :select="select" :datetimePicker="datetimePicker">
<div ref="chartRef" class="chart-container"></div>
</SidePanelItem>
</template>
@ -15,7 +15,23 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
defineOptions({
name: 'yanchengshuiwenChangeMod'
});
//
const select = ref({
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',

View File

@ -1,7 +1,19 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue";
import HuanbaozdjcgzkzQK from "@/modules/huanbaozdjcgzkzQK/index.vue"
import HuanbaozdjcgzkzQK from "@/modules/huanbaozdjcgzkzQK/index.vue";
import SZYCBH from "@/modules/waterQuality/index.vue"
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
const JidiSelectEventStore = useJidiSelectEventStore();
const wbsCode = ref('')
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
wbsCode.value = newVal.wbsCode
},
{ deep: true, immediate: true }
);
</script>
<template>
@ -12,6 +24,7 @@ import HuanbaozdjcgzkzQK from "@/modules/huanbaozdjcgzkzQK/index.vue"
<div class="rightContent">
<RightDrawer>
<HuanbaozdjcgzkzQK />
<SZYCBH v-if="wbsCode != 'all'" />
</RightDrawer>
</div>
</div>

View File

@ -1,8 +1,21 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue";
import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/index.vue"
import EnvironmentalQuality from "@/modules/EnvironmentalQuality/index.vue" //
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import SZYCBH from "@/modules/waterQuality/index.vue"
const JidiSelectEventStore = useJidiSelectEventStore();
const wbsCode = ref('');
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
console.log(newVal);
wbsCode.value = newVal.wbsCode;
},
{ deep: true }
);
</script>
<template>
@ -14,6 +27,8 @@ import EnvironmentalQuality from "@/modules/EnvironmentalQuality/index.vue" //
<RightDrawer>
<ShuiZhiJianCeGongZuoQingKuang />
<EnvironmentalQuality />
<SZYCBH v-if="wbsCode != 'all'"></SZYCBH>
</RightDrawer>
</div>
</div>

View File

@ -1,4 +1,5 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue";
@ -7,6 +8,21 @@ import ZengZhiZhanJieShaoMod from "@/modules/zengZhiZhanJieShaoMod/index.vue"
import ZZZJSYXQKTT from "@/modules/zengzhizhanjiansheyunxing/index.vue"
import ZZZYXSJTJ from "@/modules/zengzhizhanyunxingsjtj/index.vue"
import FLZLLB from "@/modules/GYZLLB/index.vue"
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
const JidiSelectEventStore = useJidiSelectEventStore();
const wbsCode = ref('all');
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
console.log(newVal);
if (newVal.wbsCode == 'all') {
wbsCode.value = 'all';
} else {
wbsCode.value = newVal.wbsCode;
}
},
{ deep: true }
);
</script>
<template>
@ -17,8 +33,8 @@ import FLZLLB from "@/modules/GYZLLB/index.vue"
<div class="rightContent">
<RightDrawer>
<ZZZJSYXQKTT />
<ZengZhiZhanJieShaoMod />
<ZengZhiJiHuaWanChengQingKuang />
<ZengZhiZhanJieShaoMod v-if="wbsCode != 'all'" />
<ZengZhiJiHuaWanChengQingKuang v-if="wbsCode != 'all'" />
<FLZLLB title="放流总量" />
<ZZZYXSJTJ />
</RightDrawer>

1492
package-lock.json generated

File diff suppressed because it is too large Load Diff

6
package.json Normal file
View File

@ -0,0 +1,6 @@
{
"dependencies": {
"cesium": "^1.140.0",
"vite-plugin-cesium": "^1.2.23"
}
}