初始化柏悦物流海外版 PDA

This commit is contained in:
2026-08-20 20:10:20 +08:00
commit 02a187377d
377 changed files with 49737 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
import test from 'node:test'
import assert from 'node:assert/strict'
test('shared audio feedback reuses one player and switches success and error sounds', async () => {
const calls = []
const player = {
src: '',
stop() { calls.push('stop') },
play() { calls.push(`play:${this.src}`) },
destroy() { calls.push('destroy') }
}
let created = 0
globalThis.uni = {
createInnerAudioContext() { created += 1; return player }
}
const audio = await import('../src/utils/audio-feedback.js')
assert.equal(audio.playSuccessSound(), true)
assert.equal(audio.playErrorSound(), true)
assert.equal(created, 1)
assert.deepEqual(calls, [
'stop', 'play:/static/mp3/success.mp3',
'stop', 'play:/static/mp3/fail.mp3'
])
audio.destroyFeedbackSound()
assert.equal(calls.at(-1), 'destroy')
delete globalThis.uni
})
test('shared audio feedback is a safe no-op outside uni-app', async () => {
const audio = await import('../src/utils/audio-feedback.js')
assert.equal(audio.playFeedbackSound('unknown'), false)
assert.equal(audio.playSuccessSound(), false)
})
+38
View File
@@ -0,0 +1,38 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { navigateBackOr, navigateToUnique } from '../src/utils/navigation.js'
test('navigateBackOr returns through the stack and falls back when the stack is empty', () => {
const calls = []
globalThis.uni = {
navigateBack: (options) => calls.push(['back', options]),
reLaunch: (options) => calls.push(['reLaunch', options])
}
globalThis.getCurrentPages = () => [{ route: 'pages/home/home' }, { route: 'pages/profile/profile' }]
navigateBackOr('/pages/home/home')
assert.equal(calls[0][0], 'back')
calls.length = 0
globalThis.getCurrentPages = () => [{ route: 'pages/profile/profile' }]
navigateBackOr('/pages/home/home')
assert.deepEqual(calls, [['reLaunch', { url: '/pages/home/home' }]])
calls.length = 0
globalThis.getCurrentPages = () => [{ route: 'pages/home/home' }, { route: 'pages/profile/profile' }]
globalThis.uni.navigateBack = ({ fail }) => fail()
navigateBackOr('/pages/home/home')
assert.deepEqual(calls, [['reLaunch', { url: '/pages/home/home' }]])
})
test('navigateToUnique does not stack the current utility page twice', () => {
const calls = []
globalThis.uni = { navigateTo: (options) => calls.push(options) }
globalThis.getCurrentPages = () => [{ route: 'pages/profile/profile' }]
navigateToUnique('/pages/profile/profile')
assert.deepEqual(calls, [])
navigateToUnique('/pages/history/history')
assert.deepEqual(calls, [{ url: '/pages/history/history' }])
})
+36
View File
@@ -0,0 +1,36 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
test('overseas PDA is an independent Vue 3 app with separate packaging identity', async () => {
const [manifest, pages, pkg] = await Promise.all([
read('../src/manifest.json'), read('../src/pages.json'), read('../package.json')
])
assert.match(manifest, /"name"\s*:\s*"柏悦物流海外版"/)
assert.match(manifest, /"packagename"\s*:\s*"com\.baiyuelogistics\.pda\.overseas"/)
assert.match(manifest, /"vueVersion"\s*:\s*"3"/)
assert.doesNotMatch(pages, /pages\/picking|pages\/tasks/)
assert.match(pkg, /"build:app"\s*:\s*"uni build -p app"/)
})
test('overseas workbench contains only confirmed inbound and in-warehouse domains', async () => {
const [data, session, runtime] = await Promise.all([
read('../src/data/overseas-workbench.js'), read('../src/stores/session.js'), read('../src/config/runtime.js')
])
for (const label of ['入仓作业', '库内作业', '换标作业', '现场查询']) assert.match(data, new RegExp(label))
for (const excluded of ['集装箱拣货', '装柜取证', '海外派送', '出库履约']) assert.doesNotMatch(data, new RegExp(excluded))
assert.match(session, /overseas-pda-auth-session/)
assert.match(runtime, /VITE_OVERSEAS_API_BASE_URL/)
})
test('login has no committed demo credentials and operation page consumes hardware scans', async () => {
const [login, operation] = await Promise.all([
read('../src/pages/login/login.vue'), read('../src/pages/operation/operation.vue')
])
assert.match(login, /柏悦物流海外版/)
assert.doesNotMatch(login, /ChangeMe|platform_admin/)
assert.match(operation, /startScanBroadcast/)
assert.match(operation, /业务接口待接入/)
})
+25
View File
@@ -0,0 +1,25 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import {
SCAN_BROADCAST_ACTION,
SCAN_BROADCAST_EXTRA,
isDuplicateScan,
normalizeScanValue,
resetScanDeduplication
} from '../src/utils/scan-broadcast.js'
test('scanner uses the confirmed PDA broadcast contract', () => {
assert.equal(SCAN_BROADCAST_ACTION, 'android.intent.action.SCANRESULT')
assert.equal(SCAN_BROADCAST_EXTRA, 'value')
assert.equal(normalizeScanValue(' EL-38201\r\n'), 'EL-38201')
assert.equal(normalizeScanValue(null), '')
})
test('scanner drops only immediate duplicate broadcasts', () => {
resetScanDeduplication()
assert.equal(isDuplicateScan('EL-38201', 1000), false)
assert.equal(isDuplicateScan('EL-38201', 1050), true)
assert.equal(isDuplicateScan('EL-38201', 1100), false)
assert.equal(isDuplicateScan('EL-38202', 1110), false)
})