Browse Source

详情页增加折线图

develop
fuguobin 1 year ago
parent
commit
a24a3d2aab
  1. 2
      .env.development
  2. 3
      .env.production
  3. 10
      src/api/table/types.ts
  4. 2
      src/types/auto-imports.d.ts
  5. 15
      src/types/components.d.ts
  6. 14
      src/views/details/index.scss
  7. 211
      src/views/details/index.vue
  8. 14
      src/views/monitoring/components/header.vue
  9. 2
      src/views/monitoring/screen/components/infoPanel.vue
  10. 2
      src/views/monitoring/screen/index.scss
  11. 4
      vite.config.ts

2
.env.development

@ -3,4 +3,4 @@ VITE_APP_ENV = 'development'
VITE_APP_TITLE = 'vue-vite-project-admin'
VITE_APP_PORT = 8089
##VITE_APP_WS_API = 'ws://localhost:9010' ## websocket地址
VITE_APP_BASE_API = 'http://10.10.10.56:9010/' ## '/dev-api'线上接口 '/mock'本地模拟数据
VITE_APP_BASE_API = '/dev-api' ## '/dev-api'线上接口 '/mock'本地模拟数据

3
.env.production

@ -5,5 +5,6 @@ VITE_APP_PORT = 8089
#VITE_APP_WS_API = 'ws://board.heatiot.cn:8001/prod-api' ## websocket地址
#VITE_APP_BASE_API = 'http://board.heatiot.cn:8001/prod-api/' ## 线上接口
#VITE_APP_WS_API = 'ws://${window.location.host}/ws' ## websocket地址 ws://10.10.10.56:9000/websocket/
VITE_APP_BASE_API = '/prod-api/' ## '/dev-api'线上接口 '/mock'本地模拟数据
VITE_APP_BASE_API = '/prod-api/' ## 正式环境
# VITE_APP_BASE_API = '/biprod-api/' ## 测试环境

10
src/api/table/types.ts

