gaoluyang
2025-12-11 3791cb8c977f753dfabd0d48a161dd8bff11b4b4
1.安佑-BI大屏展示数据修改
2.安佑-规格型号修改
已修改3个文件
910 ■■■■■ 文件已修改
src/api/viewIndex.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/index.vue 895 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/viewIndex.js
@@ -44,4 +44,12 @@
        url: '/sales/ledger/getAmountHalfYear',
        method: 'get'
    })
}
// 产品合格率接口
export const qualityProductQualifiedRate = () => {
  return request({
    url: '/home/qualityProductQualifiedRate',
    method: 'get'
  })
}
src/views/basicData/product/index.vue
@@ -146,7 +146,7 @@
            <el-form-item label="规格型号:" prop="model">
              <el-input
                v-model="modelForm.model"
                placeholder="请输入规格型号(g*袋数)"
                placeholder="请输入规格型号"
                clearable
                @keydown.enter.prevent
              />
@@ -273,11 +273,6 @@
  modelRules: {
    model: [
      { required: true, message: "请输入", trigger: "blur" },
      {
        pattern: /^[0-9*]*$/,
        message: "只能输入数字和*号",
        trigger: "blur"
      }
    ],
    unit: [{ required: true, message: "请输入", trigger: "blur" }],
    speculativeTradingName: [{ required: true, message: "请选择绑定机器", trigger: "change" }],
src/views/reportAnalysis/dataDashboard/index.vue
@@ -1,36 +1,36 @@
<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 class="factory-name">{{ userStore.currentFactoryName }}</div>
      </div>
      <!-- 主要内容区域 -->
      <div class="dashboard-content">
      <!-- 左侧区域 -->
      <div class="left-panel">
        <!-- 客户信息统计分析 -->
    <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 class="factory-name">{{ userStore.currentFactoryName }}</div>
        </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-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 class="jiantou"></div>-->
                    </div>
                    <!-- 饼图区域 -->
                    <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 82%;margin-top: 20px">
@@ -50,11 +50,52 @@
                            </li>
                        </ul>
                    </div>
        </div>
        <!-- 质量统计 -->
                <div class="panel-header">
                    <span class="panel-title">质量统计</span>
                </div>
                <!-- 质量统计 -->
<!--                <div class="panel-header">-->
<!--                    <span class="panel-title">近4个月质量统计</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="panel-header">
                    <span class="panel-title">近4个月仓库统计</span>
                </div>
                <div class="main-panel">
                    <div class="panel-item-customers">
@@ -62,24 +103,24 @@
                            <div class="quality-cardSec">
                                <div class="quality-card one"></div>
                                <div class="quality-cardTitle">
                                    <div>原材料已检测数</div>
                                    <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>出库数量</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 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"
@@ -93,85 +134,110 @@
                                         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 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>
                    </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">{{noWorkListLength}}</span>
                            <span class="equipment-label">待排产</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{workListLength}}</span>
                            <span class="equipment-label">已排产</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{noListPageProcessLength}}</span>
                            <span class="equipment-label">待报工</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{listPageProcessLength}}</span>
                            <span class="equipment-label">已报工</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">{{rawMaterialQualifiedRate}}%</span>
                            <span class="equipment-label">原材料合格率</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{processQualifiedRate}}%</span>
                            <span class="equipment-label">过程合格率</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{factoryQualifiedRate}}%</span>
                            <span class="equipment-label">出厂合格率</span>
                        </div>
                        <div class="equipment-item">
                            <span class="equipment-value">{{inventoryTurnoverRate}}%</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>
@@ -191,31 +257,31 @@
                                         :xAxis="xAxis3"
                                         :yAxis="yAxis3"
                                         :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
                                         style="height: 300px"></Echarts>
                                         style="height: 280px"></Echarts>
                    </div>
                </div>
      </div>
      <!-- 右侧区域 -->
      <div class="right-panel">
        <!-- 应收应付统计 -->
            </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>
                        <!--                        <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"
                                     :legend="barLegend2"
                                     :series="barSeries"
                                     :tooltip="tooltip"
                                     :xAxis="xAxis"
