feat(delivery): 新增插件搬运任务列表面板
- 新增 delivery 的 api/types 与 mock 数据,对接 SimpleLite /projection/deliveries(取消 / 重发 / 强制完成) - 新增 workbench/MissionListPanel 展示搬运任务,支持按完成 / 中止状态过滤 - components.d.ts 自动注册 MissionListPanel
This commit is contained in:
@@ -74,6 +74,7 @@ declare module 'vue' {
|
|||||||
FloatingAlarmCard: typeof import('./src/components/map-monitor/FloatingAlarmCard.vue')['default']
|
FloatingAlarmCard: typeof import('./src/components/map-monitor/FloatingAlarmCard.vue')['default']
|
||||||
FloatingAlarmStack: typeof import('./src/components/map-monitor/FloatingAlarmStack.vue')['default']
|
FloatingAlarmStack: typeof import('./src/components/map-monitor/FloatingAlarmStack.vue')['default']
|
||||||
MapMonitorConfigGroup: typeof import('./src/components/config/MapMonitorConfigGroup.vue')['default']
|
MapMonitorConfigGroup: typeof import('./src/components/config/MapMonitorConfigGroup.vue')['default']
|
||||||
|
MissionListPanel: typeof import('./src/components/workbench/MissionListPanel.vue')['default']
|
||||||
MonitorSelectionPanel: typeof import('./src/components/workbench/MonitorSelectionPanel.vue')['default']
|
MonitorSelectionPanel: typeof import('./src/components/workbench/MonitorSelectionPanel.vue')['default']
|
||||||
PermissionGuard: typeof import('./src/components/PermissionGuard.vue')['default']
|
PermissionGuard: typeof import('./src/components/PermissionGuard.vue')['default']
|
||||||
PluginListPanel: typeof import('./src/components/reflection/PluginListPanel.vue')['default']
|
PluginListPanel: typeof import('./src/components/reflection/PluginListPanel.vue')['default']
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import http from './http'
|
||||||
|
import type { DeliveryTask } from '@/types/delivery'
|
||||||
|
|
||||||
|
const MOCK = import.meta.env.VITE_USE_MOCK === 'true'
|
||||||
|
|
||||||
|
const BASE = '/sl/projection/deliveries'
|
||||||
|
|
||||||
|
export async function listDeliveries(opts?: {
|
||||||
|
includeFinished?: boolean
|
||||||
|
includeAborted?: boolean
|
||||||
|
}): Promise<DeliveryTask[]> {
|
||||||
|
if (MOCK) {
|
||||||
|
const { mockDeliveries } = await import('@/mock/data/deliveries')
|
||||||
|
return mockDeliveries()
|
||||||
|
}
|
||||||
|
const params: Record<string, string> = {}
|
||||||
|
if (opts?.includeFinished === false) params.includeFinished = 'false'
|
||||||
|
if (opts?.includeAborted === false) params.includeAborted = 'false'
|
||||||
|
const { data } = await http.get<DeliveryTask[]>(BASE, { params })
|
||||||
|
return Array.isArray(data) ? data : []
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cancelDelivery(id: number): Promise<void> {
|
||||||
|
if (MOCK) return
|
||||||
|
await http.post(`${BASE}/${id}/cancel`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function resendDelivery(id: number): Promise<void> {
|
||||||
|
if (MOCK) return
|
||||||
|
await http.post(`${BASE}/${id}/resend`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function forceCompleteDelivery(id: number): Promise<void> {
|
||||||
|
if (MOCK) return
|
||||||
|
await http.post(`${BASE}/${id}/force-complete`)
|
||||||
|
}
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mission-list-panel">
|
||||||
|
<div class="toolbar">
|
||||||
|
<el-input
|
||||||
|
v-model="search"
|
||||||
|
size="small"
|
||||||
|
clearable
|
||||||
|
placeholder="搜索任务 ID / 站点 / 车辆"
|
||||||
|
class="search"
|
||||||
|
/>
|
||||||
|
<el-checkbox v-model="showFinished" size="small" @change="emitRefresh">
|
||||||
|
含已完成
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox v-model="showAborted" size="small" @change="emitRefresh">
|
||||||
|
含取消/异常
|
||||||
|
</el-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="filteredRows"
|
||||||
|
size="small"
|
||||||
|
stripe
|
||||||
|
highlight-current-row
|
||||||
|
:row-class-name="rowClassName"
|
||||||
|
height="100%"
|
||||||
|
class="delivery-table"
|
||||||
|
table-layout="fixed"
|
||||||
|
@row-click="onRowClick"
|
||||||
|
@row-contextmenu="onRowContextMenu"
|
||||||
|
>
|
||||||
|
<el-table-column prop="id" label="ID" width="40" align="center" />
|
||||||
|
<el-table-column label="起点" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="cell-ellipsis" :title="row.srcLabel">{{ shortSite(row.srcLabel) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="终点" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="cell-ellipsis" :title="row.dstLabel">{{ shortSite(row.dstLabel) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="状态" width="52" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span
|
||||||
|
class="status-pill"
|
||||||
|
:class="`status-pill--${statusTagType(row.statusCode)}`"
|
||||||
|
:title="row.status"
|
||||||
|
>
|
||||||
|
{{ shortStatus(row.status) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="车辆" width="56" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.carName" class="cell-ellipsis" :title="row.carName">
|
||||||
|
{{ shortCar(row.carName) }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="muted">—</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div v-if="!filteredRows.length" class="empty muted">暂无搬运任务</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-show="ctxVisible"
|
||||||
|
class="ctx-menu"
|
||||||
|
:style="{ left: `${ctxX}px`, top: `${ctxY}px` }"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ctx-item"
|
||||||
|
:disabled="!canCancel(ctxRow)"
|
||||||
|
@click="runAction('cancel')"
|
||||||
|
>
|
||||||
|
取消任务
|
||||||
|
</button>
|
||||||
|
<button type="button" class="ctx-item" @click="runAction('resend')">
|
||||||
|
重发任务
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ctx-item"
|
||||||
|
:disabled="!canForceComplete(ctxRow)"
|
||||||
|
@click="runAction('force-complete')"
|
||||||
|
>
|
||||||
|
强制完成
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import type { DeliveryTask, DeliveryAction } from '@/types/delivery'
|
||||||
|
import {
|
||||||
|
cancelDelivery,
|
||||||
|
forceCompleteDelivery,
|
||||||
|
resendDelivery
|
||||||
|
} from '@/api/delivery'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
deliveries: DeliveryTask[]
|
||||||
|
selectedId?: number | null
|
||||||
|
loading?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
select: [task: DeliveryTask]
|
||||||
|
refresh: [opts: { includeFinished: boolean; includeAborted: boolean }]
|
||||||
|
actionDone: []
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const search = ref('')
|
||||||
|
const showFinished = ref(true)
|
||||||
|
const showAborted = ref(true)
|
||||||
|
|
||||||
|
const ctxVisible = ref(false)
|
||||||
|
const ctxX = ref(0)
|
||||||
|
const ctxY = ref(0)
|
||||||
|
const ctxRow = ref<DeliveryTask | null>(null)
|
||||||
|
|
||||||
|
const filteredRows = computed(() => {
|
||||||
|
const q = search.value.trim().toLowerCase()
|
||||||
|
const tokens = q ? q.split(/\s+/).filter(Boolean) : []
|
||||||
|
return props.deliveries.filter((row) => {
|
||||||
|
if (!tokens.length) return true
|
||||||
|
const hay = [
|
||||||
|
String(row.id),
|
||||||
|
row.srcLabel,
|
||||||
|
row.dstLabel,
|
||||||
|
row.status,
|
||||||
|
row.carName ?? '',
|
||||||
|
row.missionName
|
||||||
|
]
|
||||||
|
.join(' ')
|
||||||
|
.toLowerCase()
|
||||||
|
return tokens.every((t) => hay.includes(t))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
type TagType = 'success' | 'warning' | 'danger' | 'info' | 'primary'
|
||||||
|
|
||||||
|
/** 站点列:优先显示名称段,完整内容靠 tooltip */
|
||||||
|
function shortSite(label: string, maxLen = 9): string {
|
||||||
|
const idx = label.indexOf('-')
|
||||||
|
const name = idx >= 0 ? label.slice(idx + 1) : label
|
||||||
|
if (name.length <= maxLen) return name
|
||||||
|
return `${name.slice(0, maxLen)}…`
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortStatus(status: string): string {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
已下发: '待发',
|
||||||
|
执行中: '执行',
|
||||||
|
已完成: '完成',
|
||||||
|
已取消: '取消',
|
||||||
|
强制结束: '强结',
|
||||||
|
任务异常: '异常'
|
||||||
|
}
|
||||||
|
return map[status] ?? (status.length > 4 ? `${status.slice(0, 3)}…` : status)
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortCar(name: string, maxLen = 6): string {
|
||||||
|
if (name.length <= maxLen) return name
|
||||||
|
return `${name.slice(0, maxLen)}…`
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusTagType(code: string): TagType {
|
||||||
|
switch (code) {
|
||||||
|
case 'Fetching':
|
||||||
|
case 'Putting':
|
||||||
|
return 'success'
|
||||||
|
case 'Waiting':
|
||||||
|
return 'primary'
|
||||||
|
case 'Finished':
|
||||||
|
return 'info'
|
||||||
|
case 'Canceled':
|
||||||
|
case 'Terminated':
|
||||||
|
return 'warning'
|
||||||
|
case 'Error':
|
||||||
|
return 'danger'
|
||||||
|
default:
|
||||||
|
return 'info'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowClassName({ row }: { row: DeliveryTask }) {
|
||||||
|
const classes: string[] = []
|
||||||
|
if (row.id === props.selectedId) classes.push('is-selected-row')
|
||||||
|
if (row.overdue) classes.push('is-overdue-row')
|
||||||
|
return classes.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTerminal(code: string) {
|
||||||
|
return ['Finished', 'Canceled', 'Terminated', 'Error'].includes(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
function canCancel(row: DeliveryTask | null) {
|
||||||
|
return row != null && !isTerminal(row.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
function canForceComplete(row: DeliveryTask | null) {
|
||||||
|
return row != null && !isTerminal(row.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitRefresh() {
|
||||||
|
emit('refresh', {
|
||||||
|
includeFinished: showFinished.value,
|
||||||
|
includeAborted: showAborted.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRowClick(row: DeliveryTask) {
|
||||||
|
hideCtx()
|
||||||
|
emit('select', row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRowContextMenu(row: DeliveryTask, _col: unknown, e: MouseEvent) {
|
||||||
|
e.preventDefault()
|
||||||
|
ctxRow.value = row
|
||||||
|
ctxX.value = e.clientX
|
||||||
|
ctxY.value = e.clientY
|
||||||
|
ctxVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideCtx() {
|
||||||
|
ctxVisible.value = false
|
||||||
|
ctxRow.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionLabels: Record<DeliveryAction, string> = {
|
||||||
|
cancel: '取消任务',
|
||||||
|
resend: '重发任务',
|
||||||
|
'force-complete': '强制完成'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runAction(action: DeliveryAction) {
|
||||||
|
const row = ctxRow.value
|
||||||
|
hideCtx()
|
||||||
|
if (!row) return
|
||||||
|
|
||||||
|
if (action === 'cancel' && !canCancel(row)) return
|
||||||
|
if (action === 'force-complete' && !canForceComplete(row)) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定对任务 #${row.id}(${row.srcLabel} → ${row.dstLabel})执行「${actionLabels[action]}」?`,
|
||||||
|
'确认操作',
|
||||||
|
{ type: 'warning', confirmButtonText: '确定', cancelButtonText: '取消' }
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (action === 'cancel') await cancelDelivery(row.id)
|
||||||
|
else if (action === 'resend') await resendDelivery(row.id)
|
||||||
|
else await forceCompleteDelivery(row.id)
|
||||||
|
ElMessage.success(`${actionLabels[action]} 已提交`)
|
||||||
|
emit('actionDone')
|
||||||
|
} catch (err) {
|
||||||
|
ElMessage.error(`${actionLabels[action]} 失败:${(err as Error).message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDocClick() {
|
||||||
|
hideCtx()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('click', onDocClick))
|
||||||
|
onUnmounted(() => document.removeEventListener('click', onDocClick))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mission-list-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 0;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex: none;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.toolbar .search {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery-table {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mission-list-panel :deep(.delivery-table .el-table__inner-wrapper),
|
||||||
|
.mission-list-panel :deep(.delivery-table .el-table__header-wrapper),
|
||||||
|
.mission-list-panel :deep(.delivery-table .el-table__body-wrapper) {
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.delivery-table table) {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.delivery-table th.el-table__cell),
|
||||||
|
.mission-list-panel :deep(.delivery-table td.el-table__cell) {
|
||||||
|
padding: 3px 2px;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.delivery-table .cell) {
|
||||||
|
padding: 0 2px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.delivery-table th .cell) {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-ellipsis {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-pill {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.status-pill--success { color: var(--mg-status-success); }
|
||||||
|
.status-pill--primary { color: var(--mg-status-info); }
|
||||||
|
.status-pill--warning { color: var(--mg-status-warning); }
|
||||||
|
.status-pill--danger { color: var(--mg-status-danger); }
|
||||||
|
.status-pill--info { color: var(--mg-text-muted); }
|
||||||
|
|
||||||
|
.mission-list-panel :deep(.el-table),
|
||||||
|
.mission-list-panel :deep(.el-table th.el-table__cell),
|
||||||
|
.mission-list-panel :deep(.el-table .cell) {
|
||||||
|
color: var(--mg-text-light);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.el-table tr) {
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell) {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.is-selected-row) td {
|
||||||
|
background: rgba(109, 40, 217, 0.35) !important;
|
||||||
|
}
|
||||||
|
.mission-list-panel :deep(.is-overdue-row) td {
|
||||||
|
color: var(--mg-status-danger) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.muted {
|
||||||
|
color: var(--mg-text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctx-menu {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9000;
|
||||||
|
min-width: 128px;
|
||||||
|
padding: 4px 0;
|
||||||
|
background: #1e1e2e;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
.ctx-item {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ctx-item:hover:not(:disabled) {
|
||||||
|
background: rgba(var(--mg-accent-rgb, 142, 200, 252), 0.2);
|
||||||
|
}
|
||||||
|
.ctx-item:disabled {
|
||||||
|
color: rgba(255, 255, 255, 0.35);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import type { DeliveryTask } from '@/types/delivery'
|
||||||
|
|
||||||
|
export async function mockDeliveries(): Promise<DeliveryTask[]> {
|
||||||
|
await new Promise((r) => setTimeout(r, 60))
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 101,
|
||||||
|
missionId: 1,
|
||||||
|
missionName: '链式搬运',
|
||||||
|
missionTypeName: 'FengTianChainedDeliveryMission',
|
||||||
|
srcSiteId: 1,
|
||||||
|
srcLabel: '1-取货台 A',
|
||||||
|
dstSiteId: 8,
|
||||||
|
dstLabel: '8-放货台 B',
|
||||||
|
status: '执行中',
|
||||||
|
statusCode: 'Fetching',
|
||||||
|
carId: 1,
|
||||||
|
carName: 'AGV-01',
|
||||||
|
priority: 1,
|
||||||
|
createTime: new Date().toISOString(),
|
||||||
|
overdue: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 102,
|
||||||
|
missionId: 1,
|
||||||
|
missionName: '链式搬运',
|
||||||
|
missionTypeName: 'FengTianChainedDeliveryMission',
|
||||||
|
srcSiteId: 3,
|
||||||
|
srcLabel: '3-缓存区',
|
||||||
|
dstSiteId: 12,
|
||||||
|
dstLabel: '12-工位 W2',
|
||||||
|
status: '已下发',
|
||||||
|
statusCode: 'Waiting',
|
||||||
|
carId: null,
|
||||||
|
carName: null,
|
||||||
|
priority: 0,
|
||||||
|
createTime: new Date(Date.now() - 45 * 60_000).toISOString(),
|
||||||
|
overdue: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 99,
|
||||||
|
missionId: 1,
|
||||||
|
missionName: '链式搬运',
|
||||||
|
missionTypeName: 'FengTianChainedDeliveryMission',
|
||||||
|
srcSiteId: 2,
|
||||||
|
srcLabel: '2-原料区',
|
||||||
|
dstSiteId: 5,
|
||||||
|
dstLabel: '5-成品区',
|
||||||
|
status: '已完成',
|
||||||
|
statusCode: 'Finished',
|
||||||
|
carId: 2,
|
||||||
|
carName: 'AGV-02',
|
||||||
|
priority: 1,
|
||||||
|
createTime: new Date(Date.now() - 3600_000).toISOString(),
|
||||||
|
overdue: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/** 插件搬运任务(AbstractChainedDeliveryMission.GetDeliveries)投影行 */
|
||||||
|
export interface DeliveryTask {
|
||||||
|
id: number
|
||||||
|
missionId: number
|
||||||
|
missionName: string
|
||||||
|
missionTypeName: string
|
||||||
|
srcSiteId: number
|
||||||
|
srcLabel: string
|
||||||
|
dstSiteId: number
|
||||||
|
dstLabel: string
|
||||||
|
status: string
|
||||||
|
statusCode: string
|
||||||
|
carId?: number | null
|
||||||
|
carName?: string | null
|
||||||
|
priority: number
|
||||||
|
createTime?: string | null
|
||||||
|
overdue?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeliveryAction = 'cancel' | 'resend' | 'force-complete'
|
||||||
Reference in New Issue
Block a user