Files
pda-overseas-uniapp/src/pages/home/home.vue
T

127 lines
6.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view v-if="user" class="page-shell portal-page home-page">
<PortalHeader ref="portalHeader" title="海外仓工作台" :user="user" menu @menu-change="menuOpen = $event" />
<view class="home-menu">
<view class="home-overview">
<view class="home-overview-copy">
<text class="home-overview-eyebrow">OVERSEAS WAREHOUSE</text>
<text class="home-overview-title">{{ greeting }},{{ displayName }}</text>
<text class="home-overview-warehouse">{{ warehouseLabel }}</text>
</view>
</view>
<view class="home-workload-toolbar"><text>作业待办</text><button :disabled="countsLoading" @tap="refreshCounts"><uni-icons type="refresh" color="#135ee8" size="18" /><text>{{ countsLoading ? '刷新中…' : '刷新' }}</text></button></view>
<view v-for="group in groups" :key="group.key" class="home-group">
<view class="home-group-title"><view class="home-group-mark" :class="`home-group-mark-${group.key}`"></view><text>{{ group.name }}</text></view>
<view class="home-operation-grid">
<button v-for="operation in group.operations" :key="operation.name" class="home-operation" :class="{ 'home-operation-primary': operation.available, 'home-operation-disabled': !operation.available }" :disabled="!operation.available" @tap="openOperation(operation)">
<view class="home-operation-icon" aria-hidden="true"><uni-icons :type="operation.iconType" :color="operation.available ? '#135ee8' : '#9aa6b2'" size="28" /></view>
<text class="home-operation-name">{{ operation.name }}</text>
<text v-if="operation.available" class="home-operation-pending" :class="countBadge(operation).tone">{{ countBadge(operation).label }}</text>
<text v-else class="home-operation-unavailable">暂未开放</text>
</button>
</view>
</view>
</view>
</view>
</template>
<script>
import PortalHeader from '@/components/PortalHeader.vue'
import { getCurrentWarehouseProfile } from '@/api/inbound.js'
import { loadWorkbenchCounts, workbenchBadge } from '@/api/workbench.js'
import { MODULES } from '@/data/overseas-workbench.js'
import { applyWarehouseProfile, session, requireSession } from '@/stores/session.js'
import { restoreWarehouseWork, warehouseWork } from '@/stores/warehouse-work.js'
const HOME_GROUPS = MODULES.map((module) => ({
...module,
available: module.operations.some((operation) => operation.available),
operations: module.operations.map((operation) => ({ ...operation, iconType: operation.iconType || 'circle' }))
}))
export default {
components: { PortalHeader },
data() { return { user: session.currentUser, groups: HOME_GROUPS, menuOpen: false, counts: {}, countsLoading: false, countsGeneration: 0 } },
computed: {
displayName() {
const name = String(this.user?.name || '').trim()
return name && !/^[a-z0-9._-]+$/i.test(name) ? name : '仓库作业员'
},
warehouseLabel() {
return String(this.user?.warehouseName || '').trim() || '海外仓未关联'
},
greeting() {
const hour = new Date().getHours()
if (hour < 6) return '夜间作业请注意安全'
if (hour < 12) return '早上好'
if (hour < 18) return '下午好'
return '晚上好'
}
},
async onShow() {
if (!requireSession()) return
const generation = ++this.countsGeneration
this.user = session.currentUser
this.counts = {}; this.countsLoading = true
if (!this.user?.warehouseCode || !this.user?.warehouseName) await this.loadWarehouseProfile()
if (generation !== this.countsGeneration) return
this.countsLoading = false
if (!session.currentUser) { this.user = null; return }
this.user = session.currentUser
await this.refreshCounts()
},
onHide() { this.invalidateCounts() },
onUnload() { this.invalidateCounts() },
beforeUnmount() { this.invalidateCounts() },
onBackPress() {
if (!this.menuOpen) return false
this.$refs.portalHeader.closeMenu()
return true
},
methods: {
countBadge(operation) { return workbenchBadge(operation.key, this.counts[operation.key]) },
countsScope() { const user = session.currentUser; return user?.id && user?.warehouseId ? `${session.apiBase}:${user.id}:${user.warehouseId}` : '' },
invalidateCounts() { this.countsGeneration += 1; this.countsLoading = false; this.counts = {} },
async refreshCounts() {
if (this.countsLoading || !this.countsScope()) return
const generation = ++this.countsGeneration
const scope = this.countsScope()
const profile = { ...session.currentUser }
restoreWarehouseWork(`${profile.id}:${profile.warehouseId}`)
const activeTransferNo = warehouseWork.warehouseTransfer.currentNo
this.counts = {}; this.countsLoading = true
try {
const counts = await loadWorkbenchCounts({ profile, activeTransferNo })
if (generation === this.countsGeneration && scope === this.countsScope()) this.counts = counts
} finally {
if (generation === this.countsGeneration) {
this.countsLoading = false
if (scope !== this.countsScope()) { this.counts = {}; this.user = session.currentUser }
}
}
},
async loadWarehouseProfile() {
try { this.user = applyWarehouseProfile(await getCurrentWarehouseProfile()) } catch (_) { this.user = session.currentUser }
},
openOperation(operation) {
if (!operation.available) return
const module = this.groups.find((group) => group.operations.some((item) => item.name === operation.name))
uni.navigateTo({ url: operation.route || `/pages/operation/operation?module=${module?.key || 'query'}&op=${operation.key}` })
}
}
}
</script>
<style scoped>
.home-overview{margin-bottom:12px}
.home-workload-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;color:#526174;font-size:14px;font-weight:700}
.home-workload-toolbar button{display:flex;align-items:center;justify-content:center;gap:5px;width:auto;height:36px;margin:0;padding:0 14px;border:1px solid #b8d1f5;border-radius:20px;color:#135ee8;font-size:13px;font-weight:700;line-height:normal;background:#fff}
.home-workload-toolbar button[disabled]{opacity:.55}
.home-operation{height:auto;min-height:104px;padding:10px 6px}
.home-operation-name{min-height:17px}
.home-operation-pending{box-sizing:border-box;max-width:100%;font-size:10px;line-height:16px;white-space:normal}
.home-operation-pending.has-work{color:#9a5300;background:#fff0d6}
.home-operation-pending.is-empty,.home-operation-pending.is-loading,.home-operation-pending.is-static{color:#6f8194;background:#e7edf4}
.home-operation-pending.is-error{color:#b42318;background:#fff1f0}
</style>