feat: 智世出库资源
This commit is contained in:
parent
0a34bb770a
commit
c94fe7fd80
|
|
@ -0,0 +1,20 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export interface ExtensionResourceSnapshotVO {
|
||||||
|
resourceType: string
|
||||||
|
resourceName: string
|
||||||
|
warehouse: string
|
||||||
|
capacity: number
|
||||||
|
boundCount: number
|
||||||
|
reservedCount: number
|
||||||
|
totalCount: number
|
||||||
|
remainingCapacity: number
|
||||||
|
reservedChainCodes: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExtensionResourceSnapshots(warehouse: string) {
|
||||||
|
return request.get<never, { code: number; data: ExtensionResourceSnapshotVO[] }>(
|
||||||
|
'/api/robot/external/admin/extension-resource/snapshot',
|
||||||
|
{ params: { warehouse } },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
export interface PalletCacheStationVO {
|
|
||||||
warehouse: string
|
|
||||||
capacity: number
|
|
||||||
boundCount: number
|
|
||||||
reservedCount: number
|
|
||||||
totalCount: number
|
|
||||||
remainingCapacity: number
|
|
||||||
reservedChainCodes: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPalletCacheStationSnapshot(warehouse: string) {
|
|
||||||
return request.get<never, { code: number; data: PalletCacheStationVO }>(
|
|
||||||
'/api/robot/external/admin/pallet-cache-station/snapshot',
|
|
||||||
{ params: { warehouse } },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -181,7 +181,7 @@ export interface CallbackField {
|
||||||
}
|
}
|
||||||
|
|
||||||
const hkFields: CallbackField[] = [
|
const hkFields: CallbackField[] = [
|
||||||
{ name: 'robotTaskCode', label: '任务编号(任务链编号)', type: 'string' },
|
{ name: 'robotTaskCode', label: '机器调用编号', type: 'string' },
|
||||||
{ name: 'singleRobotCode', label: '机器人标识', type: 'string' },
|
{ name: 'singleRobotCode', label: '机器人标识', type: 'string' },
|
||||||
{ name: 'currentSeq', label: '当前执行顺序', type: 'string' },
|
{ name: 'currentSeq', label: '当前执行顺序', type: 'string' },
|
||||||
]
|
]
|
||||||
|
|
@ -199,10 +199,11 @@ const zsTaskStepOptions = [
|
||||||
{ value: 'IN_LIFTER', label: '托盘进提升机' },
|
{ value: 'IN_LIFTER', label: '托盘进提升机' },
|
||||||
{ value: 'OUT_LIFTER', label: '托盘出提升机' },
|
{ value: 'OUT_LIFTER', label: '托盘出提升机' },
|
||||||
{ value: 'VEHICLE_MOVE', label: '四向车搬运' },
|
{ value: 'VEHICLE_MOVE', label: '四向车搬运' },
|
||||||
|
{ value: 'VEHICLE_WILL_PICK', label: '四向车准备举升托盘' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const zsTaskInfoBackFields: CallbackField[] = [
|
const zsTaskInfoBackFields: CallbackField[] = [
|
||||||
{ name: 'taskCode', label: '任务编号(任务链编号)', type: 'string' },
|
{ name: 'taskCode', label: '机器调用编号', type: 'string' },
|
||||||
{ name: 'palletCode', label: '托盘码', type: 'string' },
|
{ name: 'palletCode', label: '托盘码', type: 'string' },
|
||||||
{ name: 'status', label: '任务状态', type: 'select', options: zsTaskStatusOptions },
|
{ name: 'status', label: '任务状态', type: 'select', options: zsTaskStatusOptions },
|
||||||
{ name: 'taskStep', label: '任务步骤', type: 'select', options: zsTaskStepOptions },
|
{ name: 'taskStep', label: '任务步骤', type: 'select', options: zsTaskStepOptions },
|
||||||
|
|
@ -244,6 +245,7 @@ export const callbackScenarioMap: Record<string, CallbackScenario[]> = {
|
||||||
HK_INBOUND: [hkArriveWcs],
|
HK_INBOUND: [hkArriveWcs],
|
||||||
HK_MOVE: [hkArriveWcs],
|
HK_MOVE: [hkArriveWcs],
|
||||||
HK_OUTBOUND_WAIT: [hkArriveWcs, hkArriveStation],
|
HK_OUTBOUND_WAIT: [hkArriveWcs, hkArriveStation],
|
||||||
|
HK_ARRIVE_ELEVATOR: [hkArriveWcs],
|
||||||
HK_ARRIVE_STATION: [hkArriveStation],
|
HK_ARRIVE_STATION: [hkArriveStation],
|
||||||
HK_PICK_PALLET: [{ key: 'pickPalletDone', label: 'AGV完成取货', url: '/api/robot/external/hk/pickPalletDone', fields: hkFields }],
|
HK_PICK_PALLET: [{ key: 'pickPalletDone', label: 'AGV完成取货', url: '/api/robot/external/hk/pickPalletDone', fields: hkFields }],
|
||||||
HK_PICK_UP: [{ key: 'pickUp', label: '海康举起托盘', url: '/api/robot/external/hk/pickUp', fields: hkFields }],
|
HK_PICK_UP: [{ key: 'pickUp', label: '海康举起托盘', url: '/api/robot/external/hk/pickUp', fields: hkFields }],
|
||||||
|
|
@ -251,6 +253,10 @@ export const callbackScenarioMap: Record<string, CallbackScenario[]> = {
|
||||||
HK_LEAVE_START_POINT: [{ key: 'leaveStartPoint', label: 'AGV离开起点', url: '/api/robot/external/hk/leaveStartPoint', fields: hkFields }],
|
HK_LEAVE_START_POINT: [{ key: 'leaveStartPoint', label: 'AGV离开起点', url: '/api/robot/external/hk/leaveStartPoint', fields: hkFields }],
|
||||||
ZS_INBOUND: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
ZS_INBOUND: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
ZS_OUTBOUND: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
ZS_OUTBOUND: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
|
ZS_PRE_PICK_UP: [{ key: 'taskInfoBack', label: '四向车准备举升托盘', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
|
ZS_PICK_UP: [{ key: 'taskInfoBack', label: '智世举起目标托盘', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
|
ZS_OUTBOUND_IN_LIFTER: [{ key: 'taskInfoBack', label: '托盘进提升机', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
|
ZS_OUTBOUND_FINISH: [{ key: 'taskInfoBack', label: '智世出库完成', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
ZS_MOVE: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
ZS_MOVE: [{ key: 'taskInfoBack', label: '任务状态回传', url: '/api/robot/external/zs/wms/taskInfoBack', fields: zsTaskInfoBackFields }],
|
||||||
ZS_OUTER_DETECT: [{ key: 'exceptionPickUpNotify', label: '外形检测异常', url: '/api/robot/external/zs/wms/exceptionPickUpNotify', fields: zsExceptionFields }],
|
ZS_OUTER_DETECT: [{ key: 'exceptionPickUpNotify', label: '外形检测异常', url: '/api/robot/external/zs/wms/exceptionPickUpNotify', fields: zsExceptionFields }],
|
||||||
ZS_APPLY_INBOUND: [{ key: 'palletCodeIn', label: '请求入库', url: '/api/robot/external/zs/wms/palletCodeIn', fields: zsPalletCodeInFields }],
|
ZS_APPLY_INBOUND: [{ key: 'palletCodeIn', label: '请求入库', url: '/api/robot/external/zs/wms/palletCodeIn', fields: zsPalletCodeInFields }],
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@
|
||||||
<el-icon><Tickets /></el-icon>
|
<el-icon><Tickets /></el-icon>
|
||||||
<template #title>站点排队</template>
|
<template #title>站点排队</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/station/pallet-cache">
|
<el-menu-item index="/resource/extension">
|
||||||
<el-icon><Box /></el-icon>
|
<el-icon><Box /></el-icon>
|
||||||
<template #title>托盘缓存站</template>
|
<template #title>拓展资源</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item v-if="!isMonitorMode" index="/vendor/load">
|
<el-menu-item v-if="!isMonitorMode" index="/vendor/load">
|
||||||
<el-icon><DataLine /></el-icon>
|
<el-icon><DataLine /></el-icon>
|
||||||
|
|
@ -207,7 +207,7 @@ const userStore = useUserStore()
|
||||||
const isMonitorMode = computed(() => userStore.isMonitorMode())
|
const isMonitorMode = computed(() => userStore.isMonitorMode())
|
||||||
const keepAliveNames = computed(() => {
|
const keepAliveNames = computed(() => {
|
||||||
if (isMonitorMode.value) {
|
if (isMonitorMode.value) {
|
||||||
return ['TaskChainList', 'TaskChainDetail', 'ElevatorList', 'StationQueueView', 'PalletCacheStationView', 'ExceptionDocsView']
|
return ['TaskChainList', 'TaskChainDetail', 'ElevatorList', 'StationQueueView', 'ExtensionResourceView', 'ExceptionDocsView']
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
'DashboardView',
|
'DashboardView',
|
||||||
|
|
@ -215,7 +215,7 @@ const keepAliveNames = computed(() => {
|
||||||
'TaskChainDetail',
|
'TaskChainDetail',
|
||||||
'ElevatorList',
|
'ElevatorList',
|
||||||
'StationQueueView',
|
'StationQueueView',
|
||||||
'PalletCacheStationView',
|
'ExtensionResourceView',
|
||||||
'VendorLoadView',
|
'VendorLoadView',
|
||||||
'TaskGenerateView',
|
'TaskGenerateView',
|
||||||
'ExceptionDocsView',
|
'ExceptionDocsView',
|
||||||
|
|
@ -340,7 +340,7 @@ const tabs = computed(() => [
|
||||||
{ path: '/task/chain', label: '任务链', icon: List },
|
{ path: '/task/chain', label: '任务链', icon: List },
|
||||||
{ path: '/elevator', label: '提升机', icon: SetUp },
|
{ path: '/elevator', label: '提升机', icon: SetUp },
|
||||||
{ path: '/station/queue', label: '排队', icon: Tickets },
|
{ path: '/station/queue', label: '排队', icon: Tickets },
|
||||||
{ path: '/station/pallet-cache', label: '缓存站', icon: Box },
|
{ path: '/resource/extension', label: '资源', icon: Box },
|
||||||
...(!isMonitorMode.value ? [{ path: '/vendor/load', label: '厂商负载', icon: DataLine }] : []),
|
...(!isMonitorMode.value ? [{ path: '/vendor/load', label: '厂商负载', icon: DataLine }] : []),
|
||||||
...(!isMonitorMode.value ? [{ path: '/generate', label: '生成', icon: Plus }] : []),
|
...(!isMonitorMode.value ? [{ path: '/generate', label: '生成', icon: Plus }] : []),
|
||||||
{ path: '/docs/exception', label: '异常', icon: Document },
|
{ path: '/docs/exception', label: '异常', icon: Document },
|
||||||
|
|
@ -350,7 +350,7 @@ const activeMenu = computed(() => {
|
||||||
const path = route.path
|
const path = route.path
|
||||||
if (path.startsWith('/task/chain')) return '/task/chain'
|
if (path.startsWith('/task/chain')) return '/task/chain'
|
||||||
if (path.startsWith('/station/queue')) return '/station/queue'
|
if (path.startsWith('/station/queue')) return '/station/queue'
|
||||||
if (path.startsWith('/station/pallet-cache')) return '/station/pallet-cache'
|
if (path.startsWith('/resource/extension')) return '/resource/extension'
|
||||||
if (path.startsWith('/docs/exception')) return '/docs/exception'
|
if (path.startsWith('/docs/exception')) return '/docs/exception'
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
|
|
@ -359,7 +359,7 @@ const activeTab = computed(() => {
|
||||||
const path = route.path
|
const path = route.path
|
||||||
if (path.startsWith('/task/chain')) return '/task/chain'
|
if (path.startsWith('/task/chain')) return '/task/chain'
|
||||||
if (path.startsWith('/station/queue')) return '/station/queue'
|
if (path.startsWith('/station/queue')) return '/station/queue'
|
||||||
if (path.startsWith('/station/pallet-cache')) return '/station/pallet-cache'
|
if (path.startsWith('/resource/extension')) return '/resource/extension'
|
||||||
if (path.startsWith('/docs/exception')) return '/docs/exception'
|
if (path.startsWith('/docs/exception')) return '/docs/exception'
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,10 @@ const router = createRouter({
|
||||||
meta: { title: '站点排队' },
|
meta: { title: '站点排队' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'station/pallet-cache',
|
path: 'resource/extension',
|
||||||
name: 'PalletCacheStationView',
|
name: 'ExtensionResourceView',
|
||||||
component: () => import('@/views/station/PalletCacheStationView.vue'),
|
component: () => import('@/views/resource/ExtensionResourceView.vue'),
|
||||||
meta: { title: '托盘缓存站' },
|
meta: { title: '拓展资源' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'vendor/load',
|
path: 'vendor/load',
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@
|
||||||
<el-button type="primary" :loading="loading" @click="loadData">查询</el-button>
|
<el-button type="primary" :loading="loading" @click="loadData">查询</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-alert type="info" show-icon :closable="false" class="hint">
|
<el-alert type="info" show-icon :closable="false" class="hint">
|
||||||
缓存站总占用 = 已绑定缓存站库位的托盘数量 + Redis 中在途预占缓存站名额的任务链数量。
|
拓展资源总占用 = 已绑定数量 + Redis 中在途预占名额的任务链数量。
|
||||||
</el-alert>
|
</el-alert>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<div class="board-toolbar">
|
<div class="board-toolbar">
|
||||||
<div class="board-titles">
|
<div class="board-titles">
|
||||||
<span class="board-title">托盘缓存站</span>
|
<span class="board-title">拓展资源</span>
|
||||||
<span v-if="snapshot" class="board-sub">{{ snapshot.warehouse }}</span>
|
<span v-if="snapshots.length" class="board-sub">{{ snapshots[0].warehouse }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="board-actions">
|
<div class="board-actions">
|
||||||
<span class="board-hint">点击预占任务链查看详情 · 预占数据来自 Redis Set</span>
|
<span class="board-hint">点击预占任务链查看详情 · 预占数据来自 Redis Set</span>
|
||||||
|
|
@ -30,118 +30,127 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="board-body" v-loading="loading">
|
<div class="board-body" v-loading="loading">
|
||||||
<el-empty v-if="!snapshot && !loading" description="暂无数据,请确认仓库编码" />
|
<el-empty v-if="!snapshots.length && !loading" description="暂无数据,请确认仓库编码" />
|
||||||
<div v-else-if="snapshot" class="cache-layout">
|
<div v-else class="resource-list">
|
||||||
<el-card shadow="hover" class="summary-card">
|
<el-card
|
||||||
|
v-for="resource in snapshots"
|
||||||
|
:key="resource.resourceType"
|
||||||
|
shadow="hover"
|
||||||
|
class="resource-card"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="summary-head">
|
<div class="resource-head">
|
||||||
<span class="summary-title">容量状态</span>
|
<div class="resource-title-wrap">
|
||||||
<el-tag :type="capacityStressType" size="small" effect="plain">
|
<span class="resource-title">{{ resource.resourceName }}</span>
|
||||||
占用 {{ snapshot.totalCount }} / 容量 {{ snapshot.capacity }}
|
<span class="resource-type">{{ resource.resourceType }}</span>
|
||||||
|
</div>
|
||||||
|
<el-tag :type="capacityStressType(resource)" size="small" effect="plain">
|
||||||
|
占用 {{ resource.totalCount }} / 容量 {{ resource.capacity }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="capacity-bar">
|
<div class="resource-layout">
|
||||||
<el-progress
|
<div class="summary-panel">
|
||||||
:percentage="capacityPercentage"
|
<div class="capacity-bar">
|
||||||
:status="capacityProgressStatus"
|
<el-progress
|
||||||
:stroke-width="12"
|
:percentage="capacityPercentage(resource)"
|
||||||
striped
|
:status="capacityProgressStatus(resource)"
|
||||||
striped-flow
|
:stroke-width="12"
|
||||||
/>
|
striped
|
||||||
</div>
|
striped-flow
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-block">
|
<div class="stat-block">
|
||||||
<span class="stat-k">已绑定</span>
|
<span class="stat-k">已绑定</span>
|
||||||
<span class="stat-v">{{ snapshot.boundCount }}</span>
|
<span class="stat-v">{{ resource.boundCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-block">
|
||||||
|
<span class="stat-k">在途预占</span>
|
||||||
|
<span class="stat-v">{{ resource.reservedCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-block">
|
||||||
|
<span class="stat-k">总占用</span>
|
||||||
|
<span class="stat-v">{{ resource.totalCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-block">
|
||||||
|
<span class="stat-k">剩余容量</span>
|
||||||
|
<span class="stat-v">{{ resource.remainingCapacity }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-block">
|
|
||||||
<span class="stat-k">在途预占</span>
|
<div class="chains-panel">
|
||||||
<span class="stat-v">{{ snapshot.reservedCount }}</span>
|
<div class="chains-head">
|
||||||
</div>
|
<span class="chains-title">预占任务链</span>
|
||||||
<div class="stat-block">
|
<span v-if="resource.reservedChainCodes?.length" class="chains-n">
|
||||||
<span class="stat-k">总占用</span>
|
{{ resource.reservedChainCodes.length }} 条
|
||||||
<span class="stat-v">{{ snapshot.totalCount }}</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-block">
|
|
||||||
<span class="stat-k">剩余容量</span>
|
<div v-if="resource.reservedChainCodes?.length" class="chains-scroll">
|
||||||
<span class="stat-v">{{ snapshot.remainingCapacity }}</span>
|
<button
|
||||||
|
v-for="c in resource.reservedChainCodes"
|
||||||
|
:key="`${resource.resourceType}-${c}`"
|
||||||
|
type="button"
|
||||||
|
class="chain-row"
|
||||||
|
@click="goChainDetail(c)"
|
||||||
|
>
|
||||||
|
<span class="chain-row__code">{{ c }}</span>
|
||||||
|
<span class="chain-row__sep" aria-hidden="true">:</span>
|
||||||
|
<span class="chain-row__containers">{{ chainContainersText(c) }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="chains-empty">无</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="hover" class="chains-card">
|
|
||||||
<template #header>
|
|
||||||
<div class="chains-head">
|
|
||||||
<span class="chains-title">预占任务链</span>
|
|
||||||
<span v-if="snapshot.reservedChainCodes?.length" class="chains-n">
|
|
||||||
{{ snapshot.reservedChainCodes.length }} 条
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-if="snapshot.reservedChainCodes?.length" class="chains-scroll">
|
|
||||||
<button
|
|
||||||
v-for="c in snapshot.reservedChainCodes"
|
|
||||||
:key="c"
|
|
||||||
type="button"
|
|
||||||
class="chain-row"
|
|
||||||
@click="goChainDetail(c)"
|
|
||||||
>
|
|
||||||
<span class="chain-row__code">{{ c }}</span>
|
|
||||||
<span class="chain-row__sep" aria-hidden="true">:</span>
|
|
||||||
<span class="chain-row__containers">{{ chainContainersText(c) }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div v-else class="chains-empty">无</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineOptions({ name: 'PalletCacheStationView' })
|
defineOptions({ name: 'ExtensionResourceView' })
|
||||||
import {
|
import {
|
||||||
getPalletCacheStationSnapshot,
|
getExtensionResourceSnapshots,
|
||||||
type PalletCacheStationVO,
|
type ExtensionResourceSnapshotVO,
|
||||||
} from '@/api/palletCacheStation'
|
} from '@/api/extensionResource'
|
||||||
import { getChainDetail, type TaskChainDetailVO } from '@/api/task'
|
import { getChainDetail, type TaskChainDetailVO } from '@/api/task'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const warehouse = ref('WH01')
|
const warehouse = ref('WH01')
|
||||||
const snapshot = ref<PalletCacheStationVO | null>(null)
|
const snapshots = ref<ExtensionResourceSnapshotVO[]>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
/** 任务链号 -> 容器串(冒号拼接);载入中 / 失败为占位标记 */
|
/** 任务链号 -> 容器串(冒号拼接);载入中 / 失败为占位标记 */
|
||||||
const chainContainersLabel = ref<Record<string, string>>({})
|
const chainContainersLabel = ref<Record<string, string>>({})
|
||||||
|
|
||||||
const capacityPercentage = computed(() => {
|
function capacityPercentage(resource: ExtensionResourceSnapshotVO): number {
|
||||||
const s = snapshot.value
|
if (resource.capacity <= 0) return 0
|
||||||
if (!s || s.capacity <= 0) return 0
|
return Math.min(100, Math.round((resource.totalCount / resource.capacity) * 100))
|
||||||
return Math.min(100, Math.round((s.totalCount / s.capacity) * 100))
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const capacityStressType = computed<'success' | 'warning' | 'danger' | 'info'>(() => {
|
function capacityStressType(resource: ExtensionResourceSnapshotVO): 'success' | 'warning' | 'danger' | 'info' {
|
||||||
const s = snapshot.value
|
if (resource.capacity <= 0) return resource.totalCount ? 'danger' : 'info'
|
||||||
if (!s || s.capacity <= 0) return s?.totalCount ? 'danger' : 'info'
|
if (resource.totalCount >= resource.capacity) return 'danger'
|
||||||
if (s.totalCount >= s.capacity) return 'danger'
|
if (resource.totalCount / resource.capacity >= 0.8) return 'warning'
|
||||||
if (s.totalCount / s.capacity >= 0.8) return 'warning'
|
|
||||||
return 'success'
|
return 'success'
|
||||||
})
|
}
|
||||||
|
|
||||||
const capacityProgressStatus = computed<'success' | 'warning' | 'exception' | undefined>(() => {
|
function capacityProgressStatus(resource: ExtensionResourceSnapshotVO): 'success' | 'warning' | 'exception' | undefined {
|
||||||
if (capacityStressType.value === 'danger') return 'exception'
|
const type = capacityStressType(resource)
|
||||||
if (capacityStressType.value === 'warning') return 'warning'
|
if (type === 'danger') return 'exception'
|
||||||
if (capacityStressType.value === 'success') return 'success'
|
if (type === 'warning') return 'warning'
|
||||||
|
if (type === 'success') return 'success'
|
||||||
return undefined
|
return undefined
|
||||||
})
|
}
|
||||||
|
|
||||||
function collectContainersFromDetail(d: TaskChainDetailVO): string[] {
|
function collectContainersFromDetail(d: TaskChainDetailVO): string[] {
|
||||||
const out: string[] = []
|
const out: string[] = []
|
||||||
|
|
@ -172,10 +181,10 @@ async function loadData() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
chainContainersLabel.value = {}
|
chainContainersLabel.value = {}
|
||||||
try {
|
try {
|
||||||
const res = await getPalletCacheStationSnapshot(wh)
|
const res = await getExtensionResourceSnapshots(wh)
|
||||||
snapshot.value = res.data || null
|
snapshots.value = res.data || []
|
||||||
const codes = [
|
const codes = [
|
||||||
...new Set((snapshot.value?.reservedChainCodes ?? []).filter((c) => !!c?.trim())),
|
...new Set(snapshots.value.flatMap((s) => s.reservedChainCodes ?? []).filter((c) => !!c?.trim())),
|
||||||
]
|
]
|
||||||
for (const c of codes) {
|
for (const c of codes) {
|
||||||
chainContainersLabel.value[c] = '__loading__'
|
chainContainersLabel.value[c] = '__loading__'
|
||||||
|
|
@ -192,7 +201,7 @@ async function loadData() {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
snapshot.value = null
|
snapshots.value = []
|
||||||
chainContainersLabel.value = {}
|
chainContainersLabel.value = {}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
|
@ -283,24 +292,22 @@ onMounted(loadData)
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cache-layout {
|
.resource-list {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: minmax(280px, 420px) minmax(0, 1fr);
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-card :deep(.el-card__header),
|
.resource-card :deep(.el-card__header) {
|
||||||
.chains-card :deep(.el-card__header) {
|
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-card :deep(.el-card__body),
|
.resource-card :deep(.el-card__body) {
|
||||||
.chains-card :deep(.el-card__body) {
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-head,
|
.resource-head,
|
||||||
.chains-head {
|
.chains-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
@ -309,13 +316,36 @@ onMounted(loadData)
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-title,
|
.resource-title-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-title,
|
||||||
.chains-title {
|
.chains-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--el-text-color-primary);
|
color: var(--el-text-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-type {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(280px, 420px) minmax(0, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-panel,
|
||||||
|
.chains-panel {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.capacity-bar {
|
.capacity-bar {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
@ -415,7 +445,7 @@ onMounted(loadData)
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,7 +469,7 @@ onMounted(loadData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.cache-layout {
|
.resource-layout {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -647,6 +647,7 @@ const callbackSubmitting = ref(false)
|
||||||
const selectedScenarioKey = ref('')
|
const selectedScenarioKey = ref('')
|
||||||
const currentScenarios = ref<CallbackScenario[]>([])
|
const currentScenarios = ref<CallbackScenario[]>([])
|
||||||
const activeScenario = ref<CallbackScenario | null>(null)
|
const activeScenario = ref<CallbackScenario | null>(null)
|
||||||
|
const activeCallbackTask = ref<TaskVO | null>(null)
|
||||||
const callbackForm = ref<Record<string, unknown>>({})
|
const callbackForm = ref<Record<string, unknown>>({})
|
||||||
|
|
||||||
function canMockCallback(task: TaskVO): boolean {
|
function canMockCallback(task: TaskVO): boolean {
|
||||||
|
|
@ -658,10 +659,11 @@ function canMockCallback(task: TaskVO): boolean {
|
||||||
function openMockCallback(task: TaskVO) {
|
function openMockCallback(task: TaskVO) {
|
||||||
const scenarios = callbackScenarioMap[task.type]
|
const scenarios = callbackScenarioMap[task.type]
|
||||||
if (!scenarios?.length) return
|
if (!scenarios?.length) return
|
||||||
|
activeCallbackTask.value = task
|
||||||
currentScenarios.value = scenarios
|
currentScenarios.value = scenarios
|
||||||
if (scenarios.length === 1) {
|
if (scenarios.length === 1) {
|
||||||
activeScenario.value = scenarios[0]
|
activeScenario.value = scenarios[0]
|
||||||
callbackForm.value = {}
|
callbackForm.value = buildDefaultCallbackForm(task)
|
||||||
callbackDialogVisible.value = true
|
callbackDialogVisible.value = true
|
||||||
} else {
|
} else {
|
||||||
selectedScenarioKey.value = ''
|
selectedScenarioKey.value = ''
|
||||||
|
|
@ -671,13 +673,36 @@ function openMockCallback(task: TaskVO) {
|
||||||
|
|
||||||
function confirmScenario() {
|
function confirmScenario() {
|
||||||
const scenario = currentScenarios.value.find(s => s.key === selectedScenarioKey.value)
|
const scenario = currentScenarios.value.find(s => s.key === selectedScenarioKey.value)
|
||||||
if (!scenario) return
|
const task = activeCallbackTask.value
|
||||||
|
if (!scenario || !task) return
|
||||||
scenarioDialogVisible.value = false
|
scenarioDialogVisible.value = false
|
||||||
activeScenario.value = scenario
|
activeScenario.value = scenario
|
||||||
callbackForm.value = {}
|
callbackForm.value = buildDefaultCallbackForm(task)
|
||||||
callbackDialogVisible.value = true
|
callbackDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDefaultCallbackForm(task: TaskVO): Record<string, unknown> {
|
||||||
|
const callCode = task.machineCallCode || task.chainCode || chain.value?.code || ''
|
||||||
|
const palletCode = task.sourceContainer || chain.value?.sourceContainer || ''
|
||||||
|
const form: Record<string, unknown> = {
|
||||||
|
robotTaskCode: callCode,
|
||||||
|
singleRobotCode: 'MOCK_ROBOT',
|
||||||
|
currentSeq: String(task.batchNo ?? ''),
|
||||||
|
taskCode: callCode,
|
||||||
|
palletCode,
|
||||||
|
status: 'FINISHED',
|
||||||
|
hasPick: false,
|
||||||
|
start: task.sourcePoint || chain.value?.sourcePoint || '',
|
||||||
|
end: task.targetPoint || chain.value?.targetPoint || '',
|
||||||
|
actualStart: task.sourcePoint || chain.value?.sourcePoint || '',
|
||||||
|
actualEnd: task.targetPoint || chain.value?.targetPoint || '',
|
||||||
|
}
|
||||||
|
if (task.type === 'ZS_PRE_PICK_UP') form.taskStep = 'VEHICLE_WILL_PICK'
|
||||||
|
if (task.type === 'ZS_PICK_UP') form.hasPick = true
|
||||||
|
if (task.type === 'ZS_OUTBOUND_IN_LIFTER') form.taskStep = 'IN_LIFTER'
|
||||||
|
return form
|
||||||
|
}
|
||||||
|
|
||||||
async function submitMockCallback() {
|
async function submitMockCallback() {
|
||||||
if (!activeScenario.value) return
|
if (!activeScenario.value) return
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"root":["./src/main.ts","./src/api/auth.ts","./src/api/docs.ts","./src/api/elevator.ts","./src/api/generate.ts","./src/api/palletcachestation.ts","./src/api/stationqueue.ts","./src/api/task.ts","./src/api/vendorload.ts","./src/composables/usedevice.ts","./src/constants/chainstatus.ts","./src/constants/taskstatus.ts","./src/router/index.ts","./src/stores/tabs.ts","./src/stores/user.ts","./src/utils/request.ts","./src/app.vue","./src/layouts/adminlayout.vue","./src/views/dashboard/dashboardview.vue","./src/views/docs/exceptiondocsview.vue","./src/views/elevator/elevatorlist.vue","./src/views/generate/taskgenerateview.vue","./src/views/login/loginview.vue","./src/views/station/palletcachestationview.vue","./src/views/station/stationqueueview.vue","./src/views/task/taskchaindetail.vue","./src/views/task/taskchainlist.vue","./src/views/vendor/vendorloadview.vue","./env.d.ts"],"version":"5.7.3"}
|
{"root":["./src/main.ts","./src/api/auth.ts","./src/api/docs.ts","./src/api/elevator.ts","./src/api/extensionresource.ts","./src/api/generate.ts","./src/api/stationqueue.ts","./src/api/task.ts","./src/api/vendorload.ts","./src/composables/usedevice.ts","./src/constants/chainstatus.ts","./src/constants/taskstatus.ts","./src/router/index.ts","./src/stores/tabs.ts","./src/stores/user.ts","./src/utils/request.ts","./src/app.vue","./src/layouts/adminlayout.vue","./src/views/dashboard/dashboardview.vue","./src/views/docs/exceptiondocsview.vue","./src/views/elevator/elevatorlist.vue","./src/views/generate/taskgenerateview.vue","./src/views/login/loginview.vue","./src/views/resource/extensionresourceview.vue","./src/views/station/stationqueueview.vue","./src/views/task/taskchaindetail.vue","./src/views/task/taskchainlist.vue","./src/views/vendor/vendorloadview.vue","./env.d.ts"],"version":"5.7.3"}
|
||||||
Loading…
Reference in New Issue