| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="scale-container"> |
| | | <div class="data-dashboard" :style="{ transform: `scale(${scaleRatio})` }"> |
| | | <!-- å
¨å±æé® - ç§»å¨å°å·¦ä¸è§ --> |
| | | <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="quality-cards"> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card one"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æ»å¨å¶æ°é</div> |
| | | <div>{{workInProcessStatistics.totalQuantity}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card two"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å¹³åå¨è½¬å¤©æ°</div> |
| | | <div>{{workInProcessStatistics.avgTurnoverDays}}天</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card three"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å¨è½¬æç</div> |
| | | <div>{{workInProcessStatistics.turnoverEfficiency}}%</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- å·¥åºå¨å¶åæ°éæ±ç¶å¾ --> |
| | | <div style="height: 70%"> |
| | | <Echarts ref="chart" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="workInProcessBarLegend" |
| | | :series="workInProcessBarSeries" |
| | | :tooltip="tooltip" |
| | | :xAxis="workInProcessXAxis" |
| | | :yAxis="workInProcessYAxis" |
| | | :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}" |
| | | style="height: 100%"></Echarts> |
| | | </div> |
| | | </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="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="order-statistics-cards" style="margin-bottom: 0px;"> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card four"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æ»è®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.totalOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card five"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æªå®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.uncompletedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card six"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>é¨åå®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.partialCompletedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card seven"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å·²å®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.completedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="progress-table-container" ref="progressTableRef" style="margin-top: 0px;" @scroll="handleTableScroll"> |
| | | <table class="progress-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>ç产订åå·</th> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼</th> |
| | | <th>éæ±æ°é</th> |
| | | <th>宿æ°é</th> |
| | | <th>宿è¿åº¦</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr |
| | | v-for="(item, index) in progressTableData" |
| | | :key="index" |
| | | :ref="el => setRowRef(el, index)" |
| | | :class="{ 'row-under-header': isRowUnderHeader(index) }" |
| | | > |
| | | <td>{{ item.npsNo || '-' }}</td> |
| | | <td>{{ item.productCategory || '-' }}</td> |
| | | <td>{{ item.specificationModel || '-' }}</td> |
| | | <td>{{ item.quantity || 0 }}</td> |
| | | <td>{{ item.completeQuantity || 0 }}</td> |
| | | <td> |
| | | <el-progress |
| | | :percentage="calculateProgress(item)" |
| | | :color="progressColor(calculateProgress(item))" |
| | | :status="calculateProgress(item) >= 100 ? 'success' : ''" |
| | | :stroke-width="8" |
| | | /> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </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> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import * as echarts from 'echarts' |
| | | import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue' |
| | | import autofit from 'autofit.js' |
| | | import Echarts from "@/components/Echarts/echarts.vue"; |
| | | import useUserStore from '@/store/modules/user' |
| | | import { |
| | | analysisCustomerContractAmounts, getAmountHalfYear, |
| | | homeTodos, |
| | | qualityStatistics, |
| | | statisticsReceivablePayable, |
| | | getProgressStatistics, |
| | | getWorkInProcessTurnover |
| | | } 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"; |
| | | import {productOrderListPage} from "@/api/productionManagement/productionOrder.js"; |
| | | |
| | | // å
¨å±ç¸å
³ç¶æ |
| | | const isFullscreen = ref(false); |
| | | |
| | | // ç¼©æ¾æ¯ä¾ |
| | | const scaleRatio = ref(1) |
| | | // 设计尺寸ï¼åºå尺寸ï¼- æ ¹æ®å®é
è®¾è®¡ç¨¿è°æ´ |
| | | const designWidth = 1920 |
| | | const designHeight = 1080 |
| | | |
| | | // ç¨æ·store |
| | | const userStore = useUserStore() |
| | | |
| | | // ååºå¼æ°æ® |
| | | 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 progressTableRef = ref(null) |
| | | const timerScroll = ref(null) |
| | | const progressTableScrollTimer = ref(null) |
| | | const isTableScrolling = ref(false) |
| | | const tableScrollTimeout = ref(null) |
| | | const tableRowRefs = ref([]) |
| | | const rowsUnderHeader = ref(new Set()) |
| | | |
| | | const chartStylePie = { |
| | | width: '100%', |
| | | height: '100%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | 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 orderStatisticsObject = ref({ |
| | | totalOrderCount: 0, |
| | | uncompletedOrderCount: 0, |
| | | partialCompletedOrderCount: 0, |
| | | completedOrderCount: 0, |
| | | }) |
| | | |
| | | // å¨å¶åå¨è½¬ç»è®¡å¯¹è±¡ |
| | | const workInProcessStatistics = ref({ |
| | | totalQuantity: 0, |
| | | avgTurnoverDays: 0, |
| | | turnoverEfficiency: 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: false, |
| | | textStyle: { color: '#B8C8E0' }, |
| | | data: [] |
| | | } |
| | | const barSeries11 = ref([ |
| | | { |
| | | name: 'ç产订åç»è®¡', |
| | | type: 'bar', |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | itemStyle: { |
| | | // 使ç¨å½æ°æ ¹æ®æ°æ®ç´¢å¼è¿åä¸åé¢è² |
| | | color: function(params) { |
| | | const colorStops = [ |
| | | [ |
| | | { offset: 1, color: '#00A4ED' }, |
| | | { offset: 0, color: '#4EE4FF' } |
| | | ], |
| | | [ |
| | | { offset: 1, color: '#3378FF' }, |
| | | { offset: 0, color: '#4E8AFF' } |
| | | ], |
| | | [ |
| | | { offset: 1, color: '#FF6B6B' }, |
| | | { offset: 0, color: '#FF8E8E' } |
| | | ], |
| | | [ |
| | | { offset: 1, color: '#537EF5' }, |
| | | { offset: 0, color: '#9061F8' } |
| | | ] |
| | | ] |
| | | const stops = colorStops[params.dataIndex] || colorStops[0] |
| | | return { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 0, |
| | | y2: 1, |
| | | colorStops: stops |
| | | } |
| | | } |
| | | }, |
| | | 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 workInProcessXAxis = ref([{ |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | data: [] |
| | | }]) |
| | | const workInProcessYAxis = [{ |
| | | type: 'value', |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | name: '' |
| | | }] |
| | | const workInProcessBarLegend = { |
| | | show: false, |
| | | textStyle: { color: '#B8C8E0' }, |
| | | data: [] |
| | | } |
| | | const workInProcessBarSeries = ref([ |
| | | { |
| | | name: 'å¨å¶åæ°é', |
| | | type: 'bar', |
| | | barWidth: 25, // åºå®æ±ç¶å¾å®½åº¦ä¸º40px |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | itemStyle: { |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 0, |
| | | y2: 1, |
| | | colorStops: [ |
| | | { offset: 0, color: '#4EE4FF' }, |
| | | { offset: 1, color: '#00A4ED' } |
| | | ] |
| | | } |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'top', |
| | | color: '#B8C8E0' |
| | | }, |
| | | data: [] |
| | | } |
| | | ]) |
| | | |
| | | // å¾
åäºé¡¹ |
| | | const todoList = ref([]) |
| | | |
| | | // ç产订å宿è¿åº¦è¡¨æ ¼æ°æ® |
| | | const progressTableData = ref([]) |
| | | |
| | | // 计ç®å®æè¿åº¦ç¾åæ¯ |
| | | const calculateProgress = (item) => { |
| | | if (!item) return 0 |
| | | // ä¼å
使ç¨completionStatusåæ®µ |
| | | if (item.completionStatus !== undefined && item.completionStatus !== null) { |
| | | const percentage = Number(item.completionStatus) |
| | | if (isNaN(percentage)) return 0 |
| | | return Math.min(Math.max(Math.round(percentage), 0), 100) |
| | | } |
| | | // å¦ææ²¡æcompletionStatusï¼åæ ¹æ®å®ææ°éåéæ±æ°éè®¡ç® |
| | | if (!item.quantity || item.quantity === 0) return 0 |
| | | const percentage = (item.completeQuantity || 0) / item.quantity * 100 |
| | | return Math.min(Math.max(Math.round(percentage), 0), 100) |
| | | } |
| | | |
| | | // æ ¹æ®è¿åº¦ç¾åæ¯è¿åé¢è² |
| | | const progressColor = (percentage) => { |
| | | const p = percentage || 0 |
| | | if (p < 30) return "#f56c6c" |
| | | if (p < 50) return "#e6a23c" |
| | | if (p < 80) return "#409eff" |
| | | return "#67c23a" |
| | | } |
| | | |
| | | // 计ç®ç¼©æ¾æ¯ä¾ |
| | | const calculateScale = () => { |
| | | const container = document.querySelector('.scale-container') |
| | | if (!container) return |
| | | |
| | | // è·å容å¨çå®é
尺寸 |
| | | const rect = container.getBoundingClientRect?.() |
| | | const containerWidth = container.clientWidth || rect?.width || window.innerWidth |
| | | const containerHeight = container.clientHeight || rect?.height || window.innerHeight |
| | | |
| | | // 计ç®å®½é«ç¼©æ¾æ¯ä¾ï¼åè¾å°å¼ä»¥ä¿è¯å
容宿´æ¾ç¤ºï¼çæ¯ç¼©æ¾ï¼ |
| | | const scaleX = containerWidth / designWidth |
| | | const scaleY = containerHeight / designHeight |
| | | scaleRatio.value = Math.min(scaleX, scaleY) |
| | | |
| | | // 触åå¾è¡¨resize |
| | | charts.value.forEach(chart => { |
| | | if (chart && chart.resize) { |
| | | chart.resize() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // çªå£å¤§å°ååå¤ç |
| | | const handleResize = () => { |
| | | // å»¶è¿æ§è¡ï¼ç¡®ä¿DOMæ´æ°å®æ |
| | | setTimeout(() => { |
| | | calculateScale() |
| | | }, 100) |
| | | } |
| | | |
| | | // 鿝å¾è¡¨å®ä¾ |
| | | 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 workInProcessTurnoverInfo = () => { |
| | | getWorkInProcessTurnover().then((res) => { |
| | | console.log("å¨å¶åå¨è½¬ç»è®¡æ°æ®:", res) |
| | | |
| | | if (!res || !res.data) { |
| | | console.warn('å¨å¶åå¨è½¬ç»è®¡æ°æ®ä¸ºç©º') |
| | | return |
| | | } |
| | | |
| | | // 仿¥å£è·åç»è®¡æ°æ® |
| | | workInProcessStatistics.value = { |
| | | totalQuantity: res.data.totalOrderCount || 0, |
| | | avgTurnoverDays: res.data.averageTurnoverDays || 0, |
| | | turnoverEfficiency: res.data.turnoverEfficiency || 0, |
| | | } |
| | | |
| | | // è®¾ç½®å·¥åºæ±ç¶å¾æ°æ® |
| | | // Xè½´ï¼processDetails (å·¥åºè¯¦æ
æ°ç») |
| | | // Yè½´ï¼processQuantityDetails (å·¥åºæ°é详æ
æ°ç») |
| | | if (res.data.processDetails && Array.isArray(res.data.processDetails)) { |
| | | // 设置Xè½´æ°æ®ï¼å·¥åºåç§°ï¼ |
| | | workInProcessXAxis.value[0].data = res.data.processDetails |
| | | } else { |
| | | workInProcessXAxis.value[0].data = [] |
| | | } |
| | | |
| | | if (res.data.processQuantityDetails && Array.isArray(res.data.processQuantityDetails)) { |
| | | // 设置Yè½´æ°æ®ï¼å¨å¶åæ°éï¼ |
| | | workInProcessBarSeries.value[0].data = res.data.processQuantityDetails |
| | | } else { |
| | | workInProcessBarSeries.value[0].data = [] |
| | | } |
| | | }).catch((error) => { |
| | | console.error('è·åå¨å¶åå¨è½¬ç»è®¡å¤±è´¥:', error) |
| | | }) |
| | | } |
| | | // è´¨æ£ç»è®¡ |
| | | 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 progressStatisticsInfo = () => { |
| | | // ä»ç»è®¡æ¥å£è·åç»è®¡æ°æ® |
| | | getProgressStatistics().then((res) => { |
| | | console.log("ç产订å宿è¿åº¦ç»è®¡æ°æ®:", res) |
| | | |
| | | if (!res || !res.data) { |
| | | console.warn('ç产订å宿è¿åº¦ç»è®¡æ°æ®ä¸ºç©º') |
| | | return |
| | | } |
| | | |
| | | // 仿¥å£è·åç»è®¡æ°æ® |
| | | orderStatisticsObject.value = { |
| | | totalOrderCount: res.data.totalOrderCount || 0, |
| | | uncompletedOrderCount: res.data.uncompletedOrderCount || 0, |
| | | partialCompletedOrderCount: res.data.partialCompletedOrderCount || 0, |
| | | completedOrderCount: res.data.completedOrderCount || 0 |
| | | } |
| | | progressTableData.value = res.data.completedOrderDetails || [] |
| | | // éç½®è¡å¼ç¨ |
| | | tableRowRefs.value = [] |
| | | rowsUnderHeader.value.clear() |
| | | |
| | | // å¨è·åå°æ°æ®åï¼åå§åæ»å¨åè½ |
| | | nextTick(() => { |
| | | initProgressTableScroll() |
| | | }) |
| | | }).catch((error) => { |
| | | console.error('è·åç产订å宿è¿åº¦ç»è®¡å¤±è´¥:', error) |
| | | }) |
| | | } |
| | | // è´¢å¡ç»è®¡ |
| | | // const accountStatisticsInfo = () => { |
| | | // listPageAnalysis().then((res) => { |
| | | // xAxis3.value[0].data = res.data.days |
| | | // barSeries11.value[0].data = res.data.totalIncome |
| | | // }) |
| | | // } |
| | | 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, status:0}).then((res) => { |
| | | equipmentRepair.value = res.data.total |
| | | }); |
| | | getUpkeepPage({...params, status:0}).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) |
| | | }) |
| | | // æ£ç¡®ååºå¼èµå¼ï¼å建æ°ç 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 setRowRef = (el, index) => { |
| | | if (el) { |
| | | tableRowRefs.value[index] = el |
| | | } |
| | | } |
| | | |
| | | // å¤æè¡æ¯å¦å¨è¡¨å¤´ä¸æ¹ |
| | | const isRowUnderHeader = (index) => { |
| | | return rowsUnderHeader.value.has(index) |
| | | } |
| | | |
| | | // å¤çè¡¨æ ¼æ»å¨äºä»¶ |
| | | const handleTableScroll = () => { |
| | | const tableContainer = progressTableRef.value |
| | | if (!tableContainer) return |
| | | |
| | | const thead = tableContainer.querySelector('thead') |
| | | if (!thead) return |
| | | |
| | | const theadHeight = thead.offsetHeight |
| | | const containerRect = tableContainer.getBoundingClientRect() |
| | | const containerTop = containerRect.top |
| | | const theadBottom = containerTop + theadHeight |
| | | |
| | | // æ¸
空ä¹åçè®°å½ |
| | | rowsUnderHeader.value.clear() |
| | | |
| | | // æ£æ¥æ¯ä¸è¡æ¯å¦å¨è¡¨å¤´ä¸æ¹ï¼è¢«è¡¨å¤´é®æ¡ï¼ |
| | | tableRowRefs.value.forEach((row, index) => { |
| | | if (row) { |
| | | const rowRect = row.getBoundingClientRect() |
| | | const rowTop = rowRect.top |
| | | const rowBottom = rowRect.bottom |
| | | |
| | | // 妿è¡ä¸è¡¨å¤´æéå ï¼è¡å¨è¡¨å¤´ä¸æ¹è¢«é®æ¡ï¼ |
| | | // è¡çé¡¶é¨å¨è¡¨å¤´åºé¨ä¸æ¹ï¼ä½è¡çåºé¨å¨è¡¨å¤´åºé¨ä¸æ¹ï¼è¯´æè¢«é®æ¡ |
| | | if (rowTop < theadBottom && rowBottom > containerTop) { |
| | | rowsUnderHeader.value.add(index) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // æ¸
é¤ä¹åç宿¶å¨ |
| | | if (tableScrollTimeout.value) { |
| | | clearTimeout(tableScrollTimeout.value) |
| | | } |
| | | |
| | | // æ»å¨åæ¢åæ¸
ç©ºæ·¡åæ è®° |
| | | tableScrollTimeout.value = setTimeout(() => { |
| | | rowsUnderHeader.value.clear() |
| | | }, 150) |
| | | } |
| | | |
| | | // åå§åç产订åè¿åº¦è¡¨æ ¼æ»å¨åè½ |
| | | const initProgressTableScroll = () => { |
| | | const tableContainer = progressTableRef.value |
| | | if (!tableContainer) return |
| | | |
| | | // æ¸
çä¹åçæ»å¨å¨ç»å宿¶å¨ |
| | | if (progressTableScrollTimer.value) { |
| | | cancelAnimationFrame(progressTableScrollTimer.value) |
| | | progressTableScrollTimer.value = null |
| | | } |
| | | if (tableContainer._pauseTimer) { |
| | | clearInterval(tableContainer._pauseTimer) |
| | | tableContainer._pauseTimer = null |
| | | } |
| | | |
| | | const tbody = tableContainer.querySelector('tbody') |
| | | if (!tbody) return |
| | | |
| | | // æ¸
çä¹åå¯è½åå¨çå
éè¡ï¼ä¿çåå§æ°æ®è¡ï¼ |
| | | // åå§æ°æ®è¡çæ°éåºè¯¥çäº progressTableData.value.length |
| | | const originalCount = progressTableData.value.length |
| | | const allRows = Array.from(tbody.querySelectorAll('tr')) |
| | | if (allRows.length > originalCount) { |
| | | // ç§»é¤ææè¶
è¿åå§æ°éçè¡ï¼è¿äºæ¯å
éçè¡ï¼ |
| | | for (let i = originalCount; i < allRows.length; i++) { |
| | | allRows[i].remove() |
| | | } |
| | | } |
| | | |
| | | const scrollItems = Array.from(tbody.querySelectorAll('tr')) |
| | | if (scrollItems.length === 0) return |
| | | |
| | | // è·ååå§æ°æ®é¡¹æ°é |
| | | const originalItemCount = scrollItems.length |
| | | |
| | | // 计ç®å®¹å¨é«åº¦å表头é«åº¦ |
| | | const thead = tableContainer.querySelector('thead') |
| | | const theadHeight = thead ? thead.offsetHeight : 40 |
| | | const containerHeight = tableContainer.clientHeight |
| | | const visibleHeight = containerHeight - theadHeight |
| | | |
| | | // 计ç®åå§æ°æ®çæ»é«åº¦ |
| | | const itemHeight = scrollItems[0]?.offsetHeight || 40 |
| | | const totalContentHeight = itemHeight * originalItemCount |
| | | |
| | | // å¦ææ°æ®éä¸å¤ï¼å®¹å¨å¯ä»¥å®å
¨æ¾ç¤ºæææ°æ®ï¼å°±ä¸éè¦æ»å¨åå
é |
| | | if (totalContentHeight <= visibleHeight) { |
| | | // æ°æ®éå°ï¼ä¸éè¦æ»å¨ï¼ç´æ¥è¿å |
| | | return |
| | | } |
| | | |
| | | // æ°æ®éè¶³å¤ï¼éè¦æ»å¨ï¼è¿è¡å
é以å®ç°æ ç¼æ»å¨ |
| | | const cloneCount = Math.ceil(visibleHeight / itemHeight) + 2 |
| | | |
| | | // å
éåå 个项ç®å¹¶æ·»å å°å表æ«å°¾ï¼å®ç°æ ç¼æ»å¨ |
| | | for (let i = 0; i < cloneCount; i++) { |
| | | const clone = scrollItems[i % originalItemCount].cloneNode(true) |
| | | tbody.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) |
| | | |
| | | // è®¡ç®æå¤§æ»å¨ä½ç½®ï¼åå§å
容çé«åº¦ï¼ |
| | | const maxScroll = itemHeight * originalItemCount |
| | | |
| | | // 彿»å¨è¶
è¿åå§å
容é¿åº¦æ¶ï¼éç½®ä½ç½®å®ç°æ ç¼æ»å¨ |
| | | if (scrollPosition >= maxScroll) { |
| | | scrollPosition = 0 |
| | | tableContainer.scrollTop = 0 |
| | | } else { |
| | | tableContainer.scrollTop = scrollPosition |
| | | } |
| | | } |
| | | |
| | | progressTableScrollTimer.value = requestAnimationFrame(scrollAnimation) |
| | | } |
| | | |
| | | // å¯å¨æ»å¨å¨ç» |
| | | progressTableScrollTimer.value = requestAnimationFrame(scrollAnimation) |
| | | |
| | | // 设置æ»å¨-æå-æ»å¨çå¾ªç¯ææ |
| | | const pauseTimer = setInterval(() => { |
| | | isPaused = !isPaused |
| | | }, pauseTime) |
| | | |
| | | // æ¸
ç宿¶å¨ |
| | | tableContainer._pauseTimer = pauseTimer |
| | | } |
| | | |
| | | // åå§åå¾
åäºé¡¹å表æ»å¨åè½ |
| | | 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 = () => { |
| | | // çææµ
è²ï¼RãGãB åéé½å¨ 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) |
| | | } |
| | | // å
¨å±åè½å®ç° - é对scale-containerå
ç´ |
| | | const toggleFullscreen = () => { |
| | | const element = document.querySelector('.scale-container') |
| | | |
| | | 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('scale-container') |
| | | |
| | | // å
¨å±ç¶æååæ¶ï¼å»¶è¿éæ°è®¡ç®ç¼©æ¾æ¯ä¾ï¼ç¡®ä¿DOMæ´æ°å®æï¼ |
| | | setTimeout(() => { |
| | | calculateScale() |
| | | }, 200) |
| | | } |
| | | |
| | | // çå½å¨æé©å |
| | | onMounted(() => { |
| | | initTime() |
| | | // 使ç¨nextTickç¡®ä¿DOMå®å
¨æ¸²æåååå§åå¾è¡¨ |
| | | nextTick(() => { |
| | | // 计ç®åå§ç¼©æ¾æ¯ä¾ |
| | | calculateScale() |
| | | |
| | | // åå§åautofitèªéåºï¼å¦æéè¦ä¿çautofitï¼å¯ä»¥ä¿çï¼ä½ä¸»è¦ç¼©æ¾ç±scale-containeræ§å¶ï¼ |
| | | // autofit.init({ dh: 800, dw: 1280, 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) |
| | | window.addEventListener('fullscreenchange', handleFullscreenChange) |
| | | window.addEventListener('webkitfullscreenchange', handleFullscreenChange) |
| | | window.addEventListener('MSFullscreenChange', handleFullscreenChange) |
| | | analysisCustomer() |
| | | workInProcessTurnoverInfo() |
| | | qualityStatisticsInfo() |
| | | // accountStatisticsInfo() |
| | | progressStatisticsInfo() |
| | | 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ç§åæ¢ä¸æ¬¡ |
| | | }) |
| | | |
| | | 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 |
| | | } |
| | | } |
| | | |
| | | // æ¸
çç产订åè¿åº¦è¡¨æ ¼çå¨ç»å宿¶å¨ |
| | | const progressTable = progressTableRef.value |
| | | if (progressTable) { |
| | | if (progressTableScrollTimer.value) { |
| | | cancelAnimationFrame(progressTableScrollTimer.value) |
| | | progressTableScrollTimer.value = null |
| | | } |
| | | if (progressTable._pauseTimer) { |
| | | clearInterval(progressTable._pauseTimer) |
| | | progressTable._pauseTimer = null |
| | | } |
| | | } |
| | | |
| | | // æ¸
çè¡¨æ ¼æ»å¨å®æ¶å¨ |
| | | if (tableScrollTimeout.value) { |
| | | clearTimeout(tableScrollTimeout.value) |
| | | tableScrollTimeout.value = 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> |
| | | /* å¤é¨ç¼©æ¾å®¹å¨ - å æ®æ´ä¸ªè§å£ */ |
| | | .scale-container { |
| | | position: relative; |
| | | width: 100%; |
| | | /* 页é¢å¨å¸¸è§å¸å±ä¸ï¼æé¡¶æ ï¼é»è®¤åå» 84pxï¼é¿å
å
容被è£å */ |
| | | height: calc(100vh - 84px); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* å
é¨å
容åºå - åºå®è®¾è®¡å°ºå¯¸ */ |
| | | .data-dashboard { |
| | | position: relative; |
| | | width: 1920px; |
| | | height: 1080px; |
| | | background-image: url("@/assets/BI/backImage@2x.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | transform-origin: center center; |
| | | } |
| | | |
| | | /* å
¨å±ç¶æçæ ·å¼ - ä½ç¨äºscale-container */ |
| | | .scale-container:fullscreen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | /* Webkitæµè§å¨åç¼ */ |
| | | .scale-container:-webkit-full-screen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | /* MSæµè§å¨åç¼ */ |
| | | .scale-container:-ms-fullscreen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | |
| | | .dashboard-header { |
| | | position: relative; |
| | | z-index: 1; |
| | | height: 86px; |
| | | background-image: url("@/assets/BI/biaoti.png"); |
| | | background-size: cover; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .factory-name { |
| | | font-weight: 600; |
| | | font-size: 52px; |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | 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; |
| | | } |
| | | |
| | | .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(100% - 86px); |
| | | 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: 54px; |
| | | 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"); |
| | | } |
| | | |
| | | /* 订åç»è®¡å¡çæ ·å¼ */ |
| | | .order-statistics-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | width: 100%; |
| | | height: 94px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .quality-card.four { |
| | | background-image: url("@/assets/BI/yuancailiaoyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.five { |
| | | background-image: url("@/assets/BI/guochengyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.six { |
| | | background-image: url("@/assets/BI/chuchangyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.seven { |
| | | background-image: url("@/assets/BI/yuancailiaoyijianicon@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-header { |
| | | background-image: url("@/assets/BI/kehuhetongback@2x.png"); |
| | | background-size: 100% 100%; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .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åEdge */ |
| | | } |
| | | |
| | | /* ChromeãSafariåOpera */ |
| | | .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; |
| | | } |
| | | .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; |
| | | } |
| | | |
| | | /* èªå®ä¹åéæé®ç»æ ·å¼ */ |
| | | .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); |
| | | } |
| | | |
| | | /* ç产订åè¿åº¦è¡¨æ ¼æ ·å¼ */ |
| | | .progress-table-container { |
| | | height: 200px; |
| | | overflow-y: auto; |
| | | overflow-x: hidden; |
| | | margin-top: 10px; |
| | | scrollbar-width: none; /* Firefox */ |
| | | -ms-overflow-style: none; /* IEåEdge */ |
| | | } |
| | | |
| | | .progress-table-container::-webkit-scrollbar { |
| | | display: none; /* ChromeãSafariåOpera */ |
| | | } |
| | | |
| | | .progress-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | color: #B8C8E0; |
| | | font-size: 12px; |
| | | table-layout: fixed; |
| | | } |
| | | |
| | | .progress-table thead { |
| | | position: sticky; |
| | | top: 0; |
| | | background-color: rgba(26, 88, 176, 0.9); |
| | | z-index: 10; |
| | | } |
| | | |
| | | .progress-table th { |
| | | padding: 8px 6px; |
| | | text-align: left; |
| | | font-weight: 500; |
| | | border-bottom: 1px solid rgba(184, 200, 224, 0.3); |
| | | color: #B8C8E0; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .progress-table th:nth-child(1) { width: 15%; } /* ç产订åå· */ |
| | | .progress-table th:nth-child(2) { width: 15%; } /* 产ååç§° */ |
| | | .progress-table th:nth-child(3) { width: 15%; } /* è§æ ¼ */ |
| | | .progress-table th:nth-child(4) { width: 12%; } /* éæ±æ°é */ |
| | | .progress-table th:nth-child(5) { width: 12%; } /* 宿æ°é */ |
| | | .progress-table th:nth-child(6) { width: 31%; } /* 宿è¿åº¦ */ |
| | | |
| | | .progress-table td { |
| | | padding: 8px 6px; |
| | | border-bottom: 1px solid rgba(184, 200, 224, 0.1); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-size: 12px; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | .progress-table tbody tr:hover { |
| | | background-color: rgba(184, 200, 224, 0.1); |
| | | } |
| | | |
| | | .progress-table tbody tr.row-under-header { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | /* el-progress ç»ä»¶æ ·å¼è°æ´ */ |
| | | .progress-table :deep(.el-progress) { |
| | | width: 100%; |
| | | } |
| | | |
| | | .progress-table :deep(.el-progress-bar__outer) { |
| | | background-color: rgba(184, 200, 224, 0.2); |
| | | } |
| | | |
| | | .progress-table :deep(.el-progress__text) { |
| | | color: #B8C8E0; |
| | | font-size: 11px; |
| | | } |
| | | </style> |