初始化

This commit is contained in:
张怡蓉
2025-12-23 13:36:18 +08:00
commit d427ebf6d0
1232 changed files with 239447 additions and 0 deletions

View File

@@ -0,0 +1,463 @@
<template>
<div class="app-container panel">
<!-- 顶部统计面板 -->
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="clipboard" class-name="card-panel-icon"/>
</div>
<div class="card-panel-description">
<div class="card-panel-text">入库单数</div> <!-- 入库单数 -->
<count-to :start-val="0" :end-val="Number(quantity.inbound_order) || 0" :duration="2600" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="documentation" class-name="card-panel-icon"/>
</div>
<div class="card-panel-description">
<div class="card-panel-text">出库单数</div> <!-- 出库单数 -->
<count-to :start-val="0" :end-val="Number(quantity.outbound_order) || 0" :duration="3000" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="chart" class-name="card-panel-icon"/>
</div>
<div class="card-panel-description">
<div class="card-panel-text">盘点单数</div> <!-- 盘点单数 -->
<count-to :start-val="0" :end-val="Number(quantity.inventory_sheet)|| 0" :duration="3200" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="excel" class-name="card-panel-icon"/>
</div>
<div class="card-panel-description">
<div class="card-panel-text">总单据数</div> <!-- 总单据数 -->
<count-to :start-val="0" :end-val="Number(quantity.total_documents)|| 0" :duration="3600" class="card-panel-num"/>
</div>
</div>
</el-col>
</el-row>
<!-- 中间图表区域 -->
<el-row :gutter="32" style="margin-bottom: 0px;">
<el-col :xs="24" :sm="24" :lg="16">
<div class="chart-wrapper">
<div class="chart-header">
<span>近一周入库出库统计</span> <!-- 近一周入库出库统计 -->
</div>
<line-chart :chart-data="lineChartData"/>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<div class="chart-header">
<span>库位统计</span> <!-- 库位统计 -->
</div>
<pie-chart :chart-data="pieChartData"/>
</div>
</el-col>
</el-row>
<!-- 底部列表区域 -->
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="list-wrapper">
<div class="list-header">
<span>单据列表</span> <!-- 单据列表 -->
</div>
<el-table :data="documentList" style="width: 100%" size="mini" height="300"
:header-cell-style="{backgroundColor: '#f5f7fa'}">
<el-table-column prop="id" label="单据编号"/> <!-- 单据编号 -->
<el-table-column prop="type" :formatter="type_" label="类型" width="80"/> <!-- 类型 -->
<el-table-column prop="status" :formatter="status_" label="状态" width="80"/> <!-- 状态 -->
</el-table>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="list-wrapper">
<div class="list-header">
<span>正执行任务</span> <!-- 正执行任务 -->
</div>
<el-table :data="executingTasks" style="width: 100%" size="mini" height="300"
:header-cell-style="{backgroundColor: '#f5f7fa'}">
<el-table-column prop="jobId" label="任务编号"/> <!-- 任务编号 -->
<el-table-column prop="inOrOut" label="类型" width="80"/> <!-- 类型 -->
<el-table-column prop="statusLabel" label="状态" width="80"/> <!-- 状态 -->
</el-table>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="list-wrapper">
<div class="list-header">
<span>待执行任务</span> <!-- 待执行任务 -->
</div>
<el-table :data="pendingTasks" style="width: 100%" size="mini" height="300"
:header-cell-style="{backgroundColor: '#f5f7fa'}">
<el-table-column prop="jobId" label="任务编号"/> <!-- 任务编号 -->
<el-table-column prop="inOrOut" label="类型" width="80"/> <!-- 类型 -->
<el-table-column prop="priority" label="优先级" width="80"/> <!-- 优先级 -->
</el-table>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import CountTo from 'vue-count-to'
import LineChart from './dashboard/LineChart'
import PieChart from './dashboard/PieChart'
import {finishCount, weekjob, cargospace, billStatus, jobStatus} from "@/api/index";
export default {
name: 'Index',
components: {
CountTo,
LineChart,
PieChart
},
data() {
return {
quantity: {
inbound_order: '',
outbound_order: '',
inventory_sheet: '',
total_documents: ''
},
chartType: '入库',
lineChartData: {
expectedData: [],
actualData: []
},
pieChartData: {
labels: [
'空货位', // 空货位
'满货位', // 满货位
'入库已分配', // 入库已分配
'出库已分配', // 出库已分配
'入库需盘点', // 入库需盘点
'出库需盘点' // 出库需盘点
],
datasets: [{
data: [],
backgroundColor: ['#00d083', '#fdd100', '#fd7546', '#3f5cfc', '#1d99fd', '#2bf6ff']
}]
},
documentList: [],
executingTasks: [],
pendingTasks: [],
timer: null,
isCurrentPageActive: true // 当前页面是否激活
}
},
created() {
this.getListData()
this.startTimer()
},
mounted() {
// 监听页面可见性变化
document.addEventListener('visibilitychange', this.handleVisibilityChange)
// 监听窗口焦点变化
window.addEventListener('focus', this.handleWindowFocus)
window.addEventListener('blur', this.handleWindowBlur)
// 初始检查页面状态
this.checkPageStatus()
},
activated() {
// 当组件被激活时(如从keep-alive缓存中恢复)
this.checkPageStatus()
},
deactivated() {
// 当组件被停用时(如被keep-alive缓存)
this.stopTimer()
},
beforeDestroy() {
this.stopTimer()
// 移除事件监听器
document.removeEventListener('visibilitychange', this.handleVisibilityChange)
window.removeEventListener('focus', this.handleWindowFocus)
window.removeEventListener('blur', this.handleWindowBlur)
},
// 监听路由变化
watch: {
'$route'(to, from) {
// 当路由变化时,检查是否为首页
this.checkPageStatus()
}
},
methods: {
// 启动定时器
startTimer() {
if (!this.timer && this.isCurrentPageActive) {
this.timer = setInterval(() => {
if (this.isCurrentPageActive) {
this.getListData()
}
}, 8000)
}
},
// 停止定时器
stopTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
// 检查页面状态
checkPageStatus() {
// 检查当前路由是否为首页
const isHomePage = this.$route.path === '/' || this.$route.name === 'Index'
// 检查页面是否可见
const isPageVisible = !document.hidden
// 检查窗口是否有焦点
const isWindowFocused = document.hasFocus()
const shouldBeActive = isHomePage && isPageVisible && isWindowFocused
if (shouldBeActive !== this.isCurrentPageActive) {
this.isCurrentPageActive = shouldBeActive
if (this.isCurrentPageActive) {
console.log('首页激活,启动定时器')
this.startTimer()
// 立即刷新一次数据
this.getListData()
} else {
console.log('首页非激活状态,停止定时器')
this.stopTimer()
}
}
},
// 处理页面可见性变化
handleVisibilityChange() {
this.checkPageStatus()
},
// 处理窗口获得焦点
handleWindowFocus() {
this.checkPageStatus()
},
// 处理窗口失去焦点
handleWindowBlur() {
this.checkPageStatus()
},
getListData() {
// 所有单据数量
finishCount().then(response => {
this.quantity.inbound_order = response.data.stockinCount
this.quantity.outbound_order = response.data.stockoutCount
this.quantity.inventory_sheet = response.data.stockcheckCount
this.quantity.total_documents = Number(response.data.stockinCount) + Number(response.data.stockoutCount) + Number(response.data.stockcheckCount)
})
// 周入库出库作业
weekjob().then(response => {
this.lineChartData.expectedData = response.data.inJobCounts
this.lineChartData.actualData = response.data.outJobCounts
})
// 库位统计
cargospace().then(response => {
this.pieChartData.datasets[0].data = response.data.statusCounts
})
// 单据列表
billStatus().then(response => {
this.documentList = response.data
})
// 正执行待执行作业
jobStatus().then(response => {
this.executingTasks = response.data.status3
this.pendingTasks = response.data.status2
})
},
type_(row, column) {
const type = row.type
if (type == 1) {
return '入库' // 入库
} else if (type == 2) {
return '出库' // 出库
} else if (type == 3) {
return '盘点' // 盘点
}
return ""
},
status_(row, column) {
const status = row.status
if (status == 1) {
return '未执行' // 未执行
} else if (status == 2) {
return '审核中'
} else if (status == 3) {
return '正执行'
}
return ""
}
}
}
</script>
<style lang="scss" scoped>
.panel{
background: #fafafa;
}
.panel-group {
margin-top: 18px;
.card-panel-col {
margin-bottom: 32px;
}
.card-panel {
height: 108px;
cursor: pointer;
font-size: 12px;
position: relative;
overflow: hidden;
color: #666;
background: #fff;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
border-color: rgba(0, 0, 0, .05);
&:hover {
.card-panel-icon-wrapper {
color: #fff;
}
.icon-people {
background: #27c3cc;
}
.icon-message {
background: #ffd202;
}
.icon-money {
background: #00cf7f;
}
.icon-shopping {
background: #2298f8;
}
}
.icon-people {
color: #27c3cc;
}
.icon-message {
color: #ffd202;
}
.icon-money {
color: #00cf7f;
}
.icon-shopping {
color: #2298f8;
}
.card-panel-icon-wrapper {
float: left;
margin: 14px 0 0 14px;
padding: 16px;
transition: all 0.38s ease-out;
border-radius: 6px;
}
.card-panel-icon {
float: left;
font-size: 48px;
}
.card-panel-description {
float: right;
font-weight: bold;
margin: 26px;
margin-left: 0px;
.card-panel-text {
line-height: 18px;
color: rgba(0, 0, 0, 0.45);
font-size: 16px;
margin-bottom: 12px;
}
.card-panel-num {
font-size: 20px;
}
}
}
}
.chart-wrapper {
background: #fff;
padding: 16px;
margin-bottom: 32px;
border-radius: 4px;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
}
.chart-header {
border-bottom: 1px solid #eee;
padding-bottom: 16px;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
span {
font-size: 16px;
font-weight: bold;
color: #303133;
}
}
.list-wrapper {
background: #fff;
padding: 16px;
margin-bottom: 32px;
border-radius: 4px;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
height: 380px;
.list-header {
border-bottom: 1px solid #eee;
padding-bottom: 16px;
margin-bottom: 16px;
span {
font-size: 16px;
font-weight: bold;
color: #303133;
}
}
.el-table {
::v-deep .el-table__body-wrapper {
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
&::-webkit-scrollbar-thumb {
border-radius: 3px;
background: #e0e0e0;
}
&::-webkit-scrollbar-track {
border-radius: 3px;
background: #f5f5f5;
}
}
}
}
</style>