feat(): 改为vite

This commit is contained in:
2026-03-16 17:58:57 +08:00
parent cd734d8524
commit 1ccbd4e872
74 changed files with 46574 additions and 2145 deletions
+245
View File
@@ -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
}