Release/test #11

Merged
admin merged 43 commits from release/test into main 2026-09-28 15:59:28 +08:00
4 changed files with 37 additions and 19 deletions
Showing only changes of commit 391369a3d0 - Show all commits
+1 -1
View File
@@ -171,7 +171,7 @@ export const adminNavigation: AdminNavigationNode[] = [
{ key: 'fba-carrier-rates', title: '船期价格表', icon: CircleDollarSign, path: '/first-leg-pricing/carrier-rates', permission: 'firstleg:fba-pricing:rate:view' },
{ key: 'vehicle-list', title: '车辆列表', icon: Truck, path: '/overseas-master-data/vehicles', permission: 'platform:overseas-master-data:vehicle:list' },
{ key: 'download-center', title: '下载中心', icon: Download, path: '/downloads', permission: 'platform:download:list' },
{ key: 'mojia-sku-sync', title: 'SKU同步', icon: Database, path: '/general/mojia-sku-sync', permission: 'platform:mojia-sku-sync:list' },
{ key: 'mojia-sku-sync', title: '称重机器', icon: Database, path: '/general/mojia-sku-sync', permission: 'platform:mojia-sku-sync:list' },
],
},
{
@@ -1,10 +1,14 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
export type MojiaSkuSyncStatus = 'PENDING' | 'SUCCESS' | 'FAILED'
export type MojiaMeasurementKind = 'BOX_LABEL' | 'SKU'
export interface MojiaSkuSyncRecord {
id: string
skuCode: string
measurementKind: MojiaMeasurementKind
boxCode: string
inboundCode?: string | null
skuCode?: string | null
lengthCm: number
widthCm: number
heightCm: number
@@ -13,7 +17,7 @@ export interface MojiaSkuSyncRecord {
imageUrl?: string | null
measuredAt?: string | null
receivedAt?: string | null
syncStatus: MojiaSkuSyncStatus
syncStatus?: MojiaSkuSyncStatus | null
syncFailureCode?: string | null
syncFailureReason?: string | null
lingxingSkuId?: string | null
@@ -32,7 +36,8 @@ export interface MojiaSkuSyncPage {
export interface MojiaSkuSyncQuery {
page: number
size: number
skuCode?: string
code?: string
measurementKind?: MojiaMeasurementKind
syncStatus?: MojiaSkuSyncStatus
}
@@ -11,7 +11,7 @@ import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { getApiErrorMessage } from '@/shared/api/http'
import {
getMojiaSkuSyncConfig, listMojiaSkuSync, retryMojiaSkuSync, submitLingxingVerificationCode, testLingxingConnection, updateMojiaSkuSync,
type LingxingConnectionTestResult, type MojiaSkuSyncRecord, type MojiaSkuSyncStatus,
type LingxingConnectionTestResult, type MojiaSkuSyncRecord, type MojiaSkuSyncStatus, type MojiaMeasurementKind,
} from '../api/mojiaSkuSync'
const permission = {
@@ -37,14 +37,16 @@ const submittingVerification = ref(false)
const pendingVerificationAction = ref<{ type: 'test' } | { type: 'retry', id: string, revision: number } | null>(null)
const page = ref(1)
const size = ref(20)
const form = reactive({ skuCode: '', syncStatus: '' as '' | MojiaSkuSyncStatus })
const form = reactive({ code: '', measurementKind: '' as '' | MojiaMeasurementKind, syncStatus: '' as '' | MojiaSkuSyncStatus })
const editOpen = ref(false)
const editing = ref<MojiaSkuSyncRecord | null>(null)
const editForm = reactive({ skuCode: '', lengthCm: 0, widthCm: 0, heightCm: 0, weightKg: 0, revision: 0 })
const columns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 190, fixed: 'left', slotName: 'actions' },
{ key: 'skuCode', prop: 'skuCode', label: 'SKU', minWidth: 180, showOverflowTooltip: true },
{ key: 'sourceCode', label: '上传标识', minWidth: 180, showOverflowTooltip: true, slotName: 'sourceCode' },
{ key: 'kind', label: '类型', width: 110, slotName: 'kind' },
{ key: 'inboundCode', prop: 'inboundCode', label: '命中入仓码', minWidth: 150, showOverflowTooltip: true },
{ key: 'image', label: '测量图片', width: 110, slotName: 'image' },
{ key: 'dimensions', label: '长 × 宽 × 高(cm)', width: 170, slotName: 'dimensions' },
{ key: 'weightKg', prop: 'weightKg', label: '重量(kg)', width: 110 },
@@ -65,11 +67,11 @@ async function load() {
loading.value = true
error.value = ''
try {
const result = await listMojiaSkuSync({ page: page.value, size: size.value, skuCode: form.skuCode || undefined, syncStatus: form.syncStatus || undefined })
const result = await listMojiaSkuSync({ page: page.value, size: size.value, code: form.code || undefined, measurementKind: form.measurementKind || undefined, syncStatus: form.syncStatus || undefined })
rows.value = result.records
total.value = result.total
} catch (cause) {
error.value = getApiErrorMessage(cause, 'SKU同步记录加载失败')
error.value = getApiErrorMessage(cause, '称重机器上传记录加载失败')
} finally { loading.value = false }
}
@@ -82,14 +84,22 @@ async function loadConfig() {
}
function search() { page.value = 1; void load() }
function reset() { form.skuCode = ''; form.syncStatus = ''; search() }
function reset() { form.code = ''; form.measurementKind = ''; form.syncStatus = ''; search() }
function formatTime(value?: string | null) { return value ? value.replace('T', ' ').slice(0, 19) : '—' }
function asRecord(row: unknown) { return row as MojiaSkuSyncRecord }
function syncLabel(row: unknown) { return statusLabel[asRecord(row).syncStatus] }
function syncTagType(row: unknown) { return statusType[asRecord(row).syncStatus] }
function syncLabel(row: unknown) {
const value = asRecord(row)
if (value.measurementKind === 'BOX_LABEL') return value.inboundCode ? '已命中入仓码' : '未命中'
return value.syncStatus ? statusLabel[value.syncStatus] : '—'
}
function syncTagType(row: unknown) {
const value = asRecord(row)
if (value.measurementKind === 'BOX_LABEL') return value.inboundCode ? 'success' : 'warning'
return value.syncStatus ? statusType[value.syncStatus] : 'info'
}
async function testConnection() {
const skuCode = form.skuCode.trim()
const skuCode = form.code.trim()
if (!skuCode) { ElMessage.warning('请先输入要查询的 SKU'); return }
testingConnection.value = true
try {
@@ -129,7 +139,7 @@ async function submitVerification() {
function openEdit(row: MojiaSkuSyncRecord) {
editing.value = row
Object.assign(editForm, { skuCode: row.skuCode, lengthCm: row.lengthCm, widthCm: row.widthCm, heightCm: row.heightCm, weightKg: row.weightKg, revision: row.revision })
Object.assign(editForm, { skuCode: row.skuCode || '', lengthCm: row.lengthCm, widthCm: row.widthCm, heightCm: row.heightCm, weightKg: row.weightKg, revision: row.revision })
editOpen.value = true
}
@@ -177,7 +187,7 @@ onMounted(() => { void Promise.all([loadConfig(), load()]) })
<template>
<AdminPage class="admin-density mojia-sku-sync-page">
<ListPageLayout aria-label="SKU同步">
<ListPageLayout aria-label="称重机器">
<section class="surface-panel table-panel" :aria-busy="loading">
<el-alert v-if="error" type="error" :title="error" show-icon :closable="false" />
<el-alert
@@ -187,10 +197,11 @@ onMounted(() => { void Promise.all([loadConfig(), load()]) })
show-icon
:closable="false"
/>
<DataTable :data="rows" :columns="columns" :loading="loading" row-key="id" border stripe empty-text="暂无墨家 SKU 测量记录">
<DataTable :data="rows" :columns="columns" :loading="loading" row-key="id" border stripe empty-text="暂无墨家机器上传记录">
<template #toolbar-start>
<div class="sync-filters">
<el-input v-model.trim="form.skuCode" clearable placeholder="搜索 SKU" @keyup.enter="search" />
<el-input v-model.trim="form.code" clearable placeholder="搜索箱码或 SKU" @keyup.enter="search" />
<el-select v-model="form.measurementKind" clearable placeholder="上传类型" style="width: 130px"><el-option label="箱码" value="BOX_LABEL" /><el-option label="SKU" value="SKU" /></el-select>
<el-select v-model="form.syncStatus" clearable placeholder="同步状态" style="width: 140px">
<el-option v-for="(label, value) in statusLabel" :key="value" :label="label" :value="value" />
</el-select>
@@ -203,9 +214,11 @@ onMounted(() => { void Promise.all([loadConfig(), load()]) })
<template #actions="{ row }">
<div class="density-actions">
<el-button v-if="canEdit" class="density-action" @click="openEdit(asRecord(row))"><Edit3 :size="15" />编辑</el-button>
<el-button v-if="canRetry && row.syncStatus !== 'SUCCESS'" class="density-action" data-tone="primary" :loading="actionId === row.id" @click="retry(asRecord(row))"><RotateCw :size="15" />人工推送</el-button>
<el-button v-if="canRetry && row.measurementKind === 'SKU' && row.syncStatus !== 'SUCCESS'" class="density-action" data-tone="primary" :loading="actionId === row.id" @click="retry(asRecord(row))"><RotateCw :size="15" />人工推送</el-button>
</div>
</template>
<template #sourceCode="{ row }">{{ row.measurementKind === 'SKU' ? row.skuCode : row.boxCode }}</template>
<template #kind="{ row }">{{ row.measurementKind === 'SKU' ? 'SKU测量' : '箱码测量' }}</template>
<template #image="{ row }"><el-image v-if="row.imageUrl" :src="row.imageUrl" fit="cover" class="sync-image" preview-teleported /><span v-else>—</span></template>
<template #dimensions="{ row }">{{ row.lengthCm }} × {{ row.widthCm }} × {{ row.heightCm }}</template>
<template #syncStatus="{ row }"><el-tag size="small" :type="syncTagType(row)">{{ syncLabel(row) }}</el-tag></template>
+1 -1
View File
@@ -140,6 +140,6 @@ export const overseasWarehouseRoutes = [
path: 'general/mojia-sku-sync',
name: 'mojia-sku-sync',
component: () => import('./pages/MojiaSkuSyncView.vue'),
meta: { title: 'SKU同步', description: '查看墨家测量数据并同步领星 SKU 尺寸重量', permission: permission.mojiaSkuSyncList },
meta: { title: '称重机器', description: '查看墨家机器上传的箱码和 SKU 测量记录', permission: permission.mojiaSkuSyncList },
},
] satisfies RouteRecordRaw[]