模块完善

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://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://172.16.21.142:8096'
# 汤伟 # 汤伟
VITE_APP_BASE_URL = 'http://10.84.121.21:8093' 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 /> <InfoCircleOutlined />
</a-tooltip> </a-tooltip>
</span> </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>
<div class="title_right"> <div class="title_right">
<div v-if="select.show"> <div v-if="select.show">
@ -36,7 +42,7 @@
<div v-if="datetimePicker.show"> <div v-if="datetimePicker.show">
<!-- 添加 locale 属性来设置语言 --> <!-- 添加 locale 属性来设置语言 -->
<a-date-picker v-model:value="datetimeValue" show-time <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" :format="datetimePicker.format !== null ? datetimePicker.format : undefined"
:picker="datetimePicker.picker" placeholder=" " @change="handleDateTimeChange" :picker="datetimePicker.picker" placeholder=" " @change="handleDateTimeChange"
:size="'small'" /> :size="'small'" />
@ -73,6 +79,7 @@ import dayjs, { Dayjs } from 'dayjs';
interface PromptConfig { interface PromptConfig {
show: boolean; show: boolean;
value: string; value: string;
icon?: string;
} }
interface SelectConfig { interface SelectConfig {
@ -112,6 +119,14 @@ const props = defineProps({
value: '', value: '',
}) })
}, },
iconmap: {//
type: Object as () => PromptConfig,
default: () => ({
show: false,
value: '',
icon:'iconfont icon-time',
})
},
select: { // select: { //
type: Object as () => SelectConfig, type: Object as () => SelectConfig,
default: () => ({ default: () => ({

View File

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

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <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 * as echarts from 'echarts'
import type { EChartsOption } from 'echarts' import type { EChartsOption } from 'echarts'
import type { ColumnsType } from 'ant-design-vue/es/table/interface' 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 BasicSearch from '@/components/BasicSearch/index.vue'
import BasicTable from '@/components/BasicTable/index.vue' import BasicTable from '@/components/BasicTable/index.vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
// TODO: import { useModelStore } from '@/store/modules/model'
// import { ModalTabs } from '@/components/MapModal/modalTabs' import { handleTabs } from '@/components/MapModal/setting.config'
// import { handleTabs, modalTabSetting } from '@/components/MapModal/setting.config' import { getKendoList, getKendoListCust, getIntroduce } from '@/api/shuidiankaifa'
// ==================== ====================
const USE_MOCK_DATA = true // 使 false
// ==================== Props ==================== // ==================== Props ====================
const props = defineProps<{ const props = defineProps<{
@ -57,6 +60,9 @@ interface ModalData {
// ==================== ==================== // ==================== ====================
// modelStore MapModal
const modelStore = useModelStore()
// //
const qid = ref<string>('') const qid = ref<string>('')
const jiDiList = ref<any[]>([]) const jiDiList = ref<any[]>([])
@ -78,11 +84,12 @@ const pieCode = ref<string[]>([])
const pikData = ref<PieDataItem[]>([]) const pikData = ref<PieDataItem[]>([])
const chartRef = ref<HTMLElement | null>(null) const chartRef = ref<HTMLElement | null>(null)
const chartInstance = ref<any>(null) const chartInstance = ref<any>(null)
const chartInitialized = ref<boolean>(false) //
const dataLoading = ref<boolean>(false) const dataLoading = ref<boolean>(false)
// // MapModal
const mapModal = ref<boolean>(false) // const mapModal = ref<boolean>(false)
const modalData = ref<ModalData>({ sttp: '', stcd: '', titleName: '' }) // const modalData = ref<ModalData>({ sttp: '', stcd: '', titleName: '' })
// //
const unit = computed(() => getUnitConfigByCode('Other', 'ZJRL').unit) const unit = computed(() => getUnitConfigByCode('Other', 'ZJRL').unit)
@ -99,46 +106,70 @@ const tableRef = ref<any>(null)
* 获取Tab统计数据 * 获取Tab统计数据
*/ */
async function fetchTabData(params: any): Promise<TabItem[]> { async function fetchTabData(params: any): Promise<TabItem[]> {
// TODO: API console.log('【API】获取Tab数据参数:', params)
// const res = await shuiDianKaifaZhuangKung.GetKendoList(params, sortConfig)
console.log('【模拟】获取Tab数据参数:', params)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
// seriesName ttpwr
const _name = `装机容量(${unit.value})` const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name const useTtpwrFilter = props.seriesName === _name
// GetKendoList resolve([
const mockResponse = [
{ {
key: '2', col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
items: [{ key: 'build',
SUM_TTPWR: 1069300000, // kW unit: useTtpwrFilter ? unit.value : '座',
COUNT_ENGID: 150 value: '已建',
}] count: useTtpwrFilter ? 4568.50 : 120
}, },
{ {
key: '1', col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
items: [{ key: 'building',
SUM_TTPWR: 331000000, unit: useTtpwrFilter ? unit.value : '座',
COUNT_ENGID: 80 value: '在建',
}] count: useTtpwrFilter ? 2345.30 : 85
}, },
{ {
key: '0', col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
items: [{ key: 'noBuild',
SUM_TTPWR: 179000000, unit: useTtpwrFilter ? unit.value : '座',
COUNT_ENGID: 30 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[] = [] let list: TabItem[] = []
const result = mockResponse.reduce((acc: any, cur: any) => { res.data.reduce((acc: any, cur: any) => {
if (cur.key === '0') { if (cur.key === '0') {
list.push({ list.push({
col: useTtpwrFilter ? 'ttpwr' : 'engTotal', col: useTtpwrFilter ? 'ttpwr' : 'engTotal',
@ -167,120 +198,109 @@ async function fetchTabData(params: any): Promise<TabItem[]> {
return list return list
}, []) }, [])
resolve(result) console.log('【API】Tab数据处理结果:', list)
}, 500) return list
}) } catch (error) {
console.error('【API】获取Tab数据失败:', error)
message.error('获取Tab数据失败')
return []
}
} }
/** /**
* 获取饼图分组数据完整实现React版本的复杂逻辑 * 获取饼图分组数据完整实现React版本的复杂逻辑
*/ */
async function fetchPieData(params: any): Promise<PieDataItem[]> { async function fetchPieData(params: any): Promise<PieDataItem[]> {
// TODO: API console.log('【API】获取饼图数据参数:', params)
console.log('【API】USE_MOCK_DATA:', USE_MOCK_DATA, 'qid.value:', qid.value)
console.log('【模拟】获取饼图数据,参数:', params)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
const _name = `装机容量(${unit.value})` const _name = `装机容量(${unit.value})`
const useTtpwrFilter = props.seriesName === _name const useTtpwrFilter = props.seriesName === _name
// GetKendoList console.log('【模拟数据】生成饼图数据useTtpwrFilter:', useTtpwrFilter, 'qid.value:', qid.value)
let mockResponse: any[]
let mockData: PieDataItem[]
if (qid.value === 'all') { if (qid.value === 'all') {
// baseId //
mockResponse = [ mockData = [
{ { key: 'cj', name: '长江流域', value: useTtpwrFilter ? 4568.50 : 120, unit: '', dataDimensionRecursive: 'true' },
key: 'cj', { key: 'hh', name: '黄河流域', value: useTtpwrFilter ? 2345.30 : 85, unit: '', dataDimensionRecursive: 'true' },
items: [{ { key: 'zj', name: '珠江流域', value: useTtpwrFilter ? 1230.20 : 60, unit: '', dataDimensionRecursive: 'true' },
key: 'cj_base', { key: 'hh2', name: '淮河流域', value: useTtpwrFilter ? 890.10 : 45, unit: '', dataDimensionRecursive: 'true' },
items: [{ { key: 'hj', name: '海河流域', value: useTtpwrFilter ? 567.80 : 30, unit: '', dataDimensionRecursive: 'true' }
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
}]
}]
}
] ]
console.log('【模拟数据】全基地模式,生成 5 条数据')
} else if (qid.value === 'other') { } else if (qid.value === 'other') {
// other // other
mockResponse = [ mockData = [
{ { key: 'river1', name: '长江干流', value: useTtpwrFilter ? 890.50 : 25, unit: '', dataDimensionRecursive: 'true', index: 1 },
key: 'river1', { key: 'river2', name: '黄河干流', value: useTtpwrFilter ? 567.30 : 18, unit: '', dataDimensionRecursive: 'true', index: 2 },
items: [{ { key: 'river3', name: '珠江干流', value: useTtpwrFilter ? 345.20 : 12, unit: '', dataDimensionRecursive: 'true', index: 3 }
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
}]
}
] ]
console.log('【模拟数据】other 模式,生成 3 条数据')
} else { } else {
// hbrvcd //
mockResponse = [ mockData = [
{ { key: 'cjgl', name: '长江干流', value: useTtpwrFilter ? 2345.60 : 50, unit: '', dataDimensionRecursive: 'true' },
items: [{ { key: 'cjzl', name: '长江支流', value: useTtpwrFilter ? 1234.50 : 35, unit: '', dataDimensionRecursive: 'true' },
key: 'cjgl', { key: 'cjxz', name: '长江下游', value: useTtpwrFilter ? 987.40 : 25, unit: '', dataDimensionRecursive: 'true' }
items: [{
HBRVCDNAME: '长江干流',
SUM_TTPWR: 456800000,
COUNT_BLDSTTCCODE: 50
}]
}]
},
{
items: [{
key: 'hhgl',
items: [{
HBRVCDNAME: '黄河干流',
SUM_TTPWR: 234500000,
COUNT_BLDSTTCCODE: 35
}]
}]
}
] ]
console.log('【模拟数据】单基地模式,生成 3 条数据')
} }
// ReactflatMap console.log('【模拟数据】✅ 饼图数据生成成功:', mockData.length, '条')
let list = mockResponse.flatMap((item: any) => { 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[] = [] let arr: PieDataItem[] = []
// qid // qid
@ -319,16 +339,20 @@ async function fetchPieData(params: any): Promise<PieDataItem[]> {
// other getIntroduce // other getIntroduce
if (qid.value === 'other' && list.length > 0) { if (qid.value === 'other' && list.length > 0) {
// getIntroduce const introRes = await getIntroduce(
const introRes = [ [
{ wbsCode: 'river1', orderIndex: 1 }, { field: 'wbsType', operator: 'eq', value: 'PSB_RVCD' },
{ wbsCode: 'river2', orderIndex: 2 }, { field: 'objId', operator: 'eq', value: 'other' },
{ wbsCode: 'river3', orderIndex: 3 } { 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) => { 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 { return {
...el, ...el,
index: found?.orderIndex index: found?.orderIndex
@ -337,9 +361,13 @@ async function fetchPieData(params: any): Promise<PieDataItem[]> {
} }
} }
resolve(list) console.log('【API】饼图数据处理结果:', list)
}, 500) 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 }> { async function fetchTableData(params: any): Promise<any> {
// TODO: API console.log('【API】获取表格数据参数:', params)
// const url = qid.value === 'all'
// ? '/dec-lygk-base-server/base/vmsstbprpt/GetKendoListCust'
// : '/dec-lygk-base-server/base/vmsstbprpt/GetKendoList'
console.log('【模拟】获取表格数据,参数:', params)
//
if (USE_MOCK_DATA) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
//
const buildStatus = params.bldsttCcode const buildStatus = params.bldsttCcode
const hbrvcdFilter = params.hbrvcd?.value || [] const hbrvcdFilter = Array.isArray(params.hbrvcd)
? params.hbrvcd[0]?.value || []
: []
// //
const stationTemplates = [ 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: '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: '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: 'zjgl', baseName: '珠江流域', province: '广西区' },
{ name: '大化', river: 'zjgl', baseName: '珠江基地', province: '广西区' }, { name: '大化', river: 'zjgl', baseName: '珠江流域', province: '广西区' },
{ name: '响洪甸', river: 'hhgl', baseName: '淮河基地', province: '安徽省' }, { name: '响洪甸', river: 'hhgl2', baseName: '淮河流域', province: '安徽省' },
{ name: '梅山', river: 'hhgl', baseName: '淮河基地', province: '安徽省' }, { name: '梅山', river: 'hhgl2', baseName: '淮河流域', province: '安徽省' },
{ name: '潘家口', river: 'hjgl', baseName: '海河基地', province: '河北省' }, { name: '潘家口', river: 'hjgl', baseName: '海河流域', province: '河北省' },
{ name: '大黑汀', river: 'hjgl', baseName: '海河基地', province: '河北省' }, { name: '大黑汀', river: 'hjgl', baseName: '海河流域', province: '河北省' },
{ name: '丰满', river: 'sjgl', baseName: '松花江基地', province: '吉林省' }, { name: '丰满', river: 'sjgl', baseName: '松花江流域', province: '吉林省' },
{ name: '白山', river: 'sjgl', baseName: '松花江基地', province: '吉林省' }, { name: '白山', river: 'sjgl', baseName: '松花江流域', province: '吉林省' },
{ name: '水丰', river: 'ljgl', 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) { if (filteredStations.length === 0) {
resolve({ records: [], total: 0 }) // BasicTable { data: { records: [], total: 0 } }
resolve({
data: {
records: [],
total: 0
}
})
return 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({ resolve({
data: {
records: mockRecords, records: mockRecords,
total: mockRecords.length 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 { function transUnit(value: number, from: string, to: string): number {
// TODO: //
// kWkW // kWkW
if (from === 'Other' && to === 'ZJRL') { if (from === 'Other' && to === 'ZJRL') {
return value / 10000 // kW kW return value / 10000 // kW kW
@ -523,20 +595,15 @@ function handleExport() {
} }
} }
/**
* 处理弹窗关闭
*/
function handleModalCancel() {
mapModal.value = false
modalData.value = { sttp: '', stcd: '', titleName: '' }
}
// ==================== ECharts ==================== // ==================== ECharts ====================
/** /**
* 计算饼图配置增强版支持themeecList自定义颜色 * 计算饼图配置增强版支持themeecList自定义颜色
*/ */
const chartSetting = computed<EChartsOption>(() => { 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 total = pieData.value.reduce((acc, item) => acc + item.value, 0).toFixed(2)
const flag = props.seriesName === '数量(座)' const flag = props.seriesName === '数量(座)'
@ -544,6 +611,8 @@ const chartSetting = computed<EChartsOption>(() => {
const dddd = flag ? '电站数量' : '装机容量' const dddd = flag ? '电站数量' : '装机容量'
const cccc = flag ? ' (座)' : ` (${unit.value})` const cccc = flag ? ' (座)' : ` (${unit.value})`
console.log('【chartSetting】配置信息:', { total, bbbb, dddd, cccc, seriesDataLength: pieData.value.length })
// themeecList React // themeecList React
const colors = pieData.value.map((item: any, index: any) => { const colors = pieData.value.map((item: any, index: any) => {
if (props.themeecList && props.themeecList.length > 0) { if (props.themeecList && props.themeecList.length > 0) {
@ -623,14 +692,78 @@ const chartSetting = computed<EChartsOption>(() => {
* 初始化图表 * 初始化图表
*/ */
function initChart() { 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 // 使541px × 412px
chartInstance.value = echarts.init(chartRef.value, null, { chartInstance.value = echarts.init(chartRef.value, null, {
width: 541, width: 541,
height: 412 height: 412
}) })
console.log('【图表初始化】ECharts 实例创建成功')
//
chartInstance.value.on('legendselectchanged', handleLegendSelectChanged)
//
chartInstance.value.on('click', handlePieClick)
// updateChart
if (pieData.value.length > 0) {
console.log('【图表初始化】✅ 数据已就绪,渲染图表')
updateChart() 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) { function handleRowClick(record: any) {
modalData.value = { // 使 MapModal
modelStore.params = {
sttp: 'ENG', sttp: 'ENG',
stcd: record.stcd, stcd: record.stcd,
titleName: record.stnm titleName: record.stnm
} } as any // store
mapModal.value = true modelStore.title = record.stnm ? `${record.stnm} 详情信息` : '详情信息'
modelStore.tabList = handleTabs(modelStore.params)
modelStore.modalVisible = true
console.log('【打开详情弹窗】参数:', modelStore.params)
} }
// ==================== ==================== // ==================== ====================
@ -959,7 +1097,12 @@ watch(
watch( watch(
[tabKey, tabCol, stnm, qid], [tabKey, tabCol, stnm, qid],
async () => { 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 dataLoading.value = true
try { try {
@ -979,8 +1122,12 @@ watch(
delete params.stnmContains delete params.stnmContains
} }
console.log('【Watch触发】调用 fetchPieData参数:', params)
const result = await fetchPieData(params) const result = await fetchPieData(params)
console.log('【Watch触发】✅ fetchPieData 返回结果:', result.length, '条')
console.log('【Watch触发】数据内容:', result)
// other // other
if (qid.value === 'other' && result.length > 0) { if (qid.value === 'other' && result.length > 0) {
const introRes = await fetchIntroduce({ const introRes = await fetchIntroduce({
@ -1003,11 +1150,33 @@ watch(
} }
} }
console.log('【Watch触发】更新 pieData数据量:', result.length)
pikData.value = result pikData.value = result
pieData.value = result pieData.value = result
pieCode.value = [] 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) { } catch (error) {
console.error('获取饼图数据失败:', error) console.error('【API】获取饼图数据失败:', error)
message.error('获取饼图数据失败') message.error('获取饼图数据失败')
} finally { } finally {
dataLoading.value = false dataLoading.value = false
@ -1038,10 +1207,32 @@ onMounted(() => {
qid.value = 'all' qid.value = 'all'
} }
initChart() // onMounted
// watch
console.log('【生命周期】onMounted 触发,等待数据加载后初始化图表')
window.addEventListener('resize', handleResize) 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(() => { onUnmounted(() => {
chartInstance.value?.dispose() chartInstance.value?.dispose()
window.removeEventListener('resize', handleResize) window.removeEventListener('resize', handleResize)
@ -1108,36 +1299,8 @@ onUnmounted(() => {
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
<!-- 详情弹窗 --> <!-- 详情弹窗已改用全局 MapModal 组件 AppMain.vue 中统一管理 -->
<a-modal <!-- 无需在此处添加 a-modal点击表格行会自动触发 modelStore.modalVisible -->
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>
</div> </div>
</template> </template>

View File

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

View File

@ -1,6 +1,6 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="沿程水温变化" :prompt="prompts"> <SidePanelItem title="沿程水温变化" :prompt="prompts" :select="select" :datetimePicker="datetimePicker">
<div ref="chartRef" class="chart-container"></div> <div ref="chartRef" class="chart-container"></div>
</SidePanelItem> </SidePanelItem>
</template> </template>
@ -15,7 +15,23 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
defineOptions({ defineOptions({
name: 'yanchengshuiwenChangeMod' 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({ const prompts = ref({
show: true, show: true,
value: '注:最新数据时间为2026-04-08 23', value: '注:最新数据时间为2026-04-08 23',

View File

@ -1,7 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.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> </script>
<template> <template>
@ -12,6 +24,7 @@ import HuanbaozdjcgzkzQK from "@/modules/huanbaozdjcgzkzQK/index.vue"
<div class="rightContent"> <div class="rightContent">
<RightDrawer> <RightDrawer>
<HuanbaozdjcgzkzQK /> <HuanbaozdjcgzkzQK />
<SZYCBH v-if="wbsCode != 'all'" />
</RightDrawer> </RightDrawer>
</div> </div>
</div> </div>

View File

@ -1,8 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue"; import RightDrawer from "@/components/RightDrawer/index.vue";
import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/index.vue" import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/index.vue"
import EnvironmentalQuality from "@/modules/EnvironmentalQuality/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> </script>
<template> <template>
@ -14,6 +27,8 @@ import EnvironmentalQuality from "@/modules/EnvironmentalQuality/index.vue" //
<RightDrawer> <RightDrawer>
<ShuiZhiJianCeGongZuoQingKuang /> <ShuiZhiJianCeGongZuoQingKuang />
<EnvironmentalQuality /> <EnvironmentalQuality />
<SZYCBH v-if="wbsCode != 'all'"></SZYCBH>
</RightDrawer> </RightDrawer>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.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 ZZZJSYXQKTT from "@/modules/zengzhizhanjiansheyunxing/index.vue"
import ZZZYXSJTJ from "@/modules/zengzhizhanyunxingsjtj/index.vue" import ZZZYXSJTJ from "@/modules/zengzhizhanyunxingsjtj/index.vue"
import FLZLLB from "@/modules/GYZLLB/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> </script>
<template> <template>
@ -17,8 +33,8 @@ import FLZLLB from "@/modules/GYZLLB/index.vue"
<div class="rightContent"> <div class="rightContent">
<RightDrawer> <RightDrawer>
<ZZZJSYXQKTT /> <ZZZJSYXQKTT />
<ZengZhiZhanJieShaoMod /> <ZengZhiZhanJieShaoMod v-if="wbsCode != 'all'" />
<ZengZhiJiHuaWanChengQingKuang /> <ZengZhiJiHuaWanChengQingKuang v-if="wbsCode != 'all'" />
<FLZLLB title="放流总量" /> <FLZLLB title="放流总量" />
<ZZZYXSJTJ /> <ZZZYXSJTJ />
</RightDrawer> </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"
}
}