feat(): 改为vite
This commit is contained in:
Generated
+10515
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@r-utils/uni-app",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "uni-app工具库",
|
||||
"type": "module",
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"keywords": [
|
||||
"uni-app"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"watch": "vite build --watch",
|
||||
"lint": "eslint --ext .js,ts --fix src",
|
||||
"release": "standard-version",
|
||||
"commit": "cz",
|
||||
"lint-staged": "lint-staged",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@r-utils/common": "workspace:^",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.0.7",
|
||||
"vue": "^3.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
import { toPromise, showToast } from "@/uni-helper";
|
||||
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const isAndroidApp =
|
||||
systemInfo.uniPlatform === "app" && systemInfo.osName === "android";
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const BluetoothAdapter = plus.android.importClass(
|
||||
"android.bluetooth.BluetoothAdapter",
|
||||
) as Android.BluetoothAdapter;
|
||||
const UUID = plus.android.importClass("java.util.UUID") as Android.UUID;
|
||||
const Context = plus.android.importClass("android.content.Context");
|
||||
const Intent = plus.android.importClass("android.content.Intent");
|
||||
const IntentFilter = plus.android.importClass("android.content.IntentFilter");
|
||||
const InputStream = plus.android.importClass("java.io.InputStream");
|
||||
const OutputStream = plus.android.importClass("java.io.OutputStream");
|
||||
const Activity = plus.android.importClass("android.app.Activity");
|
||||
const BluetoothSocket = plus.android.importClass(
|
||||
"android.bluetooth.BluetoothSocket",
|
||||
);
|
||||
const BluetoothDevice = plus.android.importClass(
|
||||
"android.bluetooth.BluetoothDevice",
|
||||
) as Android.BluetoothDevice;
|
||||
|
||||
const invoke = plus.android.invoke;
|
||||
// #endif
|
||||
|
||||
export interface Device extends UniNamespace.BluetoothDeviceInfo {
|
||||
// 通知服务ID
|
||||
notifyServiceId?: string;
|
||||
// 通知特征值ID
|
||||
notifyCharacterId?: string;
|
||||
// 写入服务ID
|
||||
writeServiceId?: string;
|
||||
// 写入特征值ID
|
||||
writeCharacterId?: string;
|
||||
// 读取服务ID
|
||||
readServiceId?: string;
|
||||
// 读取特征值ID
|
||||
readCharacterId?: string;
|
||||
}
|
||||
|
||||
export class BluetoothError extends Error {
|
||||
constructor(massage?: string) {
|
||||
super(massage);
|
||||
this.name = "BluetoothError";
|
||||
}
|
||||
}
|
||||
|
||||
export class BluetoothUtils {
|
||||
static async safeInit(cb: () => Promise<unknown>) {
|
||||
try {
|
||||
console.log("uni.openBluetoothAdapter");
|
||||
await uni.openBluetoothAdapter();
|
||||
return await cb();
|
||||
} catch (error) {
|
||||
if (error instanceof BluetoothError) {
|
||||
showToast(error.message, "error");
|
||||
} else {
|
||||
showToast("初始化蓝牙失败", "error");
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
console.log("uni.closeBluetoothAdapter");
|
||||
await uni.closeBluetoothAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有设备
|
||||
* @param cb
|
||||
* @param time
|
||||
* @returns
|
||||
*/
|
||||
static async getDevices(cb: (d: Device[]) => void, time: number) {
|
||||
return BluetoothUtils.safeInit(() => BluetoothUtils._getDevices(cb, time));
|
||||
}
|
||||
|
||||
private static async _getDevices(cb: (d: Device[]) => void, time = 3000) {
|
||||
console.log("BluetoothUtils._getDevices()");
|
||||
|
||||
const foundDevices = <Device[]>[];
|
||||
|
||||
let btFindReceiver = null;
|
||||
let activity = null;
|
||||
let btAdapter: Android.BluetoothAdapter = <Android.BluetoothAdapter>{};
|
||||
if (isAndroidApp) {
|
||||
btAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
}
|
||||
try {
|
||||
if (isAndroidApp) {
|
||||
activity = plus.android.runtimeMainActivity() as Android.Activity;
|
||||
console.log({ activity, btAdapter });
|
||||
|
||||
if (btAdapter.isDiscovering()) {
|
||||
btAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
btFindReceiver = plus.android.implements(
|
||||
"io.dcloud.android.content.BroadcastReceiver",
|
||||
{
|
||||
onReceive: function (
|
||||
context: Android.Context,
|
||||
intent: Android.Intent,
|
||||
) {
|
||||
// plus.android.importClass(context);
|
||||
// plus.android.importClass(intent);
|
||||
const action = intent.getAction();
|
||||
|
||||
console.log("onReceive");
|
||||
if (BluetoothDevice.ACTION_FOUND === action) {
|
||||
// 找到设备
|
||||
const device =
|
||||
intent.getParcelableExtra<Android.BluetoothDevice>(
|
||||
BluetoothDevice.EXTRA_DEVICE,
|
||||
);
|
||||
|
||||
const newDevice = {
|
||||
name: device.getName(),
|
||||
deviceId: device.getAddress(),
|
||||
RSSI: -1,
|
||||
advertisData: [],
|
||||
advertisServiceUUIDs: [],
|
||||
localName: "",
|
||||
serviceData: [],
|
||||
};
|
||||
const repetition = foundDevices.some(
|
||||
(v) => v.deviceId === newDevice.deviceId,
|
||||
);
|
||||
console.log({ newDevice });
|
||||
console.log({ repetition });
|
||||
|
||||
if (
|
||||
!repetition &&
|
||||
newDevice.name &&
|
||||
newDevice.name !== "未知设备"
|
||||
) {
|
||||
cb([newDevice]);
|
||||
foundDevices.push(newDevice);
|
||||
}
|
||||
}
|
||||
// if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action) {
|
||||
// // 搜索完成
|
||||
// }
|
||||
},
|
||||
},
|
||||
);
|
||||
const filter = plus.android.newObject(
|
||||
"android.content.IntentFilter",
|
||||
) as Android.IntentFilter;
|
||||
filter.addAction(BluetoothDevice.ACTION_FOUND);
|
||||
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
|
||||
activity.registerReceiver(btFindReceiver, filter);
|
||||
btAdapter.startDiscovery();
|
||||
} else {
|
||||
const bluetoothAdapterState = await uni.getBluetoothAdapterState();
|
||||
console.log(bluetoothAdapterState);
|
||||
|
||||
if (!bluetoothAdapterState.available) {
|
||||
throw new BluetoothError("蓝牙适配器不可用");
|
||||
}
|
||||
|
||||
if (bluetoothAdapterState.discovering) {
|
||||
const res = await uni.stopBluetoothDevicesDiscovery();
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
const sbddRes = await uni.startBluetoothDevicesDiscovery();
|
||||
console.log("startBluetoothDevicesDiscovery", sbddRes);
|
||||
|
||||
// 蓝牙设备监听 plus.bluetooth.onBluetoothDeviceFound
|
||||
uni.onBluetoothDeviceFound((result) => {
|
||||
// console.log("uni.onBluetoothDeviceFound", result);
|
||||
const newDevices = result.devices.filter((v) => {
|
||||
// console.log(foundDevices, v);
|
||||
return (
|
||||
v.name &&
|
||||
v.name !== "未知设备" &&
|
||||
!foundDevices.some((v2) => v2.deviceId === v.deviceId)
|
||||
);
|
||||
});
|
||||
if (newDevices.length > 0) {
|
||||
cb(newDevices);
|
||||
foundDevices.push(...newDevices);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return await new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
if (isAndroidApp) {
|
||||
btAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
console.log({ foundDevices });
|
||||
resolve(foundDevices);
|
||||
}, time);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error instanceof BluetoothError) {
|
||||
showToast(error.message, "error");
|
||||
} else {
|
||||
showToast("获取蓝牙设备失败", "error");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
} finally {
|
||||
if (isAndroidApp) {
|
||||
if (activity) {
|
||||
if (btFindReceiver != null) {
|
||||
activity.unregisterReceiver(btFindReceiver);
|
||||
}
|
||||
activity = null;
|
||||
}
|
||||
} else {
|
||||
await uni.stopBluetoothDevicesDiscovery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定蓝牙设备
|
||||
* @param device
|
||||
* @returns
|
||||
*/
|
||||
static async bindDevice(device: Device, cb: () => Promise<unknown>) {
|
||||
return BluetoothUtils.safeInit(() =>
|
||||
BluetoothUtils._bindDevice(device, cb),
|
||||
);
|
||||
}
|
||||
|
||||
private static async _bindDevice(device: Device, cb: () => Promise<unknown>) {
|
||||
console.log("_bindDevice", device);
|
||||
try {
|
||||
let res = null;
|
||||
if (isAndroidApp) {
|
||||
res = await cb();
|
||||
} else {
|
||||
// 失败重连5次
|
||||
for (var i = 1; i <= 5; i++) {
|
||||
try {
|
||||
await uni.createBLEConnection({
|
||||
deviceId: device.deviceId,
|
||||
});
|
||||
break;
|
||||
} catch (error) {
|
||||
console.log(`蓝牙失败重连${i}次`);
|
||||
if (i == 5) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = await new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
const services = await BluetoothUtils._getServices(device);
|
||||
console.log("services", services);
|
||||
|
||||
await BluetoothUtils._setCharacteristics(device, services);
|
||||
resolve(await cb());
|
||||
// await cb()
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
return res;
|
||||
} catch (error) {
|
||||
showToast("绑定蓝牙设备失败", "error");
|
||||
throw error;
|
||||
} finally {
|
||||
if (!isAndroidApp) {
|
||||
await uni.closeBLEConnection({
|
||||
deviceId: device.deviceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取蓝牙设备所有服务
|
||||
* @param device
|
||||
* @returns
|
||||
*/
|
||||
private static async _getServices(device: Device) {
|
||||
console.log("获取蓝牙设备所有服务");
|
||||
|
||||
// const res = await new Promise<UniNamespace.GetBLEDeviceServicesSuccess>(
|
||||
// (resolve, reject) => {
|
||||
// logger.info("uni.getBLEDeviceServices", device.deviceId);
|
||||
// uni.getBLEDeviceServices({
|
||||
// deviceId: device.deviceId,
|
||||
// success: (res) => {
|
||||
// console.log(res);
|
||||
// logger.info("res: ", res);
|
||||
// resolve(res);
|
||||
// },
|
||||
// fail: (err) => {
|
||||
// console.error(err);
|
||||
// logger.info("err: ", err);
|
||||
// reject(err);
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
const res = await uni.getBLEDeviceServices({
|
||||
deviceId: device.deviceId,
|
||||
});
|
||||
console.log(res);
|
||||
|
||||
return res.services;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置蓝牙设备特征值
|
||||
*/
|
||||
private static async _setCharacteristics(
|
||||
device: Device,
|
||||
services: UniNamespace.GetBLEDeviceServicesSuccessData[],
|
||||
) {
|
||||
console.log("_setCharacteristics", services);
|
||||
|
||||
// 获取蓝牙设备某个服务中所有特征值
|
||||
// plus.bluetooth.getBLEDeviceCharacteristics
|
||||
let notifyServiceId = "";
|
||||
let writeServiceId = "";
|
||||
let readServiceId = "";
|
||||
let notifyCharacterId = "";
|
||||
let writeCharacterId = "";
|
||||
let readCharacterId = "";
|
||||
|
||||
for (const service of services) {
|
||||
// const { notifyServiceId, writeServiceId, readServiceId } = device;
|
||||
const done = [notifyServiceId, writeServiceId, readServiceId].every(
|
||||
(v) => v !== "",
|
||||
);
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(
|
||||
"获取蓝牙设备某个服务中所有特征值/uni.getBLEDeviceCharacteristics",
|
||||
);
|
||||
const res = await uni.getBLEDeviceCharacteristics({
|
||||
deviceId: device.deviceId,
|
||||
serviceId: service.uuid,
|
||||
});
|
||||
console.log(res);
|
||||
for (const characteristic of res.characteristics) {
|
||||
console.log(characteristic);
|
||||
|
||||
// const { notifyCharacterId, writeCharacterId, readCharacterId } = device;
|
||||
const done = [
|
||||
notifyCharacterId,
|
||||
writeCharacterId,
|
||||
readCharacterId,
|
||||
].every((v) => v !== "");
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
const { uuid, properties } = characteristic;
|
||||
if (!notifyCharacterId) {
|
||||
if (properties.notify) {
|
||||
notifyCharacterId = uuid;
|
||||
notifyServiceId = service.uuid;
|
||||
}
|
||||
}
|
||||
if (!writeCharacterId) {
|
||||
if (properties.write) {
|
||||
writeCharacterId = uuid;
|
||||
writeServiceId = service.uuid;
|
||||
}
|
||||
}
|
||||
if (!readCharacterId) {
|
||||
if (properties.read) {
|
||||
readCharacterId = uuid;
|
||||
readServiceId = service.uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device.notifyServiceId = notifyServiceId;
|
||||
device.notifyCharacterId = notifyCharacterId;
|
||||
device.writeServiceId = writeServiceId;
|
||||
device.writeCharacterId = writeCharacterId;
|
||||
device.readServiceId = readServiceId;
|
||||
device.readCharacterId = readCharacterId;
|
||||
console.log(device);
|
||||
}
|
||||
|
||||
static async getBLEMTU(device: Device) {
|
||||
return BluetoothUtils.bindDevice(device, () =>
|
||||
BluetoothUtils._getBLEMTU(device),
|
||||
);
|
||||
}
|
||||
|
||||
private static async _getBLEMTU(device: Device) {
|
||||
console.log("_getBLEMTU", device);
|
||||
// return new Promise<number>(async (resolve, reject) => {
|
||||
return uni.getBLEMTU({
|
||||
deviceId: device.deviceId,
|
||||
// success: (res) => {
|
||||
// resolve(res.mtu);
|
||||
// },
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
static async sendData(device: Device, data: number[]) {
|
||||
if (isAndroidApp) {
|
||||
BluetoothUtils.sendDataAndroid(device, data);
|
||||
} else {
|
||||
const buf = new ArrayBuffer(data.length);
|
||||
const dataView = new DataView(buf);
|
||||
data.forEach((d, i) => {
|
||||
dataView.setUint8(i, d);
|
||||
});
|
||||
|
||||
return await new Promise((resolve, reject) => {
|
||||
uni.writeBLECharacteristicValue({
|
||||
deviceId: device.deviceId ?? "",
|
||||
serviceId: device.writeServiceId ?? "",
|
||||
characteristicId: device.writeCharacterId ?? "",
|
||||
value: buf,
|
||||
success: (res) => {
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static async sendDataAndroid(device: Device, data: number[]) {
|
||||
const btAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
const deviceObj = invoke(btAdapter, "getRemoteDevice", device.deviceId);
|
||||
const PRINTER_UUID = UUID.fromString(
|
||||
"00001101-0000-1000-8000-00805F9B34FB",
|
||||
);
|
||||
const btSocket = invoke(
|
||||
deviceObj,
|
||||
"createRfcommSocketToServiceRecord",
|
||||
PRINTER_UUID,
|
||||
);
|
||||
if (!invoke(btSocket, "isConnected")) {
|
||||
console.log("检测到设备未连接,尝试连接....");
|
||||
invoke(btSocket, "connect");
|
||||
}
|
||||
console.log("设备已连接");
|
||||
|
||||
const outputStream = invoke(btSocket, "getOutputStream");
|
||||
invoke(outputStream, "write", data);
|
||||
invoke(outputStream, "flush");
|
||||
setTimeout(() => {
|
||||
invoke(outputStream, "close");
|
||||
invoke(btSocket, "close");
|
||||
}, 10 * 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./bluetooth-utils";
|
||||
export * from "./nfc";
|
||||
export * from "./printer";
|
||||
export * from "./request";
|
||||
export * from "./uni-helper";
|
||||
export * from "./upload";
|
||||
@@ -0,0 +1,206 @@
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const isAndroid =
|
||||
systemInfo.uniPlatform === "app" && systemInfo.osName === "android";
|
||||
|
||||
let runtimeMainActivity = null;
|
||||
let newObject = null;
|
||||
let getAttribute = null;
|
||||
let setAttribute = null;
|
||||
let importClass = null;
|
||||
let invoke = null;
|
||||
let Intent = null;
|
||||
let Activity = null;
|
||||
let PendingIntent = null;
|
||||
let IntentFilter = null;
|
||||
let NfcAdapter = null;
|
||||
let NdefRecord = null;
|
||||
let NdefMessage = null;
|
||||
let MifareClassic = null;
|
||||
let Ndef = null;
|
||||
let Tag = null;
|
||||
let Parcelable = null;
|
||||
let NfcV = null;
|
||||
|
||||
if (isAndroid) {
|
||||
runtimeMainActivity = plus.android.runtimeMainActivity;
|
||||
newObject = plus.android.newObject;
|
||||
getAttribute = plus.android.getAttribute;
|
||||
setAttribute = plus.android.setAttribute;
|
||||
importClass = plus.android.importClass;
|
||||
invoke = plus.android.invoke;
|
||||
|
||||
Intent = importClass("android.content.Intent");
|
||||
Activity = importClass("android.app.Activity");
|
||||
PendingIntent = importClass("android.app.PendingIntent");
|
||||
IntentFilter = importClass("android.content.IntentFilter");
|
||||
NfcAdapter = importClass("android.nfc.NfcAdapter");
|
||||
NdefRecord = importClass("android.nfc.NdefRecord");
|
||||
NdefMessage = importClass("android.nfc.NdefMessage");
|
||||
MifareClassic = importClass("android.nfc.tech.MifareClassic");
|
||||
Ndef = importClass("android.nfc.tech.Ndef");
|
||||
Tag = importClass("android.nfc.Tag");
|
||||
Parcelable = importClass("android.os.Parcelable");
|
||||
NfcV = importClass("android.nfc.tech.NfcV");
|
||||
}
|
||||
|
||||
export class AndroidNfcUtil {
|
||||
main = null;
|
||||
nfcAdapter = null;
|
||||
pendingIntent = null;
|
||||
intentFiltersArray = null;
|
||||
techListsArray = null;
|
||||
discoveredListenerList = [];
|
||||
/**
|
||||
* @type {Function}
|
||||
*/
|
||||
_discoveredHandler = null;
|
||||
/**
|
||||
* @type {Function}
|
||||
*/
|
||||
_resumeHandler = null;
|
||||
|
||||
constructor() {
|
||||
this.main = runtimeMainActivity();
|
||||
this.nfcAdapter = NfcAdapter.getDefaultAdapter(this.main);
|
||||
this._discoveredHandler = this.discoveredHandler.bind(this);
|
||||
this._resumeHandler = this.resumeHandler.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Function} cb
|
||||
*/
|
||||
addDiscoveredListener(cb) {
|
||||
this.discoveredListenerList.push(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否支持NFC
|
||||
* @returns
|
||||
*/
|
||||
static isNfcSupported() {
|
||||
const main = runtimeMainActivity();
|
||||
const nfcAdapter = NfcAdapter.getDefaultAdapter(main);
|
||||
return nfcAdapter != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否开启NFC
|
||||
* @returns {boolean} true 已开启
|
||||
*/
|
||||
static async isNfcEnabled() {
|
||||
const main = runtimeMainActivity();
|
||||
const nfcAdapter = NfcAdapter.getDefaultAdapter(main);
|
||||
return nfcAdapter && nfcAdapter.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<number[]>}
|
||||
*/
|
||||
async startNfcScan() {
|
||||
console.log("startNfcScan", this.nfcAdapter);
|
||||
|
||||
if (this.nfcAdapter == null) {
|
||||
throw new Error("该设备不支持NFC");
|
||||
} else if (!this.nfcAdapter.isEnabled()) {
|
||||
throw new Error("未开启NFC");
|
||||
} else {
|
||||
return await this.init();
|
||||
}
|
||||
}
|
||||
|
||||
async stopNfcScan() {
|
||||
console.log("stopNfcScan");
|
||||
plus.globalEvent.removeEventListener("newintent", this._discoveredHandler);
|
||||
plus.globalEvent.removeEventListener("resume", this._discoveredHandler);
|
||||
this.nfcAdapter.disableForegroundDispatch(this.main);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化ncf 并开启监听
|
||||
*/
|
||||
async init() {
|
||||
console.log("init");
|
||||
const ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
|
||||
const tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
|
||||
const tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
|
||||
this.intentFiltersArray = [ndef, tag, tech];
|
||||
|
||||
this.techListsArray = [
|
||||
["android.nfc.tech.Ndef"],
|
||||
["android.nfc.tech.IsoDep"],
|
||||
["android.nfc.tech.NfcA"],
|
||||
["android.nfc.tech.NfcB"],
|
||||
["android.nfc.tech.NfcF"],
|
||||
["android.nfc.tech.Nfcf"],
|
||||
["android.nfc.tech.Nfef"],
|
||||
["android.nfc.tech.Ndef"],
|
||||
["android.nfc.tech.NfcV"],
|
||||
["android.nfc.tech.NdefFormatable"],
|
||||
["android.nfc.tech.MifareClassi"],
|
||||
["android.nfc.tech.MifareUltralight"],
|
||||
];
|
||||
const intent = new Intent(this.main, this.main.getClass());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
|
||||
this.pendingIntent = PendingIntent.getActivity(this.main, 0, intent, 0);
|
||||
|
||||
this.nfcAdapter.enableForegroundDispatch(
|
||||
this.main,
|
||||
this.pendingIntent,
|
||||
this.intentFiltersArray,
|
||||
this.techListsArray,
|
||||
);
|
||||
|
||||
plus.globalEvent.addEventListener("newintent", this._discoveredHandler);
|
||||
plus.globalEvent.addEventListener("resume", this._resumeHandler);
|
||||
}
|
||||
|
||||
resumeHandler() {
|
||||
console.log("resumeHandler");
|
||||
this.nfcAdapter.enableForegroundDispatch(
|
||||
this.main,
|
||||
this.pendingIntent,
|
||||
this.intentFiltersArray,
|
||||
this.techListsArray,
|
||||
);
|
||||
}
|
||||
|
||||
discoveredHandler() {
|
||||
console.log("discoveredHandler");
|
||||
this.discoveredListenerList.forEach((cb) => {
|
||||
cb(this.readId());
|
||||
});
|
||||
}
|
||||
|
||||
readId() {
|
||||
console.log("readId");
|
||||
|
||||
const intent = this.main.getIntent();
|
||||
const action = intent.getAction();
|
||||
console.log("action: " + action);
|
||||
|
||||
// if (
|
||||
// NfcAdapter.ACTION_NDEF_DISCOVERED == action ||
|
||||
// NfcAdapter.ACTION_TAG_DISCOVERED == action ||
|
||||
// NfcAdapter.ACTION_TECH_DISCOVERED == action
|
||||
// ) {
|
||||
console.log("intent.getAction()", intent.getAction());
|
||||
const tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
||||
console.log("tagFromIntent.getId", tagFromIntent.getId());
|
||||
return tagFromIntent.getId();
|
||||
// }
|
||||
}
|
||||
|
||||
static async scan() {
|
||||
const androidNfcUtil = new AndroidNfcUtil();
|
||||
return await new Promise(async (resolve, reject) => {
|
||||
await androidNfcUtil.startNfcScan();
|
||||
androidNfcUtil.addDiscoveredListener((res) => {
|
||||
androidNfcUtil.stopNfcScan();
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { AndroidNfcUtil } from "./android";
|
||||
import { WeixinNfcUtil } from "./weixin";
|
||||
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const isAndroidApp =
|
||||
systemInfo.uniPlatform === "app" && systemInfo.osName === "android";
|
||||
const isAndroidWeixin =
|
||||
systemInfo.uniPlatform === "mp-weixin" && systemInfo.osName === "android";
|
||||
|
||||
export async function nfcScan() {
|
||||
if (isAndroidApp) {
|
||||
return await AndroidNfcUtil.scan();
|
||||
} else if (isAndroidWeixin) {
|
||||
return await WeixinNfcUtil.scan();
|
||||
} else {
|
||||
console.warn("不支持当前平台");
|
||||
}
|
||||
}
|
||||
|
||||
export async function isNfcEnabled() {
|
||||
if (isAndroidApp) {
|
||||
return await AndroidNfcUtil.isNfcEnabled();
|
||||
} else if (isAndroidWeixin) {
|
||||
return await WeixinNfcUtil.isNfcEnabled();
|
||||
} else {
|
||||
console.warn("不支持当前平台");
|
||||
}
|
||||
}
|
||||
|
||||
export function getNFCUtil(){
|
||||
if (isAndroidApp) {
|
||||
return new AndroidNfcUtil();
|
||||
} else if (isAndroidWeixin) {
|
||||
return new WeixinNfcUtil();
|
||||
} else {
|
||||
console.warn("不支持当前平台");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
export async function startNfcScan() {
|
||||
const nfcAdapter = wx.getNFCAdapter();
|
||||
await nfcAdapter.startDiscovery();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
nfcAdapter.onDiscovered((res) => {
|
||||
console.log("onDiscovered", res);
|
||||
const arr = Array.from(new Int8Array(res.id));
|
||||
resolve(arr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export class WeixinNfcUtil {
|
||||
nfcAdapter = null;
|
||||
discoveredListenerList = [];
|
||||
/**
|
||||
* @type {Function}
|
||||
*/
|
||||
_discoveredHandler = null;
|
||||
|
||||
constructor() {
|
||||
this.nfcAdapter = wx.getNFCAdapter();
|
||||
this._discoveredHandler = this.discoveredHandler.bind(this);
|
||||
this.nfcAdapter.onDiscovered(this._discoveredHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否开启NFC
|
||||
* NOTE 微信无法判断是否开启
|
||||
* @returns {boolean} true 已开启
|
||||
*/
|
||||
static async isNfcEnabled() {
|
||||
try {
|
||||
wx.getNFCAdapter();
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
discoveredHandler(res) {
|
||||
console.log("onDiscovered", res);
|
||||
const arr = Array.from(new Int8Array(res.id));
|
||||
this.discoveredListenerList.forEach((cb) => {
|
||||
cb(arr);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Function} cb
|
||||
*/
|
||||
addDiscoveredListener(cb) {
|
||||
this.discoveredListenerList.push(cb);
|
||||
}
|
||||
|
||||
async startNfcScan() {
|
||||
return await this.nfcAdapter.startDiscovery();
|
||||
}
|
||||
|
||||
async stopNfcScan() {
|
||||
this.nfcAdapter.offDiscovered(this._discoveredHandler);
|
||||
return await this.nfcAdapter.stopDiscovery();
|
||||
}
|
||||
|
||||
static async scan() {
|
||||
const weixinNfcUtil = new WeixinNfcUtil();
|
||||
return await new Promise(async (resolve, reject) => {
|
||||
await weixinNfcUtil.startNfcScan();
|
||||
weixinNfcUtil.addDiscoveredListener((res) => {
|
||||
weixinNfcUtil.stopNfcScan();
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { BluetoothUtils, Device } from "@/bluetooth-utils";
|
||||
import { wait } from "@r-utils/common";
|
||||
|
||||
|
||||
type DeviceData = Required<Device>;
|
||||
|
||||
export class Printer {
|
||||
device: DeviceData;
|
||||
size = 0;
|
||||
|
||||
constructor(device: DeviceData, { size = 80 } = {}) {
|
||||
this.device = device;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
async print(data: number[]) {
|
||||
console.log(
|
||||
data.length,
|
||||
data.slice(0, 100),
|
||||
data.slice(data.length - 100, data.length)
|
||||
);
|
||||
let res = null;
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
if (systemInfo.uniPlatform === "app" && systemInfo.osName === "android") {
|
||||
res = await BluetoothUtils.sendDataAndroid(this.device, data);
|
||||
} else {
|
||||
res = await BluetoothUtils.bindDevice(this.device, async () => {
|
||||
await wait(100);
|
||||
return await this._print(data);
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async _print(data: number[]):Promise<any> {
|
||||
const size = Math.min(data.length, this.size);
|
||||
if (size === 0) {
|
||||
return;
|
||||
}
|
||||
const buf = new ArrayBuffer(size);
|
||||
const dataView = new DataView(buf);
|
||||
for (let i = 0; i < size; i++) {
|
||||
dataView.setUint8(i, data[i]);
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
uni.writeBLECharacteristicValue({
|
||||
deviceId: this.device.deviceId,
|
||||
serviceId: this.device.writeServiceId,
|
||||
characteristicId: this.device.writeCharacterId,
|
||||
value: buf,
|
||||
success: (res) => {
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
await wait(30);
|
||||
return await this._print(data.slice(size));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
export type DataType = string | AnyObject | ArrayBuffer;
|
||||
|
||||
/** 请求配置 */
|
||||
export interface Config<T extends DataType>
|
||||
extends Partial<UniApp.RequestOptions> {
|
||||
baseURL?: string;
|
||||
data?: T;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 响应 */
|
||||
export interface Response<
|
||||
T extends DataType,
|
||||
D extends DataType,
|
||||
C extends Config<D> = Config<D>
|
||||
> extends UniApp.RequestSuccessCallbackResult {
|
||||
data: T;
|
||||
errMsg?: string;
|
||||
config: C;
|
||||
}
|
||||
|
||||
/** 成功拦截器 */
|
||||
type FulfilledInterceptor<R, T> = (res: R) => T | Promise<T>;
|
||||
/** 失败拦截器 */
|
||||
type RejectedInterceptor = (error: any) => any;
|
||||
/** 拦截器管理 */
|
||||
class InterceptorManager<R> {
|
||||
/** 拦截器列表 */
|
||||
handlers: [FulfilledInterceptor<R, any>?, RejectedInterceptor?][] = [];
|
||||
|
||||
/** 添加拦截器 */
|
||||
add<T = R>(
|
||||
onFulfilled?: FulfilledInterceptor<R, T>,
|
||||
onRejected?: RejectedInterceptor
|
||||
): number {
|
||||
this.handlers.push([onFulfilled, onRejected]);
|
||||
return this.handlers.length - 1;
|
||||
}
|
||||
|
||||
/** 移除拦截器 */
|
||||
remove(id: number) {
|
||||
return this.handlers.splice(id, 1);
|
||||
}
|
||||
|
||||
forEach(
|
||||
fn: (
|
||||
onFulfilled?: FulfilledInterceptor<R, any>,
|
||||
onRejected?: RejectedInterceptor
|
||||
) => void
|
||||
) {
|
||||
this.handlers.forEach(([onFulfilled, onRejected]) => {
|
||||
fn(onFulfilled, onRejected);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求类
|
||||
*/
|
||||
export class Request {
|
||||
/** 请求配置 */
|
||||
config: Config<any>;
|
||||
/** 拦截器 */
|
||||
interceptors: {
|
||||
/** 请求拦截器 */
|
||||
request: InterceptorManager<Config<any>>;
|
||||
/** 响应拦截器 */
|
||||
response: InterceptorManager<any>;
|
||||
};
|
||||
|
||||
constructor(config: Config<any> = { url: "" }) {
|
||||
this.config = config;
|
||||
this.interceptors = {
|
||||
request: new InterceptorManager(),
|
||||
response: new InterceptorManager(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求主方法
|
||||
*/
|
||||
async request<
|
||||
RESPD extends DataType,
|
||||
REQD extends DataType,
|
||||
R = Response<RESPD, REQD>
|
||||
>(config: Config<REQD>): Promise<R> {
|
||||
// 合并方法配置 与 实例配置
|
||||
let newConfig = Object.assign({}, this.config, config);
|
||||
|
||||
// 赋值默认URL
|
||||
newConfig.url = newConfig.url ?? "";
|
||||
// 如果设置了 baseURL 并且 url 不是绝对路径,则拼接 baseURL
|
||||
if (newConfig.baseURL && !/https?\/\//.test(newConfig.url)) {
|
||||
newConfig.url = newConfig.baseURL + newConfig.url;
|
||||
}
|
||||
|
||||
// 执行请求拦截器
|
||||
this.interceptors.request.forEach((onFulfilled, onRejected) => {
|
||||
try {
|
||||
if (onFulfilled) {
|
||||
newConfig = onFulfilled(newConfig);
|
||||
}
|
||||
} catch (error) {
|
||||
if (onRejected) {
|
||||
throw onRejected(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 发送请求
|
||||
// let responsePromise = await new Promise<Response<RESPD>>((resolve, reject) => {
|
||||
// uni.request({
|
||||
// ...newConfig,
|
||||
// success(result) {
|
||||
// resolve(result);
|
||||
// },
|
||||
// fail(result) {
|
||||
// reject(result);
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
let responsePromise = await (<Promise<R>>uni.request({
|
||||
...newConfig,
|
||||
url: newConfig.url,
|
||||
}));
|
||||
|
||||
// 替换新请求的配置
|
||||
responsePromise = {
|
||||
...responsePromise,
|
||||
config: newConfig,
|
||||
};
|
||||
|
||||
// 执行响应拦截器
|
||||
this.interceptors.response.forEach((onFulfilled, onRejected) => {
|
||||
// this.interceptors?.response.handlers.forEach((handler) => {
|
||||
// const [onFulfilled, onRejected] = handler;
|
||||
// responsePromise = responsePromise.then(onFulfilled, onRejected);
|
||||
try {
|
||||
if (typeof onFulfilled !== "undefined") {
|
||||
responsePromise = onFulfilled(responsePromise);
|
||||
}
|
||||
} catch (error) {
|
||||
if (typeof onRejected !== "undefined") {
|
||||
onRejected(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return responsePromise;
|
||||
}
|
||||
|
||||
/** GET 请求 */
|
||||
get<RESPD extends DataType, REQD extends DataType, R = Response<RESPD, REQD>>(
|
||||
url: string,
|
||||
config?: Config<REQD>
|
||||
): Promise<R> {
|
||||
return this.request({ ...config, url, method: "GET" });
|
||||
}
|
||||
|
||||
/** POST 请求 */
|
||||
post<
|
||||
RESPD extends DataType,
|
||||
REQD extends DataType,
|
||||
R = Response<RESPD, REQD>
|
||||
>(url: string, data?: REQD, config?: Config<REQD>): Promise<R> {
|
||||
return this.request({ ...config, url, method: "POST", data });
|
||||
}
|
||||
|
||||
/** PUT 请求 */
|
||||
put<
|
||||
RESPD extends DataType,
|
||||
REQD extends DataType,
|
||||
R = Response<RESPD, REQD>
|
||||
>(url: string, data?: REQD, config?: Config<REQD>): Promise<R> {
|
||||
return this.request({ ...config, url, method: "PUT", data });
|
||||
}
|
||||
}
|
||||
|
||||
export default Request;
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./Request";
|
||||
@@ -0,0 +1,245 @@
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
/** 扫码 */
|
||||
export async function scanCode() {
|
||||
const res = await new Promise<UniApp.ScanCodeSuccessRes>(
|
||||
(resolve, reject) => {
|
||||
uni.scanCode({
|
||||
success(res) {
|
||||
resolve(res);
|
||||
},
|
||||
fail(res) {
|
||||
reject(res);
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
console.log({ res });
|
||||
return res.result;
|
||||
}
|
||||
|
||||
/** 获取当前页面 */
|
||||
export function getCurrentPage() {
|
||||
const pages = getCurrentPages();
|
||||
return pages[pages.length - 1];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用 TypeScript 工具类型实现自动类型推断的 toPromise
|
||||
*
|
||||
* 核心思路:
|
||||
* 1. 使用类似 Parameters<T>[0] 的方式提取函数第一个参数类型
|
||||
* 2. 从参数类型中提取 success 回调的参数类型
|
||||
* 3. 使用条件类型和 infer 关键字实现类型推断
|
||||
* 4. 虽然不能直接用 ReturnType(因为uni API返回void),但可以用类似思路提取回调参数类型
|
||||
*/
|
||||
|
||||
// 方法1:直接使用 Parameters<T> 工具类型
|
||||
// type ExtractFirstParameter<T> = Parameters<T>[0]; // 这样也可以,但需要T是函数类型
|
||||
|
||||
// 方法2:使用条件类型实现(更灵活,等价于 Parameters<T>[0])
|
||||
type ExtractFirstParameter<T> = T extends (arg: infer P, ...args: unknown[]) => unknown ? P : never;
|
||||
|
||||
// 提取 success 回调的参数类型(类似 ReturnType 的思路,但提取回调参数)
|
||||
type ExtractSuccessResult<T> = T extends { success?: (result: infer R) => void } ? R : never;
|
||||
|
||||
// 提取函数参数类型并排除回调函数(用于args参数)
|
||||
type ExtractOptions<T> = T extends (options: infer P) => unknown
|
||||
? Omit<P, "success" | "fail" | "complete">
|
||||
: never;
|
||||
|
||||
// 类型测试示例(编译时验证)
|
||||
// type TestDownloadOptions = ExtractOptions<typeof uni.downloadFile>; // UniNamespace.DownloadFileOption 去除回调
|
||||
// type TestDownloadResult = ExtractSuccessResult<Parameters<typeof uni.downloadFile>[0]>; // UniNamespace.DownloadSuccessData
|
||||
|
||||
/**
|
||||
* 将 uni-app 回调方法转换为 Promise(使用工具类型自动推断)
|
||||
*
|
||||
* 优势:
|
||||
* - 无需手动指定泛型参数
|
||||
* - 完全基于 TypeScript 工具类型实现
|
||||
* - 支持所有 uni-app API,不需要为每个API单独写重载
|
||||
* - 类型安全,有完整的智能提示
|
||||
*
|
||||
* @example
|
||||
* // 自动推断为 Promise<UniNamespace.DownloadSuccessData>
|
||||
* const downloadRes = await toPromise(uni.downloadFile, { url: 'https://example.com/file.jpg' });
|
||||
* console.log(downloadRes.tempFilePath); // ✅ 类型安全,有智能提示
|
||||
*
|
||||
* // 自动推断为 Promise<UniNamespace.ScanCodeSuccessRes>
|
||||
* const scanRes = await toPromise(uni.scanCode, {});
|
||||
* console.log(scanRes.result); // ✅ 类型安全,有智能提示
|
||||
*
|
||||
* // 自动推断为 Promise<UniNamespace.UploadFileSuccessCallbackResult>
|
||||
* const uploadRes = await toPromise(uni.uploadFile, {
|
||||
* url: '/upload',
|
||||
* filePath: 'temp://file.jpg',
|
||||
* name: 'file'
|
||||
* });
|
||||
* console.log(uploadRes.statusCode); // ✅ 类型安全,有智能提示
|
||||
*
|
||||
* // 自动推断为 Promise<UniNamespace.RequestSuccessCallbackResult>
|
||||
* const requestRes = await toPromise(uni.request, { url: '/api/data' });
|
||||
* console.log(requestRes.data); // ✅ 类型安全,有智能提示
|
||||
*/
|
||||
export function toPromise<F extends (options: Record<string, unknown>) => void>(
|
||||
uniFun: F,
|
||||
args?: ExtractOptions<F>,
|
||||
): Promise<ExtractSuccessResult<ExtractFirstParameter<F>>> {
|
||||
type OptionsType = ExtractFirstParameter<F>;
|
||||
type ResultType = ExtractSuccessResult<OptionsType>;
|
||||
|
||||
return new Promise<ResultType>((resolve, reject) => {
|
||||
uniFun({
|
||||
...args,
|
||||
success(res: ResultType) {
|
||||
resolve(res);
|
||||
},
|
||||
fail(err: unknown) {
|
||||
reject(err);
|
||||
},
|
||||
} as OptionsType);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function showToast(
|
||||
title: string,
|
||||
icon: "success" | "loading" | "error" | "none" = "none",
|
||||
options?: UniNamespace.ShowToastOptions,
|
||||
) {
|
||||
uni.showToast({
|
||||
...options,
|
||||
title,
|
||||
icon,
|
||||
duration: options?.duration ?? 1000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过URL生成canvas二维码
|
||||
* @param canvasId
|
||||
* @param url 图片URL
|
||||
* @param x 定位于canvas左边宽度,单位px
|
||||
* @param y 定位于canvas顶部高度,单位px
|
||||
* @param width 二维码宽度,单位px
|
||||
* @param height 二维码高度,单位px
|
||||
* @param thisArg 页面上下文
|
||||
* @returns 图像像素点数据
|
||||
*/
|
||||
export async function getCanvasImageData(
|
||||
canvasId: string,
|
||||
url: string,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
thisArg: ComponentInternalInstance,
|
||||
) {
|
||||
const context = uni.createCanvasContext(canvasId, thisArg);
|
||||
|
||||
const imgRes = await toPromise(
|
||||
uni.downloadFile,
|
||||
{
|
||||
url,
|
||||
},
|
||||
);
|
||||
|
||||
console.log(imgRes);
|
||||
context.drawImage(imgRes.tempFilePath, x, y, width, height);
|
||||
await new Promise((resolve) => {
|
||||
context.draw(false, (res) => {
|
||||
console.log(res);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
const imageData: UniNamespace.CanvasGetImageDataRes =
|
||||
await uni.canvasGetImageData({
|
||||
canvasId: canvasId,
|
||||
x,
|
||||
y,
|
||||
width: width,
|
||||
height: height,
|
||||
});
|
||||
|
||||
return imageData.data;
|
||||
}
|
||||
|
||||
export async function getCanvasImageDataSimplify(
|
||||
canvasId: string,
|
||||
url: string,
|
||||
width = 200,
|
||||
height = 200,
|
||||
thisArg: ComponentInternalInstance,
|
||||
) {
|
||||
return await getCanvasImageData(canvasId, url, 0, 0, width, height, thisArg);
|
||||
}
|
||||
|
||||
export async function getCanvasImageDataTransObj({
|
||||
canvasId,
|
||||
url,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
thisArg,
|
||||
}: {
|
||||
canvasId: string;
|
||||
url: string;
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
thisArg: ComponentInternalInstance;
|
||||
}) {
|
||||
return await getCanvasImageData(canvasId, url, x, y, width, height, thisArg);
|
||||
}
|
||||
|
||||
export function rpxToPx(rpx: number | string) {
|
||||
if (typeof rpx === "string") {
|
||||
rpx = Number.parseInt(rpx);
|
||||
}
|
||||
const screenWidth = uni.getSystemInfoSync().screenWidth;
|
||||
return (screenWidth * rpx) / 750;
|
||||
}
|
||||
|
||||
export function pxToRpx(px: number | string) {
|
||||
if (typeof px === "string") {
|
||||
px = Number.parseInt(px);
|
||||
}
|
||||
const screenWidth = uni.getSystemInfoSync().screenWidth;
|
||||
return (750 * px) / screenWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出程序
|
||||
*/
|
||||
export function exitApp() {
|
||||
// #ifdef APP-PLUS
|
||||
if (plus.os.name?.toLowerCase() === "android") {
|
||||
plus.runtime.quit();
|
||||
} else {
|
||||
const threadClass = plus.ios.importClass("NSThread");
|
||||
const mainThread = plus.ios.invoke(threadClass, "mainThread");
|
||||
plus.ios.invoke(mainThread, "exit");
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有安卓权限
|
||||
*/
|
||||
export function checkAndroidPermission(permissionList: string[]) {
|
||||
// #ifdef APP-PLUS
|
||||
const ActivityCompat = plus.android.importClass(
|
||||
"androidx.core.app.ActivityCompat",
|
||||
) as Android.ActivityCompat;
|
||||
const activity = plus.android.runtimeMainActivity();
|
||||
|
||||
return permissionList.every((v) => {
|
||||
const p = ActivityCompat.checkSelfPermission(activity, v);
|
||||
return p === 0;
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
type UploadResponseData = {
|
||||
originalFileName: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
type UploadResult = {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: UploadResponseData;
|
||||
};
|
||||
|
||||
type UploadResponse = {
|
||||
errno: number;
|
||||
errmsg: string;
|
||||
originalFileName: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
export async function upload(
|
||||
options: UniApp.UploadFileOption,
|
||||
): Promise<UploadResult> {
|
||||
console.log(options);
|
||||
|
||||
return new Promise<UniApp.UploadFileSuccessCallbackResult>(
|
||||
(resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: options.url,
|
||||
filePath: options.filePath,
|
||||
name: options.name ?? "ImageFile",
|
||||
// header: {
|
||||
// Authorization: `Bearer ${token}`,
|
||||
// },
|
||||
// formData: {
|
||||
// shopId: userStore.shop?.shopId,
|
||||
// },
|
||||
success(res) {
|
||||
console.log(res);
|
||||
resolve(res);
|
||||
},
|
||||
fail(err) {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
},
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.statusCode === 200) {
|
||||
const data: UploadResponse = JSON.parse(res.data);
|
||||
return {
|
||||
code: data.errno,
|
||||
msg:
|
||||
data.errmsg != null && data.errmsg != "" ? data.errmsg : "上传成功",
|
||||
data: {
|
||||
originalFileName: data.originalFileName,
|
||||
url: data.url,
|
||||
},
|
||||
} as UploadResult;
|
||||
} else {
|
||||
throw new Error(res.errMsg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
|
||||
uni.showToast({
|
||||
icon: "none",
|
||||
title: err ?? "网络错误",
|
||||
});
|
||||
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"include": ["src/**/*.ts", "src/**/*.js"],
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["dom", "esnext"],
|
||||
"types": ["@dcloudio/types"],
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"allowJs": true
|
||||
}
|
||||
}
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
/// <reference types="@dcloudio/types" />
|
||||
|
||||
declare namespace Android {
|
||||
class ActivityCompat implements PlusAndroidInstanceObject {
|
||||
checkSelfPermission(context: Context, permission: string): number;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
class Build implements PlusAndroidClassObject {
|
||||
readonly VERSION: {
|
||||
SDK_INT: number;
|
||||
ECLAIR_0_1: number;
|
||||
};
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
class BluetoothAdapter implements PlusAndroidInstanceObject {
|
||||
readonly ACTION_DISCOVERY_FINISHED =
|
||||
"android.bluetooth.device.extra.DEVICE";
|
||||
startDiscovery(): boolean;
|
||||
cancelDiscovery(): boolean;
|
||||
isDiscovering(): boolean;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
getDefaultAdapter(): BluetoothAdapter;
|
||||
getBondedDevices(): Set<BluetoothDevice>;
|
||||
}
|
||||
class BluetoothDevice implements PlusAndroidInstanceObject {
|
||||
readonly ACTION_FOUND = "android.bluetooth.device.action.FOUND";
|
||||
readonly EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
|
||||
getName(): string;
|
||||
getAddress(): string;
|
||||
createRfcommSocketToServiceRecord(uuid: UUID): BluetoothSocket;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
|
||||
interface Set<E> extends PlusAndroidClassObject {
|
||||
iterator(): Iterator<E>;
|
||||
}
|
||||
interface BluetoothSocket extends PlusAndroidClassObject {
|
||||
isConnected(): boolean;
|
||||
}
|
||||
interface UUID extends PlusAndroidClassObject {
|
||||
fromString(name: string): UUID;
|
||||
}
|
||||
class Context implements PlusAndroidInstanceObject {
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
class Intent implements PlusAndroidInstanceObject {
|
||||
getParcelableExtra<T>(name: string): T;
|
||||
getAction(): string;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
class BroadcastReceiver {}
|
||||
class IntentFilter implements PlusAndroidInstanceObject {
|
||||
addAction(action: string): void;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
class Activity implements PlusAndroidInstanceObject {
|
||||
registerReceiver(receiver: BroadcastReceiver, filter: IntentFilter): Intent;
|
||||
unregisterReceiver(receiver: BroadcastReceiver): void;
|
||||
plusGetAttribute(name?: string | undefined): unknown;
|
||||
plusSetAttribute(name?: string | undefined, value?: unknown): void;
|
||||
}
|
||||
}
|
||||
Vendored
+1074
File diff suppressed because it is too large
Load Diff
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
interface Config {
|
||||
/** 环境 */
|
||||
ENV?: string;
|
||||
|
||||
/** api 基础地址 */
|
||||
API_BASE_URL?: string;
|
||||
|
||||
/** appId */
|
||||
APP_ID?: string;
|
||||
|
||||
/** static 目录基础地址 */
|
||||
STATIC_BASE_URL?: string;
|
||||
|
||||
/** 上传文件地址 */
|
||||
UPLOAD_URL?: string;
|
||||
|
||||
/** 文件地址 */
|
||||
FILE_BASE_URL?: string;
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module "uview-ui";
|
||||
declare module "uview-plus";
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
declare global {
|
||||
function setInterval(handler: TimerHandler, timeout?: number): number;
|
||||
}
|
||||
|
||||
export {};
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import * as QQMapWX from "@jonny1994/qqmap-wx-jssdk";
|
||||
export * from "@jonny1994/qqmap-wx-jssdk";
|
||||
/**
|
||||
* 行政区划列表
|
||||
* @example
|
||||
* cidx: [103, 118]
|
||||
* fullname: "张家口市"
|
||||
* id: "130700"
|
||||
* location: {lat: 40.82444, lng: 114.88755}
|
||||
* name: "张家口"
|
||||
* pinyin: ["zhang", "jia", "kou"]
|
||||
*/
|
||||
export interface GetCityListSuccessResultResult {
|
||||
/**
|
||||
* 行政区划唯一标识
|
||||
* @example "110000"
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* 简称,如“内蒙古”
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 全称,如“内蒙古自治区”
|
||||
* @example "北京市"
|
||||
*/
|
||||
fullname: string;
|
||||
/**
|
||||
* 中心点坐标
|
||||
* @example {lat: 39.90469, lng: 116.40717}
|
||||
*/
|
||||
location: QQMapWX.ResultLocation;
|
||||
/**
|
||||
* 行政区划拼音,每一下标为一个字的全拼,如:[“nei”,“meng”,“gu”]
|
||||
*/
|
||||
pinyin: string[];
|
||||
/**
|
||||
* 子级行政区划在下级数组中的下标位置
|
||||
* @example [0, 15]
|
||||
*/
|
||||
cidx?: number[];
|
||||
}
|
||||
|
||||
export interface GetCityListSuccessResult extends QQMapWX.CommonResult {
|
||||
/**
|
||||
* 结果数组,第0项,代表一级行政区划,第1项代表二级行政区划,以此类推;使用getchildren接口时,仅为指定父级行政区划的子级
|
||||
*/
|
||||
result: GetCityListSuccessResultResult[];
|
||||
}
|
||||
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
/// <reference types="@dcloudio/types" />
|
||||
|
||||
declare namespace UniNamespace {
|
||||
type LocaldataItem = {
|
||||
text: string;
|
||||
value: string;
|
||||
children?: LocaldataItem[];
|
||||
};
|
||||
type LocaldataNodeclickValue = {
|
||||
text: string;
|
||||
value: string;
|
||||
parent_value?: string;
|
||||
};
|
||||
type LocaldataChangeValue = { text: string; value: string };
|
||||
type Event<T> = { detail: T };
|
||||
type InputEvent = Event<{ value: string }>;
|
||||
type PickerEvent = Event<{ value: string }>;
|
||||
type PickerViewEvent = Event<{ value: unknown[] }>;
|
||||
type ScrollEvent = Event<{ scrollTop: number }>;
|
||||
type SwiperEvent = Event<{ current: number }>;
|
||||
type UniDataPickerEvent = Event<{ value: LocaldataChangeValue[] }>;
|
||||
|
||||
interface WriteBLECharacteristicValueOptions2 {
|
||||
/**
|
||||
* 蓝牙设备 id,参考 device 对象
|
||||
*/
|
||||
deviceId: string;
|
||||
/**
|
||||
* 蓝牙特征值对应服务的 uuid
|
||||
*/
|
||||
serviceId: string;
|
||||
/**
|
||||
* 蓝牙特征值的 uuid
|
||||
*/
|
||||
characteristicId: string;
|
||||
/**
|
||||
* 蓝牙设备特征值对应的二进制值
|
||||
*/
|
||||
value: ArrayBuffer;
|
||||
/**
|
||||
* 成功则返回本机蓝牙适配器状态
|
||||
*/
|
||||
success?: (result: StopBluetoothDevicesDiscoverySuccess) => void;
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
fail?: (result: unknown) => void;
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
complete?: (result: unknown) => void;
|
||||
}
|
||||
|
||||
interface BluetoothError {
|
||||
code: number;
|
||||
}
|
||||
|
||||
interface StopBluetoothDevicesDiscoveryOptions2 {
|
||||
/**
|
||||
* 成功则返回本机蓝牙适配器状态
|
||||
*/
|
||||
success?: (result: StopBluetoothDevicesDiscoverySuccess) => void;
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
fail?: (result: BluetoothError) => void;
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
complete?: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
// type DataType = string | AnyObject | ArrayBuffer;
|
||||
interface Uni {
|
||||
// request<T extends DataType, D extends DataType>(
|
||||
// options: RequestOptionsGeneric<D>
|
||||
// ): Promise<RequestSuccessCallbackResultGeneric<T>>;
|
||||
request(
|
||||
options: UniApp.RequestOptions,
|
||||
): Promise<UniApp.RequestSuccessCallbackResult>;
|
||||
|
||||
writeBLECharacteristicValue(
|
||||
options: UniNamespace.WriteBLECharacteristicValueOptions2,
|
||||
): void;
|
||||
|
||||
stopBluetoothDevicesDiscovery(
|
||||
options: UniNamespace.StopBluetoothDevicesDiscoveryOptions,
|
||||
): void;
|
||||
}
|
||||
|
||||
// interface RequestOptionsGeneric<T extends DataType>
|
||||
// extends UniApp.RequestOptions {
|
||||
// data?: T;
|
||||
// }
|
||||
|
||||
// interface RequestSuccessCallbackResultGeneric<T extends DataType>
|
||||
// extends UniApp.RequestSuccessCallbackResult {
|
||||
// data: T;
|
||||
// errMsg?: string;
|
||||
// }
|
||||
|
||||
// interface PlusIoDirectoryEntry extends PlusIoFileEntry {
|
||||
// file(
|
||||
// succesCB?: (result: PlusIoFile) => void,
|
||||
// errorCB?: (result: any) => void
|
||||
// ): void;
|
||||
// }
|
||||
|
||||
interface PlusIo {
|
||||
resolveLocalFileSystemURL(
|
||||
url?: string,
|
||||
succesCB?: (result: PlusIoFileEntry) => void,
|
||||
errorCB?: (result: any) => void,
|
||||
): void;
|
||||
}
|
||||
|
||||
// interface PlusIoFileEvent {
|
||||
// target?: PlusIoFileReader;
|
||||
// }
|
||||
|
||||
interface PlusIoFileReader {
|
||||
onload?: (result: PlusIoFileEvent) => void;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/index.ts'),
|
||||
formats: ['es', 'cjs'],
|
||||
fileName: (format) => `index.${format === 'es' ? 'mjs' : 'cjs'}`,
|
||||
},
|
||||
rollupOptions: {
|
||||
// uni / plus / wx 是 uni-app 运行时注入的全局变量,无需 external
|
||||
external: ['vue', 'lodash', /^@r-utils\/.*/],
|
||||
},
|
||||
sourcemap: true,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
dts({
|
||||
include: ['src'],
|
||||
outDir: 'dist',
|
||||
}),
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user