@ -62,9 +62,17 @@ export interface TableVo {
*/
export interface PanelVo {
backImg: string;
ext: any;
ext: string;
extJsb: extVo;
id: number;
title: string;
type: string;
value?: number;
}
export interface extVo {
extData: any;
}
export interface RoleQuery {
time: string;
}

2
src/types/auto-imports.d.ts

@ -6,7 +6,6 @@ declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElNotification: typeof import('element-plus/es')['ElNotification']
const ElTree: typeof import('element-plus/es')['ElTree']
const NEllipsis: typeof import('naive-ui')['NEllipsis']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
@ -278,7 +277,6 @@ declare module 'vue' {
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']>
readonly ElTree: UnwrapRef<typeof import('element-plus/es')['ElTree']>
readonly NEllipsis: UnwrapRef<typeof import('naive-ui')['NEllipsis']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>

15
src/types/components.d.ts

@ -13,6 +13,7 @@ declare module '@vue/runtime-core' {
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCol: typeof import('element-plus/es')['ElCol']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
@ -21,13 +22,9 @@ declare module '@vue/runtime-core' {
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
@ -35,16 +32,9 @@ declare module '@vue/runtime-core' {
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
IEpDelete: typeof import('~icons/ep/delete')['default']
IEpEdit: typeof import('~icons/ep/edit')['default']
IEpPlus: typeof import('~icons/ep/plus')['default']
IEpPosition: typeof import('~icons/ep/position')['default']
IEpRefresh: typeof import('~icons/ep/refresh')['default']
IEpSearch: typeof import('~icons/ep/search')['default']
LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
NBadge: typeof import('naive-ui')['NBadge']
@ -73,7 +63,4 @@ declare module '@vue/runtime-core' {
Video: typeof import('./../components/Video/index.vue')['default']
WangEditor: typeof import('./../components/WangEditor/index.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

14
src/views/details/index.scss

@ -0,0 +1,14 @@
.details {
padding: 1.5rem;
.search {
margin-bottom: 1.5rem;
}
.echart {
.comparisonInfo {
.stackedLine {
width: 100%;
height: 500px;
}
}
}
}

211
src/views/details/index.vue

@ -1,62 +1,187 @@
<template>
<div class="roleContainer">
<div class="details">
<el-card class="search" shadow="always">
<el-form ref="queryFormRef" :model="searchForm" :inline="true">
<el-form-item label="关键字" prop="keywords">
<el-input
v-model="searchForm.keywords"
clearable
style="width: 200px"
placeholder="用户名/昵称/手机号"
@keyup.enter="getUserData"
<el-form ref="searchRef" :inline="true" :model="searchForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="时间" prop="time">
<el-date-picker
v-model="searchForm.time"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
:default-time="defaultTime1"
/>
</el-form-item>
<el-form-item label="颗粒度" prop="particle">
<el-select v-model="searchForm.particle" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="设备" prop="device">
<el-select v-model="searchForm.device" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="参数" prop="parameter">
<el-select v-model="searchForm.parameter" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getUserData"><i-ep-search />搜索</el-button>
<el-button @click="resetClick"><i-ep-refresh />重置</el-button>
<el-button type="primary" @click="submitForm(searchRef)">确认</el-button>
<el-button @click="resetForm(searchRef)">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="list" shadow="always"> 内容 </el-card>
<el-card class="echart" shadow="always">
<div class="comparisonInfo">
<div ref="stackedRef" class="stackedLine" />
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
// import { getRolePage } from '@/api/role';
// import { listMenuOptions } from '@/api/menu';
// import { RolePageVO, RoleForm, RoleQuery } from '@/api/role/types';
// const queryFormRef = ref(ElForm);
// const roleData = ref<RolePageVO[]>();
// const searchForm = reactive<RoleQuery>({
// pageNum: 1,
// pageSize: 10
// });
import * as echarts from 'echarts';
import { Ref } from 'vue';
const stackedRef: Ref<HTMLElement | any> = ref(null);
import type { FormInstance } from 'element-plus';
onMounted(() => {
// getUserData();
const searchRef = ref<FormInstance>();
const defaultTime1 = new Date(2000, 1, 1, 12, 0, 0); // '12:00:00'
const searchForm = reactive({
time: '',
particle: '',
device: '',
parameter: ''
});
//
// function getUserData() {
// loading.value = true;
// getRolePage(searchForm)
// .then(({ data }) => {
// // roleData.value = data.list;
// })
// .finally(() => {
// loading.value = false;
// });
// }
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(valid => {
if (valid) {
console.log('submit!');
} else {
console.log('error submit!');
return false;
}
});
};
//
// function resetClick() {
// queryFormRef.value.resetFields();
// searchForm.pageNum = 1;
// getUserData();
// }
</script>
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
const optionss = [
{
value: 'Option1',
label: 'Option1'
},
{
value: 'Option2',
label: 'Option2'
},
{
value: 'Option3',
label: 'Option3'
},
{
value: 'Option4',
label: 'Option4'
},
{
value: 'Option5',
label: 'Option5'
}
];
const options = {
title: {
text: 'Temperature Change in the Coming Week'
},
tooltip: {
trigger: 'axis'
},
legend: {},
toolbox: {
show: true,
feature: {
dataZoom: {
yAxisIndex: 'none'
},
dataView: { readOnly: false },
magicType: { type: ['line', 'bar'] },
restore: {},
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} °C'
}
},
series: [
{
name: 'Highest',
type: 'line',
data: [10, 11, 13, 11, 12, 12, 9],
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
},
markLine: {
data: [{ type: 'average', name: 'Avg' }]
}
},
{
name: 'Lowest',
type: 'line',
data: [1, -2, 2, 5, 3, 2, 0],
markPoint: {
data: [{ name: '周最低', value: -2, xAxis: 1, yAxis: -1.5 }]
},
markLine: {
data: [
{ type: 'average', name: 'Avg' },
[
{
symbol: 'none',
x: '90%',
yAxis: 'max'
},
{
symbol: 'circle',
label: {
position: 'start',
formatter: 'Max'
},
type: 'max',
name: '最高点'
}
]
]
}
}
]
};
onMounted(() => {
//
const chart = echarts.init(stackedRef.value);
chart.setOption(options);
//
window.addEventListener('resize', () => {
chart.resize();
});
});
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

14
src/views/monitoring/components/header.vue

@ -187,14 +187,14 @@ function returnBack() {
}
function waringClick() {
//
if (waringData.value.length === 0) {
ElNotification({
message: '暂没有报警信息!',
type: 'info',
})
} else {
// if (waringData.value.length === 0) {
// ElNotification({
// message: '',
// type: 'info',
// })
// } else {
waringDrawer.value = true
}
// }
}
// function getWeatherData() {

2
src/views/monitoring/screen/components/infoPanel.vue

@ -23,7 +23,7 @@
<p>{{ item.title }}</p>
</div>
<div class="numValueMore" v-if="item.type === 'B'">
<div class="numItem" v-for="(res, index) in item.ext" :key="index">
<div class="numItem" v-for="(res, index) in item.extJsb.extData" :key="index">
<span>{{ res.name }}</span>
<span><countTo :start="1" :end="res.value" :duration="3000"></countTo></span>
<span>{{ res.unit }}</span>

2
src/views/monitoring/screen/index.scss

@ -541,7 +541,7 @@
.numValueMore {
flex: 1;
margin-left: 1rem;
margin-left: 1.5rem;
span {
font-size: 1.4rem;
line-height: 30px;

4
vite.config.ts

@ -45,9 +45,9 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
hmr: true, //配置HMR
proxy: {
[env.VITE_APP_BASE_API]: {
// target: 'http://172.1.2.106:9000/',//本地接口地址
target: 'http://172.1.2.196:9010/',//本地接口地址
// target: 'http://172.1.2.48:9000/',//本地接口地址
target: 'http://board.heatiot.cn:8001/prod-api/', //线上接口地址
// target: 'http://board.heatiot.cn:8001/prod-api/', //线上接口地址
changeOrigin: true,
rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
}

Loading…
Cancel
Save