diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 8a0dc7bd..3d0ec1d3 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -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:", diff --git a/apps/web-antd/src/assets/digitalIntelligence/bg.png b/apps/web-antd/src/assets/digitalIntelligence/bg.png new file mode 100644 index 00000000..c0c998d5 Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/bg.png differ diff --git a/apps/web-antd/src/assets/digitalIntelligence/center-bg.png b/apps/web-antd/src/assets/digitalIntelligence/center-bg.png new file mode 100644 index 00000000..806c2197 Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/center-bg.png differ diff --git a/apps/web-antd/src/assets/digitalIntelligence/circle1.png b/apps/web-antd/src/assets/digitalIntelligence/circle1.png new file mode 100644 index 00000000..daa1236a Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/circle1.png differ diff --git a/apps/web-antd/src/assets/digitalIntelligence/circle2.png b/apps/web-antd/src/assets/digitalIntelligence/circle2.png new file mode 100644 index 00000000..ff2d166c Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/circle2.png differ diff --git a/apps/web-antd/src/assets/digitalIntelligence/circle3.png b/apps/web-antd/src/assets/digitalIntelligence/circle3.png new file mode 100644 index 00000000..bb325802 Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/circle3.png differ diff --git a/apps/web-antd/src/assets/digitalIntelligence/circle4.png b/apps/web-antd/src/assets/digitalIntelligence/circle4.png new file mode 100644 index 00000000..3d89c3b5 Binary files /dev/null and b/apps/web-antd/src/assets/digitalIntelligence/circle4.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/bg.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/bg.png new file mode 100644 index 00000000..40c8a453 Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/bg.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/center-bg.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/center-bg.png new file mode 100644 index 00000000..05a4bd1c Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/center-bg.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number-icon.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number-icon.png new file mode 100644 index 00000000..c549bc0f Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number-icon.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number.png new file mode 100644 index 00000000..6cfcb8af Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-number.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline-icon.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline-icon.png new file mode 100644 index 00000000..f3225017 Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline-icon.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline.png new file mode 100644 index 00000000..0fe6f7c6 Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-offline.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online-icon.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online-icon.png new file mode 100644 index 00000000..aea0f1aa Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online-icon.png differ diff --git a/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online.png b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online.png new file mode 100644 index 00000000..e1db3fcf Binary files /dev/null and b/apps/web-antd/src/assets/energyConsumptionAnalysis/devices-online.png differ diff --git a/apps/web-antd/src/assets/monitor/bg.png b/apps/web-antd/src/assets/monitor/bg.png new file mode 100644 index 00000000..65aebcd0 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/bg.png differ diff --git a/apps/web-antd/src/assets/monitor/device-alerts-bg1.png b/apps/web-antd/src/assets/monitor/device-alerts-bg1.png new file mode 100644 index 00000000..04f13394 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/device-alerts-bg1.png differ diff --git a/apps/web-antd/src/assets/monitor/device-alerts-bg2.png b/apps/web-antd/src/assets/monitor/device-alerts-bg2.png new file mode 100644 index 00000000..4158a9ec Binary files /dev/null and b/apps/web-antd/src/assets/monitor/device-alerts-bg2.png differ diff --git a/apps/web-antd/src/assets/monitor/device-alerts-bg3.png b/apps/web-antd/src/assets/monitor/device-alerts-bg3.png new file mode 100644 index 00000000..26197a77 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/device-alerts-bg3.png differ diff --git a/apps/web-antd/src/assets/monitor/device-alerts-button1.png b/apps/web-antd/src/assets/monitor/device-alerts-button1.png new file mode 100644 index 00000000..0fe6f7c6 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/device-alerts-button1.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor1.png b/apps/web-antd/src/assets/monitor/monitor1.png new file mode 100644 index 00000000..176098c4 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor1.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor2.png b/apps/web-antd/src/assets/monitor/monitor2.png new file mode 100644 index 00000000..710b230e Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor2.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor3.png b/apps/web-antd/src/assets/monitor/monitor3.png new file mode 100644 index 00000000..e8a3fde1 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor3.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor4.png b/apps/web-antd/src/assets/monitor/monitor4.png new file mode 100644 index 00000000..8100fd06 Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor4.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor5.png b/apps/web-antd/src/assets/monitor/monitor5.png new file mode 100644 index 00000000..1bba6f8e Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor5.png differ diff --git a/apps/web-antd/src/assets/monitor/monitor6.png b/apps/web-antd/src/assets/monitor/monitor6.png new file mode 100644 index 00000000..63fa17ca Binary files /dev/null and b/apps/web-antd/src/assets/monitor/monitor6.png differ diff --git a/apps/web-antd/src/assets/navigation/科技数据粒子上升蓝色.gif b/apps/web-antd/src/assets/navigation/科技数据粒子上升蓝色.gif new file mode 100644 index 00000000..84c21274 Binary files /dev/null and b/apps/web-antd/src/assets/navigation/科技数据粒子上升蓝色.gif differ diff --git a/apps/web-antd/src/assets/property/bg.png b/apps/web-antd/src/assets/property/bg.png new file mode 100644 index 00000000..f435684f Binary files /dev/null and b/apps/web-antd/src/assets/property/bg.png differ diff --git a/apps/web-antd/src/assets/property/center-bg.png b/apps/web-antd/src/assets/property/center-bg.png new file mode 100644 index 00000000..806c2197 Binary files /dev/null and b/apps/web-antd/src/assets/property/center-bg.png differ diff --git a/apps/web-antd/src/assets/property/customer-circle.png b/apps/web-antd/src/assets/property/customer-circle.png new file mode 100644 index 00000000..ed8cda48 Binary files /dev/null and b/apps/web-antd/src/assets/property/customer-circle.png differ diff --git a/apps/web-antd/src/assets/property/personnel-duty-circle1.png b/apps/web-antd/src/assets/property/personnel-duty-circle1.png new file mode 100644 index 00000000..c35e3c5f Binary files /dev/null and b/apps/web-antd/src/assets/property/personnel-duty-circle1.png differ diff --git a/apps/web-antd/src/assets/property/personnel-duty-circle2.png b/apps/web-antd/src/assets/property/personnel-duty-circle2.png new file mode 100644 index 00000000..80c1e6af Binary files /dev/null and b/apps/web-antd/src/assets/property/personnel-duty-circle2.png differ diff --git a/apps/web-antd/src/assets/property/personnel-duty-circle3.png b/apps/web-antd/src/assets/property/personnel-duty-circle3.png new file mode 100644 index 00000000..0de3f98b Binary files /dev/null and b/apps/web-antd/src/assets/property/personnel-duty-circle3.png differ diff --git a/apps/web-antd/src/assets/property/personnel-duty-circle4.png b/apps/web-antd/src/assets/property/personnel-duty-circle4.png new file mode 100644 index 00000000..d9165a3f Binary files /dev/null and b/apps/web-antd/src/assets/property/personnel-duty-circle4.png differ diff --git a/apps/web-antd/src/assets/security/bg.png b/apps/web-antd/src/assets/security/bg.png new file mode 100644 index 00000000..18a0b933 Binary files /dev/null and b/apps/web-antd/src/assets/security/bg.png differ diff --git a/apps/web-antd/src/assets/security/button1.png b/apps/web-antd/src/assets/security/button1.png new file mode 100644 index 00000000..0cf7c268 Binary files /dev/null and b/apps/web-antd/src/assets/security/button1.png differ diff --git a/apps/web-antd/src/assets/security/button2.png b/apps/web-antd/src/assets/security/button2.png new file mode 100644 index 00000000..7b2cad56 Binary files /dev/null and b/apps/web-antd/src/assets/security/button2.png differ diff --git a/apps/web-antd/src/assets/security/button3.png b/apps/web-antd/src/assets/security/button3.png new file mode 100644 index 00000000..132cfcf1 Binary files /dev/null and b/apps/web-antd/src/assets/security/button3.png differ diff --git a/apps/web-antd/src/assets/security/center-bg.png b/apps/web-antd/src/assets/security/center-bg.png new file mode 100644 index 00000000..4ea7a987 Binary files /dev/null and b/apps/web-antd/src/assets/security/center-bg.png differ diff --git a/apps/web-antd/src/assets/security/monitor1.png b/apps/web-antd/src/assets/security/monitor1.png new file mode 100644 index 00000000..0833a0fa Binary files /dev/null and b/apps/web-antd/src/assets/security/monitor1.png differ diff --git a/apps/web-antd/src/assets/security/monitor2.png b/apps/web-antd/src/assets/security/monitor2.png new file mode 100644 index 00000000..5bbd443a Binary files /dev/null and b/apps/web-antd/src/assets/security/monitor2.png differ diff --git a/apps/web-antd/src/assets/security/stop-icon.png b/apps/web-antd/src/assets/security/stop-icon.png new file mode 100644 index 00000000..6a9b7969 Binary files /dev/null and b/apps/web-antd/src/assets/security/stop-icon.png differ diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue index 49641fd1..4d5fee5d 100644 --- a/apps/web-antd/src/layouts/basic.vue +++ b/apps/web-antd/src/layouts/basic.vue @@ -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: '返回导航', + }, ]; /** * 租户选中状态 不显示个人中心 diff --git a/apps/web-antd/src/main.ts b/apps/web-antd/src/main.ts index f3228461..dd4b82e7 100644 --- a/apps/web-antd/src/main.ts +++ b/apps/web-antd/src/main.ts @@ -1,7 +1,7 @@ import { initPreferences } from '@vben/preferences'; import { unmountGlobalLoading } from '@vben/utils'; import { overridesPreferences } from './preferences'; - +import './utils/flexible' /** * 应用初始化完成之后再进行页面加载渲染 */ diff --git a/apps/web-antd/src/router/routes/core.ts b/apps/web-antd/src/router/routes/core.ts index 172f3d18..a966a897 100644 --- a/apps/web-antd/src/router/routes/core.ts +++ b/apps/web-antd/src/router/routes/core.ts @@ -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 }; diff --git a/apps/web-antd/src/store/auth.ts b/apps/web-antd/src/store/auth.ts index 9c819e3c..cdb33525 100644 --- a/apps/web-antd/src/store/auth.ts +++ b/apps/web-antd/src/store/auth.ts @@ -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) { diff --git a/apps/web-antd/src/utils/echartsResize.ts b/apps/web-antd/src/utils/echartsResize.ts new file mode 100644 index 00000000..6b175400 --- /dev/null +++ b/apps/web-antd/src/utils/echartsResize.ts @@ -0,0 +1,119 @@ +import type { ECharts } from 'echarts' + +/** + * ECharts 图表自适应管理器 + * 用于监听图表容器大小变化并自动调整图表大小 + */ +export class EChartsResizeManager { + private charts: Map = 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() +} \ No newline at end of file diff --git a/apps/web-antd/src/utils/flexible.ts b/apps/web-antd/src/utils/flexible.ts new file mode 100644 index 00000000..5040a06c --- /dev/null +++ b/apps/web-antd/src/utils/flexible.ts @@ -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 \ No newline at end of file diff --git a/apps/web-antd/src/utils/pie3d.ts b/apps/web-antd/src/utils/pie3d.ts new file mode 100644 index 00000000..efee8056 --- /dev/null +++ b/apps/web-antd/src/utils/pie3d.ts @@ -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 +} \ No newline at end of file diff --git a/apps/web-antd/src/utils/threeDBarOption.ts b/apps/web-antd/src/utils/threeDBarOption.ts new file mode 100644 index 00000000..497b302d --- /dev/null +++ b/apps/web-antd/src/utils/threeDBarOption.ts @@ -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' } + ]) + } + } + ] + } + } + }] + } +} \ No newline at end of file diff --git a/apps/web-antd/src/views/property/greenPlantRentalManagement/leasePogramManagement/rentalPlan-modal.vue b/apps/web-antd/src/views/property/greenPlantRentalManagement/leasePogramManagement/rentalPlan-modal.vue index 78292f7c..a1c3a868 100644 --- a/apps/web-antd/src/views/property/greenPlantRentalManagement/leasePogramManagement/rentalPlan-modal.vue +++ b/apps/web-antd/src/views/property/greenPlantRentalManagement/leasePogramManagement/rentalPlan-modal.vue @@ -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(); diff --git a/apps/web-antd/src/views/property/greenPlantRentalManagement/reportStatistics/index.vue b/apps/web-antd/src/views/property/greenPlantRentalManagement/reportStatistics/index.vue index 7a50cebe..c2410298 100644 --- a/apps/web-antd/src/views/property/greenPlantRentalManagement/reportStatistics/index.vue +++ b/apps/web-antd/src/views/property/greenPlantRentalManagement/reportStatistics/index.vue @@ -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 + '
'; + params.forEach((item:any) => { + result += item.marker + item.seriesName + ':' + item.data + '%
'; + }); + 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 + '
'; + params.forEach((item:any) => { + if (item.seriesName === '完成率') { + // 假设原始数据是 80,显示为 80% + result += item.marker + item.seriesName + ':' + item.data + '%
'; + } else { + result += item.marker + item.seriesName + ':' + item.data + '
'; + } + }); + 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) {
绿植租赁业务统计报表:
-
+