feat: 接入大屏修复bug

This commit is contained in:
fyy
2025-07-10 17:52:54 +08:00
parent 0d2a4db6a6
commit b1d0c117fc
60 changed files with 6394 additions and 20 deletions

View File

@@ -48,6 +48,7 @@
"crypto-js": "^4.2.0",
"dayjs": "catalog:",
"echarts": "^5.5.1",
"echarts-gl": "^2.0.9",
"jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21",
"pinia": "catalog:",

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -11,6 +11,7 @@ import {
GiteeIcon,
GitHubOutlined,
UserOutlined,
} from '@vben/icons';
import {
BasicLayout,
@@ -30,6 +31,7 @@ import { resetRoutes } from '#/router';
import { useAuthStore, useNotifyStore } from '#/store';
import { useTenantStore } from '#/store/tenant';
import LoginForm from '#/views/_core/authentication/login.vue';
// import { TagOutlined } from '@ant-design/icons-vue';
const userStore = useUserStore();
const authStore = useAuthStore();
@@ -83,6 +85,13 @@ const menus = computed(() => {
icon: CircleHelp,
text: $t('ui.widgets.qa'),
},
{
handler: () => {
router.push('/navigation');
},
// icon: TagOutlined,
text: '返回导航',
},
];
/**
* 租户选中状态 不显示个人中心

View File

@@ -1,7 +1,7 @@
import { initPreferences } from '@vben/preferences';
import { unmountGlobalLoading } from '@vben/utils';
import { overridesPreferences } from './preferences';
import './utils/flexible'
/**
* 应用初始化完成之后再进行页面加载渲染
*/

View File

@@ -100,6 +100,67 @@ const coreRoutes: RouteRecordRaw[] = [
},
],
},
{
component: () => import('#/views/screen/navigation/Navigation.vue'),
name: 'navigation',
path: '/navigation',
meta: {
title: '导航页面', // 或者用 $t('page.navigation.title')
requiresAuth: true, // 如果需要登录验证
},
},
{
component: () => import('#/views/screen/energyConsumptionAnalysis/index.vue'),
name: 'energyAnalysis',
path: '/energyAnalysis',
meta: {
title: '能耗大屏',
requiresAuth: true, // 如果需要登录验证
},
}, {
component: () => import('#/views/screen/property/index.vue'),
name: 'property',
path: '/property',
meta: {
title: '物业大屏',
requiresAuth: true, // 如果需要登录验证
},
}, {
component: () => import('#/views/screen/security/index.vue'),
name: 'security',
path: '/security',
meta: {
title: '安防大屏',
requiresAuth: true, // 如果需要登录验证
},
},
{
component: () => import('#/views/screen/monitor/index.vue'),
name: 'monitor',
path: '/monitor',
meta: {
title: '监控大屏',
requiresAuth: true, // 如果需要登录验证
},
},
{
component: () => import('#/views/screen/security/index.vue'),
name: 'security',
path: '/security',
meta: {
title: '安防大屏',
requiresAuth: true, // 如果需要登录验证
},
},
{
component: () => import('#/views/screen/digitalIntelligence/index.vue'),
name: 'digitalIntelligence',
path: '/digitalIntelligence',
meta: {
title: '商务中心数智管理平台',
requiresAuth: true, // 如果需要登录验证
},
},
];
export { coreRoutes, fallbackNotFoundRoute };

View File

