@hlw-uni/mp-vue 2.1.52 → 2.1.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/app.d.ts +2 -20
  2. package/dist/composables/device/index.d.ts +5 -70
  3. package/dist/composables/index.d.ts +5 -14
  4. package/dist/composables/navigator/index.d.ts +15 -39
  5. package/dist/composables/request/client.d.ts +21 -0
  6. package/dist/composables/request/index.d.ts +6 -0
  7. package/dist/composables/request/service.d.ts +30 -0
  8. package/dist/composables/{http → request}/types.d.ts +0 -3
  9. package/dist/composables/share/index.d.ts +7 -66
  10. package/dist/composables/utils/index.d.ts +25 -32
  11. package/dist/hlw.d.ts +2 -4
  12. package/dist/index.d.ts +2 -3
  13. package/dist/index.js +484 -1256
  14. package/dist/index.mjs +483 -1255
  15. package/package.json +2 -1
  16. package/src/app.ts +3 -143
  17. package/src/components/hlw-ad/index.vue +2 -2
  18. package/src/components/hlw-page/index.vue +1 -1
  19. package/src/composables/device/index.ts +110 -83
  20. package/src/composables/index.ts +9 -39
  21. package/src/composables/navigator/index.ts +77 -77
  22. package/src/composables/request/client.ts +204 -0
  23. package/src/composables/request/index.ts +15 -0
  24. package/src/composables/request/service.ts +54 -0
  25. package/src/composables/{http → request}/types.ts +0 -4
  26. package/src/composables/share/index.ts +64 -168
  27. package/src/composables/theme/index.ts +4 -2
  28. package/src/composables/theme/palette.ts +22 -4
  29. package/src/composables/utils/index.ts +131 -95
  30. package/src/hlw.ts +6 -14
  31. package/src/index.ts +2 -3
  32. package/dist/composables/_internal/unwrap.d.ts +0 -15
  33. package/dist/composables/ad/index.d.ts +0 -78
  34. package/dist/composables/algo/index.d.ts +0 -7
  35. package/dist/composables/algo/uuid.d.ts +0 -17
  36. package/dist/composables/color/index.d.ts +0 -8
  37. package/dist/composables/contact/index.d.ts +0 -32
  38. package/dist/composables/format/index.d.ts +0 -9
  39. package/dist/composables/http/client.d.ts +0 -66
  40. package/dist/composables/http/index.d.ts +0 -8
  41. package/dist/composables/loading/index.d.ts +0 -7
  42. package/dist/composables/page-meta/index.d.ts +0 -18
  43. package/dist/composables/storage/index.d.ts +0 -16
  44. package/dist/composables/validate/index.d.ts +0 -12
  45. package/dist/error.d.ts +0 -1
  46. package/src/composables/_internal/unwrap.ts +0 -19
  47. package/src/composables/ad/index.ts +0 -412
  48. package/src/composables/algo/index.ts +0 -7
  49. package/src/composables/algo/uuid.ts +0 -27
  50. package/src/composables/color/index.ts +0 -44
  51. package/src/composables/contact/index.ts +0 -92
  52. package/src/composables/format/index.ts +0 -48
  53. package/src/composables/http/client.ts +0 -237
  54. package/src/composables/http/index.ts +0 -8
  55. package/src/composables/http/useRequest.ts +0 -107
  56. package/src/composables/loading/index.ts +0 -23
  57. package/src/composables/page-meta/index.ts +0 -49
  58. package/src/composables/storage/index.ts +0 -76
  59. package/src/composables/validate/index.ts +0 -58
  60. package/src/error.ts +0 -5
  61. /package/dist/composables/{http → request}/adapters/alist.d.ts +0 -0
  62. /package/dist/composables/{http → request}/adapters/base.d.ts +0 -0
  63. /package/dist/composables/{http → request}/adapters/cos.d.ts +0 -0
  64. /package/dist/composables/{http → request}/adapters/index.d.ts +0 -0
  65. /package/dist/composables/{http → request}/adapters/oss.d.ts +0 -0
  66. /package/dist/composables/{http → request}/adapters/qiniu.d.ts +0 -0
  67. /package/src/composables/{http → request}/adapters/alist.ts +0 -0
  68. /package/src/composables/{http → request}/adapters/base.ts +0 -0
  69. /package/src/composables/{http → request}/adapters/cos.ts +0 -0
  70. /package/src/composables/{http → request}/adapters/index.ts +0 -0
  71. /package/src/composables/{http → request}/adapters/oss.ts +0 -0
  72. /package/src/composables/{http → request}/adapters/qiniu.ts +0 -0
