123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467 |
- <template>
- <div class="bootstrap-scope">
- <div class="widget-chart">
- <!-- 主容器 -->
- <div class="pcoded-main-container">
- <div class="pcoded-wrapper">
- <div class="pcoded-content">
- <div class="pcoded-inner-content">
- <div class="main-body">
- <div class="page-wrapper">
- <!-- 主要内容区域 -->
- <div class="row">
- <!-- 云计算存储卡片 -->
- <!-- <div class="col-xl-4 col-md-12">
- <div class="card">
- <div class="card-body pb-0">
- <div class="row">
- <div class="col-auto">
- <h6>云计算</h6>
- </div>
- </div>
- <div class="row mt-2">
- <div class="col-auto">
- <span class="d-block">
- 存储
- </span>
- <h6 class="ms-3 mt-1">10.5 GB</h6>
- </div>
- <div class="col">
- <span class="d-block">
- 带宽
- </span>
- <h6 class="ms-3 mt-1">50 GB</h6>
- </div>
- </div>
- </div>
- <div ref="storageChart" style="height: 100px"></div>
- </div>
- </div> -->
- <div class="col-xl-8">
- <div class="card">
- <div class="card-header">
- <div class="row">
- <div class="col">
- <h5>C/GPU使用率</h5>
- </div>
- <!-- <div class="col-auto text-end">
- <span>This Month</span>
- </div> -->
- </div>
- </div>
- <div class="card-body">
- <div class="row mb-2">
- <div class="col-auto">
- <h4 class="m-0">
- {{ cpuValue + "%"
- }}<i
- class="feather icon-arrow-up text-c-green"
- ></i>
- </h4>
- <span>CPU使用率</span>
- </div>
- <div class="col-auto">
- <h4 class="m-0">
- {{ GpuValue + "%"
- }}<i
- class="feather icon-arrow-down text-c-red"
- ></i>
- </h4>
- <span>GPU使用率</span>
- </div>
- <!-- <div class="col">
- <h4 class="m-0">
- 40.05%<i
- class="feather icon-arrow-up text-c-green"
- ></i>
- </h4>
- <span>Bounce Rate</span>
- </div> -->
- </div>
- <div
- ref="siteVisitorChart"
- style="height: 285px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- -->
- <div class="col-xl-4">
- <div class="row">
- <!-- 支持分析卡片 -->
- <div class="col-xl-12 col-md-6">
- <div class="card">
- <div class="card-body">
- <div class="row">
- <div class="col-6">
- <h6>Memory</h6>
- </div>
- <!-- <div class="col">
- <div class="dropdown float-end">
- <a
- class="dropdown-toggle text-c-blue"
- href="#"
- data-bs-toggle="dropdown"
- >
- 最近5个月
- </a>
- <div class="dropdown-menu dropdown-menu-end">
- <a class="dropdown-item" href="#">1周</a>
- <a class="dropdown-item" href="#">2年</a>
- <a class="dropdown-item" href="#">3个月</a>
- </div>
- </div>
- </div> -->
- </div>
- <div class="row">
- <div class="col-6">
- <h2 class="mt-2 mb-0">
- {{ currentPercentage.total + "GB" }}
- </h2>
- <span>总内存</span>
- <h6 class="mb-0 mt-3">
- 空闲内存:
- <span class="text-primary">{{
- currentPercentage.free + "GB"
- }}</span>
- </h6>
- <h6>
- 已使用:
- <span class="text-danger">{{
- currentPercentage.used + "GB"
- }}</span>
- </h6>
- </div>
- <div class="col">
- <!-- 支持工单完成率图表 -->
- <div
- ref="hdComplitedTicket"
- style="height: 130px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 知识库统计卡片 -->
- <div class="col-xl-12 col-md-6">
- <div class="card">
- <div class="card-body">
- <div
- class="row"
- style="display: flex; align-items: center"
- >
- <div class="col-auto">
- <h6>知识库统计</h6>
- </div>
- <div
- class="col"
- style="
- display: flex;
- justify-content: flex-end;
- "
- >
- <el-select
- v-model="kenValue"
- @change="kenChange"
- placeholder="请选择"
- >
- <el-option
- v-for="item in kenList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- >
- </el-option>
- </el-select>
- <!-- <div class="dropdown float-end">
- <a
- class="dropdown-toggle text-c-blue"
- href="#"
- data-bs-toggle="dropdown"
- >
- 最近30天
- </a>
- <div
- class="dropdown-menu dropdown-menu-end"
- >
- <a class="dropdown-item" href="#">1周</a>
- <a class="dropdown-item" href="#">2年</a>
- <a class="dropdown-item" href="#"
- >3个月</a
- >
- </div>
- </div> -->
- </div>
- </div>
- <div class="row">
- <div class="col-6 p-r-0">
- <template
- v-for="(count, type) in fileTypeCounts"
- >
- <h6
- :key="type"
- class="my-3"
- v-if="
- ['pdf', 'docx', 'xlsx'].includes(
- type.toLowerCase()
- )
- "
- >
- <i
- class="feather"
- :class="getFileTypeIcon(type)"
- style="
- font-size: 20px;
- margin-right: 8px;
- "
- :style="{
- color: getFileTypeColor(type),
- }"
- ></i>
- {{ type.toUpperCase() }}
- <span class="ms-2"> </span>
- <span
- :class="getChangeClass(type)"
- class="ms-2 f-14"
- >
- <i
- class="feather"
- :class="getChangeIcon(type)"
- ></i>
- {{ count }}
- <!-- {{ getChangePercentage(type) }} -->
- </span>
- </h6>
- </template>
- </div>
- <div class="col-6">
- <!-- 设备占比饼图 -->
- <div
- ref="chartPercent"
- style="height: 131px"
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- <div class="col-xl-12 col-md-6">
- <div class="card">
- <div class="card-body">
- <h6>Traffic tracker</h6>
- <div class="row mt-2">
- <div class="col-6">
- <span class="d-block text-uppercase"
- >Inbound</span
- >
- <h3 class="mt-1">180 GB</h3>
- <div
- ref="transactions1"
- style="
- height: 50px;
- width: 100%;
- margin: 0 auto;
- "
- ></div>
- </div>
- <div class="col-6">
- <span class="d-block text-uppercase"
- >Outbound</span
- >
- <h3 class="mt-1">597.1 GB</h3>
- <div
- ref="transactions2"
- style="
- height: 50px;
- width: 100%;
- margin: 0 auto;
- "
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="col-xl-12 col-md-6">
- <div class="card">
- <div class="card-body">
- <div class="row d-flex align-items-center">
- <div class="col-6 p-r-0">
- <span class="d-block mb-1"
- ><i
- class="fas fa-circle f-10 m-r-5"
- style="color: #a367dc"
- ></i
- >Desktop [66.6%]</span
- >
- <span class="d-block mb-1"
- ><i
- class="fas fa-circle f-10 m-r-5"
- style="color: #67b7dc"
- ></i
- >Mobile [29.7%]</span
- >
- <span class="d-block"
- ><i
- class="fas fa-circle f-10 m-r-5"
- style="color: #6771dc"
- ></i
- >Tablet [38.6%]</span
- >
- </div>
- <div class="col-6">
- <div
- ref="deviceChart"
- id="device-chart"
- style="height: 140px"
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div> -->
- </div>
- </div>
- <!-- 其他统计卡片组 -->
- <div class="col-sm-12">
- <div class="row g-0">
- <!-- 交易量卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>知识库数量</span>
- <h3>{{ kenList.length }}</h3>
- <div
- ref="real4Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- 当前库存卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>文件已解析数量</span>
- <h3>{{ docList.run_3 }}</h3>
- <div
- ref="real6Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- 跳出率卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>文件未解析数量</span>
- <h3>{{ docList.run_0 }}</h3>
- <div
- ref="real1Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- 订单总额卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>文档数量</span>
- <h3>{{ docTotal }}</h3>
- <div
- ref="real5Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- 收入卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>模版数量</span>
- <h3>{{ temTotal }}</h3>
- <div
- ref="real2Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- <!-- 新购买卡片 -->
- <div class="col-md-4 col-xl-2 col-sm-6">
- <div class="card">
- <div class="card-body">
- <span>模块数量</span>
- <h3>{{ pageTotal }}</h3>
- <div
- ref="real3Chart"
- style="height: 20px; width: 100%"
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import * as am4core from "@amcharts/amcharts4/core";
- import * as am4charts from "@amcharts/amcharts4/charts";
- import am4themes_animated from "@amcharts/amcharts4/themes/animated";
- import BootstrapWrapper from "@/components/BootstrapWrapper/index.vue";
- import { searchlistDoc, searchList } from "@/api/document";
- import { pageTemplate } from "@/api/template";
- import {
- listBuckets,
- structure_count,
- GET_Rbq,
- gpu_info,
- doc_status,
- } from "@/api/knowledge";
- export default {
- name: "WidgetChart",
- components: {
- BootstrapWrapper,
- },
- data() {
- return {
- charts: {}, // 存储图表实例
- chartData: {},
- currentPercentage: {},
- cpuValue: 0,
- GpuValue: 0,
- kenValue: null, //知识库
- kenList: [],
- previousCounts: {}, // 用于存储上一次的数量,计算变化率
- fileTypeCounts: {}, // 用于存储上一次的数量,计算变化率
- docTotal: 0,
- temTotal: 0,
- pageTotal: 0,
- docList: {},
- chartUpdateInterval: null, // 添加新的数据属性用于存储定时器
- isPageVisible: !document.hidden, // 添加新的数据属性
- };
- },
- watch: {
- $route: {
- immediate: true,
- handler(newRoute) {
- this.isOnDashboard = newRoute.path === "/dashboard";
- this.handleRouteChange();
- },
- },
- // 监听页面可见性
- isPageVisible: {
- immediate: true,
- handler(newValue) {
- console.log(newValue);
- if (newValue) {
- // 页面变为可见时
- console.log("Page became visible");
- this.initSiteVisitorChart();
- } else {
- // 页面变为不可见时
- console.log("Page became hidden");
- this.cleanupCharts();
- }
- },
- },
- },
- mounted() {
- document.addEventListener("visibilitychange", this.handleVisibilityChange);
- // 使用动画主题
- am4core.useTheme(am4themes_animated);
- this.init();
- // 初始化各个图表
- this.initHdComplitedTicket();
- this.initChartPercent();
- this.initStorageChart();
- this.initRealTimeCharts();
- this.initSiteVisitorChart(); // 添加这行
- this.initTransactionCharts();
- this.initDeviceChart(); // 添加这行
- },
- // 修改生命周期钩子
- activated() {
- console.log(1123);
- // 当组件被激活时重新初始化图表
- this.initSiteVisitorChart();
- },
- deactivated() {
- // 当组件被停用时清理资源
- this.cleanupCharts();
- },
- beforeDestroy() {
- // 组件销毁前清理所有资源
- this.cleanupCharts();
- this.closeWebSocket();
- // 清理其他图表实例
- Object.values(this.charts).forEach((chart) => {
- if (chart) {
- if (typeof chart.dispose === "function") {
- chart.dispose();
- } else if (typeof chart === "number") {
- clearInterval(chart);
- }
- }
- });
- },
- methods: {
- // 处理页面可见性变化
- handleVisibilityChange() {
- this.isPageVisible = !document.hidden;
- },
- closeWebSocket() {
- if (this.ws) {
- this.ws.close();
- this.ws = null;
- }
- },
- handleRouteChange() {
- if (this.isOnDashboard) {
- this.initWebSocket(); // 初始化 WebSocket
- } else {
- this.closeWebSocket();
- }
- },
- /* websocket 请求 */
- initWebSocket() {
- // 获取基础 API 地址并替换 http/https 为 ws/wss
- const wsUrl = process.env.VUE_APP_BASE_API.replace(/^http/, "ws");
- // 创建 WebSocket 连接
- this.ws = new WebSocket(`${wsUrl}/ws/monitoring`);
- // 连接成功回调
- this.ws.onopen = () => {
- console.log("WebSocket连接成功");
- };
- // 接收消息回调
- this.ws.onmessage = (event) => {
- try {
- const data = JSON.parse(event.data);
- // 检查数据结构是否完整
- if (
- data &&
- data.data &&
- data.data.system &&
- data.data.system.cpu &&
- data.data.system.cpu.memory
- ) {
- // 更新图表数据
- this.chartData = data;
- this.cpuValue = data.data.system.cpu.total_usage;
- this.GpuValue = data.data.system.gpu.devices[0]?.power || 0;
- this.currentPercentage = data.data.system.cpu.memory;
- } else {
- console.warn("Received incomplete data structure:", data);
- }
- } catch (error) {
- console.error("Error processing WebSocket message:", error);
- }
- };
- // 连接关闭回调
- this.ws.onclose = () => {
- console.log("WebSocket连接关闭");
- };
- // 连接错误回调
- this.ws.onerror = (error) => {
- console.error("WebSocket连接错误:", error);
- };
- },
- // 初始化支持工单完成率图表
- initHdComplitedTicket() {
- const chart = am4core.create(
- this.$refs.hdComplitedTicket,
- am4charts.GaugeChart
- );
- chart.logo.disabled = true;
- chart.innerRadius = am4core.percent(82);
- // 修改主轴配置
- const axis = chart.xAxes.push(new am4charts.ValueAxis());
- axis.min = 0;
- axis.max = 100;
- axis.strictMinMax = true;
- // 设置固定的半径
- axis.renderer.radius = 80; // 使用固定像素值而不是百分比
- axis.renderer.inside = true;
- axis.renderer.line.strokeOpacity = 0;
- axis.renderer.ticks.template.strokeOpacity = 1;
- axis.renderer.ticks.template.length = 10;
- axis.renderer.grid.template.disabled = true;
- axis.renderer.labels.template.radius = 40;
- axis.renderer.labels.template.adapter.add("text", () => "");
- // 修改第二轴配置
- const axis2 = chart.xAxes.push(new am4charts.ValueAxis());
- axis2.min = 0;
- axis2.max = 100;
- // 设置固定的内半径
- axis2.renderer.innerRadius = 65; // 使用固定像素值
- axis2.renderer.radius = 80; // 设置固定的外半径
- axis2.strictMinMax = true;
- axis2.renderer.labels.template.disabled = true;
- axis2.renderer.ticks.template.disabled = true;
- axis2.renderer.grid.template.disabled = true;
- // 配置填充范围
- const range0 = axis2.axisRanges.create();
- range0.value = 0;
- range0.endValue = 50;
- range0.axisFill.fillOpacity = 1;
- range0.axisFill.fill = am4core.color("#19BCBF");
- const range1 = axis2.axisRanges.create();
- range1.value = 50;
- range1.endValue = 100;
- range1.axisFill.fillOpacity = 1;
- range1.axisFill.fill = am4core.color("#eff3f6");
- // 添加标签
- const label = chart.radarContainer.createChild(am4core.Label);
- label.isMeasured = false;
- label.fontSize = 18;
- label.x = am4core.percent(50);
- label.y = am4core.percent(100);
- label.horizontalCenter = "middle";
- label.verticalCenter = "bottom";
- label.text = "50%";
- const label2 = chart.radarContainer.createChild(am4core.Label);
- label2.isMeasured = false;
- label2.fontSize = 12;
- label2.x = am4core.percent(50);
- label2.y = am4core.percent(100);
- label2.horizontalCenter = "middle";
- label2.verticalCenter = "top";
- label2.text = "Complited Ticket";
- // 配置指针
- const hand = chart.hands.push(new am4charts.ClockHand());
- hand.axis = axis2;
- hand.innerRadius = am4core.percent(20);
- hand.startWidth = 0;
- hand.pin.disabled = true;
- hand.value = 50;
- hand.disabled = true;
- // 更新事件处理
- hand.events.on("propertychanged", (ev) => {
- range0.endValue = ev.target.value;
- range1.value = ev.target.value;
- axis2.invalidate();
- });
- // 设置图表容器的固定大小
- //chart.width = 160; // 设置固定宽度
- // 定时更新数据
- const interval = setInterval(() => {
- const value = this.currentPercentage.percent; // Math.round(Math.random() * 100);
- label.text = value + "%";
- new am4core.Animation(
- hand,
- {
- property: "value",
- to: value,
- },
- 1000,
- am4core.ease.cubicOut
- ).start();
- }, 2000);
- chart.padding(0, 0, 0, 0);
- // 保存图表实例和定时器
- this.charts.hdComplitedTicket = {
- chart: chart,
- interval: interval,
- };
- },
- // 初始化设备占比饼图
- initChartPercent() {
- const chart = am4core.create(this.$refs.chartPercent, am4charts.PieChart);
- chart.logo.disabled = true;
- chart.innerRadius = 30;
- // 配置系列
- const pieSeries = chart.series.push(new am4charts.PieSeries());
- pieSeries.dataFields.value = "size";
- pieSeries.dataFields.category = "sector";
- pieSeries.labels.template.disabled = true;
- pieSeries.ticks.template.disabled = true;
- pieSeries.colors.step = 3;
- this.charts.chartPercent = chart;
- },
- // 初始化存储使用趋势图
- initStorageChart() {
- const chart = am4core.create(this.$refs.storageChart, am4charts.XYChart);
- // 添加数据
- chart.data = [
- {
- date: "2012-03-01",
- price: 180,
- price1: 50,
- },
- {
- date: "2012-03-02",
- price: 252,
- price1: 40,
- },
- {
- date: "2012-03-03",
- price: 185,
- price1: 55,
- },
- {
- date: "2012-03-04",
- price: 110,
- price1: 38,
- },
- {
- date: "2012-03-05",
- price: 158,
- price1: 87,
- },
- {
- date: "2012-03-06",
- price: 200,
- price1: 67,
- },
- {
- date: "2012-03-07",
- price: 187,
- price1: 100,
- },
- ];
- // 配置X轴
- const dateAxis = chart.xAxes.push(new am4charts.DateAxis());
- dateAxis.renderer.grid.template.location = 0;
- dateAxis.renderer.grid.template.disabled = true;
- dateAxis.startLocation = 0.6;
- dateAxis.endLocation = 0.4;
- dateAxis.renderer.inside = true;
- dateAxis.renderer.labels.template.fill = am4core.color("#463699");
- // 配置Y轴
- const valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
- valueAxis.logarithmic = true;
- valueAxis.renderer.minGridDistance = 0;
- valueAxis.renderer.inside = true;
- valueAxis.renderer.labels.template.disabled = true;
- // 配置第一个数据系列
- const series = chart.series.push(new am4charts.LineSeries());
- series.dataFields.valueY = "price";
- series.dataFields.dateX = "date";
- series.tensionX = 0.77;
- series.strokeWidth = 2;
- series.fillOpacity = 0.1;
- series.tooltipText = "{valueY.value}";
- series.fill = am4core.color("#19BCBF");
- series.stroke = am4core.color("#19BCBF");
- // 配置第二个数据系列
- const series1 = chart.series.push(new am4charts.LineSeries());
- series1.dataFields.valueY = "price1";
- series1.dataFields.dateX = "date";
- series1.tensionX = 0.77;
- series1.strokeWidth = 2;
- series1.fillOpacity = 0.1;
- series1.tooltipText = "{valueY.value}";
- series1.fill = am4core.color("#463699");
- series1.stroke = am4core.color("#463699");
- // 添加第一个系列的圆点
- const bullet = series.bullets.push(new am4charts.CircleBullet());
- bullet.circle.fill = am4core.color("#fff");
- bullet.circle.strokeWidth = 3;
- // 添加第二个系列的圆点
- const bullet1 = series1.bullets.push(new am4charts.CircleBullet());
- bullet1.circle.fill = am4core.color("#fff");
- bullet1.circle.strokeWidth = 3;
- // 添加光标
- chart.cursor = new am4charts.XYCursor();
- chart.cursor.fullWidthLineX = true;
- chart.cursor.xAxis = dateAxis;
- chart.cursor.lineX.strokeWidth = 0;
- chart.cursor.lineX.fill = am4core.color("#fff");
- chart.cursor.lineX.fillOpacity = 0;
- chart.padding(0, 0, 0, 0);
- this.charts.storageChart = chart;
- },
- // 修改initSiteVisitorChart方法
- initSiteVisitorChart() {
- // 如果已存在图表实例,先销毁它
- if (this.charts.siteVisitorChart) {
- this.charts.siteVisitorChart.dispose();
- }
- const chart = am4core.create(
- this.$refs.siteVisitorChart,
- am4charts.XYChart
- );
- chart.logo.disabled = true;
- chart.hiddenState.properties.opacity = 0;
- chart.padding(0, 0, 0, 0);
- chart.zoomOutButton.disabled = true;
- // 初始化数据
- const data = [];
- let visits = 10;
- for (let i = 0; i <= 30; i++) {
- visits -= Math.round(
- (Math.random() < 0.5 ? 1 : -1) * Math.random() * 10
- );
- data.push({
- date: new Date().setSeconds(i - 30),
- cpuValue: this.cpuValue || 0, //Math.abs(visits),
- gpuValue: this.GpuValue || 0,
- });
- }
- chart.data = data;
- // 配置X轴
- const dateAxis = chart.xAxes.push(new am4charts.DateAxis());
- dateAxis.renderer.grid.template.location = 0;
- dateAxis.renderer.minGridDistance = 30;
- dateAxis.dateFormats.setKey("second", "ss");
- dateAxis.periodChangeDateFormats.setKey("second", "[bold]h:mm a");
- dateAxis.periodChangeDateFormats.setKey("minute", "[bold]h:mm a");
- dateAxis.periodChangeDateFormats.setKey("hour", "[bold]h:mm a");
- dateAxis.renderer.inside = true;
- dateAxis.renderer.axisFills.template.disabled = true;
- dateAxis.renderer.ticks.template.disabled = true;
- dateAxis.interpolationDuration = 500;
- dateAxis.rangeChangeDuration = 500;
- // 配置Y轴
- const valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
- valueAxis.tooltip.disabled = true;
- valueAxis.interpolationDuration = 500;
- valueAxis.rangeChangeDuration = 500;
- valueAxis.renderer.inside = true;
- valueAxis.renderer.minLabelPosition = 0.05;
- valueAxis.renderer.maxLabelPosition = 0.95;
- valueAxis.renderer.axisFills.template.disabled = true;
- valueAxis.renderer.ticks.template.disabled = true;
- // CPU 数据系列(红色)
- const cpuSeries = chart.series.push(new am4charts.LineSeries());
- cpuSeries.dataFields.dateX = "date";
- cpuSeries.dataFields.valueY = "cpuValue";
- cpuSeries.interpolationDuration = 500;
- cpuSeries.defaultState.transitionDuration = 0;
- cpuSeries.tensionX = 0.8;
- cpuSeries.stroke = am4core.color("#FF425C"); // 红色
- cpuSeries.strokeWidth = 2;
- // CPU 系列渐变
- cpuSeries.fillOpacity = 1;
- const cpuGradient = new am4core.LinearGradient();
- cpuGradient.addColor(am4core.color("#FF425C"), 0.2);
- cpuGradient.addColor(am4core.color("#FF425C"), 0);
- cpuSeries.fill = cpuGradient;
- // GPU 数据系列(蓝色)
- const gpuSeries = chart.series.push(new am4charts.LineSeries());
- gpuSeries.dataFields.dateX = "date";
- gpuSeries.dataFields.valueY = "gpuValue";
- gpuSeries.interpolationDuration = 500;
- gpuSeries.defaultState.transitionDuration = 0;
- gpuSeries.tensionX = 0.8;
- gpuSeries.stroke = am4core.color("#19BCBF"); // 蓝色
- gpuSeries.strokeWidth = 2;
- // GPU 系列渐变
- gpuSeries.fillOpacity = 1;
- const gpuGradient = new am4core.LinearGradient();
- gpuGradient.addColor(am4core.color("#19BCBF"), 0.2);
- gpuGradient.addColor(am4core.color("#19BCBF"), 0);
- gpuSeries.fill = gpuGradient;
- // CPU 圆点
- const cpuBullet = cpuSeries.createChild(am4charts.CircleBullet);
- cpuBullet.circle.radius = 5;
- cpuBullet.fillOpacity = 1;
- cpuBullet.fill = am4core.color("#FF425C");
- cpuBullet.isMeasured = false;
- // GPU 圆点
- const gpuBullet = gpuSeries.createChild(am4charts.CircleBullet);
- gpuBullet.circle.radius = 5;
- gpuBullet.fillOpacity = 1;
- gpuBullet.fill = am4core.color("#19BCBF");
- gpuBullet.isMeasured = false;
- // 更新两个系列的圆点位置
- cpuSeries.events.on("validated", () => {
- cpuBullet.moveTo(cpuSeries.dataItems.last.point);
- cpuBullet.validatePosition();
- });
- gpuSeries.events.on("validated", () => {
- gpuBullet.moveTo(gpuSeries.dataItems.last.point);
- gpuBullet.validatePosition();
- });
- // 设置初始缩放
- chart.events.on("datavalidated", () => {
- dateAxis.zoom({ start: 1 / 15, end: 1.2 }, false, true);
- });
- // 存储图表实例
- this.charts.siteVisitorChart = chart;
- /* // 启动数据更新
- setTimeout(() => {
- this.startVisitorDataInterval(cpuSeries, gpuSeries);
- }, 100); */
- // 修改数据更新逻辑
- this.startVisitorDataInterval(cpuSeries, gpuSeries);
- },
- // 修改 startVisitorDataInterval 方法
- startVisitorDataInterval(cpuSeries, gpuSeries) {
- // 清除已存在的定时器
- if (this.chartUpdateInterval) {
- clearInterval(this.chartUpdateInterval);
- }
- this.chartUpdateInterval = setInterval(() => {
- const lastDataItem = cpuSeries.dataItems.getIndex(
- cpuSeries.dataItems.length - 1
- );
- if (lastDataItem && lastDataItem.dateX) {
- cpuSeries.chart.addData(
- {
- date: new Date(lastDataItem.dateX.getTime() + 1000),
- cpuValue: this.cpuValue || 0,
- gpuValue: this.GpuValue || 0,
- },
- 1
- );
- }
- }, 1000);
- },
- // 添加清理方法
- cleanupCharts() {
- // 清除定时器
- if (this.chartUpdateInterval) {
- clearInterval(this.chartUpdateInterval);
- this.chartUpdateInterval = null;
- }
- // 清除图表实例
- if (this.charts.siteVisitorChart) {
- this.charts.siteVisitorChart.dispose();
- this.charts.siteVisitorChart = null;
- }
- },
- handleVisitorChartVisibility() {
- if (document.hidden) {
- if (this.charts.siteVisitorInterval) {
- clearInterval(this.charts.siteVisitorInterval);
- }
- } else {
- const series = this.charts.siteVisitorChart.series.getIndex(0);
- this.startVisitorDataInterval(series);
- }
- },
- // 初始化实时数据小图表
- initRealTimeCharts() {
- // 交易量图表
- const real4Chart = am4core.create(
- this.$refs.real4Chart,
- am4charts.XYChart
- );
- // ... 配置real4Chart
- this.charts.real4Chart = real4Chart;
- // 库存图表
- const real6Chart = am4core.create(
- this.$refs.real6Chart,
- am4charts.XYChart
- );
- // ... 配置real6Chart
- this.charts.real6Chart = real6Chart;
- // 跳出率图表
- const real1Chart = am4core.create(
- this.$refs.real1Chart,
- am4charts.XYChart
- );
- // ... 配置real1Chart
- this.charts.real1Chart = real1Chart;
- // 订单总额图表
- const real5Chart = am4core.create(
- this.$refs.real5Chart,
- am4charts.XYChart
- );
- // ... 配置real5Chart
- this.charts.real5Chart = real5Chart;
- // 收入图表
- const real2Chart = am4core.create(
- this.$refs.real2Chart,
- am4charts.XYChart
- );
- // ... 配置real2Chart
- this.charts.real2Chart = real2Chart;
- // 新购买图表
- const real3Chart = am4core.create(
- this.$refs.real3Chart,
- am4charts.XYChart
- );
- // ... 配置real3Chart
- this.charts.real3Chart = real3Chart;
- },
- initTransactionCharts() {
- // Transactions 1 Chart
- const transactions1 = am4core.create(
- this.$refs.transactions1,
- am4charts.XYChart
- );
- transactions1.data = this.generateTransactionData("#19BCBF");
- this.configureTransactionChart(transactions1);
- this.charts.transactions1 = transactions1;
- // Transactions 2 Chart
- const transactions2 = am4core.create(
- this.$refs.transactions2,
- am4charts.XYChart
- );
- transactions2.data = this.generateTransactionData("#FF425C");
- this.configureTransactionChart(transactions2);
- this.charts.transactions2 = transactions2;
- },
- generateTransactionData(color) {
- const data = [];
- for (let i = 0; i <= 12; i++) {
- data.push({
- category: i,
- value: Math.random() * 30 + 10,
- color: color,
- });
- }
- return data;
- },
- configureTransactionChart(chart) {
- // Create axes
- const categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
- categoryAxis.dataFields.category = "category";
- categoryAxis.renderer.grid.template.disabled = true;
- categoryAxis.renderer.labels.template.disabled = true;
- categoryAxis.renderer.minGridDistance = 10;
- const valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
- valueAxis.renderer.grid.template.disabled = true;
- valueAxis.renderer.labels.template.disabled = true;
- valueAxis.min = 0;
- valueAxis.max = 50;
- // Create series
- const series = chart.series.push(new am4charts.ColumnSeries());
- series.dataFields.valueY = "value";
- series.dataFields.categoryX = "category";
- series.columns.template.propertyFields.fill = "color";
- series.columns.template.propertyFields.stroke = "color";
- series.columns.template.width = am4core.percent(40);
- // Add tooltip
- series.tooltipText = "{valueY}";
- chart.cursor = new am4charts.XYCursor();
- chart.cursor.behavior = "none";
- // Remove padding
- chart.paddingBottom = 0;
- chart.paddingTop = 0;
- chart.paddingLeft = 0;
- chart.paddingRight = 0;
- },
- initDeviceChart() {
- const chart = am4core.create(this.$refs.deviceChart, am4charts.PieChart);
- // 添加数据
- chart.data = [
- { sector: "Mobile", size: 14.6 },
- { sector: "Tablet", size: 9.3 },
- { sector: "Desktop", size: 22.5 },
- ];
- // 设置内圆半径
- chart.innerRadius = 30;
- // 添加并配置饼图系列
- const pieSeries = chart.series.push(new am4charts.PieSeries());
- pieSeries.dataFields.value = "size";
- pieSeries.dataFields.category = "sector";
- pieSeries.labels.template.disabled = true;
- pieSeries.ticks.template.disabled = true;
- pieSeries.colors.step = 2;
- // 保存图表实例
- this.charts.deviceChart = chart;
- },
- /* 初始化 */
- init() {
- structure_count().then((res) => {
- if (res.status !== 200) return;
- this.kenList = res.data;
- if (this.kenList.length > 0) {
- this.kenValue = this.kenList[0].id;
- this.kenVal = this.kenList[0];
- // 处理文件类型统计数据
- this.updateChartPercentData(this.kenList[0]);
- }
- });
- GET_Rbq().then((res) => {
- console.log(res);
- });
- /* 获取文档数量 */
- searchlistDoc({ page: 1, pageSize: 9999 }).then((res) => {
- this.docTotal = res.data.dataList.length;
- });
- searchList({ page: 1, pageSize: 9999 }).then((res) => {
- if (!res) return;
- this.temTotal = res.data.dataList.length;
- });
- pageTemplate({ page: 1, pageSize: 9999 }).then((res) => {
- if (!res) return;
- this.pageTotal = res.data.dataList.length;
- });
- /* 获取文件解析数量 */
- doc_status().then((res) => {
- this.docList = res.data.data.run_stats;
- console.log(this.docList.run_3);
- });
- },
- /* 选择知识库 */
- kenChange(val) {
- this.kenVal = this.kenList.find((el) => el.id === val);
- // 更新图表数据
- this.updateChartPercentData(this.kenVal);
- },
- // 更新文件类型统计数据
- updateChartPercentData(kenData) {
- if (!kenData) return;
- // 获取所有的 file_type_stats
- const allFileStats = this.getAllFileTypeStats(kenData);
- // 合并所有的文件统计数据
- const mergedFileStats = this.mergeFileStats(allFileStats);
- // 保存上一次的数据用于计算变化率
- this.previousCounts = { ...this.fileTypeCounts };
- // 更新当前数据
- this.fileTypeCounts = mergedFileStats;
- // 计算总文件数和百分比
- const totalFiles = Object.values(mergedFileStats).reduce(
- (a, b) => a + b,
- 0
- );
- // 转换数据格式
- const chartData = Object.entries(mergedFileStats).map(
- ([type, count]) => ({
- sector: type.toUpperCase(),
- size: count /* Number(((count / totalFiles) * 100).toFixed(1)) */,
- count: count,
- })
- );
- // 更新图表数据
- if (this.charts.chartPercent) {
- this.charts.chartPercent.data = chartData;
- }
- },
- // 获取文件类型对应的图标
- getFileTypeIcon(type) {
- const icons = {
- pdf: "icon-file-text",
- docx: "icon-file",
- xlsx: "icon-file",
- };
- return icons[type.toLowerCase()] || "icon-file";
- },
- // 获取文件类型对应的颜色
- getFileTypeColor(type) {
- const colors = {
- pdf: "#dc67ce",
- docx: "#8067dc",
- xlsx: "#67b7dc",
- };
- return colors[type.toLowerCase()] || "#666666";
- },
- // 计算变化率
- getChangePercentage(type) {
- const currentCount = this.fileTypeCounts[type] || 0;
- const previousCount = this.previousCounts[type] || currentCount;
- if (previousCount === 0) return "0%";
- const change = ((currentCount - previousCount) / previousCount) * 100;
- return `${Math.abs(change).toFixed(1)}%`;
- },
- // 获取变化率的图标
- getChangeIcon(type) {
- const currentCount = this.fileTypeCounts[type] || 0;
- const previousCount = this.previousCounts[type] || currentCount;
- return currentCount >= previousCount
- ? "icon-arrow-up"
- : "icon-arrow-down";
- },
- // 获取变化率的样式类
- getChangeClass(type) {
- const currentCount = this.fileTypeCounts[type] || 0;
- const previousCount = this.previousCounts[type] || currentCount;
- return currentCount >= previousCount ? "text-c-green" : "text-c-red";
- },
- // 递归获取所有的 file_type_stats
- getAllFileTypeStats(data) {
- let results = [];
- // 处理当前层级的 file_type_stats
- if (data.file_type_stats) {
- results.push(data.file_type_stats);
- }
- // 处理 directories 中的 file_type_stats
- if (data.directories && Array.isArray(data.directories)) {
- data.directories.forEach((dir) => {
- results = results.concat(this.getAllFileTypeStats(dir));
- });
- }
- return results;
- },
- // 合并多个 file_type_stats 对象
- mergeFileStats(fileStatsList) {
- return fileStatsList.reduce((merged, current) => {
- Object.entries(current).forEach(([type, count]) => {
- merged[type] = (merged[type] || 0) + count;
- });
- return merged;
- }, {});
- },
- },
- // 修改beforeDestroy钩子
- beforeDestroy() {
- // 清理所有图表实例
- Object.values(this.charts).forEach((chart) => {
- if (chart) {
- if (typeof chart.dispose === "function") {
- chart.dispose();
- } else if (typeof chart === "number") {
- clearInterval(chart);
- }
- }
- });
- this.closeWebSocket(); // 组件销毁前关闭 WebSocket
- // 移除事件监听器
- document.removeEventListener(
- "visibilitychange",
- this.handleVisitorChartVisibility
- );
- },
- };
- </script>
- <style lang="scss" scoped>
- .widget-chart {
- height: calc(100vh - 85px);
- padding: 15px;
- font-family: "Roboto", sans-serif;
- font-size: 14px;
- color: #686c71;
- font-weight: 400;
- background: #f8f9fa;
- a {
- text-decoration: none;
- }
- // 卡片基础样式
- .card {
- border-radius: 2px;
- box-shadow: 0 0px 0 1px #e2e5e8;
- border: none;
- margin-bottom: 24px;
- background: #fff;
- .card-body {
- padding: 1.5rem;
- h6 {
- color: #111;
- font-size: 16px;
- .text-primary {
- color: #19bcbf !important;
- }
- .text-danger {
- color: #ff425c !important;
- }
- }
- }
- }
- // 文字样式
- h2 {
- font-size: 28px;
- font-weight: 600;
- color: #333;
- margin: 0;
- }
- h6 {
- font-size: 14px;
- color: #6c757d;
- margin-bottom: 0.5rem;
- }
- // 图标样式
- .feather {
- width: 20px;
- height: 20px;
- vertical-align: text-bottom;
- }
- // 颜色方案
- .text-c-blue {
- color: #19bcbf;
- }
- .text-c-green {
- color: #2ed8b6;
- }
- .text-c-red {
- color: #ff5370;
- }
- .text-c-purple {
- color: #8067dc;
- }
- // 下拉菜单样式
- .dropdown-toggle {
- &:after {
- margin-left: 0.5em;
- }
- }
- .dropdown-menu {
- border-radius: 4px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- .dropdown-item {
- padding: 0.5rem 1rem;
- &:hover {
- background-color: #f8f9fa;
- }
- }
- }
- // 图表容器样式
- [ref="hdComplitedTicket"],
- [ref="chartPercent"],
- [ref="storageChart"] {
- margin: 1rem 0;
- }
- // 小型图表样式
- [ref^="real"] {
- height: 20px;
- width: 100%;
- margin-top: 0.5rem;
- }
- // 统计数字样式
- .mt-2 {
- h3 {
- font-size: 24px;
- font-weight: 600;
- color: #333;
- margin: 0.5rem 0;
- }
- }
- // 图标指标样式
- .fas.fa-circle {
- font-size: 10px;
- margin-right: 8px;
- &.text-c-blue {
- color: #19bcbf;
- }
- &.text-c-purple {
- color: #8067dc;
- }
- }
- }
- // 响应式布局调整
- @media (max-width: 768px) {
- .widget-chart {
- .card {
- margin-bottom: 16px;
- }
- }
- }
- </style>
- <style src="./css/bootstrap.min.css" scoped></style>
|