@@ -58,7 +58,7 @@ export const useAuthStore = defineStore('auth', () => {
} else {
onSuccess
? await onSuccess?.()
: await router.push(preferences.app.defaultHomePath);
: await router.push('/navigation');
}
if (userInfo?.realName) {

View File

@@ -0,0 +1,119 @@
import type { ECharts } from 'echarts'
/**
* ECharts 图表自适应管理器
* 用于监听图表容器大小变化并自动调整图表大小
*/
export class EChartsResizeManager {
private charts: Map<ECharts, ResizeObserver> = new Map()
private resizeHandler: (() => void) | null = null
constructor() {
this.initResizeListener()
}
/**
* 添加图表到管理器
* @param chart ECharts 实例
*/
addChart(chart: ECharts): void {
if (chart && !this.charts.has(chart)) {
// 获取图表容器元素
const container = chart.getDom()
if (container) {
// 为每个图表创建独立的 ResizeObserver
const observer = new ResizeObserver(() => {
if (chart && !chart.isDisposed()) {
chart.resize()
}
})
// 监听图表容器的大小变化
observer.observe(container)
this.charts.set(chart, observer)
}
}
}
/**
* 移除图表
* @param chart ECharts 实例
*/
removeChart(chart: ECharts): void {
const observer = this.charts.get(chart)
if (observer) {
observer.disconnect()
this.charts.delete(chart)
}
}
/**
* 清空所有图表
*/
clearCharts(): void {
this.charts.forEach(observer => {
observer.disconnect()
})
this.charts.clear()
}
/**
* 重新调整所有图表大小
*/
resizeAllCharts(): void {
this.charts.forEach((observer, chart) => {
if (chart && !chart.isDisposed()) {
chart.resize()
}
})
}
/**
* 初始化窗口大小变化监听器
*/
private initResizeListener(): void {
// 监听窗口大小变化
this.resizeHandler = () => {
this.resizeAllCharts()
}
window.addEventListener('resize', this.resizeHandler)
}
/**
* 销毁监听器
*/
destroy(): void {
if (this.resizeHandler) {
window.removeEventListener('resize', this.resizeHandler)
this.resizeHandler = null
}
this.clearCharts()
}
}
// 创建全局实例
export const echartsResizeManager = new EChartsResizeManager()
/**
* 便捷函数:添加图表到管理器
* @param chart ECharts 实例
*/
export function addChartToResizeManager(chart: ECharts): void {
echartsResizeManager.addChart(chart)
}
/**
* 便捷函数:移除图表
* @param chart ECharts 实例
*/
export function removeChartFromResizeManager(chart: ECharts): void {
echartsResizeManager.removeChart(chart)
}
/**
* 便捷函数:手动触发所有图表重新调整大小
*/
export function resizeAllCharts(): void {
echartsResizeManager.resizeAllCharts()
}

View File

@@ -0,0 +1,12 @@
function setRootFontSize(): void {
const baseWidth = 1920 // 设计稿宽度
const baseFontSize = 16 // 设计稿根字体
const screenWidth = window.innerWidth
const fontSize = (screenWidth / baseWidth) * baseFontSize
document.documentElement.style.fontSize = fontSize + 'px'
}
setRootFontSize()
window.addEventListener('resize', setRootFontSize)
export default setRootFontSize

View File

@@ -0,0 +1,264 @@
import * as echarts from 'echarts'
import 'echarts-gl'
interface Pie3DData {
name: string
value: number
itemStyle?: {
color?: string
opacity?: number
}
startRatio?: number
endRatio?: number
}
interface Pie3DOptions {
data: Pie3DData[]
height?: number
hoverHeightScale?: number
selectOffset?: number
distance?: number
boxHeight?: number
radius?: number
}
interface ParametricEquation {
u: { min: number; max: number; step: number }
v: { min: number; max: number; step: number }
x: (u: number, v: number) => number
y: (u: number, v: number) => number
z: (u: number, v: number) => number
}
interface SeriesItem {
name: string
type: string
parametric: boolean
wireframe: { show: boolean }
pieData?: Pie3DData
pieStatus?: { selected: boolean; hovered: boolean; k: number }
itemStyle?: any
parametricEquation?: ParametricEquation
}
/**
* 渲染3D饼图支持点击选中外移、鼠标悬停高亮升高、高亮修正无label/legend。
* @param dom - 容器DOM
* @param options - 配置项
* options.data: [{name, value, itemStyle}]
* options.height: 饼图厚度
* options.hoverHeightScale: 高亮时高度放大倍数
* options.selectOffset: 选中时外移距离默认0.1
* options.distance: 视角距离
* options.boxHeight: grid3D.boxHeight
* options.radius: 半径缩放
* @returns echartsInstance
*/
export function renderPie3DChart(dom: HTMLElement, options: Pie3DOptions): echarts.ECharts | undefined {
if (!dom) return
const myChart = echarts.init(dom)
const hoverHeightScale = options.hoverHeightScale || 1.2
const selectOffset = options.selectOffset || 0.1
const distance = options.distance || 120
const gridBoxHeight = options.boxHeight || 10
const R = options.radius || 0.8
const fixedH = 100
// 生成扇形的曲面参数方程
function getParametricEquation(startRatio: number, endRatio: number, isSelected: boolean, isHovered: boolean, k: number, h: number): ParametricEquation {
const midRatio = (startRatio + endRatio) / 2
const startRadian = startRatio * Math.PI * 2
const endRadian = endRatio * Math.PI * 2
const midRadian = midRatio * Math.PI * 2
if (startRatio === 0 && endRatio === 1) isSelected = false
k = typeof k !== 'undefined' ? k : 1
const offsetX = isSelected ? Math.cos(midRadian) * selectOffset : 0
const offsetY = isSelected ? Math.sin(midRadian) * selectOffset : 0
const hoverRate = isHovered ? 1.05 : 1
return {
u: { min: -Math.PI, max: Math.PI * 3, step: Math.PI / 32 },
v: { min: 0, max: Math.PI * 2, step: Math.PI / 20 },
x: function(u: number, v: number) {
if (u < startRadian) return offsetX + R * Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
if (u > endRadian) return offsetX + R * Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
return offsetX + R * Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate
},
y: function(u: number, v: number) {
if (u < startRadian) return offsetY + R * Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
if (u > endRadian) return offsetY + R * Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
return offsetY + R * Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate
},
z: function(u: number, v: number) {
if (u < -Math.PI * 0.5) return Math.sin(u)
if (u > Math.PI * 2.5) return Math.sin(u) * h * .1
return Math.sin(v) > 0 ? 1 * h * .1 : -1
}
}
}
// 生成series
function getPie3D(pieData: Pie3DData[]): SeriesItem[] {
const series: SeriesItem[] = []
let sumValue = 0
let startValue = 0
let endValue = 0
const k = 1 // 实心饼图
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value
const seriesItem: SeriesItem = {
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
parametric: true,
wireframe: { show: false },
pieData: pieData[i],
pieStatus: { selected: false, hovered: false, k: k }
}
if (pieData[i].itemStyle) {
const itemStyle: any = {}
const itemStyleObj: any = pieData[i].itemStyle
if (itemStyleObj.color) itemStyle.color = itemStyleObj.color
if (itemStyleObj.opacity !== undefined) itemStyle.opacity = itemStyleObj.opacity
seriesItem.itemStyle = itemStyle
}
series.push(seriesItem)
}
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData!.value
series[i].pieData!.startRatio = startValue / sumValue
series[i].pieData!.endRatio = endValue / sumValue
series[i].parametricEquation = getParametricEquation(
series[i].pieData!.startRatio!,
series[i].pieData!.endRatio!,
false,
false,
k,
fixedH // 所有块厚度一样
)
startValue = endValue
}
// 透明圆环用于高亮修正
series.push({
name: 'mouseoutSeries',
type: 'surface',
parametric: true,
wireframe: { show: false },
itemStyle: { opacity: 0 },
parametricEquation: {
u: { min: 0, max: Math.PI * 2, step: Math.PI / 20 },
v: { min: 0, max: Math.PI, step: Math.PI / 20 },
x: function(u: number, v: number) { return Math.sin(v) * Math.sin(u) + Math.sin(u) },
y: function(u: number, v: number) { return Math.sin(v) * Math.cos(u) + Math.cos(u) },
z: function(u: number, v: number) { return Math.cos(v) > 0 ? 0.1 : -0.1 }
}
})
return series
}
const series = getPie3D(options.data)
// 不加pie2d不加legend不加label
const option = {
backgroundColor: 'rgba(0,0,0,0)',
legend: undefined,
tooltip: undefined,
xAxis3D: { min: -1, max: 1 },
yAxis3D: { min: -1, max: 1 },
zAxis3D: { min: -1, max: 1 },
grid3D: {
show: false,
boxHeight: gridBoxHeight,
viewControl: {
alpha: 35,
distance: distance,
rotateSensitivity: 0,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotate: false
}
},
series: series
}
myChart.setOption(option, true)
// 选中/高亮交互
let hoveredIndex = ''
// // 点击选中(外移)
// myChart.on('click', function(params) {
// if (!series[params.seriesIndex] || series[params.seriesIndex].type !== 'surface') return;
// let isSelected = !series[params.seriesIndex].pieStatus.selected;
// let isHovered = series[params.seriesIndex].pieStatus.hovered;
// let k = series[params.seriesIndex].pieStatus.k;
// let startRatio = series[params.seriesIndex].pieData.startRatio;
// let endRatio = series[params.seriesIndex].pieData.endRatio;
// // 取消之前选中
// if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
// let prev = series[selectedIndex];
// prev.parametricEquation = getParametricEquation(
// prev.pieData.startRatio, prev.pieData.endRatio, false, prev.pieStatus.hovered, k, prev.pieData.value
// );
// prev.pieStatus.selected = false;
// }
// // 当前选中/取消
// series[params.seriesIndex].parametricEquation = getParametricEquation(
// startRatio, endRatio, isSelected, isHovered, k, series[params.seriesIndex].pieData.value
// );
// series[params.seriesIndex].pieStatus.selected = isSelected;
// isSelected ? selectedIndex = params.seriesIndex : selectedIndex = '';
// myChart.setOption({ series });
// });
// 悬停高亮(升高)
myChart.on('mouseover', function(params: any) {
if (!series[params.seriesIndex] || !series[params.seriesIndex].pieData) return
if (hoveredIndex === params.seriesIndex) return
// 取消之前高亮
if (hoveredIndex !== '') {
const prev = series[parseInt(hoveredIndex)]
if (!prev || !prev.pieData) return
prev.parametricEquation = getParametricEquation(
prev.pieData.startRatio!,
prev.pieData.endRatio!,
prev.pieStatus!.selected,
false,
prev.pieStatus!.k,
fixedH
)
prev.pieStatus!.hovered = false
hoveredIndex = ''
}
// 当前高亮
const cur = series[params.seriesIndex]
cur.parametricEquation = getParametricEquation(
cur.pieData!.startRatio!,
cur.pieData!.endRatio!,
cur.pieStatus!.selected,
true,
cur.pieStatus!.k,
fixedH * hoverHeightScale
)
cur.pieStatus!.hovered = true
hoveredIndex = params.seriesIndex.toString()
myChart.setOption({ series })
})
// 全局移出,修正高亮残留
myChart.on('globalout', function() {
if (hoveredIndex !== '') {
const prev = series[parseInt(hoveredIndex)]
if (!prev || !prev.pieData) return
prev.parametricEquation = getParametricEquation(
prev.pieData.startRatio!,
prev.pieData.endRatio!,
prev.pieStatus!.selected,
false,
prev.pieStatus!.k,
fixedH
)
prev.pieStatus!.hovered = false
hoveredIndex = ''
myChart.setOption({ series })
}
})
return myChart
}

View File