@@ -1,189 +1,85 @@
1
- /**
2
- * useShare - 小程序分享 composable
3
- *
4
- * 两层 API 并存:
5
- * - useShare(config) —— SDK 层:直接注册 onShareAppMessage / onShareTimeline 钩子
6
- * - useShareConfig(...) —— 业务层:lazy load 后端配置 + cache + fallback resolver
7
- */
8
- import { onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app';
9
- import { ref } from 'vue';
10
- import { unwrapPayload, type AdapterPayload } from '../_internal/unwrap';
1
+ import {
2
+ onShareAppMessage as registerShareAppMessage,
3
+ onShareTimeline as registerShareTimeline,
4
+ } from "@dcloudio/uni-app";
11
5
 
12
- export interface ShareAppMessageContent {
13
- /** 分享标题 */
6
+ export interface ShareConfig {
14
7
  title?: string;
15
- /** 分享路径,必须是以 / 开头的完整路径 */
16
8
  path?: string;
17
- /** 自定义图片路径 */
18
9
  imageUrl?: string;
19
10
  }
20
11
 
21
- export interface ShareTimelineContent {
22
- /** 朋友圈分享标题 */
23
- title?: string;
24
- /** 页面携带的 query 参数 */
25
- query?: string;
26
- /** 自定义图片路径 */
27
- imageUrl?: string;
28
- }
29
-
30
- export interface ShareConfig extends ShareAppMessageContent {
31
- /** 朋友圈专属配置,不填则复用朋友分享配置 */
32
- timeline?: ShareTimelineContent;
33
- }
34
-
35
- /**
36
- * 分享来源。
37
- * - `button` 页面内转发按钮
38
- * - `menu` 右上角菜单
39
- */
40
- export type ShareFrom = 'button' | 'menu';
12
+ export type ShareConfigResolver = ShareConfig | (() => ShareConfig);
41
13
 
42
- export type ShareConfigResolver = (from: ShareFrom) => ShareConfig;
43
-
44
- /**
45
- * 注册小程序分享钩子。
46
- */
47
- export function useShare(config: ShareConfig | ShareConfigResolver) {
48
- /**
49
- * 根据分享来源解析最终分享配置。
50
- */
51
- const resolve = (from: ShareFrom): ShareConfig =>
52
- typeof config === 'function' ? config(from) : config;
53
-
54
- /**
55
- * 注册分享给朋友的回调。
56
- */
57
- onShareAppMessage((options: { from?: string } | undefined) => {
58
- const resolved = resolve((options?.from as ShareFrom) ?? 'menu');
59
- const payload: ShareAppMessageContent = {};
60
- if (resolved.title !== undefined) payload.title = resolved.title;
61
- if (resolved.path !== undefined) payload.path = resolved.path;
62
- if (resolved.imageUrl !== undefined) payload.imageUrl = resolved.imageUrl;
63
- return payload;
64
- });
65
-
66
- /**
67
- * 注册分享到朋友圈的回调。
68
- */
69
- onShareTimeline(() => {
70
- const resolved = resolve('menu');
71
- const timeline = resolved.timeline ?? {};
72
- const payload: ShareTimelineContent = {};
73
- const title = timeline.title ?? resolved.title;
74
- const imageUrl = timeline.imageUrl ?? resolved.imageUrl;
75
- if (title !== undefined) payload.title = title;
76
- if (timeline.query !== undefined) payload.query = timeline.query;
77
- if (imageUrl !== undefined) payload.imageUrl = imageUrl;
78
- return payload;
79
- });
14
+ export interface ShareHandlers {
15
+ onShareAppMessage: (config?: ShareConfigResolver) => void;
16
+ onShareTimeline: (config?: ShareConfigResolver) => void;
17
+ showShareMenu: () => void;
80
18
  }
81
19
 
82
- /* ============================================================
83
- * useShareConfig —— 业务层:lazy load 后端聚合配置 + cache + fallback resolver
84
- *
85
- * 后端按页面 key 聚合返回各页 title / image,前端拉一次缓存全局共用。
86
- * 返回的 resolver 同时喂给 onShareAppMessage 和 onShareTimeline。
87
- *
88
- * 使用方式:
89
- *
90
- * 1. App.vue / bootstrap 注入回调:
91
- *
92
- * setConfigShare({
93
- * getConfig: async () => {
94
- * const res = await getShareConfig();
95
- * return res.code === 1 ? res.data : null;
96
- * },
97
- * });
98
- *
99
- * 2. 任意页面 setup:
100
- *
101
- * const share = useShareConfig("index", {
102
- * title: "兜底标题",
103
- * path: "/pages/index/index",
104
- * });
105
- * onShareAppMessage(share);
106
- * onShareTimeline(share);
107
- * ============================================================ */
108
-
109
- /** 单页分享配置 */
110
- export interface PageShareItem {
111
- title: string;
112
- image: string;
20
+ function resolveConfig(config?: ShareConfigResolver): ShareConfig {
21
+ return typeof config === "function" ? config() : (config ?? {});
113
22
  }
114
23
 
115
- /** 后端返回的页面 key 配置映射 */
116
- export type ShareConfigMap = Record<string, PageShareItem>;
117
-
118
- /**
119
- * Adapter 注入接口 —— getConfig 支持「已解包」或「ThinkAdmin envelope」两种返回值。
120
- * 业务方可以直接传 envelope-returning 接口:setConfigShare({ getConfig: getShareConfig })
121
- */
122
- export interface ShareConfigAdapter {
123
- getConfig: () => Promise<AdapterPayload<ShareConfigMap>>;
124
- }
125
-
126
- /** 页面声明的兜底文案 / 跳转路径 */
127
- export interface PageShareFallback {
128
- /** 后端 title 为空时用 */
129
- title: string;
130
- /** 分享跳转路径(必须 / 开头);path 不走后端,由页面自定义 */
131
- path: string;
132
- /** 后端 image 为空时用;通常留空让微信自动截图 */
133
- image?: string;
24
+ function buildPayload(base: ShareConfigResolver, extra?: ShareConfigResolver): ShareConfig {
25
+ const current = {
26
+ ...resolveConfig(base),
27
+ ...resolveConfig(extra),
28
+ };
29
+ const payload: ShareConfig = {};
30
+ if (current.title) payload.title = current.title;
31
+ if (current.path) payload.path = current.path;
32
+ if (current.imageUrl) payload.imageUrl = current.imageUrl;
33
+ return payload;
134
34
  }
135
35
 
136
- /** 分享 payload —— 同时喂给 onShareAppMessage / onShareTimeline */
137
- export interface SharePayload {
138
- title: string;
139
- path: string;
140
- imageUrl?: string;
36
+ function showShareMenu(): void {
37
+ const api = typeof uni !== "undefined" ? (uni as unknown as {
38
+ showShareMenu?: (options: {
39
+ withShareTicket?: boolean;
40
+ menus?: string[];
41
+ fail?: () => void;
42
+ }) => void;
43
+ }) : undefined;
44
+
45
+ api?.showShareMenu?.({
46
+ withShareTicket: true,
47
+ menus: ["shareAppMessage", "shareTimeline"],
48
+ fail: () => undefined,
49
+ });
141
50
  }
142
51
 
143
- let shareAdapter: ShareConfigAdapter | null = null;
144
- const shareCache = ref<ShareConfigMap | null>(null);
145
- let sharePending: Promise<void> | null = null;
52
+ export function useShare(config: ShareConfigResolver = {}): ShareHandlers {
53
+ let appMessageRegistered = false;
54
+ let timelineRegistered = false;
146
55
 
147
- /**
148
- * 注入业务回调(应用启动时调用一次;不调用则始终用 fallback)。
149
- */
150
- export function setConfigShare(a: ShareConfigAdapter): void {
151
- shareAdapter = a;
152
- }
56
+ const onShareAppMessage = (extra?: ShareConfigResolver) => {
57
+ if (appMessageRegistered) return;
58
+ appMessageRegistered = true;
59
+ showShareMenu();
60
+ registerShareAppMessage(() => buildPayload(config, extra));
61
+ };
153
62
 
154
- function loadShareConfig(): Promise<void> {
155
- if (shareCache.value) return Promise.resolve();
156
- if (sharePending) return sharePending;
157
- if (!shareAdapter?.getConfig) {
158
- console.warn("[useShareConfig] adapter.getConfig 未注入;先调用 setConfigShare()");
159
- return Promise.resolve();
160
- }
161
- sharePending = shareAdapter.getConfig()
162
- .then((raw) => {
163
- const cfg = unwrapPayload(raw);
164
- if (cfg) shareCache.value = cfg;
165
- })
166
- .catch((e) => {
167
- console.warn("[useShareConfig] load failed", e);
168
- })
169
- .finally(() => {
170
- sharePending = null;
63
+ const onShareTimeline = (extra?: ShareConfigResolver) => {
64
+ if (timelineRegistered) return;
65
+ timelineRegistered = true;
66
+ showShareMenu();
67
+ registerShareTimeline(() => {
68
+ const payload = buildPayload(config, extra);
69
+ return {
70
+ title: payload.title,
71
+ query: payload.path?.split("?")[1],
72
+ imageUrl: payload.imageUrl,
73
+ };
171
74
  });
172
- return sharePending;
173
- }
75
+ };
76
+
77
+ onShareAppMessage();
78
+ onShareTimeline();
174
79
 
175
- /**
176
- * 业务级分享配置 helper —— 返回 resolver,可直接喂 onShareAppMessage / onShareTimeline。
177
- * 后端配置异步加载,加载完成前先用 fallback、加载完后自动切到后端值。
178
- */
179
- export function useShareConfig(pageKey: string, fallback: PageShareFallback) {
180
- void loadShareConfig();
181
- return (): SharePayload => {
182
- const remote = shareCache.value?.[pageKey];
183
- const title = remote?.title || fallback.title;
184
- const image = remote?.image || fallback.image;
185
- const payload: SharePayload = { title, path: fallback.path };
186
- if (image) payload.imageUrl = image;
187
- return payload;
80
+ return {
81
+ onShareAppMessage,
82
+ onShareTimeline,
83
+ showShareMenu,
188
84
  };
189
85
  }
@@ -1,8 +1,6 @@
1
1
  import { computed } from "vue";
2
- import { useColor } from "@/composables/color";
3
2
  import { useThemeStore } from "../../stores/theme";
4
3
 
5
- const { varsToStyle } = useColor();
6
4
  import { getCurrentFontVars } from "./font";
7
5
  import { getCurrentThemeVars } from "./palette";
8
6
 
@@ -25,6 +23,10 @@ export function buildThemeStyle(): string {
25
23
  });
26
24
  }
27
25
 
26
+ function varsToStyle(vars: Record<string, string>): string {
27
+ return Object.entries(vars).map(([key, value]) => `${key}:${value}`).join(";") + ";";
28
+ }
29
+
28
30
  /**
29
31
  * 获取主题样式字符串,用于注入 <page-meta :page-style>。
30
32
  *
@@ -1,7 +1,3 @@
1
- import { useColor } from "@/composables/color";
2
-
3
- const { hexToRgba, darkenHex } = useColor();
4
-
5
1
  export interface ThemeColor {
6
2
  label: string;
7
3
  value: string;
@@ -65,3 +61,25 @@ export function getCurrentThemeVars(): Record<string, string> {
65
61
  "--info-dark": darkenHex(THEME_SEMANTIC_COLORS.info),
66
62
  };
67
63
  }
64
+
65
+ const HEX_RE = /^#[0-9a-fA-F]{6}$/;
66
+
67
+ function parseHex(hex: string): [number, number, number] {
68
+ if (!HEX_RE.test(hex)) throw new Error(`Invalid hex color: ${hex}`);
69
+ return [
70
+ parseInt(hex.slice(1, 3), 16),
71
+ parseInt(hex.slice(3, 5), 16),
72
+ parseInt(hex.slice(5, 7), 16),
73
+ ];
74
+ }
75
+
76
+ function hexToRgba(hex: string, alpha: number): string {
77
+ const [r, g, b] = parseHex(hex);
78
+ return `rgba(${r},${g},${b},${alpha})`;
79
+ }
80
+
81
+ function darkenHex(hex: string, amount = 0.15): string {
82
+ const [r, g, b] = parseHex(hex);
83
+ const darken = (value: number) => Math.max(0, Math.round(value * (1 - amount)));
84
+ return `#${darken(r).toString(16).padStart(2, "0")}${darken(g).toString(16).padStart(2, "0")}${darken(b).toString(16).padStart(2, "0")}`;
85
+ }
@@ -2,160 +2,183 @@
2
2
  * 小程序通用工具。
3
3
  */
4
4
 
5
- export interface DownloadFileOptions {
6
- /** 下载地址 */
5
+ export interface DownloadOpt {
7
6
  url: string;
8
- /** 文件保存路径,可选 */
9
- filePath?: string;
10
- /** HTTP 请求头,可选 */
7
+ path?: string;
11
8
  header?: Record<string, string>;
12
- /** 下载进度回调,可选 */
13
- onProgress?: (progress: number, totalBytesWritten: number, totalBytesExpectedToWrite: number) => void;
9
+ progress?: (value: number, done: number, total: number) => void;
14
10
  }
15
11
 
16
- export interface DownloadFileResult {
17
- /** 是否成功 */
18
- success: boolean;
19
- /** 临时文件路径 */
20
- tempFilePath?: string;
21
- /** 状态码 */
22
- statusCode?: number;
23
- /** 错误信息 */
24
- errMsg?: string;
12
+ export interface DownloadRes {
13
+ ok: boolean;
14
+ path?: string;
15
+ code?: number;
16
+ msg?: string;
25
17
  }
26
18
 
27
- export type TapEvent = {
28
- currentTarget?: { dataset?: Record<string, any> };
29
- target?: { dataset?: Record<string, any> };
30
- };
19
+ function withQuery(url: string, qs: string) {
20
+ if (!qs) return url;
21
+ return `${url}${url.includes("?") ? "&" : "?"}${qs}`;
22
+ }
31
23
 
32
- /**
33
- * 剪贴板、下载与相册保存工具集合。
34
- */
35
- export function useUtils() {
36
- /**
37
- * 复制文本到剪贴板,可选显示成功提示。
38
- * 也可直接作为 tap 事件处理函数,从 data-copy 读取文本。
39
- */
40
- function copy(data: string | TapEvent, showToast = true): Promise<boolean> {
41
- if (typeof data !== "string") {
42
- const dataset = data?.currentTarget?.dataset || data?.target?.dataset;
43
- const text = dataset?.copy;
44
- if (text == null || text === "") return Promise.resolve(false);
45
- return copy(String(text), dataset?.copyToast !== "false");
46
- }
24
+ function toQuery(data: Record<string, unknown>) {
25
+ return Object.entries(data)
26
+ .filter(([, val]) => val !== undefined && val !== null)
27
+ .map(([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(val))}`)
28
+ .join("&");
29
+ }
30
+
31
+ function signText(url: string) {
32
+ const [path, qs] = url.split("?");
33
+ return qs ? `${qs.split("&").filter(Boolean).sort().join("&")}&` : `${path}&`;
34
+ }
35
+
36
+ function toNumber(val: unknown, def: number): number {
37
+ const next = Number(val);
38
+ return Number.isFinite(next) ? next : def;
39
+ }
40
+
41
+ function toBoolean(val: unknown, def: boolean): boolean {
42
+ if (typeof val === "boolean") return val;
43
+ if (val === 0 || val === "0") return false;
44
+ if (val === 1 || val === "1") return true;
45
+ return def;
46
+ }
47
47
 
48
- return new Promise((resolve) => {
48
+ export function useUtils() {
49
+ function copy(text: string, tip = true): Promise<boolean> {
50
+ return new Promise((ok) => {
49
51
  uni.setClipboardData({
50
- data,
52
+ data: text,
51
53
  showToast: false,
52
54
  success: () => {
53
- if (showToast) {
55
+ if (tip) {
54
56
  uni.showToast({ title: "复制成功", icon: "none", duration: 1500 });
55
57
  }
56
- resolve(true);
58
+ ok(true);
57
59
  },
58
- fail: () => resolve(false),
60
+ fail: () => ok(false),
59
61
  });
60
62
  });
61
63
  }
62
64
 
63
- /**
64
- * 从事件 dataset 的 data-copy 字段读取文本并复制。
65
- */
66
- function copyFromEvent(event: TapEvent) {
67
- return copy(event);
68
- }
69
-
70
- /**
71
- * 读取当前剪贴板文本内容。
72
- */
73
65
  function paste(): Promise<string> {
74
- return new Promise((resolve) => {
66
+ return new Promise((ok) => {
75
67
  uni.getClipboardData({
76
- success: (res) => resolve(res.data),
77
- fail: () => resolve(""),
68
+ success: (res) => ok(res.data),
69
+ fail: () => ok(""),
78
70
  });
79
71
  });
80
72
  }
81
73
 
82
- /**
83
- * 将本地图片保存到系统相册。
84
- */
85
- function saveImage(filePath: string): Promise<boolean> {
86
- return new Promise((resolve) => {
74
+ function auth() {
75
+ uni.showModal({
76
+ title: "提示",
77
+ content: "需要授权相册权限",
78
+ confirmText: "去设置",
79
+ success: (res) => {
80
+ if (res.confirm) uni.openSetting();
81
+ },
82
+ });
83
+ }
84
+
85
+ function saveImage(path: string): Promise<boolean> {
86
+ return new Promise((ok) => {
87
87
  uni.saveImageToPhotosAlbum({
88
- filePath,
88
+ filePath: path,
89
89
  success: () => {
90
90
  uni.showToast({ title: "保存成功", icon: "success" });
91
- resolve(true);
91
+ ok(true);
92
92
  },
93
93
  fail: (err) => {
94
- if (err.errMsg.includes("auth deny") || err.errMsg.includes("authorize")) {
95
- uni.showModal({
96
- title: "提示",
97
- content: "需要授权相册权限",
98
- confirmText: "去设置",
99
- success: (res) => {
100
- if (res.confirm) uni.openSetting();
101
- },
102
- });
94
+ const msg = String(err.errMsg || "");
95
+ if (msg.includes("auth deny") || msg.includes("authorize")) {
96
+ auth();
103
97
  } else {
104
98
  uni.showToast({ title: "保存失败", icon: "none" });
105
99
  }
106
- resolve(false);
100
+ ok(false);
107
101
  },
108
102
  });
109
103
  });
110
104
  }
111
105
 
112
- /**
113
- * 下载文件并返回下载结果。
114
- */
115
- function downloadFile(options: DownloadFileOptions): Promise<DownloadFileResult> {
116
- return new Promise((resolve) => {
106
+ function saveVideo(path: string): Promise<boolean> {
107
+ return new Promise((ok) => {
108
+ uni.saveVideoToPhotosAlbum({
109
+ filePath: path,
110
+ success: () => {
111
+ uni.showToast({ title: "保存成功", icon: "success" });
112
+ ok(true);
113
+ },
114
+ fail: (err) => {
115
+ const msg = String(err.errMsg || "");
116
+ if (msg.includes("auth deny") || msg.includes("authorize")) {
117
+ auth();
118
+ } else {
119
+ uni.showToast({ title: "保存失败", icon: "none" });
120
+ }
121
+ ok(false);
122
+ },
123
+ });
124
+ });
125
+ }
126
+
127
+ function download(opt: DownloadOpt): Promise<DownloadRes> {
128
+ return new Promise((ok) => {
117
129
  const task = uni.downloadFile({
118
- url: options.url,
119
- filePath: options.filePath,
120
- header: options.header,
130
+ url: opt.url,
131
+ filePath: opt.path,
132
+ header: opt.header,
121
133
  success: (res) => {
122
134
  if (res.statusCode === 200) {
123
- resolve({ success: true, tempFilePath: res.tempFilePath, statusCode: res.statusCode });
135
+ ok({ ok: true, path: res.tempFilePath, code: res.statusCode });
124
136
  } else {
125
- resolve({ success: false, statusCode: res.statusCode, errMsg: `下载失败,状态码:${res.statusCode}` });
137
+ ok({ ok: false, code: res.statusCode, msg: `下载失败,状态码:${res.statusCode}` });
126
138
  }
127
139
  },
128
- fail: (err) => resolve({ success: false, errMsg: err.errMsg }),
140
+ fail: (err) => ok({ ok: false, msg: err.errMsg }),
129
141
  });
130
142
 
131
- if (options.onProgress) {
143
+ if (opt.progress) {
132
144
  task.onProgressUpdate((res) => {
133
- options.onProgress!(res.progress, res.totalBytesWritten, res.totalBytesExpectedToWrite);
145
+ opt.progress!(res.progress, res.totalBytesWritten, res.totalBytesExpectedToWrite);
134
146
  });
135
147
  }
136
148
  });
137
149
  }
138
150
 
139
- /**
140
- * 下载远程图片并直接保存到相册。
141
- */
142
- async function downloadAndSaveImage(url: string, onProgress?: (progress: number) => void): Promise<boolean> {
151
+ async function saveImageUrl(url: string, progress?: (value: number) => void): Promise<boolean> {
143
152
  try {
144
153
  uni.showLoading({ title: "下载中...", mask: true });
154
+ const res = await download({ url, progress: progress ? (value) => progress(value) : undefined });
155
+ uni.hideLoading();
145
156
 
146
- const result = await downloadFile({
147
- url,
148
- onProgress: onProgress ? (progress) => onProgress(progress) : undefined,
149
- });
157
+ if (!res.ok || !res.path) {
158
+ uni.showToast({ title: res.msg || "下载失败", icon: "none" });
159
+ return false;
160
+ }
161
+
162
+ return await saveImage(res.path);
163
+ } catch {
164
+ uni.hideLoading();
165
+ uni.showToast({ title: "操作失败", icon: "none" });
166
+ return false;
167
+ }
168
+ }
150
169
 
170
+ async function saveVideoUrl(url: string, progress?: (value: number) => void): Promise<boolean> {
171
+ try {
172
+ uni.showLoading({ title: "下载中...", mask: true });
173
+ const res = await download({ url, progress: progress ? (value) => progress(value) : undefined });
151
174
  uni.hideLoading();
152
175
 
153
- if (!result.success || !result.tempFilePath) {
154
- uni.showToast({ title: result.errMsg || "下载失败", icon: "none" });
176
+ if (!res.ok || !res.path) {
177
+ uni.showToast({ title: res.msg || "下载失败", icon: "none" });
155
178
  return false;
156
179
  }
157
180
 
158
- return await saveImage(result.tempFilePath);
181
+ return await saveVideo(res.path);
159
182
  } catch {
160
183
  uni.hideLoading();
161
184
  uni.showToast({ title: "操作失败", icon: "none" });
@@ -163,5 +186,18 @@ export function useUtils() {
163
186
  }
164
187
  }
165
188
 
166
- return { copy, copyFromEvent, paste, saveImage, downloadFile, downloadAndSaveImage };
189
+ return {
190
+ withQuery,
191
+ toQuery,
192
+ signText,
193
+ toNumber,
194
+ toBoolean,
195
+ copy,
196
+ paste,
197
+ saveImage,
198
+ saveVideo,
199
+ download,
200
+ saveImageUrl,
201
+ saveVideoUrl,
202
+ };
167
203
  }
package/src/hlw.ts CHANGED
@@ -1,37 +1,29 @@
1
1
  /**
2
2
  * hlw - 全局命名空间工厂
3
- * 提供 $msg、$device、$http、$utils、$color 的统一访问入口。
4
- *
5
- * 注意:广告能力请直接 `import { useAd } from "@hlw-uni/mp-vue"`,不再通过 hlw.$ad 暴露。
3
+ * 提供 $msg、$device、$request、$utils 的统一访问入口。
6
4
  */
7
5
  import { useMsg } from '@/composables/msg';
8
6
  import { useDevice, type DeviceInfo } from '@/composables/device';
9
- import { http } from '@/composables/http';
7
+ import { useRequest } from '@/composables/request';
10
8
  import { useUtils } from '@/composables/utils';
11
- import { useColor } from '@/composables/color';
12
9
 
13
10
  export interface HlwInstance {
14
11
  $msg: ReturnType<typeof useMsg>;
15
12
  $device: DeviceInfo;
16
- $http: typeof http;
13
+ $request: ReturnType<typeof useRequest>;
17
14
  $utils: ReturnType<typeof useUtils>;
18
- $color: ReturnType<typeof useColor>;
19
15
  }
20
16
 
21
17
  let _msg: ReturnType<typeof useMsg> | null = null;
22
- let _device: ReturnType<typeof useDevice> | null = null;
23
18
  let _utils: ReturnType<typeof useUtils> | null = null;
24
- let _color: ReturnType<typeof useColor> | null = null;
25
19
 
26
20
  export const hlw: HlwInstance = {
27
21
  /** 延迟创建消息提示实例。 */
28
22
  get $msg() { return (_msg ??= useMsg()); },
29
23
  /** 延迟读取并缓存设备信息。 */
30
- get $device() { return (_device ??= useDevice()).value!; },
31
- /** 复用全局 HTTP 实例。 */
32
- $http: http,
24
+ get $device() { return useDevice().info; },
25
+ /** 复用全局请求实例。 */
26
+ $request: useRequest(),
33
27
  /** 延迟创建通用工具实例。 */
34
28
  get $utils() { return (_utils ??= useUtils()); },
35
- /** 延迟创建颜色工具实例。 */
36
- get $color() { return (_color ??= useColor()); },
37
29
  };