优化
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
| AppID、平台图标与打包资源 | `src/manifest.json`、`static/app-icons/` | Android/iOS 尺寸映射由 `tests/app-icons.test.mjs` 锁定;独立 AppID、签名和发布通道不得复用国内 PDA |
|
||||
| 登录、刷新与会话 | `src/pages/login/login.vue`、`src/api/auth.js`、`src/stores/session.js` | 国内 Auth 签发 Token;API 根见 `src/config/runtime.js` |
|
||||
| 海外仓工作台与模块入口 | `src/pages/home/home.vue`、`src/pages/module/module.vue` | `src/data/overseas-workbench.js` 是模块与作业可用性入口;首页通过 `/api/pda/v1/last-leg/receiving-containers/warehouse-profile` 读取 Token 绑定仓的中文主档名称 |
|
||||
| 中英西多语言 | `src/i18n/index.js`、`src/i18n/locales/`、`src/pages/profile/profile.vue` | 语言仅允许 `zh-CN`、`en`、`es`,首次跟随设备且本地持久化;业务配置使用稳定 key,不以翻译后的名称驱动流程 |
|
||||
| 中英西多语言预留 | `src/i18n/index.js`、`src/i18n/locales/` | 当前只保留 `zh-CN`、`en`、`es` 初始化、空资源目录和本地语言状态能力;业务文案仍统一使用中文,需求稳定前不迁移页面、不开放语言切换入口 |
|
||||
| 柜号签收、照片与入仓真实作业 | `src/pages/operation/operation.vue`、`src/api/inbound.js`、`src/api/receiving-adapter.js`、`src/api/overseas.js`、`src/stores/receiving.js` | 三个固定照片角色各一张,支持拍照/相册、鉴权预览及更换失败保留原图;Backend `lastleg-service/inboundplan/pda/controller/ReceivingContainerController.java`、`ReceivingContainerService.java`,公网前缀 `/api/pda/v1/last-leg/receiving-containers/**` |
|
||||
| 库内、托盘、换标与现场查询待接前端 | `src/data/overseas-workbench.js` 中对应 `available: false` 入口 | Backend 已有 `pda/stocktake/`、`pda/move/`、`pda/warehouse/`、`palletops/`、`relabel/pda/` 与 `overseas-pda-operations-v1.yaml`;本应用新增专用 API/状态恢复和测试前不得启用 |
|
||||
| 扫码设备与诊断 | `src/utils/scan-broadcast.js`、`src/pages/scanner-test/scanner-test.vue` | `src/components/ScanTargetInput.vue`、声音反馈工具;广播 Action/Extra 见本文件服务边界 |
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<text class="receiving-summary-status">{{ statusLabel }}</text>
|
||||
</view>
|
||||
<view class="receiving-summary-context">
|
||||
<text>收货仓:{{ session?.overseasWarehouseName || '—' }}</text>
|
||||
<text>目的仓:{{ destinationSummary }}</text>
|
||||
<text class="receiving-summary-warehouse">收货仓:{{ session?.overseasWarehouseName || '—' }}</text>
|
||||
<view class="receiving-summary-destinations"><text class="destination-label">目的仓:</text><view class="destination-tags"><text v-for="value in destinationValues" :key="value">{{ value }}</text></view></view>
|
||||
</view>
|
||||
<view class="receiving-summary-metrics">
|
||||
<view><text class="metric-value">{{ inboundCodeCount }}</text><text class="metric-label">入仓码</text></view>
|
||||
@@ -24,7 +24,7 @@
|
||||
computed: {
|
||||
inboundCodeCount() { return Array.isArray(this.session?.inbounds) ? this.session.inbounds.length : 0 },
|
||||
plannedPalletCount() { return (this.session?.inbounds || []).reduce((sum, item) => sum + Math.max(0, Number(item?.plannedPalletCount || 0)), 0) },
|
||||
destinationSummary() { const values = (this.session?.inbounds || []).map((item) => item?.fbaWarehouseCode || item?.destinationWarehouseName || item?.destinationWarehouseCode).filter(Boolean); return [...new Set(values)].join(' / ') || '—' },
|
||||
destinationValues() { const values = (this.session?.inbounds || []).map((item) => item?.fbaWarehouseCode || item?.destinationWarehouseName || item?.destinationWarehouseCode).filter(Boolean); const unique = [...new Set(values)]; return unique.length ? unique : ['—'] },
|
||||
totalPackages() { return Math.max(0, Number(this.session?.totalPackages || 0)) },
|
||||
receivedPackages() { return Math.max(0, Number(this.session?.receivedPackages || 0)) },
|
||||
pendingPackages() { return Math.max(0, Number(this.session?.pendingPackages ?? this.totalPackages - this.receivedPackages)) },
|
||||
@@ -39,7 +39,7 @@
|
||||
.receiving-summary-head,.receiving-summary-progress>view:first-child{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
||||
.receiving-summary-label,.receiving-summary-container,.metric-value,.metric-label{display:block}.receiving-summary-label{color:#718095;font-size:9px;line-height:13px}.receiving-summary-container{margin-top:1px;color:#17324d;font-size:17px;font-weight:850;line-height:22px}
|
||||
.receiving-summary-status{flex-shrink:0;padding:4px 8px;border-radius:99px;color:#1668dc;font-size:9px;font-weight:700;background:#e3efff}
|
||||
.receiving-summary-context{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);gap:8px;margin-top:7px;color:#617389;font-size:9px;line-height:14px}.receiving-summary-context text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.receiving-summary-context{display:flex;flex-direction:column;gap:4px;margin-top:7px;color:#617389;font-size:9px;line-height:14px}.receiving-summary-warehouse{display:block}.receiving-summary-destinations{display:flex;min-width:0;align-items:flex-start}.destination-label{flex-shrink:0}.destination-tags{display:flex;min-width:0;flex-wrap:wrap;gap:3px 4px}.destination-tags text{padding:0 5px;border-radius:99px;color:#42617f;line-height:14px;background:#e8f0fa;white-space:nowrap}
|
||||
.receiving-summary-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:7px;padding:7px 2px;border-radius:9px;background:rgba(255,255,255,.8)}.receiving-summary-metrics>view{display:flex;align-items:center;flex-direction:column;border-right:1px solid #e3eaf2}.receiving-summary-metrics>view:last-child{border-right:0}
|
||||
.metric-value{color:#17324d;font-size:17px;font-weight:850;line-height:21px}.metric-pending{color:#b66a08}.metric-label{margin-top:1px;color:#718095;font-size:8px;line-height:12px;text-align:center}
|
||||
.receiving-summary-progress{margin-top:7px;color:#607287;font-size:9px}.progress-track{height:5px;margin-top:5px;overflow:hidden;border-radius:99px;background:#dfe8f2}.progress-fill{height:100%;border-radius:inherit;background:#1677e8}
|
||||
|
||||
@@ -38,7 +38,7 @@ test('login has no committed demo credentials and inbound operation implements t
|
||||
read('../src/pages/login/login.vue'), read('../src/config/runtime.js'),
|
||||
read('../src/pages/operation/operation.vue'), read('../src/api/inbound.js'), read('../src/api/receiving-adapter.js'), read('../src/api/overseas.js')
|
||||
])
|
||||
assert.match(login, /\$t\('app\.title'\)/)
|
||||
assert.match(login, /柏悦物流海外版/)
|
||||
assert.doesNotMatch(login, /ChangeMe|platform_admin/)
|
||||
assert.match(login, /DEV_LOGIN\.username|DEV_LOGIN\.password/)
|
||||
assert.match(runtime, /runtimeEnvironment\.DEV|VITE_PDA_DEV_USERNAME|VITE_PDA_DEV_PASSWORD/)
|
||||
@@ -66,9 +66,9 @@ test('unimplemented warehouse operations cannot submit prototype scans', async (
|
||||
read('../src/pages/operation/operation.vue'), read('../src/pages/home/home.vue'), read('../src/pages/module/module.vue')
|
||||
])
|
||||
assert.doesNotMatch(operation, /prototypeScan|prototypeInput/)
|
||||
assert.match(operation, /operation\.unavailableTitle|operation\.unavailableDescription/)
|
||||
assert.match(home, /common\.unavailable/)
|
||||
assert.match(module, /module\.onlyReceiving/)
|
||||
assert.match(operation, /功能暂未开放|扫码不会提交/)
|
||||
assert.match(home, /暂未开放/)
|
||||
assert.match(module, /当前仅开放拆柜收货,其他作业暂未开放/)
|
||||
})
|
||||
|
||||
test('receiving phases use a compiled container summary with cabinet and aggregate facts', async () => {
|
||||
@@ -78,20 +78,22 @@ test('receiving phases use a compiled container summary with cabinet and aggrega
|
||||
assert.match(operation, /import ReceivingSessionSummary/)
|
||||
assert.equal((operation.match(/<ReceivingSessionSummary/g) || []).length, 3)
|
||||
assert.doesNotMatch(operation, /const SessionSummary|template:\s*`<view class="container-card summary-card/)
|
||||
for (const fact of ['containerNo', 'inboundCodeCount', 'plannedPalletCount', 'destinationSummary', 'totalPackages', 'receivedPackages', 'pendingPackages']) assert.match(summary, new RegExp(fact))
|
||||
for (const fact of ['containerNo', 'inboundCodeCount', 'plannedPalletCount', 'destinationValues', 'totalPackages', 'receivedPackages', 'pendingPackages']) assert.match(summary, new RegExp(fact))
|
||||
assert.match(summary, /receiving-summary-metrics/)
|
||||
assert.match(summary, /grid-template-columns:repeat\(4/)
|
||||
assert.match(summary, /padding:10px 12px/)
|
||||
assert.match(summary, /destination-tags\{[^}]*flex-wrap:wrap/)
|
||||
assert.doesNotMatch(summary, /destinationSummary|text-overflow:ellipsis/)
|
||||
})
|
||||
|
||||
test('Chinese English and Spanish locale resources are installed and selectable', async () => {
|
||||
test('Chinese English and Spanish locale scaffolding is installed without exposing unfinished translations', async () => {
|
||||
const [main, i18n, zh, en, es, profile, inbound] = await Promise.all([
|
||||
read('../src/main.js'), read('../src/i18n/index.js'), read('../src/i18n/locales/zh-CN.js'),
|
||||
read('../src/i18n/locales/en.js'), read('../src/i18n/locales/es.js'), read('../src/pages/profile/profile.vue'), read('../src/api/inbound.js')
|
||||
])
|
||||
assert.match(main, /app\.use\(i18n\)/)
|
||||
for (const locale of [zh, en, es]) for (const key of ['operationPhase', 'receivingSummary', 'warehouseOperator']) assert.match(locale, new RegExp(key))
|
||||
for (const locale of [zh, en, es]) assert.match(locale, /export default \{\}/)
|
||||
assert.match(i18n, /SUPPORTED_LOCALES = \['zh-CN', 'en', 'es'\]/)
|
||||
assert.match(profile, /setLocale|LOCALE_OPTIONS/)
|
||||
assert.doesNotMatch(profile, /setLocale|LOCALE_OPTIONS|profile\.language/)
|
||||
assert.match(inbound, /warehouse-profile/)
|
||||
})
|
||||
|
||||
@@ -53,8 +53,8 @@ test('camera replaces only one fixed slot and failed retake preserves its previo
|
||||
assert.match(page, /previous\?\.fileId \? \{ \.\.\.previous, status: 'error'/)
|
||||
assert.match(page, /status: 'uploading'/)
|
||||
assert.match(page, /status: 'error'/)
|
||||
assert.match(page, /photoStateLabel\(photo\)[\s\S]*operation\.retakeFailedKept[\s\S]*operation\.uploadFailed/)
|
||||
assert.match(page, /photoSlots\[index\]\?\.fileId \? \$t\('operation\.retake'\) : \$t\('operation\.takePhoto'\)/)
|
||||
assert.match(page, /photoStateLabel\(photo\)[\s\S]*已保留原图[\s\S]*上传失败/)
|
||||
assert.match(page, /photoSlots\[index\]\?\.fileId \? '重拍' : '拍照'/)
|
||||
assert.match(page, /previewPhoto\(index\)/)
|
||||
assert.match(page, /uploadedPhotoCount\(\) \{ return this\.photoSlots\.filter\(\(item\) => item\?\.fileId\)\.length \}/)
|
||||
assert.match(page, /photosReady\(\) \{ return this\.uploadedPhotoCount === 3 && !this\.photoSlots\.some/)
|
||||
|
||||
Reference in New Issue
Block a user