From 78be42499a817cafa3c0b07451b5509df941a56f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 09 九月 2025 13:29:28 +0800
Subject: [PATCH] BI大屏开发
---
src/views/index.vue | 1
src/assets/BI/yuancailiaoyijianicon@2x.png | 0
src/assets/BI/jiantou@2x.png | 0
src/assets/BI/icon@2x.png | 0
src/views/reportAnalysis/dataDashboard/index.vue | 1761 +++++++++++++++++++++++++++++++++++++++++++++++
src/assets/BI/zonghetongbingtubiankuang@2x.png | 0
src/api/financialManagement/expenseManagement.js | 7
src/assets/BI/shujutongjiicon@2x.png | 0
src/assets/BI/hetongjineback@2x.png | 0
src/assets/BI/shijianmingxiicon@2x.png | 0
src/components/Echarts/echarts.vue | 1
src/assets/BI/border@2x.png | 0
src/assets/BI/hetongjineicon1@2x.png | 0
vite.config.js | 164 ++--
src/assets/BI/biaoti.png | 0
src/assets/BI/guochengyijianicon@2x.png | 0
src/assets/BI/pieback@2x.png | 0
src/assets/BI/chuchangyijianicon@2x.png | 0
src/assets/BI/kehuhetongback@2x.png | 0
src/assets/BI/caiwufenxiback@2x.png | 0
src/assets/BI/shijianmingchengbeijing@2x.png | 0
src/assets/BI/shujutongji@2x.png | 0
src/assets/BI/hetongicon.png | 0
src/assets/BI/backImage@2x.png | 0
src/router/index.js | 35
src/assets/BI/hetongjineicon@2x.png | 0
src/assets/BI/hetongtitleback@2x.png | 0
src/main.js | 226 +++---
package.json | 1
29 files changed, 1,986 insertions(+), 210 deletions(-)
diff --git a/package.json b/package.json
index 7ec9b1d..9f1dc17 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"@vue-office/excel": "^1.7.14",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.11.0",
+ "autofit.js": "^3.2.8",
"axios": "0.28.1",
"clipboard": "2.0.11",
"dayjs": "^1.11.13",
diff --git a/src/api/financialManagement/expenseManagement.js b/src/api/financialManagement/expenseManagement.js
index 317dc47..a22af1b 100644
--- a/src/api/financialManagement/expenseManagement.js
+++ b/src/api/financialManagement/expenseManagement.js
@@ -8,6 +8,13 @@
params,
});
};
+export const listPageAnalysis = (params) => {
+ return request({
+ url: "/account/accountExpense/report/analysis",
+ method: "get",
+ params,
+ });
+};
// 鏂板
export function add(data) {
diff --git a/src/assets/BI/backImage@2x.png b/src/assets/BI/backImage@2x.png
new file mode 100644
index 0000000..5c62ec6
--- /dev/null
+++ b/src/assets/BI/backImage@2x.png
Binary files differ
diff --git a/src/assets/BI/biaoti.png b/src/assets/BI/biaoti.png
new file mode 100644
index 0000000..f905f1c
--- /dev/null
+++ b/src/assets/BI/biaoti.png
Binary files differ
diff --git a/src/assets/BI/border@2x.png b/src/assets/BI/border@2x.png
new file mode 100644
index 0000000..07555cb
--- /dev/null
+++ b/src/assets/BI/border@2x.png
Binary files differ
diff --git a/src/assets/BI/caiwufenxiback@2x.png b/src/assets/BI/caiwufenxiback@2x.png
new file mode 100644
index 0000000..3f242d4
--- /dev/null
+++ b/src/assets/BI/caiwufenxiback@2x.png
Binary files differ
diff --git a/src/assets/BI/chuchangyijianicon@2x.png b/src/assets/BI/chuchangyijianicon@2x.png
new file mode 100644
index 0000000..bc3677a
--- /dev/null
+++ b/src/assets/BI/chuchangyijianicon@2x.png
Binary files differ
diff --git a/src/assets/BI/guochengyijianicon@2x.png b/src/assets/BI/guochengyijianicon@2x.png
new file mode 100644
index 0000000..0c64bdc
--- /dev/null
+++ b/src/assets/BI/guochengyijianicon@2x.png
Binary files differ
diff --git a/src/assets/BI/hetongicon.png b/src/assets/BI/hetongicon.png
new file mode 100644
index 0000000..60c2f0e
--- /dev/null
+++ b/src/assets/BI/hetongicon.png
Binary files differ
diff --git a/src/assets/BI/hetongjineback@2x.png b/src/assets/BI/hetongjineback@2x.png
new file mode 100644
index 0000000..c15ed6a
--- /dev/null
+++ b/src/assets/BI/hetongjineback@2x.png
Binary files differ
diff --git a/src/assets/BI/hetongjineicon1@2x.png b/src/assets/BI/hetongjineicon1@2x.png
new file mode 100644
index 0000000..38c86da
--- /dev/null
+++ b/src/assets/BI/hetongjineicon1@2x.png
Binary files differ
diff --git a/src/assets/BI/hetongjineicon@2x.png b/src/assets/BI/hetongjineicon@2x.png
new file mode 100644
index 0000000..60c2f0e
--- /dev/null
+++ b/src/assets/BI/hetongjineicon@2x.png
Binary files differ
diff --git a/src/assets/BI/hetongtitleback@2x.png b/src/assets/BI/hetongtitleback@2x.png
new file mode 100644
index 0000000..c15ed6a
--- /dev/null
+++ b/src/assets/BI/hetongtitleback@2x.png
Binary files differ
diff --git a/src/assets/BI/icon@2x.png b/src/assets/BI/icon@2x.png
new file mode 100644
index 0000000..267a738
--- /dev/null
+++ b/src/assets/BI/icon@2x.png
Binary files differ
diff --git a/src/assets/BI/jiantou@2x.png b/src/assets/BI/jiantou@2x.png
new file mode 100644
index 0000000..38c86da
--- /dev/null
+++ b/src/assets/BI/jiantou@2x.png
Binary files differ
diff --git a/src/assets/BI/kehuhetongback@2x.png b/src/assets/BI/kehuhetongback@2x.png
new file mode 100644
index 0000000..22a7ead
--- /dev/null
+++ b/src/assets/BI/kehuhetongback@2x.png
Binary files differ
diff --git a/src/assets/BI/pieback@2x.png b/src/assets/BI/pieback@2x.png
new file mode 100644
index 0000000..c8930cc
--- /dev/null
+++ b/src/assets/BI/pieback@2x.png
Binary files differ
diff --git a/src/assets/BI/shijianmingchengbeijing@2x.png b/src/assets/BI/shijianmingchengbeijing@2x.png
new file mode 100644
index 0000000..0ed2813
--- /dev/null
+++ b/src/assets/BI/shijianmingchengbeijing@2x.png
Binary files differ
diff --git a/src/assets/BI/shijianmingxiicon@2x.png b/src/assets/BI/shijianmingxiicon@2x.png
new file mode 100644
index 0000000..3c3a7b7
--- /dev/null
+++ b/src/assets/BI/shijianmingxiicon@2x.png
Binary files differ
diff --git a/src/assets/BI/shujutongji@2x.png b/src/assets/BI/shujutongji@2x.png
new file mode 100644
index 0000000..69b6834
--- /dev/null
+++ b/src/assets/BI/shujutongji@2x.png
Binary files differ
diff --git a/src/assets/BI/shujutongjiicon@2x.png b/src/assets/BI/shujutongjiicon@2x.png
new file mode 100644
index 0000000..780fc22
--- /dev/null
+++ b/src/assets/BI/shujutongjiicon@2x.png
Binary files differ
diff --git a/src/assets/BI/yuancailiaoyijianicon@2x.png b/src/assets/BI/yuancailiaoyijianicon@2x.png
new file mode 100644
index 0000000..dc4a72c
--- /dev/null
+++ b/src/assets/BI/yuancailiaoyijianicon@2x.png
Binary files differ
diff --git a/src/assets/BI/zonghetongbingtubiankuang@2x.png b/src/assets/BI/zonghetongbingtubiankuang@2x.png
new file mode 100644
index 0000000..a322aa5
--- /dev/null
+++ b/src/assets/BI/zonghetongbingtubiankuang@2x.png
Binary files differ
diff --git a/src/components/Echarts/echarts.vue b/src/components/Echarts/echarts.vue
index d8264ad..29abba8 100644
--- a/src/components/Echarts/echarts.vue
+++ b/src/components/Echarts/echarts.vue
@@ -113,6 +113,7 @@
const option = {
color: props.color.length ? props.color : undefined,
backgroundColor: props.options.backgroundColor || '#fff',
+ textStyle: props.options.textStyle || { color: '#333' },
xAxis: props.xAxis,
yAxis: props.yAxis,
dataset: props.dataset,
diff --git a/src/main.js b/src/main.js
index 00205af..da4c54d 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,113 +1,113 @@
-import { createApp } from "vue";
-
-import Cookies from "js-cookie";
-
-import ElementPlus from "element-plus";
-import "element-plus/dist/index.css";
-import "element-plus/theme-chalk/dark/css-vars.css";
-import locale from "element-plus/es/locale/lang/zh-cn";
-
-import "@/assets/styles/index.scss"; // global css
-
-import App from "./App";
-import store from "./store";
-import router from "./router";
-import directive from "./directive"; // directive
-
-// 娉ㄥ唽鎸囦护
-import plugins from "./plugins"; // plugins
-import { download } from "@/utils/request";
-
-// svg鍥炬爣
-import "virtual:svg-icons-register";
-import SvgIcon from "@/components/SvgIcon";
-import elementIcons from "@/components/SvgIcon/svgicon";
-import "./assets/fonts/font.css";
-
-import "./permission"; // permission control
-
-import { useDict } from "@/utils/dict";
-import {
- parseTime,
- resetForm,
- addDateRange,
- handleTree,
- selectDictLabel,
- selectDictLabels,
-} from "@/utils/ruoyi";
-
-// 鍒嗛〉缁勪欢
-import Pagination from "@/components/Pagination";
-// 鑷畾涔夎〃鏍煎伐鍏风粍浠�
-import RightToolbar from "@/components/RightToolbar";
-// 瀵屾枃鏈粍浠�
-import Editor from "@/components/Editor";
-// 鏂囦欢涓婁紶缁勪欢
-import FileUpload from "@/components/FileUpload";
-// 鍥剧墖涓婁紶缁勪欢
-import ImageUpload from "@/components/ImageUpload";
-// 鍥剧墖棰勮缁勪欢
-import ImagePreview from "@/components/ImagePreview";
-// 瀛楀吀鏍囩缁勪欢
-import DictTag from "@/components/DictTag";
-// 琛ㄦ牸缁勪欢
-import PIMTable from "@/components/PIMTable/PIMTable.vue";
-
-import { getToken } from "@/utils/auth";
-import {
- calculateTaxExclusiveTotalPrice,
- summarizeTable,
- calculateTaxIncludeTotalPrice,
-} from "@/utils/summarizeTable.js";
-
-const app = createApp(App);
-
-// 鍏ㄥ眬鏂规硶鎸傝浇
-app.config.globalProperties.useDict = useDict;
-app.config.globalProperties.download = download;
-app.config.globalProperties.parseTime = parseTime;
-app.config.globalProperties.resetForm = resetForm;
-app.config.globalProperties.summarizeTable = summarizeTable;
-app.config.globalProperties.calculateTaxExclusiveTotalPrice =
- calculateTaxExclusiveTotalPrice;
-app.config.globalProperties.calculateTaxIncludeTotalPrice =
- calculateTaxIncludeTotalPrice;
-app.config.globalProperties.handleTree = handleTree;
-app.config.globalProperties.addDateRange = addDateRange;
-app.config.globalProperties.selectDictLabel = selectDictLabel;
-app.config.globalProperties.selectDictLabels = selectDictLabels;
-app.config.globalProperties.javaApi = "http://114.132.189.42:8099";
-app.config.globalProperties.HaveJson = (val) => {
- return JSON.parse(JSON.stringify(val));
-};
-app.config.globalProperties.uploadHeader = {
- Authorization: "Bearer " + getToken(),
-};
-
-// 鍏ㄥ眬缁勪欢鎸傝浇
-app.component("DictTag", DictTag);
-app.component("Pagination", Pagination);
-app.component("FileUpload", FileUpload);
-app.component("ImageUpload", ImageUpload);
-app.component("ImagePreview", ImagePreview);
-app.component("RightToolbar", RightToolbar);
-app.component("Editor", Editor);
-app.component("PIMTable", PIMTable);
-
-app.use(router);
-app.use(store);
-app.use(plugins);
-app.use(elementIcons);
-app.component("svg-icon", SvgIcon);
-
-directive(app);
-
-// 浣跨敤element-plus 骞朵笖璁剧疆鍏ㄥ眬鐨勫ぇ灏�
-app.use(ElementPlus, {
- locale: locale,
- // 鏀寔 large銆乨efault銆乻mall
- size: Cookies.get("size") || "default",
-});
-app._context.components.ElDialog.props.closeOnClickModal.default = false;
-
-app.mount("#app");
+import { createApp } from "vue";
+
+import Cookies from "js-cookie";
+
+import ElementPlus from "element-plus";
+import "element-plus/dist/index.css";
+import "element-plus/theme-chalk/dark/css-vars.css";
+import locale from "element-plus/es/locale/lang/zh-cn";
+
+import "@/assets/styles/index.scss"; // global css
+
+import App from "./App";
+import store from "./store";
+import router from "./router";
+import directive from "./directive"; // directive
+
+// 娉ㄥ唽鎸囦护
+import plugins from "./plugins"; // plugins
+import { download } from "@/utils/request";
+
+// svg鍥炬爣
+import "virtual:svg-icons-register";
+import SvgIcon from "@/components/SvgIcon";
+import elementIcons from "@/components/SvgIcon/svgicon";
+import "./assets/fonts/font.css";
+
+import "./permission"; // permission control
+
+import { useDict } from "@/utils/dict";
+import {
+ parseTime,
+ resetForm,
+ addDateRange,
+ handleTree,
+ selectDictLabel,
+ selectDictLabels,
+} from "@/utils/ruoyi";
+
+// 鍒嗛〉缁勪欢
+import Pagination from "@/components/Pagination";
+// 鑷畾涔夎〃鏍煎伐鍏风粍浠�
+import RightToolbar from "@/components/RightToolbar";
+// 瀵屾枃鏈粍浠�
+import Editor from "@/components/Editor";
+// 鏂囦欢涓婁紶缁勪欢
+import FileUpload from "@/components/FileUpload";
+// 鍥剧墖涓婁紶缁勪欢
+import ImageUpload from "@/components/ImageUpload";
+// 鍥剧墖棰勮缁勪欢
+import ImagePreview from "@/components/ImagePreview";
+// 瀛楀吀鏍囩缁勪欢
+import DictTag from "@/components/DictTag";
+// 琛ㄦ牸缁勪欢
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+
+import { getToken } from "@/utils/auth";
+import {
+ calculateTaxExclusiveTotalPrice,
+ summarizeTable,
+ calculateTaxIncludeTotalPrice,
+} from "@/utils/summarizeTable.js";
+
+const app = createApp(App);
+
+// 鍏ㄥ眬鏂规硶鎸傝浇
+app.config.globalProperties.useDict = useDict;
+app.config.globalProperties.download = download;
+app.config.globalProperties.parseTime = parseTime;
+app.config.globalProperties.resetForm = resetForm;
+app.config.globalProperties.summarizeTable = summarizeTable;
+app.config.globalProperties.calculateTaxExclusiveTotalPrice =
+ calculateTaxExclusiveTotalPrice;
+app.config.globalProperties.calculateTaxIncludeTotalPrice =
+ calculateTaxIncludeTotalPrice;
+app.config.globalProperties.handleTree = handleTree;
+app.config.globalProperties.addDateRange = addDateRange;
+app.config.globalProperties.selectDictLabel = selectDictLabel;
+app.config.globalProperties.selectDictLabels = selectDictLabels;
+app.config.globalProperties.javaApi = "http://114.132.189.42:9037";
+app.config.globalProperties.HaveJson = (val) => {
+ return JSON.parse(JSON.stringify(val));
+};
+app.config.globalProperties.uploadHeader = {
+ Authorization: "Bearer " + getToken(),
+};
+
+// 鍏ㄥ眬缁勪欢鎸傝浇
+app.component("DictTag", DictTag);
+app.component("Pagination", Pagination);
+app.component("FileUpload", FileUpload);
+app.component("ImageUpload", ImageUpload);
+app.component("ImagePreview", ImagePreview);
+app.component("RightToolbar", RightToolbar);
+app.component("Editor", Editor);
+app.component("PIMTable", PIMTable);
+
+app.use(router);
+app.use(store);
+app.use(plugins);
+app.use(elementIcons);
+app.component("svg-icon", SvgIcon);
+
+directive(app);
+
+// 浣跨敤element-plus 骞朵笖璁剧疆鍏ㄥ眬鐨勫ぇ灏�
+app.use(ElementPlus, {
+ locale: locale,
+ // 鏀寔 large銆乨efault銆乻mall
+ size: Cookies.get("size") || "default",
+});
+app._context.components.ElDialog.props.closeOnClickModal.default = false;
+
+app.mount("#app");
diff --git a/src/router/index.js b/src/router/index.js
index 9cfde33..437e523 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -76,20 +76,20 @@
}
]
},
- {
- path: '/main/MobileChat',
- component: Layout,
- redirect: '',
- hidden: true,
- children: [
- {
- path: '',
- component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
- name: 'MobileChat',
- meta: { title: 'AI瀵硅瘽', icon: 'dashboard', affix: true}
- }
- ]
- },
+ // {
+ // path: '/main/MobileChat',
+ // component: Layout,
+ // redirect: '',
+ // hidden: true,
+ // children: [
+ // {
+ // path: '',
+ // component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
+ // name: 'MobileChat',
+ // meta: { title: 'AI瀵硅瘽', icon: 'dashboard', affix: true}
+ // }
+ // ]
+ // },
{
path: '/user',
component: Layout,
@@ -111,6 +111,13 @@
name: "DeviceInfo",
meta: { title: "璁惧淇℃伅", icon: "monitor" },
},
+ {
+ path: "/data-dashboard",
+ component: () => import("@/views/reportAnalysis/dataDashboard/index.vue"),
+ hidden: true,
+ name: "DataDashboard",
+ meta: { title: "鏁版嵁澶у睆", icon: "dashboard" },
+ },
];
// 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
diff --git a/src/views/index.vue b/src/views/index.vue
index 0e7fdcf..2888b16 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -386,7 +386,6 @@
}
// 搴斾粯搴旀敹缁熻
const statisticsReceivable = (type) => {
- console.log(type)
statisticsReceivablePayable({type: radio1.value}).then((res) => {
barSeries.value[0].data = [
// { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } },
diff --git a/src/views/reportAnalysis/dataDashboard/index.vue b/src/views/reportAnalysis/dataDashboard/index.vue
new file mode 100644
index 0000000..da10fd7
--- /dev/null
+++ b/src/views/reportAnalysis/dataDashboard/index.vue
@@ -0,0 +1,1761 @@
+<template>
+ <div class="data-dashboard">
+ <!-- 鍏ㄥ睆鎸夐挳 - 绉诲姩鍒板乏涓婅 -->
+ <button class="fullscreen-btn" @click="toggleFullscreen" :title="isFullscreen ? '閫�鍑哄叏灞�' : '鍏ㄥ睆鏄剧ず'">
+ <svg v-if="!isFullscreen" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+ <path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/>
+ </svg>
+ <svg v-else width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+ <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>
+ </svg>
+ </button>
+
+ <!-- 椤堕儴鏍囬鏍� -->
+ <div class="dashboard-header">
+ </div>
+
+ <!-- 涓昏鍐呭鍖哄煙 -->
+ <div class="dashboard-content">
+ <!-- 宸︿晶鍖哄煙 -->
+ <div class="left-panel">
+ <!-- 瀹㈡埛淇℃伅缁熻鍒嗘瀽 -->
+ <div class="panel-header">
+ <span class="panel-title">瀹㈡埛淇℃伅缁熻鍒嗘瀽</span>
+ </div>
+ <div class="panel-item-customers">
+ <div class="panel-title-second">
+ <div class="panel-title-icon"></div>
+ <div class="total-customers">
+ <span class="label">鎬诲悎鍚岄噾棰�(鍏�)</span>
+ <span class="value">{{sum}}</span>
+ </div>
+<!-- <div class="jiantou"></div>-->
+ </div>
+ <!-- 楗煎浘鍖哄煙 -->
+ <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 82%;margin-top: 20px">
+ <div style="width: 240px; height: 240px; background-image: url('/src/assets/BI/zonghetongbingtubiankuang@2x.png'); background-size: contain; background-position: center; background-repeat: no-repeat; display: flex; align-items: center; justify-content: center;">
+ <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie"
+ :series="materialPieSeries"
+ :tooltip="pieTooltip"
+ :options="{backgroundColor: 'transparent'}"
+ style="margin-left: 5px;"></Echarts>
+ </div>
+ <ul class="contract-list" style="margin: 0; padding: 0; display: flex; flex-direction: column;justify-content: space-around; height: 100%; overflow-y: auto; scroll-behavior: smooth;" ref="refContractList">
+ <li v-for="item in materialPieSeries[0].data" :key="item.name" style="list-style: none; margin-bottom: 12px;">
+ <div style="display: flex;align-items: center;justify-content: space-between;width: 100%">
+ <div class="line" :style="{color: item.itemStyle.color}">鈻� {{item.name}}</div>
+ <div style="font-weight: 700;font-size: 16px;color: #85B1E4;">锟{item.value}}</div>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+ <!-- 璐ㄩ噺缁熻 -->
+ <div class="panel-header">
+ <span class="panel-title">璐ㄩ噺缁熻</span>
+ </div>
+ <div class="main-panel">
+ <div class="panel-item-customers">
+ <div class="quality-cards">
+ <div class="quality-cardSec">
+ <div class="quality-card one"></div>
+ <div class="quality-cardTitle">
+ <div>鍘熸潗鏂欏凡妫�娴嬫暟</div>
+ <div>{{qualityStatisticsObject.supplierNum}}浠�</div>
+ </div>
+ </div>
+ <div class="quality-cardSec">
+ <div class="quality-card two"></div>
+ <div class="quality-cardTitle">
+ <div>杩囩▼妫�楠屾暟閲�</div>
+ <div>{{qualityStatisticsObject.processNum}}浠�</div>
+ </div>
+ </div>
+ <div class="quality-cardSec">
+ <div class="quality-card three"></div>
+ <div class="quality-cardTitle">
+ <div>鍑哄巶宸叉鏁伴噺</div>
+ <div>{{qualityStatisticsObject.factoryNum}}浠�</div>
+ </div>
+ </div>
+ </div>
+ <Echarts ref="chart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="barLegend"
+ :series="barSeries1"
+ :tooltip="tooltip"
+ :xAxis="xAxis1"
+ :yAxis="yAxis1"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 260px"></Echarts>
+ </div>
+ </div>
+ </div>
+
+ <!-- 涓棿鍖哄煙 -->
+ <div class="center-panel">
+ <!-- 椤堕儴缁熻鍗$墖 -->
+ <div class="stats-cards">
+ <div class="stat-card">
+ <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-content">
+ <span class="card-label">鍛樺伐鎬绘暟</span>
+ <span class="card-value">{{totalStaff}}</span>
+ </div>
+ </div>
+ <div class="stat-card">
+ <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-content">
+ <span class="card-label">瀹㈡埛鎬绘暟</span>
+ <span class="card-value">{{totalCustomers}}</span>
+ </div>
+ </div>
+ <div class="stat-card">
+ <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-content">
+ <span class="card-label">渚涘簲鍟嗘�绘暟</span>
+ <span class="card-value">{{totalSuppliers}}</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 璁惧缁熻 -->
+ <div class="equipment-stats">
+ <div class="equipment-header">
+ <img src="@/assets/BI/shujutongjiicon@2x.png" alt="鍥炬爣" class="equipment-icon" />
+ <span class="equipment-title">璁惧缁熻</span>
+ </div>
+ <div class="equipment-items">
+ <div class="equipment-item">
+ <span class="equipment-value">{{equipmentNum}}</span>
+ <span class="equipment-label">璁惧鎬绘暟</span>
+ </div>
+ <div class="equipment-item">
+ <span class="equipment-value">{{equipmentRepair}}</span>
+ <span class="equipment-label">寰呯淮淇澶�</span>
+ </div>
+ <div class="equipment-item">
+ <span class="equipment-value">{{equipmentMaintain}}</span>
+ <span class="equipment-label">寰呬繚鍏昏澶�</span>
+ </div>
+ <div class="equipment-item">
+ <span class="equipment-value">{{totalMeasuring}}</span>
+ <span class="equipment-label">璁¢噺鍣ㄥ叿鎬绘暟</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 浜嬩欢鍚嶇О -->
+ <div class="event-info">
+ <div class="event-header">
+ <img src="@/assets/BI/shijianmingxiicon@2x.png" alt="鍥炬爣" class="event-icon" />
+ <span class="event-title">浜嬩欢鍚嶇О</span>
+ </div>
+ <div class="event-content">
+ <ul class="todo-list" v-if="todoList.length > 0" ref="refTodoList">
+ <li v-for="item in todoList" :key="item.id">
+ <div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
+ <div style="display: flex;justify-content: space-between;align-items: center;">
+ <div class="todo-title">寰呭姙缂栧彿锛歿{item.approveId}}</div>
+ <div class="todo-division">閮ㄩ棬锛歿{item.approveDeptName}}</div>
+ <div class="todo-time">{{item.approveTime}}</div>
+ </div>
+ <div class="todo-division">寰呭姙浜嬬敱锛歿{item.approveReason}}</div>
+ </div>
+ </li>
+ </ul>
+ <div v-else style="text-align: center">
+ 鏆傛棤鏁版嵁
+ </div>
+ </div>
+ </div>
+
+ <div class="financial-header">
+ <span class="financial-title">璐㈠姟鍒嗘瀽</span>
+ </div>
+ <div class="main-panel">
+ <div class="panel-item-customers">
+ <div class="event-header">
+ <img src="@/assets/BI/shijianmingxiicon@2x.png" alt="鍥炬爣" class="event-icon" />
+ <span class="event-title">缁忚惀鎴愭灉鍒嗘瀽</span>
+ </div>
+ <Echarts ref="chart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="barLegend1"
+ :series="barSeries11"
+ :tooltip="tooltip"
+ :xAxis="xAxis3"
+ :yAxis="yAxis3"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 300px"></Echarts>
+ </div>
+ </div>
+ </div>
+
+ <!-- 鍙充晶鍖哄煙 -->
+ <div class="right-panel">
+ <!-- 搴旀敹搴斾粯缁熻 -->
+ <div class="panel-header">
+ <span class="panel-title">搴旀敹搴斾粯缁熻</span>
+ </div>
+ <div class="panel-item-customers">
+ <div style="display: flex;justify-content: space-between;margin-bottom: 20px;">
+ <div class="section-title">搴旀敹搴斾粯缁熻</div>
+ <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable" class="custom-radio-group">
+ <el-radio-button label="鎸夊懆" :value="1" />
+ <el-radio-button label="鎸夋湀" :value="2" />
+ <el-radio-button label="鎸夊搴�" :value="3" />
+ </el-radio-group>
+ </div>
+ <Echarts ref="chart"
+ :color="barColors2"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="barLegend2"
+ :series="barSeries"
+ :tooltip="tooltip"
+ :xAxis="xAxis"
+ :yAxis="yAxis"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 260px"></Echarts>
+ </div>
+
+ <!-- 鍥炴涓庡紑绁ㄥ垎鏋� -->
+ <div class="panel-header">
+ <span class="panel-title">鍥炴涓庡紑绁ㄥ垎鏋�</span>
+ </div>
+ <div class="panel-item-customers" style="padding-top: 60px;">
+ <Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries"
+ :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" :options="{backgroundColor: 'transparent', textStyle: {color: '#FFFFFF'}}" style="height: 270px;"></Echarts>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import autofit from 'autofit.js'
+import Echarts from "@/components/Echarts/echarts.vue";
+import {
+ analysisCustomerContractAmounts, getAmountHalfYear,
+ homeTodos,
+ qualityStatistics,
+ statisticsReceivablePayable
+} from "@/api/viewIndex.js";
+import {staffOnJobListPage} from "@/api/personnelManagement/employeeRecord.js";
+import {listCustomer} from "@/api/basicData/customerFile.js";
+import {listSupplier} from "@/api/basicData/supplierManageFile.js";
+import {getLedgerPage} from "@/api/equipmentManagement/ledger.js";
+import {getRepairPage} from "@/api/equipmentManagement/repair.js";
+import {getUpkeepPage} from "@/api/equipmentManagement/upkeep.js";
+import {measuringInstrumentListPage} from "@/api/equipmentManagement/measurementEquipment.js";
+import {listPageAnalysis} from "@/api/financialManagement/expenseManagement.js";
+
+// 鍏ㄥ睆鐩稿叧鐘舵��
+const isFullscreen = ref(false);
+
+// 鍝嶅簲寮忔暟鎹�
+const currentTime = ref('')
+const currentDate = ref('')
+const timer = ref(null)
+const charts = ref([])
+
+// 鍥捐〃寮曠敤
+const customerPieChartRef = ref(null)
+const salesBarChartRef = ref(null)
+const dataBarChartRef = ref(null)
+const financialAreaChartRef = ref(null)
+const realtimeLineChartRef = ref(null)
+const refContractList = ref(null)
+const refTodoList = ref(null)
+const timerScroll = ref(null)
+
+const chartStylePie = {
+ width: '140%',
+ height: '140%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+}
+const materialPieSeries = ref([
+ {
+ type: 'pie',
+ radius: ['0%', '90%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 0
+ },
+ label: {
+ show: false
+ },
+ data: []
+ }
+])
+const pieLegend = reactive({
+ show: false,
+})
+const sum = ref(0)
+const totalStaff = ref(0)
+const totalCustomers = ref(0)
+const totalSuppliers = ref(0)
+const yny = ref(0)
+const chain = ref(0)
+const equipmentNum = ref(0)
+const equipmentRepair = ref(0)
+const equipmentMaintain = ref(0)
+const totalMeasuring = ref(0)
+const pieTooltip = reactive({
+ trigger: 'item',
+ formatter: function (params) {
+ // 鍔ㄦ�佺敓鎴愭彁绀轰俊鎭紝鍩轰簬鏁版嵁椤圭殑 name 灞炴��
+ const description = params.name === '鏈湀鍥炴閲戦' ? '鏈湀鍥炴閲戦' : '搴旀敹娆鹃噾棰�';
+ return `<div style="color: #B8C8E0">${description} ${params.value}鍏� ${params.percent}%</div>`;
+ },
+ position: 'right'
+})
+
+const qualityStatisticsObject = ref({
+ supplierNum: 0,
+ processNum: 0,
+ factoryNum: 0,
+})
+const chartStyle = {
+ width: '100%',
+ height: '150%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+}
+const barSeries = ref([
+ {
+ name: '搴斾粯閲戦',
+ type: 'bar',
+ data: [],
+ label: {
+ show: true,
+ },
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#00A4ED' },
+ { offset: 1, color: '#4EE4FF' }
+ ])
+ }
+ },
+ {
+ name: '搴旀敹閲戦',
+ type: 'bar',
+ data: [],
+ label: {
+ show: true,
+ },
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#537EF5' },
+ { offset: 1, color: '#9061F8' }
+ ])
+ }
+ }
+])
+const radio1 = ref(1)
+const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8']
+const grid = {
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true
+}
+const lineLegend = {
+ show: true,
+ textStyle: { color: '#B8C8E0' },
+ data: ['寮�绁�', '鍥炴']
+}
+const lineSeries = ref([
+ {
+ type: 'line',
+ data: [],
+ label: {
+ show: true
+ },
+ showSymbol: true, // 鏄剧ず鍦嗙偣
+ },
+])
+const tooltipLine = {
+ trigger: 'axis',
+}
+const yAxis2 = ref([
+ {
+ type: 'value',
+ }
+])
+const xAxis2 = ref([
+ {
+ type: 'category',
+ data: [],
+ axisLabel: {
+ interval: 0,
+ formatter: function(value) {
+ return value.replace(/~/g, '\n');
+ },
+ }
+ }
+])
+const barLegend2 = {
+ show: true,
+ textStyle: { color: '#B8C8E0' },
+ data: ['搴斾粯閲戦', '搴旀敹閲戦']
+}
+const barLegend = {
+ show: true,
+ textStyle: { color: '#B8C8E0' },
+ data: ['鍘熸潗鏂欎笉鍚堟牸鏁�', '杩囩▼涓嶅悎鏍兼暟', '鍑哄巶涓嶅悎鏍兼暟']
+}
+const barLegend1 = {
+ show: true,
+ textStyle: { color: '#B8C8E0' },
+ data: ['鎬绘敹鍏�', '鎬绘敮鍑�', '鍑�鏀跺叆']
+}
+const barSeries11 = ref([
+ {
+ name: '鎬绘敹鍏�',
+ type: 'bar',
+ barGap: 0,
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#00A4ED' },
+ { offset: 0, color: '#4EE4FF' }
+ ]
+ }
+ },
+ data: []
+ },
+ {
+ name: '鎬绘敮鍑�',
+ type: 'bar',
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#3378FF' },
+ { offset: 0, color: '#4E8AFF' }
+ ]
+ }
+ },
+ data: []
+ },
+ {
+ name: '鍑�鏀跺叆',
+ type: 'bar',
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#537EF5' },
+ { offset: 0, color: '#9061F8' }
+ ]
+ }
+ },
+ data: []
+ },
+])
+const barSeries1 = ref([
+ {
+ name: '鍘熸潗鏂欎笉鍚堟牸鏁�',
+ type: 'bar',
+ barGap: 0,
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#00A4ED' },
+ { offset: 0, color: '#4EE4FF' }
+ ]
+ }
+ },
+ data: []
+ },
+ {
+ name: '杩囩▼涓嶅悎鏍兼暟',
+ type: 'bar',
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#3378FF' },
+ { offset: 0, color: '#4E8AFF' }
+ ]
+ }
+ },
+ data: []
+ },
+ {
+ name: '鍑哄巶涓嶅悎鏍兼暟',
+ type: 'bar',
+ emphasis: {
+ focus: 'series'
+ },
+ itemStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 1, color: '#537EF5' },
+ { offset: 0, color: '#9061F8' }
+ ]
+ }
+ },
+ data: []
+ },
+])
+const tooltip = {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow'
+ },
+ formatter: function (params) {
+ let result = params[0].axisValueLabel + '<br/>';
+ params.forEach(item => {
+ result += `<div style="color: #B8C8E0">${item.marker} ${item.seriesName}: ${item.value}</div>`;
+ });
+ return result;
+ }
+}
+const xAxis = [{
+ type: 'value',
+}]
+const yAxis = [{
+ type: 'category',
+ data: ['搴旀敹搴斾粯缁熻']
+}]
+const xAxis1 = ref([{
+ type: 'category',
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ data: []
+}])
+const yAxis1 = [{
+ type: 'value',
+ axisLabel: { color: '#B8C8E0' }
+}]
+const xAxis3 = ref([{
+ type: 'category',
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ data: []
+}])
+const yAxis3 = [{
+ type: 'value',
+ axisLabel: { color: '#B8C8E0' }
+}]
+
+// 寰呭姙浜嬮」
+const todoList = ref([])
+
+// 绐楀彛澶у皬鍙樺寲澶勭悊
+const handleResize = () => {
+ charts.value.forEach(chart => {
+ if (chart && chart.resize) {
+ chart.resize()
+ }
+ })
+}
+
+// 閿�姣佸浘琛ㄥ疄渚�
+const disposeCharts = () => {
+ charts.value.forEach(chart => {
+ if (chart && chart.dispose) {
+ chart.dispose()
+ }
+ })
+ charts.value = []
+}
+// 鍚堝悓閲戦
+const analysisCustomer = () => {
+ analysisCustomerContractAmounts().then((res) => {
+ sum.value = res.data.sum
+ yny.value = res.data.yny
+ chain.value = res.data.chain
+ // 涓烘瘡涓暟鎹」鍒嗛厤闅忔満棰滆壊
+ materialPieSeries.value[0].data = res.data.item.map(item => ({
+ ...item,
+ itemStyle: { color: getRandomColor() }
+ }))
+ })
+}
+// 璐ㄦ缁熻
+const qualityStatisticsInfo = () => {
+ qualityStatistics().then((res) => {
+ res.data.item.forEach(item => {
+ xAxis1.value[0].data.push(item.date)
+ barSeries1.value[0].data.push(item.supplierNum)
+ barSeries1.value[1].data.push(item.processNum)
+ barSeries1.value[2].data.push(item.factoryNum)
+ })
+ qualityStatisticsObject.value.supplierNum = res.data.supplierNum
+ qualityStatisticsObject.value.processNum = res.data.processNum
+ qualityStatisticsObject.value.factoryNum = res.data.factoryNum
+ })
+}
+// 璐㈠姟缁熻
+const accountStatisticsInfo = () => {
+ listPageAnalysis().then((res) => {
+ xAxis3.value[0].data = res.data.days
+ barSeries11.value[0].data = res.data.totalIncome
+ barSeries11.value[1].data = res.data.totalExpense
+ barSeries11.value[2].data = res.data.netIncome
+ })
+}
+const getNum = () => {
+ const params = {
+ pageNum: -1,
+ pageSize: -1,
+ }
+ staffOnJobListPage({...params, staffState: 1}).then(res => {
+ totalStaff.value = res.data.total
+ })
+ listCustomer(params).then((res) => {
+ totalCustomers.value = res.total;
+ });
+ listSupplier(params).then((res) => {
+ totalSuppliers.value = res.data.total
+ });
+}
+const getLedgerNum = () => {
+ const params = {
+ pageNum: -1,
+ pageSize: -1,
+ }
+ getLedgerPage(params).then((res) => {
+ equipmentNum.value = res.data.total
+ });
+ getRepairPage(params).then((res) => {
+ equipmentRepair.value = res.data.total
+ });
+ getUpkeepPage(params).then((res) => {
+ equipmentMaintain.value = res.data.total
+ });
+ measuringInstrumentListPage(params).then((res) => {
+ totalMeasuring.value = res.data.total
+ });
+}
+// 寰呭姙浜嬮」
+const todoInfoS = () => {
+ homeTodos().then((res) => {
+ todoList.value = res.data
+ // 鍦ㄨ幏鍙栧埌寰呭姙浜嬮」鏁版嵁鍚庯紝鍒濆鍖栨粴鍔ㄥ姛鑳�
+ nextTick(() => {
+ initTodoListScroll()
+ })
+ })
+}
+// 搴斾粯搴旀敹缁熻
+const statisticsReceivable = (type) => {
+ statisticsReceivablePayable({type: radio1.value}).then((res) => {
+ // 璁剧疆搴斾粯閲戦鏁版嵁
+ barSeries.value[0].data = [
+ { value: res.data.payableMoney }
+ ]
+ // 璁剧疆搴旀敹閲戦鏁版嵁
+ barSeries.value[1].data = [
+ { value: res.data.receivableMoney }
+ ]
+ })
+}
+const getAmountHalfYearNum = async () => {
+ const res = await getAmountHalfYear()
+ console.log(res)
+ const monthName = []
+ const receiptAmount = []
+ const invoiceAmount = []
+ res.data.forEach(item => {
+ monthName.push(item.month)
+ receiptAmount.push(item.receiptAmount)
+ invoiceAmount.push(item.invoiceAmount)
+ })
+ // 姝g‘鍝嶅簲寮忚祴鍊硷細鍒涘缓鏂扮殑 xAxis 鍜� series 瀵硅薄
+ xAxis2.value[0].data = monthName
+ xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~'));
+ lineSeries.value = [
+ {
+ name: '寮�绁�',
+ type: 'line',
+ data: receiptAmount,
+ stack: 'Total',
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {
+ offset: 0,
+ color: 'rgba(131, 207, 255, 1)'
+ },
+ {
+ offset: 1,
+ color: 'rgba(186, 228, 255, 1)'
+ }
+ ])
+ },
+ itemStyle: {
+ color: '#2D99FF',
+ borderColor: '#2D99FF'
+ },
+ emphasis: {
+ focus: 'series'
+ },
+ lineStyle: {
+ width: 0
+ },
+ showSymbol: true,
+ },
+ {
+ name: '鍥炴',
+ type: 'line',
+ data: invoiceAmount,
+ stack: 'Total',
+ lineStyle: {
+ width: 0
+ },
+ itemStyle: {
+ color: '#83CFFF',
+ borderColor: '#83CFFF'
+ },
+ showSymbol: true,
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {
+ offset: 0,
+ color: 'rgba(54, 153, 255, 1)'
+ },
+ {
+ offset: 1,
+ color: 'rgba(89, 169, 254, 1)'
+ }
+ ])
+ },
+ emphasis: {
+ focus: 'series'
+ },
+ }
+ ]
+}
+
+// 鑷姩杞崲鍛ㄣ�佹湀銆佸搴︾殑瀹氭椂鍣�
+const autoSwitchTimer = ref(null)
+// 鍒濆鍖栧緟鍔炰簨椤瑰垪琛ㄦ粴鍔ㄥ姛鑳�
+const initTodoListScroll = () => {
+ const todoList = refTodoList.value
+ // 寮哄埗鍚敤婊氬姩锛屼笉妫�鏌ヤ换浣曟潯浠�
+ if (todoList) {
+ // 鍒涘缓涓�涓厠闅嗛」锛岀敤浜庡疄鐜版棤缂濇粴鍔�
+ const scrollItems = Array.from(todoList.querySelectorAll('li'))
+ if (scrollItems.length > 0) {
+ // 纭繚鏈夎冻澶熺殑椤圭洰鐢ㄤ簬婊氬姩
+ // 濡傛灉椤圭洰澶皯锛屽澶嶅埗鍑犳浠ョ‘淇濇粴鍔ㄦ晥鏋�
+ if (scrollItems.length < 4) {
+ const originalItems = [...scrollItems]
+ for (let i = 0; i < 4; i++) {
+ originalItems.forEach(item => {
+ const clone = item.cloneNode(true)
+ todoList.appendChild(clone)
+ })
+ }
+ // 閲嶆柊鑾峰彇鎵�鏈夐」鐩�
+ scrollItems.push(...Array.from(todoList.querySelectorAll('li')).slice(scrollItems.length));
+ }
+ const itemHeight = scrollItems[0]?.offsetHeight || 0
+ const containerHeight = todoList.clientHeight
+ const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
+
+ // 鍏嬮殕鍓嶅嚑涓」鐩苟娣诲姞鍒板垪琛ㄦ湯灏撅紝瀹炵幇鏃犵紳婊氬姩
+ for (let i = 0; i < cloneCount; i++) {
+ const clone = scrollItems[i % scrollItems.length].cloneNode(true)
+ todoList.appendChild(clone)
+ }
+
+ let scrollPosition = 0
+ const scrollSpeed = 1.5 // 澧炲姞婊氬姩閫熷害锛屼娇婊氬姩鏇村姞鏄庢樉
+ const pauseTime = 3000 // 婊氬姩鏆傚仠鏃堕棿
+ let isPaused = false
+ let lastTimestamp = 0
+
+ // 杩炵画婊氬姩鍔ㄧ敾鍑芥暟
+ function scrollAnimation(timestamp) {
+ if (!lastTimestamp) lastTimestamp = timestamp
+ const deltaTime = timestamp - lastTimestamp
+ lastTimestamp = timestamp
+
+ if (!isPaused) {
+ scrollPosition += scrollSpeed * (deltaTime / 16) // 鏍囧噯鍖栦负60fps鐨勯�熷害
+
+ // 褰撴粴鍔ㄨ秴杩囧師濮嬪唴瀹归暱搴︽椂锛岄噸缃綅缃疄鐜版棤缂濇粴鍔�
+ const maxScroll = Math.max(todoList.scrollHeight - containerHeight - cloneCount * itemHeight, itemHeight * scrollItems.length)
+ if (scrollPosition >= maxScroll) {
+ scrollPosition = 0
+ todoList.scrollTop = 0
+ } else {
+ todoList.scrollTop = scrollPosition
+ }
+ }
+
+ todoList._animationFrame = requestAnimationFrame(scrollAnimation)
+ }
+
+ // 鍚姩婊氬姩鍔ㄧ敾
+ todoList._animationFrame = requestAnimationFrame(scrollAnimation)
+
+ // 璁剧疆婊氬姩-鏆傚仠-婊氬姩鐨勫惊鐜晥鏋�
+ const pauseTimer = setInterval(() => {
+ isPaused = !isPaused
+ }, pauseTime)
+
+ // 娓呯悊瀹氭椂鍣�
+ todoList._pauseTimer = pauseTimer
+ }
+ }
+}
+const getRandomColor = () => {
+ // 鐢熸垚娴呰壊锛歊銆丟銆丅 鍒嗛噺閮藉湪 150-255 涔嬮棿
+ const r = Math.floor(Math.random() * 106) + 150; // 150-255
+ const g = Math.floor(Math.random() * 106) + 150; // 150-255
+ const b = Math.floor(Math.random() * 106) + 150; // 150-255
+ // 灏� RGB 杞崲涓哄崄鍏繘鍒堕鑹�
+ return '#' + r.toString(16).padStart(2, '0') + g.toString(16).padStart(2, '0') + b.toString(16).padStart(2, '0');
+}
+
+// 鏇存柊鏃堕棿
+const updateTime = () => {
+ const now = new Date()
+ currentTime.value = now.toLocaleTimeString('zh-CN', { hour12: false })
+ currentDate.value = now.toLocaleDateString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ weekday: 'long'
+ })
+}
+
+// 鍒濆鍖栨椂闂�
+const initTime = () => {
+ updateTime()
+ timer.value = setInterval(updateTime, 1000)
+}
+
+// 瀹㈡埛楗煎浘
+const initCustomerPieChart = () => {
+ if (!customerPieChartRef.value) return
+ const chart = echarts.init(customerPieChartRef.value)
+ const option = {
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
+ },
+ series: [{
+ name: '瀹㈡埛鍒嗗竷',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ center: ['50%', '50%'],
+ data: [
+ { value: 25, name: '娼滃湪瀹㈡埛', itemStyle: { color: '#00d4ff' } },
+ { value: 25, name: '鎰忓悜瀹㈡埛', itemStyle: { color: '#0099ff' } },
+ { value: 25, name: '绛剧害瀹㈡埛', itemStyle: { color: '#6666ff' } },
+ { value: 25, name: '娴佸け瀹㈡埛', itemStyle: { color: '#ffcc00' } }
+ ],
+ label: {
+ show: false
+ }
+ }]
+ }
+ chart.setOption(option)
+ charts.value.push(chart)
+}
+
+// 閿�鍞煴鐘跺浘
+const initSalesBarChart = () => {
+ if (!salesBarChartRef.value) return
+ const chart = echarts.init(salesBarChartRef.value)
+ const option = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ xAxis: {
+ type: 'category',
+ data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
+ axisLine: { lineStyle: { color: '#333' } },
+ axisLabel: { color: '#B8C8E0' },
+ },
+ yAxis: {
+ type: 'value',
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ splitLine: { lineStyle: { color: '#333' } }
+ },
+ series: [{
+ data: [150, 200, 180, 220, 190],
+ type: 'bar',
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: 'rgba(0,164,237,0)' },
+ { offset: 1, color: '#4EE4FF' }
+ ])
+ }
+ }]
+ }
+ chart.setOption(option)
+ charts.value.push(chart)
+}
+
+// 鏁版嵁缁熻妯悜鏌辩姸鍥�
+const initDataBarChart = () => {
+ if (!dataBarChartRef.value) return
+ const chart = echarts.init(dataBarChartRef.value)
+ const option = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ grid: {
+ left: '10%',
+ right: '10%',
+ top: '10%',
+ bottom: '10%'
+ },
+ xAxis: {
+ type: 'value',
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ splitLine: { lineStyle: { color: '#333' } }
+ },
+ yAxis: {
+ type: 'category',
+ data: ['璁捐鏁版嵁', '璐㈠姟鏁版嵁', '鐢熶骇鏁版嵁', '鍚堝悓鏁版嵁'],
+ axisLine: { lineStyle: { color: '#333' } },
+ axisLabel: { color: '#B8C8E0' }
+ },
+ series: [{
+ data: [80, 100, 120, 90],
+ type: 'bar',
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+ { offset: 0, color: 'rgba(0,164,237,0)' },
+ { offset: 1, color: '#4EE4FF' }
+ ])
+ }
+ }]
+ }
+ chart.setOption(option)
+ charts.value.push(chart)
+}
+
+// 璐㈠姟鍒嗘瀽闈㈢Н鍥�
+const initFinancialAreaChart = () => {
+ if (!financialAreaChartRef.value) return
+ const chart = echarts.init(financialAreaChartRef.value)
+ const option = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ grid: {
+ left: '10%',
+ right: '10%',
+ top: '10%',
+ bottom: '20%'
+ },
+ xAxis: {
+ type: 'category',
+ data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
+ axisLine: { lineStyle: { color: '#333' } },
+ axisLabel: { color: '#B8C8E0' }
+ },
+ yAxis: {
+ type: 'value',
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ splitLine: { lineStyle: { color: '#333' } }
+ },
+ series: [{
+ data: [150, 180, 200, 170, 190],
+ type: 'line',
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: 'rgba(0, 212, 255, 0.3)' },
+ { offset: 1, color: 'rgba(0, 212, 255, 0.1)' }
+ ])
+ },
+ lineStyle: { color: '#00d4ff' },
+ itemStyle: { color: '#00d4ff' }
+ }]
+ }
+ chart.setOption(option)
+ charts.value.push(chart)
+}
+
+// 瀹炴椂鏁版嵁鎶樼嚎鍥�
+const initRealtimeLineChart = () => {
+ if (!realtimeLineChartRef.value) return
+ const chart = echarts.init(realtimeLineChartRef.value)
+ const option = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ grid: {
+ left: '10%',
+ right: '10%',
+ top: '10%',
+ bottom: '20%'
+ },
+ xAxis: {
+ type: 'category',
+ data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
+ axisLine: { lineStyle: { color: '#333' } },
+ axisLabel: { color: '#B8C8E0' }
+ },
+ yAxis: {
+ type: 'value',
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: { color: '#B8C8E0' },
+ splitLine: { lineStyle: { color: '#333' } }
+ },
+ series: [
+ {
+ name: '鏁版嵁1',
+ data: [120, 140, 160, 130, 150],
+ type: 'line',
+ lineStyle: { color: '#00d4ff' },
+ itemStyle: { color: '#00d4ff' }
+ },
+ {
+ name: '鏁版嵁2',
+ data: [100, 120, 140, 110, 130],
+ type: 'line',
+ lineStyle: { color: '#0099ff' },
+ itemStyle: { color: '#0099ff' }
+ }
+ ]
+ }
+ chart.setOption(option)
+ charts.value.push(chart)
+}
+
+// 鍏ㄥ睆鍔熻兘瀹炵幇 - 閽堝data-dashboard鍏冪礌
+const toggleFullscreen = () => {
+ const element = document.querySelector('.data-dashboard')
+
+ if (!element) return
+
+ if (!isFullscreen.value) {
+ if (element.requestFullscreen) {
+ element.requestFullscreen()
+ } else if (element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen()
+ } else if (element.msRequestFullscreen) {
+ element.msRequestFullscreen()
+ }
+ } else {
+ if (document.exitFullscreen) {
+ document.exitFullscreen()
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen()
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen()
+ }
+ }
+}
+
+// 鐩戝惉鍏ㄥ睆鍙樺寲浜嬩欢
+const handleFullscreenChange = () => {
+ const fullscreenElement = document.fullscreenElement ||
+ document.webkitFullscreenElement ||
+ document.msFullscreenElement
+ isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
+}
+
+// 鐢熷懡鍛ㄦ湡閽╁瓙
+onMounted(() => {
+ initTime()
+ // 浣跨敤nextTick纭繚DOM瀹屽叏娓叉煋鍚庡啀鍒濆鍖栧浘琛�
+ nextTick(() => {
+ // 鍒濆鍖朼utofit鑷�傚簲
+ autofit.init({ dh: 1440, dw: 2560, el: '.data-dashboard', resize: true }, false)
+
+ // 娣诲姞鑷姩婊氬姩鍔ㄧ敾鏁堟灉 - 瀹㈡埛淇℃伅鍒楄〃
+ const contractList = refContractList.value
+ if (contractList && contractList.scrollHeight > contractList.clientHeight) {
+ // 鍒涘缓涓�涓厠闅嗛」锛岀敤浜庡疄鐜版棤缂濇粴鍔�
+ const scrollItems = Array.from(contractList.querySelectorAll('li'))
+ const itemHeight = scrollItems[0]?.offsetHeight || 0
+ const containerHeight = contractList.clientHeight
+ const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
+
+ // 鍏嬮殕鍓嶅嚑涓」鐩苟娣诲姞鍒板垪琛ㄦ湯灏撅紝瀹炵幇鏃犵紳婊氬姩
+ for (let i = 0; i < cloneCount; i++) {
+ const clone = scrollItems[i % scrollItems.length].cloneNode(true)
+ contractList.appendChild(clone)
+ }
+
+ let scrollPosition = 0
+ const scrollSpeed = 1.5 // 澧炲姞婊氬姩閫熷害锛屼娇婊氬姩鏇村姞鏄庢樉
+ const pauseTime = 3000 // 婊氬姩鏆傚仠鏃堕棿
+ let isPaused = false
+ let lastTimestamp = 0
+
+ // 杩炵画婊氬姩鍔ㄧ敾鍑芥暟
+ function scrollAnimation(timestamp) {
+ if (!lastTimestamp) lastTimestamp = timestamp
+ const deltaTime = timestamp - lastTimestamp
+ lastTimestamp = timestamp
+
+ if (!isPaused) {
+ scrollPosition += scrollSpeed * (deltaTime / 16) // 鏍囧噯鍖栦负60fps鐨勯�熷害
+
+ // 褰撴粴鍔ㄨ秴杩囧師濮嬪唴瀹归暱搴︽椂锛岄噸缃綅缃疄鐜版棤缂濇粴鍔�
+ if (scrollPosition >= contractList.scrollHeight - containerHeight - cloneCount * itemHeight) {
+ scrollPosition = 0
+ contractList.scrollTop = 0
+ } else {
+ contractList.scrollTop = scrollPosition
+ }
+ }
+
+ timerScroll.value = requestAnimationFrame(scrollAnimation)
+ }
+
+ // 鍚姩婊氬姩鍔ㄧ敾
+ timerScroll.value = requestAnimationFrame(scrollAnimation)
+
+ // 璁剧疆婊氬姩-鏆傚仠-婊氬姩鐨勫惊鐜晥鏋�
+ const pauseTimer = setInterval(() => {
+ isPaused = !isPaused
+ }, pauseTime)
+
+ // 娓呯悊瀹氭椂鍣�
+ contractList._pauseTimer = pauseTimer
+ }
+
+ // 寰呭姙浜嬮」鍒楄〃婊氬姩鍔熻兘宸茬Щ鑷硉odoInfoS鍑芥暟涓紝鍦ㄨ幏鍙栨暟鎹悗鍒濆鍖�
+ })
+
+ window.addEventListener('resize', handleResize)
+ analysisCustomer()
+ qualityStatisticsInfo()
+ accountStatisticsInfo()
+ getNum()
+ getLedgerNum()
+ todoInfoS()
+ statisticsReceivable()
+ getAmountHalfYearNum()
+
+ // 璁剧疆鑷姩杞崲鍛ㄣ�佹湀銆佸搴︾殑瀹氭椂鍣紝姣�10绉掑垏鎹竴娆�
+ autoSwitchTimer.value = setInterval(() => {
+ // 寰幆鍒囨崲锛�1(鍛�) -> 2(鏈�) -> 3(瀛e害) -> 1(鍛�)
+ radio1.value = radio1.value === 3 ? 1 : radio1.value + 1
+ statisticsReceivable()
+ }, 10000) // 10绉掑垏鎹竴娆�
+})
+
+onBeforeUnmount(() => {
+ if (timer.value) {
+ clearInterval(timer.value)
+ }
+ if (timerScroll.value) {
+ cancelAnimationFrame(timerScroll.value)
+ }
+ // 娓呯悊婊氬姩鍒楄〃鐨勬殏鍋滃畾鏃跺櫒
+ const contractList = refContractList.value
+ if (contractList && contractList._pauseTimer) {
+ clearInterval(contractList._pauseTimer)
+ }
+
+ // 娓呯悊寰呭姙浜嬮」鍒楄〃鐨勫姩鐢诲拰瀹氭椂鍣�
+ const todoList = refTodoList.value
+ if (todoList) {
+ if (todoList._animationFrame) {
+ cancelAnimationFrame(todoList._animationFrame)
+ todoList._animationFrame = null
+ }
+ if (todoList._pauseTimer) {
+ clearInterval(todoList._pauseTimer)
+ todoList._pauseTimer = null
+ }
+ }
+
+ // 娓呯悊鑷姩杞崲鍛ㄣ�佹湀銆佸搴︾殑瀹氭椂鍣�
+ if (autoSwitchTimer.value) {
+ clearInterval(autoSwitchTimer.value)
+ autoSwitchTimer.value = null
+ }
+
+ window.removeEventListener('resize', handleResize)
+ window.removeEventListener('fullscreenchange', handleFullscreenChange)
+ window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
+ window.removeEventListener('MSFullscreenChange', handleFullscreenChange)
+ // 绉婚櫎鎴戜滑娣诲姞鐨刟utofit鍔ㄦ�佽皟鏁寸洃鍚櫒
+ if (window._autofitUpdateHandler) {
+ window.removeEventListener('resize', window._autofitUpdateHandler)
+ delete window._autofitUpdateHandler
+ }
+ disposeCharts()
+ // 鍏抽棴autofit
+ autofit.off()
+})
+</script>
+
+<style scoped>
+.data-dashboard {
+ position: relative;
+ width: 100vw;
+ overflow: hidden;
+ background-image: url("@/assets/BI/backImage@2x.png");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+/* 鍏ㄥ睆鐘舵�佺殑鏍峰紡 */
+.data-dashboard:fullscreen {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background-color: inherit;
+ z-index: 9999;
+}
+
+/* Webkit娴忚鍣ㄥ墠缂� */
+.data-dashboard:-webkit-full-screen {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background-color: inherit;
+ z-index: 9999;
+}
+
+/* MS娴忚鍣ㄥ墠缂� */
+.data-dashboard:-ms-fullscreen {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background-color: inherit;
+ z-index: 9999;
+}
+
+/* 鍏ㄥ睆鐘舵�佷笅鐨勫唴瀹瑰尯鍩熼�傞厤 */
+.data-dashboard:fullscreen .dashboard-content {
+ height: calc(100vh - 120px);
+}
+
+.data-dashboard:-webkit-full-screen .dashboard-content {
+ height: calc(100vh - 120px);
+}
+
+.data-dashboard:-ms-fullscreen .dashboard-content {
+ height: calc(100vh - 120px);
+}
+
+.dashboard-header {
+ position: relative;
+ z-index: 1;
+ height: 170px;
+ background-image: url("@/assets/BI/biaoti.png");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.fullscreen-btn {
+ position: absolute;
+ top: 10px;
+ left: 20px;
+ width: 40px;
+ height: 40px;
+ background: rgba(0, 20, 60, 0.8);
+ border: 1px solid rgba(0, 212, 255, 0.3);
+ border-radius: 6px;
+ color: #00d4ff;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ z-index: 10000;
+}
+
+.fullscreen-btn:hover {
+ background: rgba(0, 30, 90, 0.9);
+ border-color: rgba(0, 212, 255, 0.5);
+}
+
+.dashboard-content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ gap: 30px;
+ padding: 0 30px;
+ height: calc(100vh - 120px);
+ overflow: hidden;
+}
+
+/* 纭繚鍚勯潰鏉胯兘澶熸纭樉绀� */
+.left-panel, .center-panel, .right-panel {
+ overflow: hidden;
+}
+
+.left-panel,
+.right-panel {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ width: 520px;
+}
+
+.center-panel {
+ flex: 1.5;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+.panel-item-customers {
+ border: 1px solid #1A58B0;
+ padding: 18px;
+ width: 100%;
+ height: 540px;
+}
+.panel-title-second {
+ height: 60px;
+ display: flex;
+ gap: 12px;
+ margin-bottom: 20px;
+ align-items: center;
+}
+.quality-cards {
+ display: flex;
+ gap: 12px;
+ width: 100%;
+ height: 94px;
+ justify-content: space-between;
+ align-items: center;
+}
+.quality-cardSec {
+ display: flex;
+}
+.quality-cardTitle {
+ font-weight: 400;
+ font-size: 14px;
+ color: #FFFFFF;
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+}
+.quality-card {
+ width: 80px;
+ height: 60px;
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+.quality-card.one {
+ background-image: url("@/assets/BI/yuancailiaoyijianicon@2x.png");
+}
+.quality-card.two {
+ background-image: url("@/assets/BI/guochengyijianicon@2x.png");
+}
+.quality-card.three {
+ background-image: url("@/assets/BI/chuchangyijianicon@2x.png");
+
+}
+.panel-title-icon {
+ width: 60px;
+ height: 60px;
+ background-image: url("@/assets/BI/hetongicon.png");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+.panel-item {
+ background: rgba(0, 20, 60, 0.8);
+ border: 1px solid rgba(0, 212, 255, 0.3);
+ border-radius: 12px;
+ padding: 30px;
+ backdrop-filter: blur(10px);
+ min-height: 200px;
+}
+
+.panel-header {
+ background-image: url("@/assets/BI/kehuhetongback@2x.png");
+ background-size: 100% 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ height: 36px;
+}
+
+.panel-title {
+ width: 100%;
+ font-weight: 500;
+ font-size: 16px;
+ color: #D9ECFF;
+ padding-left: 46px;
+ line-height: 36px;
+}
+.total-customers {
+ background-image: url("@/assets/BI/hetongjineback@2x.png");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ width: 90%;
+ height: 60px;
+ display: flex;
+ align-items: center;
+ padding: 0 20px;
+ gap: 20px;
+}
+
+.total-customers .label {
+ font-weight: 500;
+ font-size: 16px;
+ color: #FFFFFF;
+}
+
+.total-customers .value {
+ font-weight: 500;
+ font-size: 40px;
+ background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.contract-list {
+ margin-top: 16px;
+ font-size: 14px;
+ color: #666;
+ list-style: none;
+ padding: 0;
+ height: 82%;
+ overflow-y: auto;
+ width: 460px;
+ /* 闅愯棌婊氬姩鏉′絾淇濈暀婊氬姩鍔熻兘 */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE鍜孍dge */
+}
+
+/* Chrome銆丼afari鍜孫pera */
+.contract-list::-webkit-scrollbar {
+ display: none;
+}
+.line {
+ position: relative;
+ width: 230px;
+}
+.line::after {
+ content: '';
+ position: absolute;
+ right: 2px;
+ top: 0;
+ bottom: 0;
+ width: 1px;
+ background-color: #C9C5C5;
+ border-radius: 2px;
+}
+.contract-list li {
+ margin-top: 10px;
+}
+.stats-cards {
+ display: flex;
+ gap: 30px;
+}
+
+.stat-card {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background-image: url("@/assets/BI/border@2x.png");
+ background-size: 100% 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ height: 142px;
+}
+
+.card-icon {
+ width: 100px;
+ height: 100px;
+ margin: 20px 20px 0 10px;
+}
+
+.card-content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.card-value {
+ font-weight: 500;
+ font-size: 40px;
+ background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.card-label {
+ font-weight: 400;
+ font-size: 19px;
+ color: rgba(208,231,255,0.7);
+}
+
+.equipment-stats {
+ border: 1px solid #1A58B0;
+ padding: 18px;
+ height: 240px;
+}
+.equipment-header {
+ font-weight: 500;
+ font-size: 21px;
+ display: flex;
+ border-bottom: 1px solid;
+ border-image: linear-gradient( 270deg, rgba(0,126,255,0) 0%, rgba(0,126,255,0.4549) 35%, #007EFF 78%, #007EFF 100%) 1;
+ padding-bottom: 2px;
+}
+.equipment-title {
+ font-weight: 500;
+ font-size: 21px;
+ background: linear-gradient(360deg, #056DFF 0%, #43E8FC 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ line-height: 50px;
+}
+.equipment-icon {
+ width: 50px;
+ height: 50px;
+}
+.equipment-items {
+ display: flex;
+ justify-content: space-around;
+ gap: 30px;
+}
+
+.equipment-item {
+ text-align: center;
+}
+
+.equipment-value {
+ display: block;
+ font-weight: 500;
+ font-size: 40px;
+ color: #FFFFFF;
+ width: 120px;
+ height: 110px;
+ line-height: 110px;
+ background-image: url("@/assets/BI/shujutongji@2x.png");
+ background-size: 100% 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ margin-bottom: 8px;
+}
+
+.equipment-label {
+ font-weight: 500;
+ font-size: 21px;
+ color: #FFFFFE;
+}
+
+.event-info {
+ background-image: url("@/assets/BI/shijianmingchengbeijing@2x.png");
+ background-size: 100% 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ padding: 20px;
+ height: 186px;
+}
+.event-header {
+ display: flex;
+ align-items: center;
+}
+.event-icon {
+ width: 40px;
+ height: 40px;
+}
+.event-title {
+ font-weight: 500;
+ font-size: 24px;
+ color: #FFFFFE;
+ line-height: 30px;
+}
+.todo-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ height: 120px; /* 鎸夌敤鎴疯姹傝皟鏁撮珮搴� */
+ overflow: hidden;
+ font-size: 15px;
+}
+.todo-list li {
+ border-radius: 8px;
+ margin-bottom: 12px;
+ padding: 12px 40px;
+ height: 74px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+.todo-title {
+ font-weight: 400;
+ font-size: 20px;
+ color: #FFFFFE;
+ position: relative;
+}
+.todo-title::before {
+ content: ''; /* 蹇呴渶锛岃〃绀鸿繖閲屾湁涓�涓唴瀹� */
+ position: absolute;
+ left: -10px; /* 瀹氫綅鍒板乏渚� */
+ top: 50%; /* 鍨傜洿灞呬腑 */
+ transform: translateY(-50%); /* 寰皟鍨傜洿灞呬腑 */
+ width: 6px; /* 鍦嗙殑鐩村緞 */
+ height: 6px; /* 鍦嗙殑鐩村緞 */
+ background: #498CEB;
+ border-radius: 50%; /* 璁╁叾鍙樻垚鍦嗗舰 */
+}
+.todo-division {
+ font-weight: 400;
+ font-size: 20px;
+ color: #FFFFFE;
+}
+.todo-time {
+ font-weight: 400;
+ font-size: 20px;
+ color: #FFFFFE;
+}
+.data-statistics {
+ flex: 1;
+}
+.financial-header {
+ background-image: url("@/assets/BI/caiwufenxiback@2x.png");
+ background-size: 100% 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+.financial-title {
+ width: 100%;
+ font-weight: 500;
+ font-size: 16px;
+ color: #D9ECFF;
+ padding-left: 46px;
+ line-height: 36px;
+}
+.data-legend {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+ margin-bottom: 20px;
+}
+
+.legend-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.legend-color {
+ width: 12px;
+ height: 12px;
+ border-radius: 4px;
+}
+
+.legend-text {
+ font-size: 12px;
+ color: #999;
+}
+
+.horizontal-bar-chart {
+ height: 150px;
+}
+
+.financial-analysis,
+.realtime-analysis {
+ flex: 1;
+}
+
+.financial-tabs,
+.realtime-tabs {
+ display: flex;
+ gap: 16px;
+ margin-bottom: 20px;
+}
+
+.tab {
+ padding: 12px 24px;
+ background: rgba(0, 0, 0, 0.3);
+ border: 1px solid rgba(0, 212, 255, 0.3);
+ border-radius: 6px;
+ color: #999;
+ cursor: pointer;
+ transition: all 0.3s;
+}
+
+.tab.active {
+ background: rgba(0, 212, 255, 0.2);
+ color: #00d4ff;
+ border-color: #00d4ff;
+}
+
+.area-chart,
+.line-chart {
+ height: 150px;
+}
+
+/* 鑷畾涔夊崟閫夋寜閽粍鏍峰紡 */
+.custom-radio-group :deep(.el-radio-button__inner) {
+ background-color: transparent;
+ color: white;
+ border-color: rgba(255, 255, 255, 0.3);
+}
+
+.custom-radio-group :deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
+ background-color: rgba(255, 255, 255, 0.2);
+ color: white;
+ border-color: rgba(255, 255, 255, 0.5);
+ box-shadow: -1px 0 0 0 rgba(255, 255, 255, 0.5);
+}
+</style>
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index 26e8edc..b4b6129 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,82 +1,82 @@
-import { defineConfig, loadEnv } from "vite";
-import path from "path";
-import createVitePlugins from "./vite/plugins";
-
-// https://vitejs.dev/config/
-export default defineConfig(({ mode, command }) => {
- const env = loadEnv(mode, process.cwd());
- const { VITE_APP_ENV } = env;
- const baseUrl =
- VITE_APP_ENV == "development"
- ? "http://114.132.189.42:8089" // 寮�鍙戠幆澧冨悗绔帴鍙�
- : "http://114.132.189.42:8089"; // 鐢熶骇鐜鍚庣鎺ュ彛
-
- return {
- // 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
- // 榛樿鎯呭喌涓嬶紝vite 浼氬亣璁句綘鐨勫簲鐢ㄦ槸琚儴缃插湪涓�涓煙鍚嶇殑鏍硅矾寰勪笂
- // 渚嬪 https://www.ruoyi.vip/銆傚鏋滃簲鐢ㄨ閮ㄧ讲鍦ㄤ竴涓瓙璺緞涓婏紝浣犲氨闇�瑕佺敤杩欎釜閫夐」鎸囧畾杩欎釜瀛愯矾寰勩�備緥濡傦紝濡傛灉浣犵殑搴旂敤琚儴缃插湪 https://www.ruoyi.vip/admin/锛屽垯璁剧疆 baseUrl 涓� /admin/銆�
- base: VITE_APP_ENV === "production" ? "/" : "/",
- plugins: createVitePlugins(env, command === "build"),
- resolve: {
- // https://cn.vitejs.dev/config/#resolve-alias
- alias: {
- // 璁剧疆璺緞
- "~": path.resolve(__dirname, "./"),
- // 璁剧疆鍒悕
- "@": path.resolve(__dirname, "./src"),
- },
- // https://cn.vitejs.dev/config/#resolve-extensions
- extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
- },
- // 鎵撳寘閰嶇疆
- build: {
- // https://vite.dev/config/build-options.html
- sourcemap: command === "build" ? false : "inline",
- outDir: "dist",
- assetsDir: "assets",
- chunkSizeWarningLimit: 2000,
- rollupOptions: {
- output: {
- chunkFileNames: "static/js/[name]-[hash].js",
- entryFileNames: "static/js/[name]-[hash].js",
- assetFileNames: "static/[ext]/[name]-[hash].[ext]",
- },
- },
- },
- // vite 鐩稿叧閰嶇疆
- server: {
- port: 80,
- host: true,
- open: true,
- proxy: {
- // https://cn.vitejs.dev/config/#server-proxy
- "/dev-api": {
- target: baseUrl,
- changeOrigin: true,
- rewrite: (p) => p.replace(/^\/dev-api/, ""),
- },
- // springdoc proxy
- "^/v3/api-docs/(.*)": {
- target: baseUrl,
- changeOrigin: true,
- },
- },
- },
- css: {
- postcss: {
- plugins: [
- {
- postcssPlugin: "internal:charset-removal",
- AtRule: {
- charset: (atRule) => {
- if (atRule.name === "charset") {
- atRule.remove();
- }
- },
- },
- },
- ],
- },
- },
- };
-});
+import { defineConfig, loadEnv } from "vite";
+import path from "path";
+import createVitePlugins from "./vite/plugins";
+
+// https://vitejs.dev/config/
+export default defineConfig(({ mode, command }) => {
+ const env = loadEnv(mode, process.cwd());
+ const { VITE_APP_ENV } = env;
+ const baseUrl =
+ VITE_APP_ENV == "development"
+ ? "http://114.132.189.42:9036" // 寮�鍙戠幆澧冨悗绔帴鍙�
+ : "http://114.132.189.42:9036"; // 鐢熶骇鐜鍚庣鎺ュ彛
+
+ return {
+ // 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
+ // 榛樿鎯呭喌涓嬶紝vite 浼氬亣璁句綘鐨勫簲鐢ㄦ槸琚儴缃插湪涓�涓煙鍚嶇殑鏍硅矾寰勪笂
+ // 渚嬪 https://www.ruoyi.vip/銆傚鏋滃簲鐢ㄨ閮ㄧ讲鍦ㄤ竴涓瓙璺緞涓婏紝浣犲氨闇�瑕佺敤杩欎釜閫夐」鎸囧畾杩欎釜瀛愯矾寰勩�備緥濡傦紝濡傛灉浣犵殑搴旂敤琚儴缃插湪 https://www.ruoyi.vip/admin/锛屽垯璁剧疆 baseUrl 涓� /admin/銆�
+ base: VITE_APP_ENV === "production" ? "/" : "/",
+ plugins: createVitePlugins(env, command === "build"),
+ resolve: {
+ // https://cn.vitejs.dev/config/#resolve-alias
+ alias: {
+ // 璁剧疆璺緞
+ "~": path.resolve(__dirname, "./"),
+ // 璁剧疆鍒悕
+ "@": path.resolve(__dirname, "./src"),
+ },
+ // https://cn.vitejs.dev/config/#resolve-extensions
+ extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
+ },
+ // 鎵撳寘閰嶇疆
+ build: {
+ // https://vite.dev/config/build-options.html
+ sourcemap: command === "build" ? false : "inline",
+ outDir: "dist",
+ assetsDir: "assets",
+ chunkSizeWarningLimit: 2000,
+ rollupOptions: {
+ output: {
+ chunkFileNames: "static/js/[name]-[hash].js",
+ entryFileNames: "static/js/[name]-[hash].js",
+ assetFileNames: "static/[ext]/[name]-[hash].[ext]",
+ },
+ },
+ },
+ // vite 鐩稿叧閰嶇疆
+ server: {
+ port: 80,
+ host: true,
+ open: true,
+ proxy: {
+ // https://cn.vitejs.dev/config/#server-proxy
+ "/dev-api": {
+ target: baseUrl,
+ changeOrigin: true,
+ rewrite: (p) => p.replace(/^\/dev-api/, ""),
+ },
+ // springdoc proxy
+ "^/v3/api-docs/(.*)": {
+ target: baseUrl,
+ changeOrigin: true,
+ },
+ },
+ },
+ css: {
+ postcss: {
+ plugins: [
+ {
+ postcssPlugin: "internal:charset-removal",
+ AtRule: {
+ charset: (atRule) => {
+ if (atRule.name === "charset") {
+ atRule.remove();
+ }
+ },
+ },
+ },
+ ],
+ },
+ },
+ };
+});
--
Gitblit v1.9.3