@@ -0,0 +1,129 @@
import * as echarts from 'echarts'
interface ThreeDBarOptionConfig {
xData: string[]
yData: number[]
barWidth?: number
colorConfig?: {
left0?: string
left08?: string
top03?: string
top1?: string
}
}
export function getThreeDBarOption({ xData, yData, barWidth = 30, colorConfig = {} }: ThreeDBarOptionConfig) {
// 注册 shape 只需一次,防止多次注册报错
if (!(echarts.graphic as any).registered3DBar) {
const leftShape = echarts.graphic.extendShape({
buildPath(ctx: any, shape: any) {
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape
const WIDTH = 15
const OBLIQUE_ANGLE_HEIGHT = 8
const p1 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
const p2 = [basicsXAxis - WIDTH, bottomYAxis]
const p3 = [basicsXAxis, bottomYAxis]
const p4 = [basicsXAxis, topBasicsYAxis]
ctx.moveTo(p1[0], p1[1])
ctx.lineTo(p2[0], p2[1])
ctx.lineTo(p3[0], p3[1])
ctx.lineTo(p4[0], p4[1])
}
})
const rightShape = echarts.graphic.extendShape({
buildPath(ctx: any, shape: any) {
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape
const WIDTH = 15
const OBLIQUE_ANGLE_HEIGHT = 2
const p1 = [basicsXAxis, topBasicsYAxis]
const p2 = [basicsXAxis, bottomYAxis]
const p3 = [basicsXAxis + WIDTH, bottomYAxis]
const p4 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
ctx.moveTo(p1[0], p1[1])
ctx.lineTo(p2[0], p2[1])
ctx.lineTo(p3[0], p3[1])
ctx.lineTo(p4[0], p4[1])
}
})
const topShape = echarts.graphic.extendShape({
buildPath(ctx: any, shape: any) {
const { topBasicsYAxis, basicsXAxis } = shape
const WIDTH = 15
const OBLIQUE_ANGLE_HEIGHT = 8
const p1 = [basicsXAxis, topBasicsYAxis]
const p2 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
const p3 = [basicsXAxis, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT * 2]
const p4 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
ctx.moveTo(p1[0], p1[1])
ctx.lineTo(p2[0], p2[1])
ctx.lineTo(p3[0], p3[1])
ctx.lineTo(p4[0], p4[1])
}
})
echarts.graphic.registerShape('leftShape', leftShape)
echarts.graphic.registerShape('rightShape', rightShape)
echarts.graphic.registerShape('topShape', topShape)
;(echarts.graphic as any).registered3DBar = true
}
return {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', top: "12%", containLabel: true },
xAxis: [{
type: 'category',
data: xData,
axisTick: { alignWithLabel: true },
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
}],
yAxis: [{
type: 'value',
axisLine: { show: false },
splitLine: { lineStyle: { color: '#1b4a7a' } },
axisLabel: { color: '#fff' }
}],
series: [{
type: 'custom',
data: yData,
barWidth,
renderItem(params: any, api: any) {
const basicsCoord = api.coord([api.value(0), api.value(1)])
const topBasicsYAxis = basicsCoord[1]
const basicsXAxis = basicsCoord[0]
const bottomYAxis = api.coord([api.value(0), 0])[1]
return {
type: 'group',
children: [
{
type: 'leftShape',
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
style: {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colorConfig.left0 || '#2ADBEF' },
{ offset: 1, color: colorConfig.left08 || '#2677F9 ' },
])
}
},
{
type: 'rightShape',
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
style: {
fill: '#114EAD '
}
},
{
type: 'topShape',
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
style: {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0.3, color: colorConfig.top03 || '#6DF0FF' },
{ offset: 1, color: colorConfig.top1 || '#6DF0FF' }
])
}
}
]
}
}
}]
}
}

View File

