| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- <template>
- <div class="connectAnalysis">
- <div class="filter-area">
- <Row style="width:100%">
- <Col :span="6">
- <div class="filter-section param-section">
- <span class="filter-label">煤矿名称:</span>
- <div class="param-selector">
- <MineCascader style="width: 300px"></MineCascader>
- </div>
- </div>
- </Col>
- <Col :span="6">
- <!-- 时间选择 -->
- <div class="filter-section param-section">
- <span class="filter-label">采空区选择:</span>
- <Select ref="select" v-model:value="goafId" style="width: 300px" placeholder="请选择采空区">
- <SelectOption v-for="(item, index) in goafOption" :key="index" :value="item.value">{{ item.label }}
- </SelectOption>
- </Select>
- </div>
- </Col>
- <Col :span="6">
- <div class="filter-section param-section">
- <span class="filter-label">时间选择:</span>
- <RangePicker v-model:value="dateRange" format="YYYY-MM-DD HH:mm:ss" :placeholder="['开始时间', '结束时间']"
- style="width: 300px" :show-time="{ format: 'HH:mm:ss' }" @change="changeTime" />
- </div>
- </Col>
- <Col :span="6">
- <div class="filter-section">
- <Button type="primary" @click="generateChart">生成</Button>
- </div>
- </Col>
- </Row>
- <!-- <Row style="width:100%">
- <Col :span="8">
- <div class="filter-section param-section">
- <span class="filter-label">参数选择:</span>
- <div class="param-selector">
- <Input v-model="selectedParamsText" placeholder="请选择监测参数" readonly style="width: 300px" />
- <Button type="primary" @click="showTree = !showTree">+</Button>
- <div class="tree-popup" v-if="showTree">
- <BasicTree :treeData="treeData" :checkable="true" defaultExpandAll @check="handleTreeCheck" :checkedKeys="checkedTreeKeys" />
- </div>
- </div>
- </div>
- </Col>
- </Row> -->
- </div>
- <!-- 动态图表区域-->
- <div class="chart-area">
- <div class="chart-item" style="flex: 1 1 100%">
- <div class="chart-placeholder">
- <template v-if="generatedChartData.length">
- <CustomChart :chart-data="generatedChartData" :chart-config="generatedChartConfig"
- style="height: 100%; width: 100%" />
- </template>
- <template v-else-if="isChartGenerated">
- <div class="empty-chart">暂无匹配数据,请调整筛选条件</div>
- </template>
- <template v-else>
- <div class="empty-chart">请选择时间范围和参数,点击"生成"查看数据</div>
- </template>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { computed, ref, onMounted, watchEffect } from 'vue';
- import dayjs from 'dayjs';
- // import { treeData, historicalMockChartData } from './connectAnalysis.data'; // 引入模拟数据
- import { Select, SelectOption, Row, Col, DatePicker, Button, message, Input, } from 'ant-design-vue';
- // import { BasicTree } from '/@/components/Tree/index';
- import CustomChart from '/@/components/Configurable/detail/CustomChart.vue';
- import MineCascader from '@/components/Form/src/jeecg/components/MineCascader/MineCascader.vue'
- import { getGoafHistory, getGoafList } from './connectAnalysis.api'
- import { storeToRefs } from 'pinia';
- import { useMineStore } from '/@/store/modules/mine';
- import { useRouter } from 'vue-router';
- // 组件注册
- const RangePicker: any = DatePicker.RangePicker;
- const { currentRoute } = useRouter();
- const mineCode = ref<any>(currentRoute.value['query']['mineCode'])//传递过来的矿ID
- // 筛选相关响应式数据
- const dateRange = ref([dayjs().add(-30, 'day'), dayjs()]); // 默认时间范围(近1天)
- // const selectedParamsText = ref(''); // 参数选择框显示文本
- // const showTree = ref(false); // 控制树形选择器显示/隐藏
- // const checkedTreeKeys = ref([]); // 树形选中的key
- const selectedParams = ref(['coVal', 'ch4Val', 'c2h4Val', 'c2h2Val', 'co2Val', 'o2Val', 'sourcePressure', 'temperature']); // 选中的参数(实际用于图表)
- const generatedChartData = ref<any[]>([]); // 生成的图表数据
- const generatedChartConfig = ref({}); // 生成的图表配置
- const isChartGenerated = ref(false); // 是否已点击生成
- const goafId = ref('')//采空区id
- const goafOption = ref<any[]>([])//采空区列表
- const filteredData = ref<any[]>([])//曲线数据
- const mineStore = useMineStore();
- const { getMine, getMineCode, getMinePath, getMineTree } = storeToRefs(mineStore);
- const innerValue = computed(() => getMinePath.value.map((e) => e.fax));
- // Tree Key 与参数名映射(关键:关联树形节点和实际参数)
- const treeKeyToParamMap = computed(() => ({
- '0-0-0': 'coVal',
- '0-0-1': 'ch4Val',
- '0-0-2': 'c2h4Val',
- '0-0-3': 'c2h2Val',
- '0-0-4': 'co2Val',
- '0-0-5': 'o2Val',
- '1-1-0': 'sourcePressure',
- // '1-1-1': 'outerPressure',
- // '1-1-2': 'pressureDiff',
- '2-2': 'temperature',
- }));
- // 参数标签映射(图表系列名称)
- const paramLabelMap = computed(() => ({
- coVal: 'CO浓度(ppm)',
- ch4Val: 'CH4浓度(%)',
- c2h4Val: 'C2H4浓度(ppm)',
- c2h2Val: 'C2H2浓度(ppm)',
- co2Val: 'CO2浓度(%)',
- o2Val: 'O2浓度(%)',
- sourcePressure: '压力(kPa)',
- temperature: '温度(℃)',
- // 'innerPressure': '内压力(kPa)',
- // 'outerPressure': '外压力(kPa)',
- // 'pressureDiff': '压差(kPa)',
- // 'temperature': '温度(℃)',
- }));
- // 参数颜色映射
- const paramColorMap = computed(() => ({
- coVal: '#f5222d', // 红色
- ch4Val: '#1890ff', // 蓝色
- c2h4Val: '#faad14', // 橙色
- c2h2Val: '#52c41a', // 绿色
- co2Val: '#722ed1', // 紫色
- o2Val: '#13c2c2', // 青色
- sourcePressure: '#ff4d4f', // 浅红
- // 'outerPressure': '#40a9ff',// 浅蓝
- // 'pressureDiff': '#fa8c16', // 浅橙
- temperature: '#9254de', // 浅紫
- }));
- // // 树形选择事件处理
- // const handleTreeCheck = (checkedKeys) => {
- // checkedTreeKeys.value = checkedKeys;
- // // 转换为实际参数名
- // const params = checkedKeys
- // .map(key => treeKeyToParamMap.value[key])
- // .filter(param => param); // 过滤无效参数
- // selectedParams.value = params;
- // console.log(selectedParams.value, ' selectedParams')
- // // 更新输入框显示文本
- // const paramLabels = params.map(param => paramLabelMap.value[param]);
- // selectedParamsText.value = paramLabels.join('、');
- // console.log(selectedParamsText.value, ' selectedParamsText')
- // };
- function changeTime(val) {
- dateRange.value[0] = val[0]
- dateRange.value[1] = val[1]
- }
- // 生成折线图核心逻辑
- async function generateChart() {
- // showTree.value = false
- //获取采空区历史数据列表
- let startTime = dateRange.value[0].format('YYYY-MM-DD HH:mm:ss')
- let endTime = dateRange.value[1].format('YYYY-MM-DD HH:mm:ss')
- let res = await getGoafHistory({ pageNo: 1, pageSize: 100, startTime: startTime, endTime: endTime, goafId: goafId.value })
- if (res && res.records) {
- filteredData.value = res.records
- isChartGenerated.value = false
- } else {
- filteredData.value.length = 0
- isChartGenerated.value = true;
- }
- console.log(filteredData.value, 'filteredData')
- // 2. 构建图表数据结构(适配 CustomChart 的 line 类型)
- const timeMap = new Map();
- // 修复变量名:filteredRawData → filteredData(之前未定义)
- filteredData.value.forEach((item) => {
- const timeStr = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
- if (!timeMap.has(timeStr)) {
- timeMap.set(timeStr, { time: timeStr });
- }
- // 只保留选中的参数数据
- selectedParams.value.forEach((param) => {
- if (item[param] !== undefined) {
- timeMap.get(timeStr)[param] = item[param];
- }
- });
- });
- // 转换为数组并按时间排序
- const chartData = Array.from(timeMap.values()).sort((a, b) => {
- return dayjs(a.time).valueOf() - dayjs(b.time).valueOf();
- });
- generatedChartData.value = chartData;
- console.log(generatedChartData.value, 'generatedChartData')
- // 3. 构建图表配置(折线图类型,完善适配逻辑)
- generatedChartConfig.value = {
- type: 'line', // 折线图
- clear: true, // 每次生成清空之前的图表
- legend: { show: true, top: 10, right: 10, textStyle: { color: '#fff', fontSize: 14 } },
- xAxis: [
- {
- type: 'category',
- axisLabel: {
- rotate: 30,
- textStyle: {
- color: '#fff',
- },
- formatter: (value) => dayjs(value).format('HH:mm:ss'),
- interval: Math.max(1, Math.floor(chartData.length / 10)), // 控制x轴标签密度
- },
- },
- ],
- yAxis: selectedParams.value.map((param) => ({
- type: 'value',
- axisLabel: {
- textStyle: {
- color: '#fff',
- },
- },
- name: paramLabelMap.value[param].split('(')[1].replace(')', ''), // 显示单位
- // nameTextStyle: { color: paramColorMap.value[param] },
- nameTextStyle: { color: '#fff' },
- axisLine: { lineStyle: { color: paramColorMap.value[param] } },
- splitLine: { lineStyle: { opacity: 0.1 } },
- })),
- series: selectedParams.value.map((param, index) => ({
- name: paramLabelMap.value[param],
- type: 'line',
- readFrom: '', // 适配 CustomChart 的 baseSeries 读取逻辑
- label: paramLabelMap.value[param],
- xprop: 'time', // 对应图表数据的 x 字段(时间)
- yprop: param, // 对应图表数据的 y 字段(参数值)
- color: paramColorMap.value[param],
- smooth: true,
- symbol: 'circle',
- symbolSize: 4,
- yAxisIndex: index,
- })),
- tooltip: {
- trigger: 'axis',
- axisPointer: { type: 'cross' },
- formatter: (params) => {
- let tooltipHtml = `<div>${dayjs(params[0].axisValue).format('YYYY-MM-DD HH:mm:ss')}</div>`;
- params.forEach((param) => {
- tooltipHtml += `<div style="color: ${param.color}">${param.seriesName}: ${param.value[1]} ${param.seriesName.split('(')[1].replace(')', '')}</div>`;
- });
- return tooltipHtml;
- },
- },
- grid: { left: 60, top: 40, right: 60, bottom: 60 },
- };
- // 无数据提示
- if (chartData.length === 0) {
- message.info('当前筛选条件下无数据');
- }
- }
- //获取采空区列表
- async function getGoafListData() {
- let res = await getGoafList({ mineCode: innerValue.value[innerValue.value.length - 1] })
- if (res.length) {
- goafOption.value = res.map(el => {
- return {
- label: el.devicePos,
- value: el.id,
- }
- })
- goafId.value = goafId.value ? goafId.value : goafOption.value[0]['value']
- }
- }
- watchEffect(() => {
- innerValue.value && getGoafListData();
- });
- </script>
- <style lang="less" scoped>
- .connectAnalysis {
- padding: 16px;
- .filter-area {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- margin-bottom: 20px;
- padding: 20px;
- border: 1px solid #f0f0f0;
- border-radius: 10px;
- background: @card-bg-color;
- align-items: center;
- }
- .filter-section {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .filter-label {
- color: #666;
- min-width: 80px;
- flex-shrink: 0;
- font-weight: 500;
- }
- .param-section {
- flex: 1;
- // min-width: 300px;
- }
- .param-selector {
- display: flex;
- align-items: center;
- gap: 8px;
- position: relative;
- }
- .tree-popup {
- position: absolute;
- top: 100%;
- left: 0;
- margin-top: 8px;
- width: 300px;
- max-height: 300px;
- overflow-y: auto;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 4px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- z-index: 100;
- padding: 8px;
- }
- .chart-area {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- padding: 20px;
- border: 1px solid #f0f0f0;
- border-radius: 10px;
- background: @card-bg-color;
- }
- .chart-item {
- flex: 1;
- min-width: 200px;
- }
- .chart-placeholder {
- width: 100%;
- height: 300px;
- border-radius: 4px;
- overflow: hidden;
- background: #333;
- border: 1px solid #eee;
- }
- .empty-chart {
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- color: #999;
- font-size: 14px;
- }
- }
- </style>
|