327 lines
9.1 KiB
JavaScript
327 lines
9.1 KiB
JavaScript
// common/scanMixin.js
|
|
// 多厂商PDA扫码器兼容方案 - 策略模式 + 配置表驱动
|
|
import {
|
|
BUILTIN_SCANNER_CONFIGS,
|
|
getScanConfig,
|
|
hasShownNoConfigHint,
|
|
isPdaDevice as detectPdaDevice,
|
|
isPhoneScanConfig,
|
|
markNoConfigHintShown,
|
|
normalizeConfig,
|
|
PHONE_SCAN_CONFIG,
|
|
} from '@/common/scanConfig.js';
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
scanReceivers: [],
|
|
isPageActive: false,
|
|
registeredBrands: [],
|
|
remoteScannerConfigs: [],
|
|
usePhoneScanFallback: false,
|
|
_scanCallback: null,
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
getScannerConfigs() {
|
|
return BUILTIN_SCANNER_CONFIGS;
|
|
},
|
|
|
|
getPhoneScanConfig() {
|
|
return { ...PHONE_SCAN_CONFIG };
|
|
},
|
|
|
|
isPdaDevice() {
|
|
return detectPdaDevice();
|
|
},
|
|
|
|
shouldUsePhoneScan() {
|
|
const builtinConfigs = this.getScannerConfigs();
|
|
const activeConfig = getScanConfig(builtinConfigs);
|
|
if (activeConfig && isPhoneScanConfig(activeConfig)) {
|
|
return true;
|
|
}
|
|
if (!activeConfig && !this.isPdaDevice()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
getAllScannerConfigs() {
|
|
const builtinConfigs = this.getScannerConfigs();
|
|
if (!this.remoteScannerConfigs.length) {
|
|
return builtinConfigs;
|
|
}
|
|
|
|
const configMap = new Map();
|
|
builtinConfigs.forEach((item) => configMap.set(item.brand, item));
|
|
this.remoteScannerConfigs.forEach((item) => configMap.set(item.brand, item));
|
|
if (!configMap.has(PHONE_SCAN_CONFIG.brand)) {
|
|
configMap.set(PHONE_SCAN_CONFIG.brand, { ...PHONE_SCAN_CONFIG });
|
|
}
|
|
return Array.from(configMap.values());
|
|
},
|
|
|
|
getActiveScanConfig() {
|
|
return getScanConfig(this.getScannerConfigs());
|
|
},
|
|
|
|
getDefaultScanConfig() {
|
|
const configs = this.getAllScannerConfigs().filter((item) => !isPhoneScanConfig(item));
|
|
return configs.length ? configs[0] : null;
|
|
},
|
|
|
|
openPhoneScan(options = {}) {
|
|
const callback = options.callback || this._scanCallback;
|
|
// #ifdef APP-PLUS || MP-WEIXIN
|
|
uni.scanCode({
|
|
scanType: options.scanType || ['qrCode', 'barCode'],
|
|
success: (res) => {
|
|
this.handleScanResult(res.result, callback);
|
|
},
|
|
fail: (err) => {
|
|
console.error('手机扫码失败:', err);
|
|
if (options.fail) {
|
|
options.fail(err);
|
|
return;
|
|
}
|
|
uni.showToast({
|
|
title: '扫码失败',
|
|
icon: 'none',
|
|
});
|
|
},
|
|
});
|
|
return;
|
|
// #endif
|
|
|
|
// #ifdef H5
|
|
uni.showToast({
|
|
title: 'H5环境不支持扫码功能',
|
|
icon: 'none',
|
|
});
|
|
// #endif
|
|
},
|
|
|
|
triggerScan() {
|
|
if (this.usePhoneScanFallback) {
|
|
this.openPhoneScan();
|
|
}
|
|
},
|
|
|
|
registerScanBroadcast(scanCallback) {
|
|
this._scanCallback = scanCallback;
|
|
|
|
// #ifndef APP-PLUS
|
|
this.usePhoneScanFallback = true;
|
|
return true;
|
|
// #endif
|
|
|
|
// #ifdef APP-PLUS
|
|
if (this.shouldUsePhoneScan()) {
|
|
this.usePhoneScanFallback = true;
|
|
console.log('使用手机扫码模式');
|
|
return true;
|
|
}
|
|
|
|
this.usePhoneScanFallback = false;
|
|
const activeConfig = this.getActiveScanConfig();
|
|
|
|
if (activeConfig && !isPhoneScanConfig(activeConfig)) {
|
|
return this.registerScanBroadcastByConfig(activeConfig, scanCallback);
|
|
}
|
|
|
|
if (!hasShownNoConfigHint()) {
|
|
markNoConfigHintShown();
|
|
uni.showToast({
|
|
title: '请先在「我的-扫描设置」配置扫码枪',
|
|
icon: 'none',
|
|
duration: 2500,
|
|
});
|
|
}
|
|
|
|
const defaultConfig = this.getDefaultScanConfig();
|
|
if (!defaultConfig) {
|
|
console.error('未找到默认可用的扫码枪配置');
|
|
return false;
|
|
}
|
|
|
|
return this.registerScanBroadcastByConfig(defaultConfig, scanCallback);
|
|
// #endif
|
|
},
|
|
|
|
registerScanBroadcastByBrand(brand, scanCallback) {
|
|
// #ifdef APP-PLUS
|
|
const configs = this.getAllScannerConfigs();
|
|
const config = configs.find(c => c.brand === brand);
|
|
|
|
if (!config) {
|
|
console.error(`未找到厂商配置: ${brand}`);
|
|
return false;
|
|
}
|
|
|
|
if (isPhoneScanConfig(config)) {
|
|
this._scanCallback = scanCallback;
|
|
this.usePhoneScanFallback = true;
|
|
return true;
|
|
}
|
|
|
|
return this.registerScanBroadcastByConfig(config, scanCallback);
|
|
// #endif
|
|
},
|
|
|
|
registerScanBroadcastByConfig(config, scanCallback) {
|
|
// #ifdef APP-PLUS
|
|
const normalizedConfig = normalizeConfig(config, this.getScannerConfigs());
|
|
if (!normalizedConfig) {
|
|
console.error('扫码枪配置无效');
|
|
return false;
|
|
}
|
|
|
|
if (isPhoneScanConfig(normalizedConfig)) {
|
|
this._scanCallback = scanCallback;
|
|
this.usePhoneScanFallback = true;
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
this.registerSingleBroadcast(normalizedConfig, scanCallback);
|
|
this.registeredBrands.push(normalizedConfig.brand);
|
|
this.usePhoneScanFallback = false;
|
|
console.log(`${normalizedConfig.name}扫码广播注册成功`);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`${normalizedConfig.name}扫码广播注册失败:`, error);
|
|
return false;
|
|
}
|
|
// #endif
|
|
},
|
|
|
|
registerSingleBroadcast(config, scanCallback) {
|
|
const main = plus.android.runtimeMainActivity();
|
|
|
|
if (config.needSetup && config.setupAction) {
|
|
try {
|
|
const Intent = plus.android.importClass('android.content.Intent');
|
|
const setupIntent = new Intent(config.setupAction);
|
|
|
|
Object.keys(config.setupParams || {}).forEach(key => {
|
|
setupIntent.putExtra(key, config.setupParams[key]);
|
|
});
|
|
|
|
main.sendBroadcast(setupIntent);
|
|
console.log(`${config.name}扫码配置完成`);
|
|
} catch (error) {
|
|
console.error(`${config.name}扫码配置失败:`, error);
|
|
}
|
|
}
|
|
|
|
const IntentFilter = plus.android.importClass('android.content.IntentFilter');
|
|
const filter = new IntentFilter();
|
|
filter.addAction(config.action);
|
|
|
|
const self = this;
|
|
const receiver = plus.android.implements(
|
|
'io.dcloud.feature.internal.reflect.BroadcastReceiver',
|
|
{
|
|
onReceive: (context, intent) => {
|
|
console.log(`${config.name}扫码广播接收,isPageActive:`, self.isPageActive);
|
|
|
|
if (!self.isPageActive) return;
|
|
|
|
try {
|
|
// 广播回调里的 intent 需要按实例导入,否则 getStringExtra 不可用
|
|
plus.android.importClass(intent);
|
|
const scanResult = intent.getStringExtra(config.dataKey);
|
|
|
|
console.log(`${config.name}扫码结果:`, scanResult);
|
|
|
|
if (scanResult) {
|
|
self.handleScanResult(scanResult, scanCallback);
|
|
}
|
|
} catch (error) {
|
|
console.error(`处理${config.name}广播数据出错:`, error);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
main.registerReceiver(receiver, filter);
|
|
|
|
this.scanReceivers.push({
|
|
brand: config.brand,
|
|
receiver: receiver
|
|
});
|
|
},
|
|
|
|
handleScanResult(scanResult, scanCallback) {
|
|
try {
|
|
let cleanCode = scanResult.replace(/\s+/g, '').replace(/[\r\n]/g, '');
|
|
|
|
console.log("扫码结果:", cleanCode);
|
|
|
|
if (scanCallback) {
|
|
scanCallback(cleanCode);
|
|
}
|
|
} catch (error) {
|
|
console.error("处理扫码结果时出错:", error);
|
|
}
|
|
},
|
|
|
|
unregisterScanBroadcast() {
|
|
// #ifdef APP-PLUS
|
|
if (this.scanReceivers.length === 0) return;
|
|
|
|
try {
|
|
const main = plus.android.runtimeMainActivity();
|
|
|
|
this.scanReceivers.forEach(item => {
|
|
try {
|
|
main.unregisterReceiver(item.receiver);
|
|
console.log(`${item.brand}扫码广播注销成功`);
|
|
} catch (err) {
|
|
console.error(`${item.brand}扫码广播注销失败:`, err);
|
|
}
|
|
});
|
|
|
|
this.scanReceivers = [];
|
|
this.registeredBrands = [];
|
|
console.log('所有扫码广播注销完成');
|
|
} catch (err) {
|
|
console.error('注销扫码广播失败:', err);
|
|
}
|
|
// #endif
|
|
},
|
|
|
|
handleGoodsScan(scanCode, successCallback, errorCallback) {
|
|
const trimmedCode = scanCode ? scanCode.toString().trim() : "";
|
|
|
|
if (!trimmedCode) {
|
|
this.playError && this.playError();
|
|
errorCallback && errorCallback("无效的二维码!");
|
|
return;
|
|
}
|
|
|
|
if (this.processScanCode) {
|
|
this.processScanCode(trimmedCode, successCallback, errorCallback);
|
|
} else {
|
|
successCallback && successCallback(trimmedCode);
|
|
}
|
|
}
|
|
},
|
|
|
|
onShow() {
|
|
this.isPageActive = true;
|
|
console.log('页面显示,设置 isPageActive 为 true');
|
|
},
|
|
|
|
onHide() {
|
|
this.isPageActive = false;
|
|
},
|
|
|
|
onUnload() {
|
|
this.isPageActive = false;
|
|
this.unregisterScanBroadcast();
|
|
}
|
|
}
|