Files
bj_power/bj_power_workstation/frontend/src/views/Main.vue
T

252 lines
6.5 KiB
Vue
Raw Normal View History

2026-08-28 15:06:01 +08:00
<template>
<div class="page">
<!-- 顶部工位 / 工单 / 工件 / 同步状态 / 用户 -->
2026-08-28 15:06:01 +08:00
<header class="top-bar">
<div class="brand">工位终端</div>
<div class="chip">
<span class="lab">工位</span>
<b>{{ stationNo ? '工位 ' + stationNo + (stationName ? '·' + stationName : '') : '…' }}</b>
</div>
<div class="chip">
<span class="lab">工单</span>
<b>{{ orderNo || '未选择' }}</b>
</div>
<div class="chip">
<span class="lab">工件</span>
<b class="sn">{{ sn || '未上料' }}</b>
</div>
2026-08-28 15:06:01 +08:00
<div class="spacer"></div>
<el-button size="large" :type="pendingTotal ? 'warning' : 'default'" @click="manualFlush">
待同步 {{ pendingTotal }}
</el-button>
<el-button size="large" @click="wlRef?.open()">我的工作量</el-button>
<span class="user-name">{{ user.name || user.username || '-' }}</span>
<span class="clock">{{ clock }}</span>
<el-button size="large" type="danger" plain @click="logout">退出</el-button>
2026-08-28 15:06:01 +08:00
</header>
<!-- 不合格告警横幅 -->
2026-08-28 15:06:01 +08:00
<transition name="fade">
<div v-if="hasNg" class="alert-banner"> 存在不合格请复检</div>
2026-08-28 15:06:01 +08:00
</transition>
<el-tabs v-model="tab" type="border-card" class="main-tabs">
<el-tab-pane v-if="isOnline" label="上线建档" name="online">
<OnlinePanel />
</el-tab-pane>
<el-tab-pane v-if="isOffline" label="下线完工" name="offline">
<OfflinePanel />
</el-tab-pane>
<el-tab-pane v-if="!isVirtual" label="作业" name="work">
<WorkPanel ref="workRef" />
</el-tab-pane>
<el-tab-pane label="物料 / 叫料" name="material">
<MaterialPanel />
</el-tab-pane>
<el-tab-pane v-if="!isVirtual" label="移料" name="move">
<MovePanel />
</el-tab-pane>
<el-tab-pane v-if="!isVirtual" label="工艺文件" name="pdf">
<PdfPanel />
</el-tab-pane>
2026-09-15 16:37:39 +08:00
<el-tab-pane label="巡检 / 异常" name="inspect">
<InspectPanel />
</el-tab-pane>
</el-tabs>
<WorkloadDialog ref="wlRef" />
<!-- 全局帮助右下角悬浮?」,内容随当前页签切换 -->
<PageHelp :data="helpData" />
2026-08-28 15:06:01 +08:00
</div>
</template>
<script setup>
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
2026-08-28 15:06:01 +08:00
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import WorkPanel from './panels/WorkPanel.vue'
import MaterialPanel from './panels/MaterialPanel.vue'
import MovePanel from './panels/MovePanel.vue'
import PdfPanel from './panels/PdfPanel.vue'
2026-09-15 16:37:39 +08:00
import InspectPanel from './panels/InspectPanel.vue'
import OnlinePanel from './panels/OnlinePanel.vue'
import OfflinePanel from './panels/OfflinePanel.vue'
import WorkloadDialog from './panels/WorkloadDialog.vue'
import PageHelp from '../components/PageHelp.vue'
import {
helpInspect,
helpMaterial,
helpMove,
helpOffline,
helpOnline,
helpPdf,
helpWorkstation
} from '../help'
import { stationLogout, syncFlush } from '../api'
import { clearAuth } from '../utils/request'
2026-08-28 15:06:01 +08:00
import {
hasNg,
loadConfig,
loadMoves,
loadPoints,
loadStats,
loadTight,
loadTask,
loadWip,
orderNo,
pendingTotal,
refreshAll,
sn,
state,
stationNo,
user
} from '../store/station'
2026-08-28 15:06:01 +08:00
const router = useRouter()
const tab = ref('work')
const workRef = ref()
const wlRef = ref()
const clock = ref('')
const stationName = computed(() => state.task?.stationName || '')
// 0=上线位、13=下线位为虚拟工位,分别展示上线建档 / 下线完工面板
const isOnline = computed(() => Number(stationNo.value) === 0)
const isOffline = computed(() => Number(stationNo.value) === 13)
const isVirtual = computed(() => isOnline.value || isOffline.value)
// 帮助内容随当前页签切换(全局唯一一个 PageHelp 悬浮按钮)
const HELP_MAP = {
online: helpOnline,
offline: helpOffline,
work: helpWorkstation,
material: helpMaterial,
move: helpMove,
pdf: helpPdf,
inspect: helpInspect
}
const helpData = computed(() => HELP_MAP[tab.value] || helpWorkstation)
let timerTask = null
let timerTight = null
let timerStats = null
let timerClock = null
2026-08-28 15:06:01 +08:00
function tickClock() {
const d = new Date()
2026-08-28 15:06:01 +08:00
const p = (n) => String(n).padStart(2, '0')
clock.value = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
2026-08-28 15:06:01 +08:00
}
async function manualFlush() {
try {
const data = await syncFlush()
ElMessage.success(`本轮同步成功 ${data?.count ?? 0} 条`)
loadStats()
} catch (e) { /* 统一错误提示 */ }
2026-08-28 15:06:01 +08:00
}
function logout() {
stationLogout({ username: user?.username || '', stationNo: stationNo.value || 0 }).catch(() => {})
2026-08-28 15:06:01 +08:00
clearAuth()
router.push('/login')
}
onMounted(async () => {
tickClock()
2026-08-28 15:06:01 +08:00
await loadConfig()
// 虚拟工位默认落到对应面板;物理工位默认作业页
if (isOnline.value) tab.value = 'online'
else if (isOffline.value) tab.value = 'offline'
else tab.value = 'work'
2026-08-28 15:06:01 +08:00
refreshAll()
loadMoves()
workRef.value?.focusScan?.()
timerTask = setInterval(loadTask, 5000) // 任务 5 秒
timerTight = setInterval(loadTight, 2000) // 拧紧结果 2 秒
timerStats = setInterval(loadStats, 10000) // 同步统计 10 秒
timerClock = setInterval(() => {
tickClock()
loadPoints() // 点位台账 10 秒
loadMoves()
loadWip() // 在制品 10 秒
}, 10000)
2026-08-28 15:06:01 +08:00
})
onBeforeUnmount(() => {
clearInterval(timerTask)
clearInterval(timerTight)
clearInterval(timerStats)
clearInterval(timerClock)
2026-08-28 15:06:01 +08:00
})
</script>
<style scoped>
.page {
min-height: 100vh;
background: #f0f2f5;
2026-08-28 15:06:01 +08:00
}
.top-bar {
display: flex;
align-items: center;
gap: 14px;
padding: 10px 16px;
background: #fff;
box-shadow: 0 1px 6px rgba(0, 21, 41, 0.08);
flex-wrap: wrap;
2026-08-28 15:06:01 +08:00
}
.brand {
font-size: 20px;
font-weight: 700;
color: #1f6feb;
2026-08-28 15:06:01 +08:00
}
.chip {
2026-08-28 15:06:01 +08:00
display: flex;
align-items: baseline;
gap: 6px;
font-size: 15px;
2026-08-28 15:06:01 +08:00
}
.chip .lab {
color: #909399;
2026-08-28 15:06:01 +08:00
}
.chip b.sn {
color: #1f6feb;
2026-08-28 15:06:01 +08:00
}
.spacer {
flex: 1;
}
.user-name {
font-size: 15px;
2026-08-28 15:06:01 +08:00
}
.clock {
font-size: 15px;
color: #606266;
font-variant-numeric: tabular-nums;
2026-08-28 15:06:01 +08:00
}
.alert-banner {
background: #fef0f0;
color: #f56c6c;
2026-08-28 15:06:01 +08:00
text-align: center;
padding: 10px;
font-size: 18px;
font-weight: 700;
2026-08-28 15:06:01 +08:00
}
.main-tabs {
margin: 12px;
min-height: calc(100vh - 140px);
}
.main-tabs :deep(.el-tabs__content) {
padding: 12px;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>