@@ -12,6 +12,7 @@ import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
import productDetailModal from './rentalPlan-detial-modal.vue';
import { getDictOptions } from '#/utils/dict';
import { Item } from 'ant-design-vue/es/menu';
const emit = defineEmits<{ reload: [] }>();
@@ -69,7 +70,10 @@ const [BasicModal, modalApi] = useVbenModal({
if ((isUpdate.value || isReadonly.value) && id) {
const record = await rentalPlanInfo(id);
// 后端返回绿植产品包列表结构处理
detailTable.value = record.productList.map((item:any) => item.product);
detailTable.value = record.productList.map((item:any) => {...item.product,Item.productNum});
console.log(detailTable.value);
await formApi.setValues(record);
}
await markInitialized();

View File

@@ -87,10 +87,14 @@ onMounted(async () => {
data: xAxisData.value,
boundaryGap: false,
},
yAxis: { type: 'value' },
yAxis: { type: 'value',
axisLabel: {
formatter: (value) => `${value * 100}%`
},
},
series: [
{
name: '订单',
name: '订单趋势',
type: 'line',
data: seriesData.value ||[],
smooth: true,
@@ -123,17 +127,22 @@ onMounted(async () => {
],
});
renderCustomerTypesBar({
title: { text: '客户类型分' },
title: { text: '客户类型分' },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: countByCusTypeData.type || [],
data: ['企业客户','个人客户','政府机构','商业地产','其他'],
boundaryGap: true,
},
yAxis: { type: 'value' },
yAxis: { type: 'value',
axisLabel: {
// formatter: (value: number) => `${parseInt(value.toString())}`
},
// interval: 0,
},
series: [
{
name: '订单数',
name: '客户数',
type: 'bar',
data: countByCusTypeData.counts || [],
},
@@ -141,16 +150,28 @@ onMounted(async () => {
});
renderCustomerRenewalLine({
title: { text: '客户续租率趋势' },
tooltip: { trigger: 'axis' },
tooltip: { trigger: 'axis',
formatter: function(params:any) {
let result = params[0].axisValue + '<br/>';
params.forEach((item:any) => {
result += item.marker + item.seriesName + '' + item.data + '%<br/>';
});
return result;
}
},
xAxis: {
type: 'category',
data: countRenewRateData.month || [],
boundaryGap: false,
},
yAxis: { type: 'value' },
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value}%',
}, },
series: [
{
name: '订单数',
name: '续租率',
type: 'line',
data: countRenewRateData.rate || [],
smooth: true,
@@ -162,6 +183,19 @@ onMounted(async () => {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function(params:any) {
// params 是一个数组,包含每个系列的当前项
let result = params[0].axisValue + '<br/>';
params.forEach((item:any) => {
if (item.seriesName === '完成率') {
// 假设原始数据是 80显示为 80%
result += item.marker + item.seriesName + '' + item.data + '%<br/>';
} else {
result += item.marker + item.seriesName + '' + item.data + '<br/>';
}
});
return result;
}
},
legend: {
data: ['计划任务数', '已完成数', '完成率'],
@@ -169,7 +203,7 @@ onMounted(async () => {
xAxis: [
{
type: 'category',
data: countAchievedData.type || [],
data: ['修剪整形','肥水管理','中耕除草','病虫害防治','越冬防寒'],
},
],
yAxis: [
@@ -195,7 +229,7 @@ onMounted(async () => {
{
name: '计划任务数',
type: 'bar',
data: countAchievedData.toral || [],
data: countAchievedData.total || [],
},
{
name: '已完成数',
@@ -220,7 +254,7 @@ onMounted(async () => {
orient: 'horizontal',
left: 'center',
bottom: 10,
data: ['一星', '星', '三星', '四星', '五星'],
data: ['一星', '星', '三星', '四星', '五星'],
},
series: [
{
@@ -283,7 +317,7 @@ function formatNumber(num: number | string) {
<div class="title">
<div class="title-text">绿植租赁业务统计报表</div>
<div class="title-operate">
<div class="export">
<div class="export" style="display: none;">
<Button size="large" style="color: #fff; background-color: #22c55e">
导出数据
</Button>

View File

@@ -60,7 +60,8 @@ function generateWeekDates(): void {
return startOfWeek.add(i, 'day').format('YYYY-MM-DD');
});
weekDates.value = dates;
selectedDate.value = dates[0] ?? '';
// 默认选中今天
selectedDate.value = today.format('YYYY-MM-DD');
}
// 获取预约数据
@@ -137,7 +138,6 @@ async function fetchBookings(): Promise<void> {
});
bookingTable.value = table;
}
console.log(bookingTable.value,'bookingTable.value');
} catch (error) {
console.error('获取预约数据失败:', error);
@@ -150,7 +150,8 @@ async function fetchBookings(): Promise<void> {
function handleViewModeChange(e: RadioChangeEvent): void {
viewMode.value = e.target.value;
if (viewMode.value === 'date') {
selectedDate.value = weekDates.value[0] ?? '';
// 默认选中今天
selectedDate.value = dayjs().format('YYYY-MM-DD');
} else {
selectedRoom.value = roomList.value[0]?.id ?? '';
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,890 @@
<template>
<div class="mian">
<div class="title">
<div class="left">
<div class="left-first" id="time">--:--:--</div>
<div class="left-second" id="date">----</div>
</div>
<div class="center">南川区综合服务中心数智管理平台能耗大屏</div>
<div class="right">
<div>{{ weekDay }}</div>
<div></div>
<div>40</div>
<div class="logout" @click="logout">
<img src="../../../assets/return.png" style="width: 1.5rem; height: 1.5rem;">
<div>
退出
</div>
</div>
</div>
</div>
<div class="header">
<div class="header-item">
<span class="header-label">今年用电量</span>
<span class="header-value orange">180</span>
<span class="header-unit">亿kwh</span>
</div>
<div class="header-item">
<span class="header-label">本月用电总量</span>
<span class="header-value green">1.8</span>
<span class="header-unit">亿kwh</span>
</div>
<div class="header-item">
<span class="header-label">今年用水总量</span>
<span class="header-value blue">2600</span>
<span class="header-unit">万吨</span>
</div>
<div class="header-item">
<span class="header-label">本月用水总量</span>
<span class="header-value purple">30</span>
<span class="header-unit">万吨</span>
</div>
<div class="header-item">
<span class="header-label">设备总数</span>
<span class="header-value green">500</span>
<span class="header-unit"></span>
</div>
</div>
<div class="contents">
<div class="content">
<div class="content-left">
<div class="first">
<div class="first-total">
<div class="first-total-title">今日用电量</div>
<div class="first-total-value">
<div class="first-total-value-number">1</div>
<div class="first-total-value-number">2</div>
<div class="first-total-value-number">3</div>
</div>
<div class="first-total-unit">kwh</div>
</div>
<div ref="barChart" class="bar-chart" style="width:100%;height:80%;"></div>
</div>
<div class="second">
<div ref="powerChart" class="power-chart"></div>
</div>
<div class="third">
<div class="env-cards">
<div class="env-card">
<div class="env-card-content">
<div class="env-title">PM2.5(μg/)</div>
<div class="env-value">5</div>
</div>
</div>
<div class="env-card">
<div class="env-card-content">
<div class="env-title">PM10(μg/)</div>
<div class="env-value">120</div>
</div>
</div>
<div class="env-card">
<div class="env-card-content">
<div class="env-title">噪声(dB(A))</div>
<div class="env-value">50</div>
</div>
</div>
<div class="env-card">
<div class="env-card-content">
<div class="env-title">一氧化碳(ppm)</div>
<div class="env-value">10</div>
</div>
</div>
</div>
<div ref="envChart" class="env-chart"></div>
</div>
</div>
<div class="content-center">
<div class="content-center-first">
<div class="first-item">
<div class="item"></div>
</div>
</div>
<div class="content-center-second">
<div class="second-item">
<div class="second-item-text">645</div>
<div class="second-item-text">729</div>
<div class="second-item-text">648</div>
<div class="second-item-text">786</div>
</div>
</div>
</div>
<div class="content-right">
<div class="first">
<div class="first-total">
<div class="first-total-title">今日用水量</div>
<div class="first-total-value">
<div class="first-total-value-number">1</div>
<div class="first-total-value-number">2</div>
<div class="first-total-value-number">3</div>
</div>
<div class="first-total-unit"></div>
</div>
<div ref="pie3dChart" class="pie3d-chart"></div>
</div>
<div class="second">
<div ref="waterChart" class="water-chart"></div>
</div>
<div class="third">
<div class="device-cards">
<div class="device-card1">
<div>
<img src="../../../assets/energyConsumptionAnalysis/devices-number-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
</div>
<div class="device-card-text-box">
<div class="device-card-text">设备总数</div>
<div class="device-card1-value">650</div>
</div>
</div>
<div class="device-card2">
<div>
<img src="../../../assets/energyConsumptionAnalysis/devices-online-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
</div>
<div>
<div class="device-card-text">设备在线数</div>
<div class="device-card2-value">632</div>
</div>
</div>
<div class="device-card3">
<div>
<img src="../../../assets/energyConsumptionAnalysis/devices-offline-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
</div>
<div>
<div class="device-card-text">设备离线数</div>
<div class="device-card3-value">18</div>
</div>
</div>
</div>
<div ref="deviceChart" class="device-chart"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
import 'echarts-gl'
import { getThreeDBarOption } from '#/utils/threeDBarOption'
import { renderPie3DChart } from '#/utils/pie3d'
import { addChartToResizeManager, removeChartFromResizeManager } from '#/utils/echartsResize'
// 路由
const router = useRouter()
// 图表实例
const barChart = ref<HTMLElement>()
const powerChart = ref<HTMLElement>()
const envChart = ref<HTMLElement>()
const waterChart = ref<HTMLElement>()
const deviceChart = ref<HTMLElement>()
const pie3dChart = ref<HTMLElement>()
// 定时器
let timer: number | null = null
// 星期几
const weekDay = ref('')
// 图表实例
let barChartInstance: echarts.ECharts | null = null
let powerChartInstance: echarts.ECharts | null = null
let envChartInstance: echarts.ECharts | null = null
let waterChartInstance: echarts.ECharts | null = null
let deviceChartInstance: echarts.ECharts | null = null
let pie3dChartInstance: any = null
// 退出方法
const logout = () => {
router.push('/navigation')
}
// 更新时间
const updateTime = () => {
const now = new Date()
const time = now.toLocaleTimeString('zh-CN', { hour12: false })
const date = now.getFullYear() + '.' +
String(now.getMonth() + 1).padStart(2, '0') + '.' +
String(now.getDate()).padStart(2, '0')
// 获取星期几
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
weekDay.value = '星期' + weekDays[now.getDay()]
const timeElement = document.getElementById('time')
const dateElement = document.getElementById('date')
if (timeElement) timeElement.innerText = time
if (dateElement) dateElement.innerText = date
}
// 初始化柱状图
const initBarChart = () => {
if (!barChart.value) return
const chart = echarts.init(barChart.value)
const option = getThreeDBarOption({
xData: ['A区', 'B区', 'C区', 'D区'],
yData: [320, 452, 688, 400]
})
chart.setOption(option)
barChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化电力图表
const initPowerChart = () => {
if (!powerChart.value) return
const chart = echarts.init(powerChart.value)
const option = {
tooltip: { trigger: 'axis' },
grid: { left: 40, right: 20, top: 40, bottom: 30 },
xAxis: {
type: 'category',
data: Array.from({length: 19}, (_, i) => i + 6),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
name: '',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [{
data: [80, 120, 100, 130, 150, 180, 200, 220, 250, 285, 230, 200, 180, 150, 120, 100, 80, 60, 40],
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 0,
itemStyle: { color: '#3ec6ff' },
lineStyle: { width: 1 },
areaStyle: { color: new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#32B7E9' },
{ offset: 1, color: 'rgba(50,183,233,0)' }
]
), }
}]
}
chart.setOption(option)
powerChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化环境图表
const initEnvChart = () => {
if (!envChart.value) return
const chart = echarts.init(envChart.value)
const option = {
tooltip: { trigger: 'axis' },
grid: { left: 40, right: 20, top: 10, bottom: 20 },
xAxis: {
type: 'category',
data: Array.from({length: 8}, (_, i) => (i+1)*3),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [
{
name: '今年',
data: [100, 200, 150, 300, 250, 200, 100, 80],
type: 'line',
smooth: true,
itemStyle: { color: '#b388ff' },
lineStyle: { width: 3 },
areaStyle: { color: 'rgba(179,136,255,0.2)' },
symbol: 'circle',
symbolSize: 0,
},
{
name: '去年',
data: [80, 120, 100, 180, 150, 120, 60, 40],
type: 'line',
smooth: true,
itemStyle: { color: '#ffb300' },
lineStyle: { width: 3 },
areaStyle: { color: 'rgba(255,179,0,0.15)' },
symbol: 'circle',
symbolSize: 0,
}
]
}
chart.setOption(option)
envChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化水表图表
const initWaterChart = () => {
if (!waterChart.value) return
const chart = echarts.init(waterChart.value)
const option = {
tooltip: { trigger: 'axis' },
legend: {
data: ['今日', '平均'],
textStyle: { color: '#fff' },
right: 20,
top: 10,
bottom: 10
},
grid: { left: 40, right: 20, top: 40, bottom: 30 },
xAxis: {
type: 'category',
data: Array.from({length: 19}, (_, i) => i + 6),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [
{
name: '今日',
data: [1.2, 2.1, 1.8, 2.5, 3.0, 3.8, 4.2, 4.5, 4.8, 4.8, 4.0, 3.2, 2.5, 2.0, 1.5, 1.0, 0.8, 0.5, 0.2],
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 0,
itemStyle: { color: '#3ec6ff' },
lineStyle: { width: 1 },
areaStyle: { color: new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#32B7E9' },
{ offset: 1, color: 'rgba(50,183,233,0)' }
]
), }
},
{
name: '平均',
data: Array(19).fill(2.5),
type: 'line',
smooth: true,
symbol: 'none',
itemStyle: { color: '#ff6b00' },
lineStyle: { width: 1, type: 'solid', color: '#ff6b00' }
}
]
}
chart.setOption(option)
waterChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化设备图表
const initDeviceChart = () => {
if (!deviceChart.value) return
const chart = echarts.init(deviceChart.value)
const option = {
grid: { left: 60, right: 40, top: 10, bottom: 30 },
xAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#8697BA' } },
axisLabel: { color: '#fff' },
splitLine: { show: false }
},
yAxis: {
type: 'category',
data: ['门禁', '监控', '水表'],
axisLine: { lineStyle: { color: '#8697BA' } },
axisLabel: { color: '#A1B2C2' }
},
series: [
{
name: '设备数',
type: 'bar',
data: [650, 120, 40],
barWidth: 12,
itemStyle: {
color: function(params: any) {
const colors = [
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#2986B1' },
{ offset: 1, color: '#6941FF' }
]
),
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#33FF99' },
{ offset: 1, color: '#00908E' }
]
),
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#01B4FF' },
{ offset: 1, color: '#0336FF' }
]
),
];
return colors[params.dataIndex]
}
},
label: {
show: true,
position: 'right',
color: '#fff'
}
}
]
}
chart.setOption(option)
deviceChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化3D饼图
const initPie3DChart = () => {
if (!pie3dChart.value) return
pie3dChartInstance = renderPie3DChart(pie3dChart.value, {
data: [
{ name: 'A区域', value: 20, itemStyle: { color: '#3ffbff' } },
{ name: 'D区域', value: 20, itemStyle: { color: '#b388ff' } },
{ name: 'C区域', value: 45, itemStyle: { color: '#ff9900' } },
{ name: 'B区域', value: 15, itemStyle: { color: '#3f6bff' } },
],
hoverHeightScale: 2,
selectOffset: 0.1,
distance: 220,
boxHeight: 5
})
if (pie3dChartInstance) {
addChartToResizeManager(pie3dChartInstance)
}
}
// 组件挂载时初始化
onMounted(() => {
updateTime()
timer = setInterval(updateTime, 1000)
initBarChart()
initPowerChart()
initEnvChart()
initWaterChart()
initDeviceChart()
initPie3DChart()
})
// 组件卸载时清理
onBeforeUnmount(() => {
if (timer) {
clearInterval(timer)
}
// 从管理器中移除图表
if (barChartInstance) {
removeChartFromResizeManager(barChartInstance)
barChartInstance.dispose()
}
if (powerChartInstance) {
removeChartFromResizeManager(powerChartInstance)
powerChartInstance.dispose()
}
if (envChartInstance) {
removeChartFromResizeManager(envChartInstance)
envChartInstance.dispose()
}
if (waterChartInstance) {
removeChartFromResizeManager(waterChartInstance)
waterChartInstance.dispose()
}
if (deviceChartInstance) {
removeChartFromResizeManager(deviceChartInstance)
deviceChartInstance.dispose()
}
if (pie3dChartInstance) {
removeChartFromResizeManager(pie3dChartInstance)
pie3dChartInstance.dispose()
}
})
</script>
<style scoped>
.mian{
height: 100vh;
background: url("../../../assets/energyConsumptionAnalysis/bg.png");
background-size: 100% 100%;
background-color: #081b3a;
display: flex;
flex-direction: column;
}
.title {
height: 5.375rem;
align-items: center;
display: flex;
justify-content: space-between;
.left{
display: flex;
width: 14.3125rem;
.left-first{
padding-left: 2.3125rem;
padding-right: 3.5rem;
font-size: 1.875rem;
color: #FFFFFF;
}
.left-second{
width: 6.5rem;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.25rem;
color: #FFFFFF;
}
}
.center{
font-size: 1.9rem;
color: #fff;
text-align: center;
font-weight: bold;
letter-spacing: 0.1em;
text-shadow: 0 0 10px #1e90ff, 0 0 20px #1e90ff;
}
.right{
width: 17.3125rem;
display: flex;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.25rem;
color: #FFFFFF;
gap: .75rem;
.logout{
display: flex;
cursor: pointer;
align-items: center;
gap: .2rem;
}
}
}
.header{
/* margin-top: 1.125rem; */
margin-left: 4.625rem;
margin-right: 4.25rem;
height: 4.4rem;
display: flex;
justify-content: space-between;
.header-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0 1.5rem;
border-radius: 0.5rem;
box-shadow: 0 0 10px #0ff2, 0 0 20px #0ff2 inset;
}
.header-label {
color: #fff;
font-size: 1rem;
margin-right: 0.5rem;
letter-spacing: 0.05em;
}
.header-value {
font-size: 1.5rem;
font-weight: bold;
margin: 0 0.2rem;
}
.header-value.orange { color: #ffb300; }
.header-value.green { color: #00ffb0; }
.header-value.blue { color: #3ec6ff; }
.header-value.purple { color: #b388ff; }
.header-unit {
color: #fff;
font-size: 1rem;
margin-left: 0.2rem;
}
}
.header div{
width: 20.125rem;
}
.content{
flex:1;
height: 100%;
display: flex;
justify-content: space-between;
margin: 0 2.25rem 2.25rem 2.25rem;
.content-left{
width: 32.6875rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.first{
height: 13.9rem;
.first-total{
display: flex;
justify-content: flex-end;
align-items: center;
padding: 1rem 1rem 0 0;
font-size: 1.12rem;
color: #89EAFF;
.first-total-title{
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 1.12rem;
line-height: 1rem;
}
.first-total-value{
display: flex;
align-items: center;
.first-total-value-number{
font-family: Microsoft YaHei;
font-weight: bold;
font-size: 1.3rem;
color: #89EAFF;
line-height: 1rem;
padding: .3rem;
margin: 0 .1rem;
border: .02rem solid rgba(99,145,180,0.59);
}
}
}
}
.second{
height: 12.5rem;
/* margin-top:2.25rem;
margin-bottom: 2rem; */
.power-chart {
height: 100%;
margin-top: 0.2rem;
}
}
.third{
height: 16rem;
display: flex;
flex-direction: column;
/* justify-content: space-around; */
.env-cards {
display: flex;
justify-content: space-between;
margin-top: 5rem;
margin-left: 1rem;
margin-right: 1.1rem;
.env-card {
width: 6.9rem;
height: 3.2rem;
border-radius: 0.5rem;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
.env-card-content{
.env-title {
font-size: .9rem;
font-weight: 400;
color: #4CE2D1;
}
.env-value {
font-size: .8rem;
font-weight: bold;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
color: #FFFFFF;
}
}
}
}
.env-chart {
height: 8rem;
}
}
}
.content-center{
width: 47.5rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.content-center-first{
height: 31.9rem;
.first-item{
height: 100%;
width: 100%;
background: url("../../../assets/energyConsumptionAnalysis/center-bg.png");
background-size: 95% 95%;
background-repeat: no-repeat;
background-position: center;
}
}
.content-center-second{
height: 12.5rem;
.second-item{
margin-top: 6rem;
margin-left: 3.68rem;
margin-bottom: 6.5rem;
margin-right: 4.9rem;
display: flex;
justify-content: space-between;
.second-item-text{
width: 5.37rem;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
text-align: center;
}
}
}
}
.content-right{
width: 32.68rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.first{
height: 14.9rem;
.first-total{
display: flex;
justify-content: flex-end;
align-items: center;
padding: 1rem 1rem 0 0;
font-size: 1.12rem;
color: #89EAFF;
.first-total-title{
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 1.12rem;
line-height: 1rem;
}
.first-total-value{
display: flex;
align-items: center;
.first-total-value-number{
font-family: Microsoft YaHei;
font-weight: bold;
font-size: 1.3rem;
color: #89EAFF;
line-height: 1rem;
padding: .3rem;
margin: 0 .1rem;
border: .02rem solid rgba(99,145,180,0.59);
}
}
}
}
.second{
height: 12.5rem;
/* margin-top:2.25rem;
margin-bottom: 2rem; */
.water-chart {
height: 100%;
margin-top: 0.2rem;
}
}
.third{
height: 14rem;
.device-cards {
display: flex;
justify-content: space-between;
margin-top: 2rem;
margin-right: 1.06rem;
/* margin-bottom: 0.5rem; */
margin-left: 1.31rem;
.device-card1{
height: 3.2rem;
width: 7.21rem;
background: url("../../../assets/energyConsumptionAnalysis/devices-number.png");
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
.device-card1-value{
font-family: Arial;
font-weight: bold;
font-size: 1.25rem;
color: #02B3F4;
}
}
.device-card2{
height: 3.2rem;
width: 7.21rem;
background: url("../../../assets/energyConsumptionAnalysis/devices-online.png");
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
.device-card2-value{
font-family: Arial;
font-weight: bold;
font-size: 1.25rem;
color: #1DE39D;
}
}
.device-card3{
height: 3.2rem;
width: 7.21rem;
background: url("../../../assets/energyConsumptionAnalysis/devices-offline.png");
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
.device-card3-value{
font-family: Arial;
font-weight: bold;
font-size: 1.25rem;
color: #F19315;
}
}
.device-card-text{
font-family: Microsoft YaHei UI;
font-weight: 400;
font-size: 0.75rem;
color: #A1B2C2;
line-height: 0.75rem;
}
}
.device-chart {
height: 8rem;
/* margin-top: 0.2rem; */
}
}
}
}
.pie3d-title {
color: #fff;
font-size: 1.1rem;
font-weight: bold;
margin-bottom: 0.3rem;
}
.pie3d-water {
color: #fff;
font-size: 0.95rem;
margin-bottom: 0.2rem;
}
.pie3d-water-num {
font-size: 1.3rem;
color: #3ec6ff;
background: #0a1e3a;
border-radius: 0.2rem;
padding: 0 0.2rem;
margin: 0 0.2rem;
letter-spacing: 0.1em;
}
.pie3d-chart {
width: 100%;
height: 176px;
min-height: unset;
margin: 0 auto;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,307 @@
<template>
<div class="navigation-bg">
<div class="navigation-head">
<div class="navigation-head-left">超级管理员 欢迎你</div>
<div class="navigation-head-center">南川区综合服务中心数智平台</div>
<div class="navigation-head-right" @click="logout">
<span>
<!-- <img src="../../../assets/return.png" alt="退出"> -->
退出
</span>
</div>
</div>
<div class="navigation-body">
<div class="navigation-body-left">
<div @click="goToProperty()">基础物业</div>
<div @click="goToEnergyAnalysis()">能耗分析</div>
<div @click="goToSecurity()">安防大屏</div>
<div @click="goToMonitor()">监控大屏</div>
</div>
<div class="navigation-body-center">
<div class="top-content">
<div class="top-content-text1"><div class="text1">数据管理</div></div>
<div class="top-content-text2"><div class="text1">运行监控</div></div>
<div class="top-content-text3"><div class="text1">信息管理</div></div>
<div class="top-content-text4"><div class="text1">配置管理</div></div>
<div class="top-content-text5"><div class="text1">登录管理</div></div>
<div class="top-content-text6"><div class="text1">驾驶舱</div></div>
</div>
<div class="bottom-content">
<div class="bottom-content-text1"><div class="text">数字建模</div></div>
<div class="bottom-content-text2"><div class="text">指挥中心</div></div>
<div class="bottom-content-text3"><div class="text">软件支撑</div></div>
<div class="bottom-content-text4"><div class="text">应用管理</div></div>
<div class="bottom-content-text5"><div class="text">数据管理</div></div>
</div>
</div>
<div class="navigation-body-right">
<div @click="goToDigitalIntelligence()">商务中心</div>
<div @click="goToHome()">后台管理</div>
<div>能源管理</div>
<div>能耗分析</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { preferences } from '@vben/preferences';
const router = useRouter()
// 退出方法
const logout = () => {
// 这里可以添加清除 token、重定向登录页等逻辑
console.log('用户退出')
router.push('/login') // 假设登录页面路径为 /login
}
//物业
const goToProperty = () => {
router.push('/property')
}
//能耗分析
const goToEnergyAnalysis = () => {
router.push('/energyAnalysis')
}
// 监控大屏
const goToSecurity = () => {
router.push('/security')
}
// 监控大屏
const goToMonitor = () => {
router.push('/monitor')
}
// 商务中心数智管理平台
const goToDigitalIntelligence = () => {
router.push('/digitalIntelligence')
}
//
const goToHome = () => {
router.push(preferences.app.defaultHomePath);
}
</script>
<style scoped>
.navigation-bg {
height: 100vh;
width: 100vw;
text-align: center;
background: url("../../../assets/navigation.png");
background-size: 100% 100%;
color: #fff;
text-shadow: 0 0.125rem 0.5rem #000;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.navigation-head {
display: flex;
align-items: center;
flex-wrap: wrap;
height: 3.5rem;
}
.navigation-head-center{
font-size: 1.9rem;
color: #fff;
text-align: center;
font-weight: bold;
letter-spacing: 0.1em;
}
.navigation-head-left,
.navigation-head-right {
flex: 1 1 100%;
text-align: center;
cursor: pointer;
font-size: 1rem;
padding-left: 1.3rem;
padding-right: 1.3rem;
}
@media (min-width: 48em) {
.navigation-head-left {
flex: 1;
text-align: left;
font-size: 0.875rem;
padding-left: 1.3rem;
}
.navigation-head-center {
flex: 3;
font-size: 1.5rem;
text-align: center;
}
.navigation-head-right {
flex: 1;
text-align: right;
font-size: 0.875rem;
padding-right: 1.3rem;
}
}
.navigation-body {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
}
.navigation-body-left {
width: 12%;
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 2.25rem 1.25rem;
height: 35rem;
}
.navigation-body-left div {
background: url("../../../assets/shine.png") no-repeat center;
background-size: contain;
font-size: 1rem;
padding: 0.625rem 1.25rem;
min-width: 7.5rem;
max-width: 100%;
transition: transform 0.2s ease;
cursor: pointer;
color: #77DAFF;
}
.navigation-body-left div:hover {
color: #ffffff;
background-image: url("../../../assets/shine-lines.png");
}
.navigation-body-center{
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.top-content{
height: 70%;
padding-top: 26rem;
padding-left: 19.5rem;
padding-right: 20rem;
display: flex;
justify-content: space-between;
.top-content-text1{
font-size: 1.0625rem;
width: 4.6875rem;
height: 7.5rem;
padding-top: 0.5rem;
color: #86B6E6;
cursor: pointer;
}
.top-content-text2{
font-size: 1.0625rem;
font-weight: 600;
width: 4.6875rem;
height: 7.5rem;
padding-top: 1.25rem;
color: #86ECDE;
cursor: pointer;
}
.top-content-text3{
font-size: 1.0625rem;
font-weight: 600;
width: 4.6875rem;
height: 7.5rem;
padding-top: 2.5rem;
color: #FECFB4;
cursor: pointer;
}
.top-content-text4{
font-size: 1.0625rem;
font-weight: 600;
width: 4.6875rem;
height: 7.5rem;
padding-top: 2.625rem;
color: #CDADF4;
cursor: pointer;
}
.top-content-text5{
font-size: 1.0625rem;
font-weight: 600;
width: 4.6875rem;
height: 7.5rem;
padding-top: 1.5625rem;
color: #86ECDE;
cursor: pointer;
}
.top-content-text6{
font-size: 1.0625rem;
font-weight: 600;
width: 4.6875rem;
height: 7.5rem;
padding-top: 1.25rem;
color: #86B6E6;
cursor: pointer;
}
.text1{
padding: 0.3125rem 1.875rem;
}
}
.bottom-content{
height: 50%;
display: flex;
justify-content: space-between;
padding-top: 12.5rem;
padding-left: 23.625rem;
padding-right: 24.25rem;
font-size: 1rem;
color: #00EEFD;
.bottom-content-text1{
width: 6.875rem;
cursor: pointer;
}
.bottom-content-text2{
padding-top: 0.75rem;
width: 6.875rem;
cursor: pointer;
}
.bottom-content-text3{
padding-top: 1.125rem;
width: 6.875rem;
cursor: pointer;
}
.bottom-content-text4{
padding-top: 0.8125rem;
width: 6.875rem;
cursor: pointer;
}
.bottom-content-text5{
width: 6.875rem;
cursor: pointer;
}
.text{
align-items: center;
}
}
.navigation-body-right{
width: 12%;
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 2.25rem 1.25rem;
height: 35rem;
}
.navigation-body-right div {
background: url("../../../assets/shine.png") no-repeat center;
background-size: contain;
font-size: 1rem;
padding: 0.625rem 1.25rem;
min-width: 7.5rem;
max-width: 100%;
transition: transform 0.2s ease;
cursor: pointer;
color: #77DAFF;
}
.navigation-body-right div:hover {
background-image: url("../../../assets/shine-lines.png");
color: #ffffff;
}
</style>

View File

@@ -0,0 +1,804 @@
<template>
<div class="mian">
<div class="title">
<div class="left">
<div class="left-first" id="time">--:--:--</div>
<div class="left-second" id="date">----</div>
</div>
<div class="center">南川区综合服务中心数智管理平台物业大屏</div>
<div class="right">
<div>{{ weekDay }}</div>
<div></div>
<div>40</div>
<div class="logout" @click="logout">
<img src="../../../assets/return.png" style="width: 1.5rem; height: 1.5rem;">
<div>
退出
</div>
</div>
</div>
</div>
<div class="header">
<div class="header-item">
<span class="header-label">今年用电量</span>
<span class="header-value orange">180</span>
<span class="header-unit">亿kwh</span>
</div>
<div class="header-item">
<span class="header-label">本月用电总量</span>
<span class="header-value green">1.8</span>
<span class="header-unit">亿kwh</span>
</div>
<div class="header-item">
<span class="header-label">今年用水总量</span>
<span class="header-value blue">2600</span>
<span class="header-unit">万吨</span>
</div>
<div class="header-item">
<span class="header-label">本月用水总量</span>
<span class="header-value purple">30</span>
<span class="header-unit">万吨</span>
</div>
<div class="header-item">
<span class="header-label">设备总数</span>
<span class="header-value green">500</span>
<span class="header-unit"></span>
</div>
</div>
<div class="contents">
<div class="content">
<div class="content-left">
<div class="first">
<div ref="barChart" class="bar-chart" style="width:100%;height:100%;"></div>
</div>
<div class="second">
<div ref="powerChart" class="power-chart"></div>
</div>
<div class="third">
<div ref="envChart" class="env-chart"></div>
</div>
</div>
<div class="content-center">
<div class="content-center-first">
<div class="first-item">
<div class="item"></div>
</div>
</div>
<div class="content-center-second">
<div class="second-item">
<div class="second-item-box1">645</div>
<div class="second-item-box2">729</div>
<div class="second-item-box3">648</div>
<div class="second-item-box4">786</div>
<div class="second-item-box5">645</div>
</div>
</div>
</div>
<div class="content-right">
<div class="first">
<div ref="waterChart" class="water-chart"></div>
<!-- <div ref="pie3dChart" class="pie3d-chart"></div> -->
</div>
<div class="second">
<div class="second-box">
<div class="box-content">
<div class="box-content-label">服务数量</div>
<div class="box-content-num">132</div>
</div>
<div class="box-content">
<div class="box-content-label">服务数量</div>
<div class="box-content-num">862</div>
</div>
<div class="box-content">
<div class="box-content-label">服务数量</div>
<div class="box-content-num">272</div>
</div>
</div>
<!-- <div ref="waterChart" class="water-chart"></div> -->
</div>
<div class="third">
<div ref="deviceChart" class="device-chart"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
import 'echarts-gl'
import { getThreeDBarOption } from '#/utils/threeDBarOption'
import { renderPie3DChart } from '#/utils/pie3d'
import { addChartToResizeManager, removeChartFromResizeManager } from '#/utils/echartsResize'
// 路由
const router = useRouter()
// 图表实例
const barChart = ref<HTMLElement>()
const powerChart = ref<HTMLElement>()
const envChart = ref<HTMLElement>()
const waterChart = ref<HTMLElement>()
const deviceChart = ref<HTMLElement>()
const pie3dChart = ref<HTMLElement>()
// 定时器
let timer: number | null = null
// 星期几
const weekDay = ref('')
// 图表实例
let barChartInstance: echarts.ECharts | null = null
let powerChartInstance: echarts.ECharts | null = null
let envChartInstance: echarts.ECharts | null = null
let waterChartInstance: echarts.ECharts | null = null
let deviceChartInstance: echarts.ECharts | null = null
let pie3dChartInstance: any = null
// 退出方法
const logout = () => {
router.push('/navigation')
}
// 更新时间
const updateTime = () => {
const now = new Date()
const time = now.toLocaleTimeString('zh-CN', { hour12: false })
const date = now.getFullYear() + '.' +
String(now.getMonth() + 1).padStart(2, '0') + '.' +
String(now.getDate()).padStart(2, '0')
// 获取星期几
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
weekDay.value = '星期' + weekDays[now.getDay()]
const timeElement = document.getElementById('time')
const dateElement = document.getElementById('date')
if (timeElement) timeElement.innerText = time
if (dateElement) dateElement.innerText = date
}
// 初始化柱状图
const initBarChart = () => {
if (!barChart.value) return
const chart = echarts.init(barChart.value)
const option = getThreeDBarOption({
xData: ['A区', 'B区', 'C区', 'D区'],
yData: [320, 452, 688, 400]
})
chart.setOption(option)
barChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化电力图表
const initPowerChart = () => {
if (!powerChart.value) return
const chart = echarts.init(powerChart.value)
const option = {
tooltip: { trigger: 'axis' },
grid: { left: 40, right: 20, top: 32, bottom: 20 },
xAxis: {
type: 'category',
data: Array.from({length: 19}, (_, i) => i + 6),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
name: '',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [{
data: [80, 120, 100, 130, 150, 180, 200, 220, 250, 285, 230, 200, 180, 150, 120, 100, 80, 60, 40],
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 0,
itemStyle: { color: '#3ec6ff' },
lineStyle: { width: 1 },
areaStyle: { color: new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#32B7E9' },
{ offset: 1, color: 'rgba(50,183,233,0)' }
]
), }
}]
}
chart.setOption(option)
powerChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化环境图表
const initEnvChart = () => {
if (!envChart.value) return
const chart = echarts.init(envChart.value)
const option = {
tooltip: { trigger: 'axis' },
grid: { left: 40, right: 20, top: 40, bottom: 30 },
xAxis: {
type: 'category',
data: Array.from({length: 8}, (_, i) => (i+1)*3),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [
{
name: '今年',
data: [100, 200, 150, 300, 250, 200, 100, 80],
type: 'line',
smooth: true,
itemStyle: { color: '#b388ff' },
lineStyle: { width: 3 },
areaStyle: { color: 'rgba(179,136,255,0.2)' },
symbol: 'circle',
symbolSize: 0,
},
{
name: '去年',
data: [80, 120, 100, 180, 150, 120, 60, 40],
type: 'line',
smooth: true,
itemStyle: { color: '#ffb300' },
lineStyle: { width: 3 },
areaStyle: { color: 'rgba(255,179,0,0.15)' },
symbol: 'circle',
symbolSize: 0,
}
]
}
chart.setOption(option)
envChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化水表图表
const initWaterChart = () => {
if (!waterChart.value) return
const chart = echarts.init(waterChart.value)
const option = {
tooltip: { trigger: 'axis' },
legend: {
data: ['今日', '平均'],
textStyle: { color: '#fff' },
right: 20,
top: 10
},
grid: { left: 40, right: 20, top: 40, bottom: 30 },
xAxis: {
type: 'category',
data: Array.from({length: 19}, (_, i) => i + 6),
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#3ec6ff' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1e90ff22' } }
},
series: [
{
name: '今日',
data: [1.2, 2.1, 1.8, 2.5, 3.0, 3.8, 4.2, 4.5, 4.8, 4.8, 4.0, 3.2, 2.5, 2.0, 1.5, 1.0, 0.8, 0.5, 0.2],
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 0,
itemStyle: { color: '#3ec6ff' },
lineStyle: { width: 1 },
areaStyle: { color: new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#32B7E9' },
{ offset: 1, color: 'rgba(50,183,233,0)' }
]
), }
},
{
name: '平均',
data: Array(19).fill(2.5),
type: 'line',
smooth: true,
symbol: 'none',
itemStyle: { color: '#ff6b00' },
lineStyle: { width: 1, type: 'solid', color: '#ff6b00' }
}
]
}
chart.setOption(option)
waterChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化设备图表
const initDeviceChart = () => {
if (!deviceChart.value) return
const chart = echarts.init(deviceChart.value)
const option = {
grid: { left: 60, right: 40, top: 10, bottom: 30 },
xAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#8697BA' } },
axisLabel: { color: '#fff' },
splitLine: { show: false }
},
yAxis: {
type: 'category',
data: ['门禁', '监控', '水表'],
axisLine: { lineStyle: { color: '#8697BA' } },
axisLabel: { color: '#A1B2C2' }
},
series: [
{
name: '设备数',
type: 'bar',
data: [650, 120, 40],
barWidth: 12,
itemStyle: {
color: function(params: any) {
const colors = [
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#2986B1' },
{ offset: 1, color: '#6941FF' }
]
),
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#33FF99' },
{ offset: 1, color: '#00908E' }
]
),
new echarts.graphic.LinearGradient(
0, 0, 0, 1, // 上→下
[
{ offset: 0, color: '#01B4FF' },
{ offset: 1, color: '#0336FF' }
]
),
];
return colors[params.dataIndex]
}
},
label: {
show: true,
position: 'right',
color: '#fff'
}
}
]
}
chart.setOption(option)
deviceChartInstance = chart
addChartToResizeManager(chart)
}
// 初始化3D饼图
const initPie3DChart = () => {
if (!pie3dChart.value) return
pie3dChartInstance = renderPie3DChart(pie3dChart.value, {
data: [
{ name: 'A区域', value: 20, itemStyle: { color: '#3ffbff' } },
{ name: 'D区域', value: 20, itemStyle: { color: '#b388ff' } },
{ name: 'C区域', value: 45, itemStyle: { color: '#ff9900' } },
{ name: 'B区域', value: 15, itemStyle: { color: '#3f6bff' } },
],
hoverHeightScale: 2,
selectOffset: 0.1,
distance: 220,
boxHeight: 5
})
if (pie3dChartInstance) {
addChartToResizeManager(pie3dChartInstance)
}
}
// 组件挂载时初始化
onMounted(() => {
updateTime()
timer = setInterval(updateTime, 1000)
initBarChart()
initPowerChart()
initEnvChart()
initWaterChart()
initDeviceChart()
initPie3DChart()
})
// 组件卸载时清理
onBeforeUnmount(() => {
if (timer) {
clearInterval(timer)
}
// 从管理器中移除图表
if (barChartInstance) {
removeChartFromResizeManager(barChartInstance)
barChartInstance.dispose()
}
if (powerChartInstance) {
removeChartFromResizeManager(powerChartInstance)
powerChartInstance.dispose()
}
if (envChartInstance) {
removeChartFromResizeManager(envChartInstance)
envChartInstance.dispose()
}
if (waterChartInstance) {
removeChartFromResizeManager(waterChartInstance)
waterChartInstance.dispose()
}
if (deviceChartInstance) {
removeChartFromResizeManager(deviceChartInstance)
deviceChartInstance.dispose()
}
if (pie3dChartInstance) {
removeChartFromResizeManager(pie3dChartInstance)
pie3dChartInstance.dispose()
}
})
</script>
<style scoped>
.mian{
height: 100vh;
background: url("../../../assets/property/bg.png");
background-size: 100% 100%;
background-color: #081b3a;
display: flex;
flex-direction: column;
}
.title {
height: 5.375rem;
align-items: center;
display: flex;
justify-content: space-between;
.left{
display: flex;
width: 14.3125rem;
.left-first{
padding-left: 2.3125rem;
padding-right: 3.5rem;
font-size: 1.875rem;
color: #FFFFFF;
}
.left-second{
width: 6.5rem;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.25rem;
color: #FFFFFF;
}
}
.center{
font-size: 1.9rem;
color: #fff;
text-align: center;
font-weight: bold;
letter-spacing: 0.1em;
text-shadow: 0 0 10px #1e90ff, 0 0 20px #1e90ff;
}
.right{
width: 17.3125rem;
display: flex;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.25rem;
color: #FFFFFF;
gap: .75rem;
.logout{
display: flex;
cursor: pointer;
align-items: center;
gap: .2rem;
}
}
}
.header{
margin-top: 1.125rem;
margin-left: 4.625rem;
margin-right: 4.25rem;
height: 6rem;
display: flex;
justify-content: space-between;
.header-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0 1.5rem;
border-radius: 0.5rem;
box-shadow: 0 0 10px #0ff2, 0 0 20px #0ff2 inset;
}
.header-label {
color: #fff;
font-size: 1rem;
margin-right: 0.5rem;
letter-spacing: 0.05em;
}
.header-value {
font-size: 1.5rem;
font-weight: bold;
margin: 0 0.2rem;
}
.header-value.orange { color: #ffb300; }
.header-value.green { color: #00ffb0; }
.header-value.blue { color: #3ec6ff; }
.header-value.purple { color: #b388ff; }
.header-unit {
color: #fff;
font-size: 1rem;
margin-left: 0.2rem;
}
}
.header div{
width: 20.125rem;
}
.contents{
flex: 1;
.content{
height: 100%;
display: flex;
justify-content: space-between;
margin: 0 2.25rem 2.25rem 2.25rem;
.content-left{
width: 32.6875rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.first{
height: 16.81rem;
.pie3d-title {
color: #fff;
font-size: 1.1rem;
font-weight: bold;
margin-bottom: 0.3rem;
}
.pie3d-water {
color: #fff;
font-size: 0.95rem;
margin-bottom: 0.2rem;
}
.pie3d-water-num {
font-size: 1.3rem;
color: #3ec6ff;
background: #0a1e3a;
border-radius: 0.2rem;
padding: 0 0.2rem;
margin: 0 0.2rem;
letter-spacing: 0.1em;
}
.pie3d-chart {
width: 100%;
height: 176px;
min-height: unset;
margin: 0 auto;
}
}
.second{
height: 12rem;
/* margin-top:2.25rem; */
/* margin-bottom: 2rem; */
.power-chart {
height: 100%;
/* margin-top: 0.2rem; */
}
}
.third{
height: 12.12rem;
.env-chart {
height: 12rem;
}
}
}
.content-center{
width: 47.5rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.content-center-first{
height: 30.9rem;
.first-item{
height: 100%;
width: 100%;
background: url("../../../assets/property/center-bg.png");
background-size: 95% 95%;
background-repeat: no-repeat;
background-position: center;
}
}
.content-center-second{
display: flex;
justify-content: center;
align-items: center;
height: 12.5rem;
.second-item{
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
.second-item-box1{
width: 7rem;
height: 7rem;
display: flex;
justify-content: center;
align-items: center;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
background: url("../../../assets/property/personnel-duty-circle1.png");
background-size: 100% 100%;
}
.second-item-box2{
width: 7rem;
height: 7rem;
display: flex;
justify-content: center;
align-items: center;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
background: url("../../../assets/property/personnel-duty-circle2.png");
background-size: 100% 100%;
}
.second-item-box3{
width: 7rem;
height: 7rem;
display: flex;
justify-content: center;
align-items: center;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
background: url("../../../assets/property/personnel-duty-circle3.png");
background-size: 100% 100%;
}
.second-item-box4{
width: 7rem;
height: 7rem;
display: flex;
justify-content: center;
align-items: center;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
background: url("../../../assets/property/personnel-duty-circle1.png");
background-size: 100% 100%;
}
.second-item-box5{
width: 7rem;
height: 7rem;
display: flex;
justify-content: center;
align-items: center;
font-family: ShiShangZhongHeiJianTi;
font-weight: 400;
font-size: 1.37rem;
color: #FFFFFF;
background: url("../../../assets/property/personnel-duty-circle4.png");
background-size: 100% 100%;
}
}
}
}
.content-right{
width: 32.68rem;
display: flex;
flex-direction: column;
justify-content: space-between;
.first{
height: 16.81rem;
.water-chart {
height: 100%;
/* margin-top: 0.2rem; */
}
}
.second{
height: 11rem;
margin-top:2rem;
margin-bottom: 2rem;
.second-box{
margin-top: 2rem;
display: flex;
justify-content: space-around;
align-items: center;
.box-content{
height: 8rem;
width: 8rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.box-content-label{
font-family: Microsoft YaHei;
font-weight: 400;
font-size: .8rem;
color: #C4D6FF;
line-height: 2rem;
}
.box-content-num{
display: flex;
justify-content: center;
align-items: center;
width: 6rem;
height: 6rem;
background: url("../../../assets/property/customer-circle.png");
background-size: 100% 100%;
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 1.2rem;
color: #FFFFFF;
}
}
}
}
.third{
height: 13.12rem;
.device-chart {
height: 10rem;
margin-top: 2rem;
}
}
}
}
}
.pie3d-title {
color: #fff;
font-size: 1.1rem;
font-weight: bold;
margin-bottom: 0.3rem;
}
.pie3d-water {
color: #fff;
font-size: 0.95rem;
margin-bottom: 0.2rem;
}
.pie3d-water-num {
font-size: 1.3rem;
color: #3ec6ff;
background: #0a1e3a;
border-radius: 0.2rem;
padding: 0 0.2rem;
margin: 0 0.2rem;
letter-spacing: 0.1em;
}
.pie3d-chart {
width: 100%;
height: 176px;
min-height: unset;
margin: 0 auto;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ export default defineConfig(async () => {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
// mock代理目标地址
target: 'http://192.168.43.169:8080',
target: 'http://192.168.1.101:8080',
// target: 'http://192.168.0.108:8080',
// target: 'http://192.168.0.106:8080',
// target: 'http://47.109.37.87:3010',