chore: initial commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
export const AUDIO_FEEDBACK_SOURCES = Object.freeze({
|
||||
success: '/static/mp3/success.mp3',
|
||||
error: '/static/mp3/fail.mp3'
|
||||
})
|
||||
|
||||
let audioContext = null
|
||||
|
||||
function getAudioContext() {
|
||||
if (audioContext) return audioContext
|
||||
if (typeof uni === 'undefined' || typeof uni.createInnerAudioContext !== 'function') return null
|
||||
|
||||
audioContext = uni.createInnerAudioContext()
|
||||
audioContext.autoplay = false
|
||||
audioContext.loop = false
|
||||
audioContext.volume = 1
|
||||
return audioContext
|
||||
}
|
||||
|
||||
export function playFeedbackSound(type) {
|
||||
const source = AUDIO_FEEDBACK_SOURCES[type]
|
||||
const player = getAudioContext()
|
||||
if (!source || !player) return false
|
||||
|
||||
try {
|
||||
player.stop()
|
||||
player.src = source
|
||||
player.play()
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function playSuccessSound() {
|
||||
return playFeedbackSound('success')
|
||||
}
|
||||
|
||||
export function playErrorSound() {
|
||||
return playFeedbackSound('error')
|
||||
}
|
||||
|
||||
export function stopFeedbackSound() {
|
||||
if (!audioContext) return
|
||||
try { audioContext.stop() } catch (_) {}
|
||||
}
|
||||
|
||||
export function destroyFeedbackSound() {
|
||||
if (!audioContext) return
|
||||
try { audioContext.destroy() } catch (_) {}
|
||||
audioContext = null
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
const HOME_URL = '/pages/home/home'
|
||||
|
||||
export function getCurrentRoute() {
|
||||
if (typeof getCurrentPages !== 'function') return ''
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
return currentPage ? currentPage.route || '' : ''
|
||||
}
|
||||
|
||||
export function navigateBackOr(fallbackUrl = HOME_URL) {
|
||||
const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : []
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack({ fail: () => uni.reLaunch({ url: fallbackUrl }) })
|
||||
return
|
||||
}
|
||||
uni.reLaunch({ url: fallbackUrl })
|
||||
}
|
||||
|
||||
export function navigateToUnique(url) {
|
||||
const route = url.split('?')[0].replace(/^\//, '')
|
||||
if (getCurrentRoute() === route) return
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
export const ITEM_STATUS = Object.freeze({
|
||||
PENDING: 'pending',
|
||||
PICKED: 'picked',
|
||||
PARTIAL: 'partial',
|
||||
SKIPPED: 'skipped'
|
||||
})
|
||||
|
||||
export function createItemStates(items) {
|
||||
return items.reduce((states, item) => {
|
||||
states[item.id] = ITEM_STATUS.PENDING
|
||||
return states
|
||||
}, {})
|
||||
}
|
||||
|
||||
export function getPickSummary(items, states) {
|
||||
const summary = {
|
||||
total: items.length,
|
||||
picked: 0,
|
||||
partial: 0,
|
||||
skipped: 0,
|
||||
pending: 0
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
const status = states[item.id] || ITEM_STATUS.PENDING
|
||||
summary[status] += 1
|
||||
})
|
||||
|
||||
summary.processed = summary.picked + summary.partial + summary.skipped
|
||||
summary.progress = summary.total
|
||||
? Math.round(summary.processed / summary.total * 100)
|
||||
: 0
|
||||
summary.canSubmit = summary.total > 0 && (
|
||||
summary.pending === 0 || summary.picked > 0 || summary.partial > 0
|
||||
)
|
||||
summary.buttonText = '提交拣货完成'
|
||||
|
||||
return summary
|
||||
}
|
||||
|
||||
export function submitStates(items, states) {
|
||||
const nextStates = { ...states }
|
||||
const autoSkippedIds = []
|
||||
|
||||
items.forEach((item) => {
|
||||
const status = nextStates[item.id] || ITEM_STATUS.PENDING
|
||||
if (status === ITEM_STATUS.PENDING) {
|
||||
nextStates[item.id] = ITEM_STATUS.SKIPPED
|
||||
autoSkippedIds.push(item.id)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
states: nextStates,
|
||||
autoSkippedIds
|
||||
}
|
||||
}
|
||||
|
||||
export function classifyScan(items, states, scanCode) {
|
||||
const item = items.find((entry) => entry.sku === scanCode) || null
|
||||
if (!item) return { type: 'unknown', item: null }
|
||||
|
||||
const status = states[item.id] || ITEM_STATUS.PENDING
|
||||
if (status === ITEM_STATUS.PENDING) return { type: 'pending', item }
|
||||
|
||||
return { type: 'processed', item, status }
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
export const SCAN_BROADCAST_ACTION = 'android.intent.action.SCANRESULT'
|
||||
export const SCAN_BROADCAST_EXTRA = 'value'
|
||||
|
||||
const DUPLICATE_WINDOW_MS = 80
|
||||
|
||||
let receiver = null
|
||||
let activity = null
|
||||
let lastScan = { value: '', receivedAt: 0 }
|
||||
|
||||
export function normalizeScanValue(value) {
|
||||
if (value === null || value === undefined) return ''
|
||||
return String(value).trim()
|
||||
}
|
||||
|
||||
export function isDuplicateScan(value, receivedAt = Date.now()) {
|
||||
const duplicate = value === lastScan.value && receivedAt - lastScan.receivedAt < DUPLICATE_WINDOW_MS
|
||||
if (!duplicate) lastScan = { value, receivedAt }
|
||||
return duplicate
|
||||
}
|
||||
|
||||
export function resetScanDeduplication() {
|
||||
lastScan = { value: '', receivedAt: 0 }
|
||||
}
|
||||
|
||||
export function startScanBroadcast({ onScan, onError } = {}) {
|
||||
if (typeof onScan !== 'function') return () => {}
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
try {
|
||||
if (receiver) stopScanBroadcast()
|
||||
|
||||
activity = plus.android.runtimeMainActivity()
|
||||
const IntentFilter = plus.android.importClass('android.content.IntentFilter')
|
||||
const filter = new IntentFilter()
|
||||
filter.addAction(SCAN_BROADCAST_ACTION)
|
||||
receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
|
||||
onReceive(context, intent) {
|
||||
try {
|
||||
plus.android.importClass(intent)
|
||||
const value = normalizeScanValue(intent.getStringExtra(SCAN_BROADCAST_EXTRA))
|
||||
if (!value || isDuplicateScan(value)) return
|
||||
onScan(value)
|
||||
} catch (error) {
|
||||
if (typeof onError === 'function') onError(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
const Build = plus.android.importClass('android.os.Build')
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
const Context = plus.android.importClass('android.content.Context')
|
||||
activity.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED)
|
||||
} else {
|
||||
activity.registerReceiver(receiver, filter)
|
||||
}
|
||||
} catch (error) {
|
||||
receiver = null
|
||||
activity = null
|
||||
if (typeof onError === 'function') onError(error)
|
||||
}
|
||||
// #endif
|
||||
|
||||
return stopScanBroadcast
|
||||
}
|
||||
|
||||
export function stopScanBroadcast() {
|
||||
// #ifdef APP-PLUS
|
||||
if (activity && receiver) {
|
||||
try {
|
||||
activity.unregisterReceiver(receiver)
|
||||
} catch (_) {}
|
||||
}
|
||||
// #endif
|
||||
receiver = null
|
||||
activity = null
|
||||
resetScanDeduplication()
|
||||
}
|
||||
Reference in New Issue
Block a user