You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
14 KiB
177 lines
14 KiB
<template>
|
|
<div class="screen-wrap">
|
|
<div class="top-bar">
|
|
<div class="header-left"><div class="logo-box">LOGO</div></div>
|
|
<div class="header-center">
|
|
<div class="title">生产进度管理看板 · 家用电梯</div>
|
|
</div>
|
|
<div class="tools">
|
|
<span class="time">{{ currentTime }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="kpi-row">
|
|
<div class="kpi-card"><div class="kpi-label">排产订单</div><div class="kpi-value">{{ kpi.total }}</div></div>
|
|
<div class="kpi-card"><div class="kpi-label">进行中</div><div class="kpi-value warning">{{ kpi.processing }}</div></div>
|
|
<div class="kpi-card"><div class="kpi-label">已完成</div><div class="kpi-value success">{{ kpi.finished }}</div></div>
|
|
<div class="kpi-card"><div class="kpi-label">完工达成率</div><div class="kpi-value highlight">{{ kpi.finishRate }}%</div></div>
|
|
</div>
|
|
|
|
<div class="legend-row">
|
|
<span class="legend-item"><i class="dot done"></i>已完成</span>
|
|
<span class="legend-item"><i class="dot todo"></i>未开始</span>
|
|
</div>
|
|
|
|
<el-table class="board-table" :data="boardList" :height="tableHeight" v-loading="loading" border stripe>
|
|
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
|
|
<el-table-column prop="projectNo" label="项目号" width="140" align="center"></el-table-column>
|
|
<el-table-column prop="modelNo" label="型号" width="130" align="center"></el-table-column>
|
|
<el-table-column prop="color" label="颜色" width="90" align="center"></el-table-column>
|
|
<el-table-column prop="floorCount" label="层数" width="80" align="center"></el-table-column>
|
|
<el-table-column prop="specialRequirement" label="特殊要求" min-width="160" show-overflow-tooltip></el-table-column>
|
|
<el-table-column prop="planDeliveryDate" label="计划发货日期" width="130" align="center"></el-table-column>
|
|
<el-table-column label="仓库配料" width="105" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'stocking')"></span></template></el-table-column>
|
|
<el-table-column label="平台组装/调试" width="130" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'platformDebug')"></span></template></el-table-column>
|
|
<el-table-column label="背景墙/吊顶组装" width="140" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'bgCeiling')"></span></template></el-table-column>
|
|
<el-table-column label="门组装" width="95" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'doorAssy')"></span></template></el-table-column>
|
|
<el-table-column label="打包" width="90" align="center"><template slot-scope="scope"><span :class="getNodeCellClass(scope.row, 'pack')"></span></template></el-table-column>
|
|
<el-table-column prop="status" label="订单状态" width="100" align="center"><template slot-scope="scope"><el-tag class="board-tag" :class="getOrderStatusClass(scope.row.status)" size="small">{{ scope.row.status }}</el-tag></template></el-table-column>
|
|
<el-table-column prop="finishDate" label="完工时间" width="120" align="center"><template slot-scope="scope">{{ scope.row.finishDate || '-' }}</template></el-table-column>
|
|
</el-table>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { getHomeLiftOrderList } from '@/api/longchuang/productionPlan'
|
|
|
|
const NODE_TEMPLATE = ['stocking', 'platformDebug', 'bgCeiling', 'doorAssy', 'pack']
|
|
|
|
export default {
|
|
name: 'ScreenWholeLiftProgress',
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
tableHeight: 640,
|
|
currentTime: '',
|
|
timerId: null,
|
|
boardList: [],
|
|
kpi: { total: 0, processing: 0, finished: 0, finishRate: 0 }
|
|
}
|
|
},
|
|
mounted() {
|
|
this.setTableHeight()
|
|
this.loadBoardData()
|
|
this.updateTime()
|
|
this.timerId = setInterval(this.updateTime, 1000)
|
|
window.addEventListener('resize', this.setTableHeight)
|
|
},
|
|
beforeDestroy() {
|
|
if (this.timerId) clearInterval(this.timerId)
|
|
window.removeEventListener('resize', this.setTableHeight)
|
|
},
|
|
methods: {
|
|
setTableHeight() {
|
|
this.tableHeight = Math.max(420, window.innerHeight - 240)
|
|
},
|
|
loadBoardData() {
|
|
this.loading = true
|
|
getHomeLiftOrderList({ page: 1, limit: 300 }).then(({data}) => {
|
|
this.loading = false
|
|
const source = (data && data.code === 0 && data.page && data.page.list) ? data.page.list : this.getMockList()
|
|
this.boardList = this.buildBoardList(source)
|
|
this.buildKpi()
|
|
}).catch(() => {
|
|
this.loading = false
|
|
this.boardList = this.buildBoardList(this.getMockList())
|
|
this.buildKpi()
|
|
})
|
|
},
|
|
buildBoardList(sourceList) {
|
|
const statusAllow = ['已排产', '进行中', '已完成']
|
|
return sourceList.filter(item => statusAllow.includes(item.status)).map(item => ({ ...item, nodeStatusMap: this.toNodeStatusMap(item.nodeList) }))
|
|
},
|
|
toNodeStatusMap(nodeList) {
|
|
const map = {}
|
|
NODE_TEMPLATE.forEach(code => { map[code] = '未开始' })
|
|
;(nodeList || []).forEach(node => { map[node.nodeCode] = node.status || '未开始' })
|
|
return map
|
|
},
|
|
buildKpi() {
|
|
const total = this.boardList.length
|
|
const processing = this.boardList.filter(item => item.status === '进行中').length
|
|
const finished = this.boardList.filter(item => item.status === '已完成').length
|
|
this.kpi = { total, processing, finished, finishRate: total ? Math.round((finished / total) * 100) : 0 }
|
|
},
|
|
getNodeCellText(row, code) {
|
|
return row.nodeStatusMap[code] || '未开始'
|
|
},
|
|
getNodeCellClass(row, code) {
|
|
const status = this.getNodeCellText(row, code)
|
|
if (status === '已完成') return 'node-chip done'
|
|
return 'node-chip todo'
|
|
},
|
|
getOrderStatusClass(status) {
|
|
if (status === '已完成') return 'status-done'
|
|
if (status === '进行中') return 'status-doing'
|
|
return 'status-planned'
|
|
},
|
|
updateTime() {
|
|
const now = new Date()
|
|
const weekList = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
|
|
const d = this.dayjs(now)
|
|
this.currentTime = `${d.format('YYYY/MM/DD')} ${weekList[now.getDay()]} ${d.format('HH:mm:ss')}`
|
|
},
|
|
getMockList() {
|
|
return [
|
|
{ projectNo: 'LC-202604-001', modelNo: 'LC-HOME-820', color: '香槟白', floorCount: 4, specialRequirement: '厅门防刮', planDeliveryDate: '2026-03-18', status: '进行中', finishDate: '', nodeList: [{ nodeCode: 'stocking', status: '已完成' }, { nodeCode: 'platformDebug', status: '进行中' }] },
|
|
{ projectNo: 'LC-202604-002', modelNo: 'LC-HOME-1050', color: '希腊白', floorCount: 4, specialRequirement: '静音模式', planDeliveryDate: '2026-03-18', status: '已排产', finishDate: '', nodeList: [] },
|
|
{ projectNo: 'LC-202604-003', modelNo: 'LC-HOME-920', color: '灰灰', floorCount: 6, specialRequirement: '加装语音报站', planDeliveryDate: '2026-03-20', status: '已完成', finishDate: '2026-03-19', nodeList: NODE_TEMPLATE.map(code => ({ nodeCode: code, status: '已完成' })) },
|
|
{ projectNo: 'LC-202604-004', modelNo: 'LC-HOME-980', color: '砂岩金', floorCount: 5, specialRequirement: '加宽门套', planDeliveryDate: '2026-03-21', status: '进行中', finishDate: '', nodeList: [{ nodeCode: 'stocking', status: '已完成' }, { nodeCode: 'platformDebug', status: '已完成' }, { nodeCode: 'bgCeiling', status: '进行中' }] },
|
|
{ projectNo: 'LC-202604-005', modelNo: 'LC-HOME-760', color: '深空灰', floorCount: 3, specialRequirement: '井道照明增强', planDeliveryDate: '2026-03-22', status: '已排产', finishDate: '', nodeList: [{ nodeCode: 'stocking', status: '未开始' }] },
|
|
{ projectNo: 'LC-202604-006', modelNo: 'LC-HOME-1100', color: '曜石黑', floorCount: 7, specialRequirement: '门机静音升级', planDeliveryDate: '2026-03-23', status: '进行中', finishDate: '', nodeList: [{ nodeCode: 'stocking', status: '已完成' }, { nodeCode: 'platformDebug', status: '进行中' }, { nodeCode: 'bgCeiling', status: '未开始' }] },
|
|
{ projectNo: 'LC-202604-007', modelNo: 'LC-HOME-900', color: '雾霾蓝', floorCount: 4, specialRequirement: '控制柜防潮', planDeliveryDate: '2026-03-24', status: '已完成', finishDate: '2026-03-23', nodeList: NODE_TEMPLATE.map(code => ({ nodeCode: code, status: '已完成' })) },
|
|
{ projectNo: 'LC-202604-008', modelNo: 'LC-HOME-840', color: '珍珠白', floorCount: 5, specialRequirement: '门头发光字定制', planDeliveryDate: '2026-03-25', status: '进行中', finishDate: '', nodeList: [{ nodeCode: 'stocking', status: '已完成' }, { nodeCode: 'platformDebug', status: '已完成' }, { nodeCode: 'bgCeiling', status: '已完成' }, { nodeCode: 'doorAssy', status: '进行中' }] }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.screen-wrap{height:100vh;padding:16px;background:linear-gradient(165deg,#0a1f36 0%,#0f2b47 50%,#0a2037 100%);display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden}
|
|
.top-bar{display:flex;justify-content:space-between;align-items:center;padding:14px 18px;border-radius:12px;border:1px solid rgba(109,167,219,.24);background:rgba(9,29,49,.82)}
|
|
.top-bar{position:relative}
|
|
.header-left{display:flex;align-items:center;min-width:110px;z-index:2}
|
|
.logo-box{width:86px;height:30px;border-radius:6px;border:1px solid rgba(128,198,255,.45);color:#d8edff;font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;background:rgba(36,82,122,.35)}
|
|
.header-center{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);text-align:center;pointer-events:none;max-width:70%;width:auto;padding:6px 24px 8px;border-radius:8px;border:1px solid rgba(96,170,232,.34);background:linear-gradient(180deg,rgba(33,73,116,.52),rgba(16,44,77,.42))}
|
|
.header-center::before{content:'';position:absolute;left:50%;transform:translateX(-50%);top:-8px;width:68%;height:1px;background:linear-gradient(90deg,rgba(87,164,230,0),rgba(87,164,230,.9),rgba(87,164,230,0))}
|
|
.top-bar .tools{margin-left:auto;z-index:2}
|
|
.title{color:#8fe7ff;font-size:30px;font-weight:800;letter-spacing:3px;line-height:1.05;text-shadow:0 0 14px rgba(79,179,255,.36)}
|
|
.subtitle{margin-top:4px;color:#c7e8ff;font-size:12px;letter-spacing:1px}
|
|
.tools{display:flex;align-items:center;gap:12px}.time{color:#89d7ff;font-size:20px;font-weight:600}
|
|
.kpi-row{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:12px 0 8px}
|
|
.kpi-card{border-radius:10px;padding:12px 14px;background:rgba(14,43,70,.82);border:1px solid rgba(101,157,209,.22)}
|
|
.kpi-label{color:#b7d3ee;font-size:13px}.kpi-value{margin-top:6px;font-size:30px;font-weight:700;color:#edf6ff}
|
|
.kpi-value.warning{color:#ffd166}.kpi-value.success{color:#74dfa3}.kpi-value.highlight{color:#79d5ff}
|
|
.legend-row{display:flex;gap:16px;margin:0 0 10px 2px}.legend-item{display:inline-flex;align-items:center;color:#c7dff4;font-size:12px}
|
|
.dot{width:10px;height:10px;border-radius:50%;margin-right:6px;display:inline-block}.dot.done{background:#69e4a4}.dot.doing{background:#ffd35d}.dot.todo{background:#dbe3ee}
|
|
.board-table{border-radius:10px;overflow:hidden;border:1px solid rgba(86,140,190,.35);flex:1;min-height:0}
|
|
.board-table .cell {
|
|
line-height: 30px;
|
|
font-size: 16px;
|
|
height: 30px;
|
|
}
|
|
.screen-wrap .board-table .el-table,.screen-wrap .board-table .el-table__expanded-cell,.screen-wrap .board-table .el-table__body-wrapper,.screen-wrap .board-table .el-table__empty-block,.screen-wrap .board-table .el-table__fixed-body-wrapper{background:rgba(12,39,64,.96)!important;color:#fff!important}
|
|
.screen-wrap .board-table .el-table__header-wrapper th,.screen-wrap .board-table .el-table__fixed-header-wrapper th{background:#123a5e!important;color:#d9e9f8!important;border-color:rgba(80,133,181,.6)!important;font-size:14px!important;padding:12px 0!important}
|
|
.screen-wrap .board-table .el-table__body tr>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr>td,.screen-wrap .board-table .el-table__fixed-right .el-table__fixed-body-wrapper tr>td{background:rgba(20,52,83,.96)!important;border-color:rgba(88,139,187,.4)!important;color:#fff!important;height:46px!important;vertical-align:middle!important}
|
|
.screen-wrap .board-table .el-table--striped .el-table__body tr.el-table__row--striped>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr.el-table__row--striped>td{background:rgba(29,66,102,.96)!important}
|
|
.screen-wrap .board-table .el-table--enable-row-hover .el-table__body tr:hover>td,.screen-wrap .board-table .el-table__fixed-body-wrapper tr:hover>td{background:rgba(39,81,123,.96)!important}
|
|
.screen-wrap .board-table .el-table .cell{color:#fff!important;line-height:24px!important;overflow:visible!important}
|
|
.screen-wrap .board-table .el-table__empty-text{color:#9ac2e7!important}
|
|
.node-chip{display:inline-block!important;width:46px;height:14px;margin:0 auto;border-radius:2px}
|
|
.node-chip.done{background:#6de3a0}.node-chip.todo{background:#dce4ee}
|
|
.board-tag{display:inline-flex!important;align-items:center!important;justify-content:center!important;min-width:66px!important;height:24px!important;padding:0 10px!important;border-radius:12px!important;border:1px solid transparent!important;font-size:12px!important;font-weight:600!important;line-height:22px!important;box-sizing:border-box!important}
|
|
.board-tag.status-planned{color:#b9c7d8!important;background:rgba(96,118,141,.28)!important;border-color:rgba(185,199,216,.34)!important}
|
|
.board-tag.status-doing{color:#ffd774!important;background:rgba(120,92,27,.32)!important;border-color:rgba(255,215,116,.45)!important}
|
|
.board-tag.status-done{color:#83f3be!important;background:rgba(31,110,84,.32)!important;border-color:rgba(131,243,190,.45)!important}
|
|
</style>
|