@@ -223,18 +289,18 @@
                                     :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
                                     style="height: 260px"></Echarts>
                </div>
        <!-- 回款与开票分析 -->
         <div class="panel-header">
                <!-- 回款与开票分析 -->
                <div class="panel-header">
                    <span class="panel-title">回款与开票分析</span>
                </div>
        <div class="panel-item-customers" style="padding-top: 60px;">
                <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>
                                     :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" :options="{backgroundColor: 'transparent', textStyle: {color: '#FFFFFF'}}" style="height: 270px;"></Echarts>
                </div>
      </div>
      </div>
    </div>
            </div>
        </div>
    </div>
</template>
<script setup>
@@ -245,7 +311,7 @@
import useUserStore from '@/store/modules/user'
import {
    analysisCustomerContractAmounts, getAmountHalfYear,
    homeTodos,
    homeTodos, qualityProductQualifiedRate,
    qualityStatistics,
    statisticsReceivablePayable
} from "@/api/viewIndex.js";
@@ -257,6 +323,8 @@
import {getUpkeepPage} from "@/api/equipmentManagement/upkeep.js";
import {measuringInstrumentListPage} from "@/api/equipmentManagement/measurementEquipment.js";
import {listPageAnalysis} from "@/api/financialManagement/expenseManagement.js";
import {workListPage} from "@/api/productionManagement/productionReporting.js";
import {listPageProcess} from "@/api/productionManagement/operationScheduling.js";
// 全屏相关状态
const isFullscreen = ref(false);
@@ -312,6 +380,14 @@
const equipmentRepair = ref(0)
const equipmentMaintain = ref(0)
const totalMeasuring = ref(0)
const rawMaterialQualifiedRate = ref(0)
const processQualifiedRate = ref(0)
const factoryQualifiedRate = ref(0)
const inventoryTurnoverRate = ref(0)
const noWorkListLength = ref(0)
const workListLength = ref(0)
const noListPageProcessLength = ref(0)
const listPageProcessLength = ref(0)
const pieTooltip = reactive({
    trigger: 'item',
    formatter: function (params) {
@@ -371,7 +447,7 @@
}
const lineLegend = {
    show: true,
  textStyle: { color: '#B8C8E0' },
    textStyle: { color: '#B8C8E0' },
    data: ['开票', '回款']
}
const lineSeries = ref([
@@ -412,7 +488,7 @@
const barLegend = {
    show: true,
    textStyle: { color: '#B8C8E0' },
    data: ['原材料不合格数', '过程不合格数', '出厂不合格数']
    data: ['原材料合格数', '过程合格数', '出厂合格数']
}
const barLegend1 = {
    show: true,
@@ -487,7 +563,7 @@
])
const barSeries1 = ref([
    {
        name: '原材料不合格数',
        name: '原材料合格数',
        type: 'bar',
        barGap: 0,
        emphasis: {
@@ -509,7 +585,7 @@
        data: []
    },
    {
        name: '过程不合格数',
        name: '过程合格数',
        type: 'bar',
        emphasis: {
            focus: 'series'
@@ -530,7 +606,7 @@
        data: []
    },
    {
        name: '出厂不合格数',
        name: '出厂合格数',
        type: 'bar',
        emphasis: {
            focus: 'series'
@@ -597,21 +673,21 @@
// 窗口大小变化处理
const handleResize = () => {
  charts.value.forEach(chart => {
    if (chart && chart.resize) {
      chart.resize()
    }
  })
    charts.value.forEach(chart => {
        if (chart && chart.resize) {
            chart.resize()
        }
    })
}
// 销毁图表实例
const disposeCharts = () => {
  charts.value.forEach(chart => {
    if (chart && chart.dispose) {
      chart.dispose()
    }
  })
  charts.value = []
    charts.value.forEach(chart => {
        if (chart && chart.dispose) {
            chart.dispose()
        }
    })
    charts.value = []
}
// 合同金额
const analysisCustomer = () => {
@@ -640,6 +716,15 @@
        qualityStatisticsObject.value.factoryNum = res.data.factoryNum
    })
}
// 产品合格率
const qualityProductQualifiedRateInfo = () => {
    qualityProductQualifiedRate().then((res) => {
        rawMaterialQualifiedRate.value = res.data.rawMaterialQualifiedRate
        processQualifiedRate.value = res.data.processQualifiedRate
        factoryQualifiedRate.value = res.data.factoryQualifiedRate
        inventoryTurnoverRate.value = res.data.inventoryTurnoverRate
    })
}
// 财务统计
const accountStatisticsInfo = () => {
    listPageAnalysis().then((res) => {
@@ -649,6 +734,36 @@
        barSeries11.value[2].data = res.data.netIncome
    })
}
// 生产数据
const workListPageInfo = () => {
    const params = {
        current: -1,
        size: -1,
        status: 3
    }
    const params1 = {
        current: -1,
        size: -1,
        status: 1
    }
    // 已报工查询
    workListPage(params).then(res => {
        workListLength.value = res.data.records.length
    })
    // 已排产查询
    listPageProcess(params).then(res => {
        listPageProcessLength.value = res.data.records.length
    })
    // 待报工查询
    workListPage(params1).then(res => {
        noWorkListLength.value = res.data.records.length
    })
    // 待排产查询
    listPageProcess(params1).then(res => {
        noListPageProcessLength.value = res.data.records.length
    })
}
const getNum = () => {
    const params = {
        pageNum: -1,
@@ -669,7 +784,7 @@
        pageNum: -1,
        pageSize: -1,
    }
    getLedgerPage(params).then((res) => {
    getLedgerPage({}).then((res) => {
        equipmentNum.value = res.data.total
    });
    getRepairPage(params).then((res) => {
@@ -866,20 +981,20 @@
// 更新时间
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 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)
    updateTime()
    timer.value = setInterval(updateTime, 1000)
}
// 全屏功能实现 - 针对data-dashboard元素
const toggleFullscreen = () => {
@@ -908,146 +1023,148 @@
// 监听全屏变化事件
const handleFullscreenChange = () => {
  const fullscreenElement = document.fullscreenElement ||
                           document.webkitFullscreenElement ||
                           document.msFullscreenElement
  isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
    const fullscreenElement = document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.msFullscreenElement
    isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
}
// 生命周期钩子
onMounted(() => {
  initTime()
  // 使用nextTick确保DOM完全渲染后再初始化图表
  nextTick(() => {
    // 初始化autofit自适应
    autofit.init({ dh: 1080, dw: 1920, 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
    }
    // 待办事项列表滚动功能已移至todoInfoS函数中,在获取数据后初始化
  })
  window.addEventListener('resize', handleResize)
  analysisCustomer()
  qualityStatisticsInfo()
    initTime()
    // 使用nextTick确保DOM完全渲染后再初始化图表
    nextTick(() => {
        // 初始化autofit自适应
        autofit.init({ dh: 1080, dw: 1920, 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
        }
        // 待办事项列表滚动功能已移至todoInfoS函数中,在获取数据后初始化
    })
    window.addEventListener('resize', handleResize)
    analysisCustomer()
    qualityStatisticsInfo()
    qualityProductQualifiedRateInfo()
    accountStatisticsInfo()
  getNum()
  getLedgerNum()
  todoInfoS()
    workListPageInfo()
    getNum()
    getLedgerNum()
    todoInfoS()
    statisticsReceivable()
    getAmountHalfYearNum()
  // 设置自动轮换周、月、季度的定时器,每10秒切换一次
  autoSwitchTimer.value = setInterval(() => {
    // 循环切换:1(周) -> 2(月) -> 3(季度) -> 1(周)
    radio1.value = radio1.value === 3 ? 1 : radio1.value + 1
    statisticsReceivable()
  }, 10000) // 10秒切换一次
    // 设置自动轮换周、月、季度的定时器,每10秒切换一次
    autoSwitchTimer.value = setInterval(() => {
        // 循环切换:1(周) -> 2(月) -> 3(季度) -> 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)
  // 移除我们添加的autofit动态调整监听器
  if (window._autofitUpdateHandler) {
    window.removeEventListener('resize', window._autofitUpdateHandler)
    delete window._autofitUpdateHandler
  }
  disposeCharts()
  // 关闭autofit
  autofit.off()
    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)
    // 移除我们添加的autofit动态调整监听器
    if (window._autofitUpdateHandler) {
        window.removeEventListener('resize', window._autofitUpdateHandler)
        delete window._autofitUpdateHandler
    }
    disposeCharts()
    // 关闭autofit
    autofit.off()
})
</script>
<style scoped>
.data-dashboard {
  position: relative;
  width: 100%;
    position: relative;
    width: 100%;
    height: 100%;
    background-image: url("@/assets/BI/backImage@2x.png");
    background-size: cover;
@@ -1057,114 +1174,114 @@
/* 全屏状态的样式 */
.data-dashboard:fullscreen {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background-color: inherit;
  z-index: 9999;
    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;
    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;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    background-color: inherit;
    z-index: 9999;
}
.dashboard-header {
  position: relative;
  z-index: 1;
  height: 170px;
    position: relative;
    z-index: 1;
    height: 170px;
    background-image: url("@/assets/BI/biaoti.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
    display: flex;
    align-items: center;
    justify-content: center;
}
.factory-name {
  font-weight: 600;
font-size: 52px;
color: #FFFFFF;
top: 32px;
position: absolute;
    font-weight: 600;
    font-size: 52px;
    color: #FFFFFF;
    top: 32px;
    position: absolute;
}
.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;
    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);
    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(100% - 120px);
  overflow: hidden;
    position: relative;
    z-index: 1;
    display: flex;
    gap: 30px;
    padding: 0 30px;
    height: calc(100% - 120px);
    overflow: hidden;
}
/* 确保各面板能够正确显示 */
.left-panel, .center-panel, .right-panel {
  overflow: hidden;
    overflow: hidden;
}
.left-panel,
.right-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 24px;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 24px;
    width: 520px;
}
.center-panel {
  flex: 1.5;
  display: flex;
  flex-direction: column;
  gap: 20px;
    flex: 1.5;
    display: flex;
    flex-direction: column;
    gap: 20px;
}
.panel-item-customers {
    border: 1px solid #1A58B0;
    padding: 18px;
    width: 100%;
    height: 540px;
    height: 520px;
}
.panel-title-second {
    height: 60px;
@@ -1297,40 +1414,40 @@
    margin-top: 10px;
}
.stats-cards {
  display: flex;
  gap: 30px;
    display: flex;
    gap: 30px;
}
.stat-card {
  flex: 1;
  display: flex;
  align-items: center;
    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;
    height: 142px;
}
.card-icon {
  width: 100px;
  height: 100px;
  margin: 20px 20px 0 10px;
    width: 100px;
    height: 100px;
    margin: 20px 20px 0 10px;
}
.card-content {
  display: flex;
  flex-direction: column;
    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;
    background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.card-label {
@@ -1341,8 +1458,8 @@
.equipment-stats {
    border: 1px solid #1A58B0;
  padding: 18px;
  height: 240px;
    padding: 18px;
    height: 240px;
}
.equipment-header {
    font-weight: 500;
@@ -1366,17 +1483,17 @@
    height: 50px;
}
.equipment-items {
  display: flex;
  justify-content: space-around;
  gap: 30px;
    display: flex;
    justify-content: space-around;
    gap: 30px;
}
.equipment-item {
  text-align: center;
    text-align: center;
}
.equipment-value {
  display: block;
    display: block;
    font-weight: 500;
    font-size: 40px;
    color: #FFFFFF;
@@ -1387,7 +1504,7 @@
    background-size: 100% 100%;
    background-position: center;
    background-repeat: no-repeat;
  margin-bottom: 8px;
    margin-bottom: 8px;
}
.equipment-label {
@@ -1401,8 +1518,8 @@
    background-size: 100% 100%;
    background-position: center;
    background-repeat: no-repeat;
  padding: 20px;
  height: 186px;
    padding: 20px;
    height: 186px;
}
.event-header {
    display: flex;
@@ -1419,12 +1536,12 @@
    line-height: 30px;
}
.todo-list {
  list-style: none;
  padding: 0;
  margin: 0;
  height: 120px; /* 按用户要求调整高度 */
  overflow: hidden;
  font-size: 15px;
    list-style: none;
    padding: 0;
    margin: 0;
    height: 120px; /* 按用户要求调整高度 */
    overflow: hidden;
    font-size: 15px;
}
.todo-list li {
    border-radius: 8px;
@@ -1479,15 +1596,15 @@
/* 自定义单选按钮组样式 */
.custom-radio-group :deep(.el-radio-button__inner) {
  background-color: transparent;
  color: white;
  border-color: rgba(255, 255, 255, 0.3);
    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);
    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>