From c4e9d054916c3f085329a67c7664b4c54f9137f9 Mon Sep 17 00:00:00 2001 From: riku <risaku@163.com> Date: 星期二, 07 五月 2024 17:36:09 +0800 Subject: [PATCH] 完成折线图相关功能的迁移 --- src/utils/chart/chart-option.js | 9 + src/components/SliderBar.vue | 13 + src/views/historymode/HistoryMode.vue | 25 ++- src/assets/border.css | 2 src/components.d.ts | 2 src/components/CardButton.vue | 52 ++++++ src/components/search/SearchBar.vue | 20 + src/components/search/OptionTime.vue | 13 src/views/historymode/component/DataSheet.vue | 0 src/components/monitor/FactorLegend.vue | 4 src/components/monitor/DataTable.vue | 82 ++++++++++ src/api/monitorDataApi.js | 19 + src/components/search/OptionDevice.vue | 2 src/components/search/OptionMission.vue | 29 +-- src/components/search/OptionType.vue | 2 src/components/BaseCard.vue | 34 +++- src/views/historymode/component/TrendAnalysis.vue | 44 ++++- src/components/monitor/LineChart.vue | 105 ++++++++---- 18 files changed, 354 insertions(+), 103 deletions(-) diff --git a/src/api/monitorDataApi.js b/src/api/monitorDataApi.js index 60130ec..119248c 100644 --- a/src/api/monitorDataApi.js +++ b/src/api/monitorDataApi.js @@ -6,21 +6,30 @@ export default { /** * 鑾峰彇鏈�鏂版暟鎹� + * @param dataType 0: 绉掔骇鍊�; 1:鍒嗛挓鍊� * @returns */ - fethcRealtimeData({ deviceCode, type, page, perPage }) { - return this.fetchHistroyData({ deviceCode, type, page, perPage }); + fethcRealtimeData({ deviceCode, dataType, page, perPage }) { + return this.fetchHistroyData({ deviceCode, dataType, page, perPage }); }, /** * 鑾峰彇鍘嗗彶鏁版嵁 + * @param dataType 0: 绉掔骇鍊�; 1:鍒嗛挓鍊� * @returns */ - fetchHistroyData({ deviceCode, startTime, endTime, type, page, perPage }) { + fetchHistroyData({ + deviceCode, + startTime, + endTime, + dataType, + page, + perPage + }) { let params = `deviceCode=${deviceCode}&page=${page}&perPage=${perPage}`; - params += type ? `&type=${type}` : ''; + params += dataType ? `&type=${dataType}` : ''; params += startTime ? `&startTime=${startTime}` : ''; - params += endTime ? `&type=${endTime}` : ''; + params += endTime ? `&endTime=${endTime}` : ''; return $http.get(`air/realtime/sec?${params}`).then((res) => res.data); } }; diff --git a/src/assets/border.css b/src/assets/border.css index 533bde8..30416bf 100644 --- a/src/assets/border.css +++ b/src/assets/border.css @@ -414,7 +414,7 @@ } .ff-content-middle-s .ff-border-top { - padding: 2px 6px; + padding: 4px 8px; -webkit-clip-path: polygon(var(--border-width) var(--border-width), calc(100% - var(--border-width)) var(--border-width), diff --git a/src/components.d.ts b/src/components.d.ts index 1d653d4..2930d6a 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -9,8 +9,10 @@ export interface GlobalComponents { BaseCard: typeof import('./components/BaseCard.vue')['default'] BaseMap: typeof import('./components/map/BaseMap.vue')['default'] + CardButton: typeof import('./components/CardButton.vue')['default'] CoreHeader: typeof import('./components/core/CoreHeader.vue')['default'] CoreMenu: typeof import('./components/core/CoreMenu.vue')['default'] + DataTable: typeof import('./components/monitor/DataTable.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] diff --git a/src/components/BaseCard.vue b/src/components/BaseCard.vue index a01f0a0..76d1305 100644 --- a/src/components/BaseCard.vue +++ b/src/components/BaseCard.vue @@ -9,7 +9,7 @@ <div class="ff-footer"> <slot name="footer"></slot> </div> - <div v-if="size != 'small'" class="ff-triangle"> + <div v-if="type == 'content' && size != 'small'" class="ff-triangle"> <div class="ff-triangle-border"></div> </div> </div> @@ -20,8 +20,16 @@ export default { props: { /** + * 绫诲瀷 + * content | btn + */ + type: { + type: String, + default: 'content' + }, + /** * 鏍峰紡鎶樿澶у皬 - * small | medium + * small | medium | middle-s */ size: { type: String, @@ -29,7 +37,8 @@ }, /** * 鏍峰紡鏈濆悜 - * left | right | top-left + * content: left | right | top-left | down + * btn: left | right | down */ direction: { type: String, @@ -45,11 +54,20 @@ }, computed: { wrapClz() { - let clz = 'ff-content p-events-auto'; - clz += ` ff-content-${this.direction}`; - clz += ` ff-content-${this.size}`; - clz += `${this.borderless ? '-borderless-' + this.borderless : ''}`; - return clz; + if (this.type == 'content') { + let clz = 'ff-content p-events-auto'; + clz += ` ff-content-${this.direction}`; + clz += ` ff-content-${this.size}`; + clz += `${this.borderless ? '-borderless-' + this.borderless : ''}`; + return clz; + } else if (this.type == 'btn') { + let clz = 'ff-toggle-btn p-events-auto'; + clz += ` ff-toggle-btn-${this.direction}`; + clz += ` ff-btn-${this.size}`; + return clz; + } else { + return ''; + } } } }; diff --git a/src/components/CardButton.vue b/src/components/CardButton.vue new file mode 100644 index 0000000..e0cb7b3 --- /dev/null +++ b/src/components/CardButton.vue @@ -0,0 +1,52 @@ +<template> + <BaseCard type="btn" size="medium" direction="right" @click="handleClick"> + <template #content> + <div class="card-btn"> + <img :src="src" class="ff-img m-b-8" /> + <span v-for="(item, index) in name" :key="index"> {{ item }}</span> + </div> + </template> + </BaseCard> +</template> + +<script> +import shrinkLeft from '@/assets/mipmap/shrink_left.png'; +import shrinkRight from '@/assets/mipmap/shrink_right.png'; + +export default { + props: { + name: String, + direction: { + type: String, + default: 'left' + } + }, + emits: ['click'], + data() { + return { + src: this.direction ? shrinkLeft : shrinkRight + }; + }, + computed: {}, + methods: { + handleClick() { + if (this.src == shrinkLeft) { + this.src = shrinkRight; + } else { + this.src = shrinkLeft; + } + this.$emit('click'); + } + } +}; +</script> +<style scoped> +.card-btn { + display: flex; + flex-direction: column; +} + +.card-btn > span { + line-height: 18px; +} +</style> diff --git a/src/components/SliderBar.vue b/src/components/SliderBar.vue index 4bb44f7..7a1f519 100644 --- a/src/components/SliderBar.vue +++ b/src/components/SliderBar.vue @@ -3,6 +3,7 @@ <el-form-item label="鏁版嵁閲�"> <el-select v-model="pageSize" + @change="handleSizeChange" placeholder="鏁版嵁閲�" size="small" class="w-60" @@ -12,12 +13,13 @@ </el-select> </el-form-item> <div class="slider-wrap m-l-16"> - <el-slider v-model="progress" :marks="marks" /> + <el-slider v-model="progress" :marks="marks" @input="handleInput" /> </div> </el-row> </template> <script> export default { + emits: ['input', 'sizeChange'], data() { return { pageSize: 200, @@ -37,6 +39,15 @@ } } }; + }, + methods: { + handleInput(e) { + // console.log(e); + this.$emit('input', e); + }, + handleSizeChange(e) { + this.$emit('sizeChange', e); + } } }; </script> diff --git a/src/components/monitor/DataTable.vue b/src/components/monitor/DataTable.vue new file mode 100644 index 0000000..eff8fda --- /dev/null +++ b/src/components/monitor/DataTable.vue @@ -0,0 +1,82 @@ +<template> + <BaseCard> + <template #content> + <el-table + :data="tableData" + v-loading="loading" + table-layout="fixed" + :row-class-name="tableRowClassName" + :height="tableHeight" + border + > + <el-table-column prop="TIME" label="鏃堕棿" /> + <el-table-column + v-for="(item, index) in tableColumn" + :key="index" + :prop="item.name" + :label="item.label" + /> + </el-table> + <el-pagination + v-if="pagination" + ref="paginationRef" + class="el-pagination" + v-model:current-page="currentPage" + v-model:page-size="pageSize" + :page-sizes="[10, 20, 50, 100]" + :background="true" + layout="total, sizes, prev, pager, next, jumper" + :total="total" + /> + </template> + + <template #footer> </template> + </BaseCard> +</template> + +<script> +import { FactorDatas } from '@/model/FactorDatas'; +import { checkboxOptions } from '@/constant/checkbox-options'; +import { TYPE0 } from '@/constant/device-type'; + +export default { + props: { + factorDatas: FactorDatas, + deviceType: { + type: String, + // type0: 杞﹁浇鎴栨棤浜烘満; type1:鏃犱汉鑸� + default: TYPE0 + } + }, + data() { + return { + tableHeight: '500', + total: 0, + currentPage: 1, + pageSize: 20, + loading: false + }; + }, + computed: { + tableData() { + const list = []; + for (const key in this.factorDatas.factor) { + if (Object.hasOwnProperty.call(this.factorDatas.factor, key)) { + const f = this.factorDatas.factor[key]; + f.datas.forEach((v, i) => { + if (list.length <= i) { + list.push({ [f.factorName]: v }); + } else { + list[i][f.factorName] = v; + } + }); + } + } + return list; + }, + tableColumn() { + return checkboxOptions(this.deviceType); + } + } +}; +</script> diff --git a/src/components/monitor/FactorLegend.vue b/src/components/monitor/FactorLegend.vue index 23e576f..749c285 100644 --- a/src/components/monitor/FactorLegend.vue +++ b/src/components/monitor/FactorLegend.vue @@ -18,13 +18,13 @@ <span class="w-40 text-right">{{ item.min }}</span> <span class="w-20 text-center">~</span> <span class="w-40 text-right">{{ item.max }}</span> - <span class="w-50 m-l-8">{{ item.unit }}</span> + <span class="w-60 m-l-8">{{ item.unit }}</span> </el-row> <el-row v-else> <span class="w-40 text-right"></span> <span class="w-20 text-center">></span> <span class="w-40 text-right">{{ item.min }}</span> - <span class="w-50 m-l-8">{{ item.unit }}</span> + <span class="w-60 m-l-8">{{ item.unit }}</span> </el-row> </div> </template> diff --git a/src/components/monitor/LineChart.vue b/src/components/monitor/LineChart.vue index ccaa3e2..612cb61 100644 --- a/src/components/monitor/LineChart.vue +++ b/src/components/monitor/LineChart.vue @@ -5,7 +5,10 @@ </template> <template #footer> <!-- 鍗曢〉鏁版嵁閲�--> - <SliderBar></SliderBar> + <SliderBar + @input="(e) => (progress = e)" + @size-change="(e) => (pageSize = e)" + ></SliderBar> </template> </BaseCard> </template> @@ -29,37 +32,38 @@ }, data() { return { - lineChart: null, - option: null + allXAxis: [], + allSeries: [], + option: null, + pageSize: 200, + progress: 0 }; }, watch: { factorDatas: { handler() { - this.refreshChart(); + this.initData(); + this.changeChartRange(); }, deep: true }, selectFactorType: { handler() { - this.refreshChart(); - }, - deep: true + this.changeChartSeries(); + } + }, + progress() { + this.changeChartRange(); + }, + pageSize() { + this.changeChartRange(); } }, - computed: { - /** - * 鑾峰彇妯潗鏍� - */ - xAxis() { - return this.factorDatas.times.map((v) => { + methods: { + initData() { + this.allXAxis = this.factorDatas.times.map((v) => { return v.split(' ')[1]; }); - }, - /** - * 鑾峰彇鐩戞祴鏁版嵁绾靛潗鏍� - */ - allSeries() { const res = []; for (const key in this.factorDatas.factor) { if (Object.hasOwnProperty.call(this.factorDatas.factor, key)) { @@ -68,6 +72,7 @@ key: key, name: factorName[e.factorName], type: 'line', + allData: e.datas.map((v) => v.factorData), data: e.datas.map((v) => v.factorData), showAllSymbol: true, animationDelay: function (idx) { @@ -76,34 +81,62 @@ }); } } - return res; + this.allSeries = res; }, - showSeries() { - return this.allSeries.filter((s) => { + // 淇敼鍥捐〃灞曠ず鐨勬姌绾垮浘绫诲瀷 + changeChartSeries() { + this.option.series = this.getShowSeries(); + this.option.legend.data = this.getLegends(this.option.series); + this.lineChart.setOption(this.option, { notMerge: true }); + }, + changeChartRange() { + const { sIndex, eIndex, startPer, endPer } = this.getRange(); + const showSeries = this.getShowSeries(sIndex, eIndex); + const xAxis = this.getShowXAxis(sIndex, eIndex); + const legends = this.getLegends(showSeries); + if (!this.option) { + this.option = factorLineOption(xAxis, showSeries, legends); + } else { + this.option.xAxis.data = xAxis; + this.option.series = showSeries; + this.option.legend.data = legends; + } + // this.option.dataZoom[0].start = startPer; + // this.option.dataZoom[0].end = endPer; + this.lineChart.setOption(this.option); + }, + getShowXAxis(sIndex, eIndex) { + return this.allXAxis.slice(sIndex, eIndex); + }, + getShowSeries(sIndex, eIndex) { + const res = this.allSeries.filter((s) => { + if (sIndex && eIndex) { + s.data = s.allData.slice(sIndex, eIndex); + } return this.selectFactorType.includes(s.key); }); + return res; }, - legends() { - return this.showSeries.map((s) => { + getRange() { + let len = this.allXAxis.length - this.pageSize; + len = len < 0 ? 0 : len; + const sIndex = Math.round((len * this.progress) / 100); + const eIndex = sIndex + this.pageSize; + const startPer = (sIndex / this.allXAxis.length) * 100; + const endPer = (eIndex / this.allXAxis.length) * 100; + return { sIndex, eIndex, startPer, endPer }; + }, + getLegends(series) { + return series.map((s) => { return s.name; }); } }, - methods: { - initChart() { - this.lineChart = echarts.init(this.$refs.lineChart); - }, - refreshChart() { - const option = factorLineOption( - this.xAxis, - this.showSeries, - this.legends - ); - this.lineChart.setOption(option, { notMerge: true }); - } + beforeUnmount() { + // this.$refs.lineChart && this.$refs.lineChart.clear(); }, mounted() { - this.initChart(); + this.lineChart = echarts.init(this.$refs.lineChart); } }; </script> diff --git a/src/components/search/OptionDevice.vue b/src/components/search/OptionDevice.vue index d63fe7c..c16c1f0 100644 --- a/src/components/search/OptionDevice.vue +++ b/src/components/search/OptionDevice.vue @@ -2,7 +2,7 @@ <el-form-item label="璁惧"> <el-select :model-value="modelValue" - @change="handleChange" + @update:model-value="handleChange" placeholder="璁惧" size="small" class="w-120" diff --git a/src/components/search/OptionMission.vue b/src/components/search/OptionMission.vue index 195e3d2..8322c9d 100644 --- a/src/components/search/OptionMission.vue +++ b/src/components/search/OptionMission.vue @@ -1,17 +1,17 @@ <template> <el-form-item label="浠诲姟"> <el-select - :model-value="modelValue" + v-model="index" @change="handleChange" - placeholder="浠诲姟" + placeholder="閫夋嫨浠诲姟" size="small" class="w-150" > <el-option v-for="(s, i) in missionList" :key="i" - :label="s.label" - :value="s.value" + :label="s.missionCode" + :value="i" /> </el-select> </el-form-item> @@ -30,10 +30,11 @@ type: String, modelValue: String }, - emits: ['update:modelValue'], + emits: ['update:modelValue', 'change'], data() { return { - missionList: [] + missionList: [], + index: undefined }; }, methods: { @@ -42,21 +43,17 @@ return missionApi .fethchMission({ type: this.type, page, pageSize }) .then((res) => { - this.missionList = res.data.map((item) => { - return { - label: item.missionCode, - value: item.missionCode - }; - }); - if (this.missionList.length > 0) { - this.handleChange(this.missionList[0].value); - } + this.missionList = res.data; + // if (this.missionList.length > 0) { + // this.handleChange(0); + // } return res.head; }); }); }, handleChange(value) { - this.$emit('update:modelValue', value); + this.$emit('update:modelValue', this.missionList[value]); + // this.$emit('change', this.missionList[value]); } }, mounted() { diff --git a/src/components/search/OptionTime.vue b/src/components/search/OptionTime.vue index 24a1d9f..4c504a8 100644 --- a/src/components/search/OptionTime.vue +++ b/src/components/search/OptionTime.vue @@ -1,13 +1,12 @@ <template> <el-form-item label="鏃堕棿"> <el-date-picker - v-model="date" - @change="handleChange" + :model-value="modelValue" + @update:model-value="handleChange" :type="type" start-placeholder="閫夋嫨寮�濮嬫椂闂�" end-placeholder="閫夋嫨缁撴潫鏃堕棿" size="small" - class="w-150" /> </el-form-item> </template> @@ -15,7 +14,9 @@ <script> export default { props: { - modelValue: Array, + modelValue: { + type: Array + }, type: { type: String, default: 'datetimerange' @@ -23,9 +24,7 @@ }, emits: ['update:modelValue'], data() { - return { - date: this.modelValue - }; + return {}; }, methods: { handleChange(value) { diff --git a/src/components/search/OptionType.vue b/src/components/search/OptionType.vue index 5ed124c..b6e4817 100644 --- a/src/components/search/OptionType.vue +++ b/src/components/search/OptionType.vue @@ -2,7 +2,7 @@ <el-form-item label="绫诲瀷"> <el-select :model-value="modelValue" - @change="handleChange" + @update:model-value="handleChange" placeholder="绫诲瀷" size="small" class="w-80" diff --git a/src/components/search/SearchBar.vue b/src/components/search/SearchBar.vue index 68ee8ed..1c1202d 100644 --- a/src/components/search/SearchBar.vue +++ b/src/components/search/SearchBar.vue @@ -1,8 +1,8 @@ <template> - <BaseCard class=""> + <BaseCard size="middle-s" direction="down"> <template #content> <el-form :inline="true"> - <OptionMission v-model="formSearch.missionCode"></OptionMission> + <OptionMission v-model="mission"></OptionMission> <OptionType v-model="formSearch.type"></OptionType> <OptionDevice :type="formSearch.type" @@ -25,8 +25,8 @@ }, data() { return { + mission: {}, formSearch: { - missionCode: '', type: '', deviceCode: '', timeArray: [] @@ -37,13 +37,23 @@ watch: { searchTime(nV, oV) { if (nV != oV) { - this.timeArray = this.searchTime; + this.formSearch.timeArray = this.searchTime; + } + }, + mission(nV, oV) { + if (nV != oV) { + this.formSearch.timeArray = [ + new Date(nV.startTime), + new Date(nV.endTime) + ]; + this.formSearch.type = nV.deviceType; + this.formSearch.deviceCode = nV.deviceCode; } } }, methods: { handleClick() { - this.$emit('search', this.formSearch); + this.$emit('search', { ...this.formSearch, mission: this.mission }); } } }; diff --git a/src/utils/chart/chart-option.js b/src/utils/chart/chart-option.js index bd9de70..250e550 100644 --- a/src/utils/chart/chart-option.js +++ b/src/utils/chart/chart-option.js @@ -93,7 +93,14 @@ }, minInterval: 1 }, - series: _series + series: _series, + dataZoom: [ + { + type: 'inside', + start: 0, + end: 100 + } + ] }; } diff --git a/src/views/historymode/HistoryMode.vue b/src/views/historymode/HistoryMode.vue index 179e2cd..fc56796 100644 --- a/src/views/historymode/HistoryMode.vue +++ b/src/views/historymode/HistoryMode.vue @@ -1,7 +1,10 @@ <template> <div class="p-events-none m-t-2"> <el-row justify="center"> - <SearchBar search-time="" @search="fetchHistroyData"></SearchBar> + <SearchBar + :search-time="searchTime" + @search="fetchHistroyData" + ></SearchBar> </el-row> <el-row class="m-t-2"> <FactorRadio @@ -15,7 +18,10 @@ :factor="factorDatas.factor[factorType]" ></FactorLegend> </el-row> - <TrendAnalysis :factor-datas="factorDatas"></TrendAnalysis> + <TrendAnalysis + class="trend-analysis" + :factor-datas="factorDatas" + ></TrendAnalysis> </div> </template> @@ -72,7 +78,6 @@ // this.factorType = factorType; // this.factorName = factorName; this.factorDatas.refreshHeight(this.factorType); - // this.refreshLegend(this.factorDatas); // this.mapMaker.setFactorType(factorType); // if (!this.mapMaker.runStatus()) { @@ -110,7 +115,6 @@ deviceCode, startTime, endTime, - type, page, perPage: pageSize }) @@ -129,8 +133,10 @@ }) .then((res) => { if (res.data.length > 0) { - const s = new Date(res.data[0].time); - const e = new Date(res.data[res.data.length - 1].time); + const s = new Date(res.data[0].time.replace(' ', 'T')); + const e = new Date( + res.data[res.data.length - 1].time.replace(' ', 'T') + ); this.searchTime = [s, e]; } this.onFetchData(TYPE0, res.data); @@ -144,8 +150,9 @@ }; </script> <style scoped> -.p-events-auto { - /* background-color: antiquewhite; */ - /* padding-top: 1px; */ +.trend-analysis { + position: absolute; + left: 0; + bottom: 2px; } </style> diff --git a/src/views/historymode/component/DataSheet.vue b/src/views/historymode/component/DataSheet.vue new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/views/historymode/component/DataSheet.vue diff --git a/src/views/historymode/component/TrendAnalysis.vue b/src/views/historymode/component/TrendAnalysis.vue index d5de2d0..7960195 100644 --- a/src/views/historymode/component/TrendAnalysis.vue +++ b/src/views/historymode/component/TrendAnalysis.vue @@ -1,14 +1,22 @@ <template> <el-row class="wrap"> - <el-col span="10"> - <FactorCheckbox - :device-type="deviceType" - @change="(e) => (selectFactorType = e)" - ></FactorCheckbox> - <LineChart - :factor-datas="factorDatas" - :select-factor-type="selectFactorType" - ></LineChart> + <Transition name=""> + <el-col v-show="show" span="10"> + <FactorCheckbox + :device-type="deviceType" + @change="(e) => (selectFactorType = e)" + ></FactorCheckbox> + <LineChart + :factor-datas="factorDatas" + :select-factor-type="selectFactorType" + ></LineChart> + </el-col> + </Transition> + <el-col span="2"> + <CardButton + name="鐩戞祴瑕佺礌瓒嬪娍鍒嗘瀽" + @click="() => (show = !show)" + ></CardButton> </el-col> </el-row> </template> @@ -28,7 +36,8 @@ }, data() { return { - selectFactorType: ['1'] + selectFactorType: ['1'], + show: true }; } }; @@ -37,5 +46,20 @@ .wrap { /* display: flex; flex-direction: column; */ + /* background-color: aliceblue; */ +} + +.slide-fade-enter-active { + transition: all 0.3s ease-out; +} + +.slide-fade-leave-active { + transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); +} + +.slide-fade-enter-from, +.slide-fade-leave-to { + transform: translateX(-100%); + opacity: 0; } </style> -- Gitblit v1.9.3