@hlw-uni/mp-vue 1.2.26 → 2.0.0

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 (68) hide show
  1. package/dist/app.d.ts +33 -0
  2. package/dist/composables/ad/index.d.ts +134 -0
  3. package/dist/composables/color/index.d.ts +8 -0
  4. package/dist/composables/contact/index.d.ts +28 -0
  5. package/dist/composables/device/index.d.ts +129 -0
  6. package/dist/composables/format/index.d.ts +9 -0
  7. package/dist/composables/http/adapters/alist.d.ts +3 -0
  8. package/dist/composables/http/adapters/base.d.ts +19 -0
  9. package/dist/composables/http/adapters/cos.d.ts +3 -0
  10. package/dist/composables/http/adapters/index.d.ts +15 -0
  11. package/dist/composables/http/adapters/oss.d.ts +3 -0
  12. package/dist/composables/http/adapters/qiniu.d.ts +3 -0
  13. package/dist/composables/http/client.d.ts +66 -0
  14. package/dist/composables/http/index.d.ts +8 -0
  15. package/dist/composables/http/types.d.ts +51 -0
  16. package/dist/composables/index.d.ts +26 -0
  17. package/dist/composables/loading/index.d.ts +7 -0
  18. package/dist/composables/msg/index.d.ts +36 -0
  19. package/dist/composables/navigator/index.d.ts +47 -0
  20. package/dist/composables/page-meta/index.d.ts +18 -0
  21. package/dist/composables/refs/index.d.ts +8 -0
  22. package/dist/composables/share/index.d.ts +67 -0
  23. package/dist/composables/storage/index.d.ts +16 -0
  24. package/dist/composables/theme/font.d.ts +1 -1
  25. package/dist/composables/theme/index.d.ts +15 -2
  26. package/dist/composables/utils/index.d.ts +39 -0
  27. package/dist/composables/validate/index.d.ts +12 -0
  28. package/dist/directives/copy.d.ts +3 -0
  29. package/dist/directives/index.d.ts +1 -0
  30. package/dist/hlw.d.ts +14 -0
  31. package/dist/index.d.ts +10 -7
  32. package/dist/index.js +1722 -63
  33. package/dist/index.mjs +1721 -62
  34. package/package.json +5 -3
  35. package/src/app.ts +173 -0
  36. package/src/components/hlw-ad/index.vue +74 -30
  37. package/src/composables/ad/index.ts +386 -0
  38. package/src/composables/color/index.ts +44 -0
  39. package/src/composables/contact/index.ts +88 -0
  40. package/src/composables/device/index.ts +168 -0
  41. package/src/composables/format/index.ts +48 -0
  42. package/src/composables/http/adapters/alist.ts +19 -0
  43. package/src/composables/http/adapters/base.ts +21 -0
  44. package/src/composables/http/adapters/cos.ts +23 -0
  45. package/src/composables/http/adapters/index.ts +31 -0
  46. package/src/composables/http/adapters/oss.ts +22 -0
  47. package/src/composables/http/adapters/qiniu.ts +19 -0
  48. package/src/composables/http/client.ts +237 -0
  49. package/src/composables/http/index.ts +8 -0
  50. package/src/composables/http/types.ts +57 -0
  51. package/src/composables/http/useRequest.ts +107 -0
  52. package/src/composables/index.ts +82 -0
  53. package/src/composables/loading/index.ts +23 -0
  54. package/src/composables/msg/index.ts +132 -0
  55. package/src/composables/navigator/index.ts +104 -0
  56. package/src/composables/page-meta/index.ts +49 -0
  57. package/src/composables/refs/index.ts +30 -0
  58. package/src/composables/share/index.ts +185 -0
  59. package/src/composables/storage/index.ts +76 -0
  60. package/src/composables/theme/font.ts +26 -5
  61. package/src/composables/theme/index.ts +26 -11
  62. package/src/composables/theme/palette.ts +1 -1
  63. package/src/composables/utils/index.ts +160 -0
  64. package/src/composables/validate/index.ts +58 -0
  65. package/src/directives/copy.ts +50 -0
  66. package/src/directives/index.ts +1 -0
  67. package/src/hlw.ts +37 -0
  68. package/src/index.ts +21 -20
@@ -1,11 +1,16 @@
1
- import { ref, onMounted, onUnmounted } from "vue";
2
- import { useColor } from "@hlw-uni/mp-core";
1
+ import { computed } from "vue";
2
+ import { useColor } from "@/composables/color";
3
+ import { useThemeStore } from "../../stores/theme";
3
4
 
4
5
  const { varsToStyle } = useColor();
5
6
  import { getCurrentFontVars } from "./font";
6
7
  import { getCurrentThemeVars } from "./palette";
7
8
  import { getCurrentAppearanceVars } from "./appearance";
8
9
 
10
+ /**
11
+ * @deprecated 历史事件名;现已改用 pinia store 响应式驱动,emit 不再有效。
12
+ * 保留 export 仅为不破坏外部 import(不影响功能)。
13
+ */
9
14
  export const THEME_CHANGE_EVENT = "hlw:theme-change";
10
15
 
11
16
  /**
@@ -23,16 +28,26 @@ export function buildThemeStyle(): string {
23
28
  });
24
29
  }
25
30
 
31
+ /**
32
+ * 获取主题样式字符串,用于注入 <page-meta :page-style>。
33
+ *
34
+ * 实现走 pinia store 响应式:store.scale / primaryColor / appearance 任一变化
35
+ * → computed 重算 → page-meta 自动 setData。
36
+ *
37
+ * 注:早期版本用 uni.$emit + onMounted+uni.$on 事件总线驱动,在 vue3 + 小程序部分
38
+ * 基础库下 emit 后 ref 不响应(导致字号 / 主题色 / 外观切换不生效)。已改成响应式驱动。
39
+ */
26
40
  export function useThemePageStyle() {
27
- const themePageStyle = ref(buildThemeStyle());
28
-
29
- const onThemeChange = () => {
30
- themePageStyle.value = buildThemeStyle();
31
- };
32
-
33
- onMounted(() => uni.$on(THEME_CHANGE_EVENT, onThemeChange));
34
- onUnmounted(() => uni.$off(THEME_CHANGE_EVENT, onThemeChange));
35
-
41
+ const store = useThemeStore();
42
+ const themePageStyle = computed(() => {
43
+ // 显式 track 三个响应字段,触发 computed 重算
44
+ // setScale / setTheme / setAppearance 内部已先 set storage 再改 ref,
45
+ // 所以 buildThemeStyle 从 storage 读到的一定是最新值
46
+ void store.scale;
47
+ void store.primaryColor;
48
+ void store.appearance;
49
+ return buildThemeStyle();
50
+ });
36
51
  return { themePageStyle };
37
52
  }
38
53
 
@@ -1,4 +1,4 @@
1
- import { useColor } from "@hlw-uni/mp-core";
1
+ import { useColor } from "@/composables/color";
2
2
 
3
3
  const { hexToRgba, darkenHex } = useColor();
4
4
 
@@ -0,0 +1,160 @@
1
+ /**
2
+ * 小程序通用工具。
3
+ */
4
+
5
+ export interface DownloadFileOptions {
6
+ /** 下载地址 */
7
+ url: string;
8
+ /** 文件保存路径,可选 */
9
+ filePath?: string;
10
+ /** HTTP 请求头,可选 */
11
+ header?: Record<string, string>;
12
+ /** 下载进度回调,可选 */
13
+ onProgress?: (progress: number, totalBytesWritten: number, totalBytesExpectedToWrite: number) => void;
14
+ }
15
+
16
+ export interface DownloadFileResult {
17
+ /** 是否成功 */
18
+ success: boolean;
19
+ /** 临时文件路径 */
20
+ tempFilePath?: string;
21
+ /** 状态码 */
22
+ statusCode?: number;
23
+ /** 错误信息 */
24
+ errMsg?: string;
25
+ }
26
+
27
+ export type TapEvent = { currentTarget?: { dataset?: Record<string, any> } };
28
+
29
+ /**
30
+ * 剪贴板、下载与相册保存工具集合。
31
+ */
32
+ export function useUtils() {
33
+ /**
34
+ * 复制文本到剪贴板,可选显示成功提示。
35
+ */
36
+ function copy(data: string, showToast = true): Promise<boolean> {
37
+ return new Promise((resolve) => {
38
+ uni.setClipboardData({
39
+ data,
40
+ showToast: false,
41
+ success: () => {
42
+ if (showToast) {
43
+ uni.showToast({ title: "复制成功", icon: "none", duration: 1500 });
44
+ }
45
+ resolve(true);
46
+ },
47
+ fail: () => resolve(false),
48
+ });
49
+ });
50
+ }
51
+
52
+ /**
53
+ * 从事件 dataset 的 data-copy 字段读取文本并复制。
54
+ */
55
+ function copyFromEvent(event: TapEvent) {
56
+ const dataset = event?.currentTarget?.dataset;
57
+ const text = dataset?.copy;
58
+ if (text == null || text === "") return;
59
+ const showToast = dataset?.copyToast !== "false";
60
+ copy(String(text), showToast);
61
+ }
62
+
63
+ /**
64
+ * 读取当前剪贴板文本内容。
65
+ */
66
+ function paste(): Promise<string> {
67
+ return new Promise((resolve) => {
68
+ uni.getClipboardData({
69
+ success: (res) => resolve(res.data),
70
+ fail: () => resolve(""),
71
+ });
72
+ });
73
+ }
74
+
75
+ /**
76
+ * 将本地图片保存到系统相册。
77
+ */
78
+ function saveImage(filePath: string): Promise<boolean> {
79
+ return new Promise((resolve) => {
80
+ uni.saveImageToPhotosAlbum({
81
+ filePath,
82
+ success: () => {
83
+ uni.showToast({ title: "保存成功", icon: "success" });
84
+ resolve(true);
85
+ },
86
+ fail: (err) => {
87
+ if (err.errMsg.includes("auth deny") || err.errMsg.includes("authorize")) {
88
+ uni.showModal({
89
+ title: "提示",
90
+ content: "需要授权相册权限",
91
+ confirmText: "去设置",
92
+ success: (res) => {
93
+ if (res.confirm) uni.openSetting();
94
+ },
95
+ });
96
+ } else {
97
+ uni.showToast({ title: "保存失败", icon: "none" });
98
+ }
99
+ resolve(false);
100
+ },
101
+ });
102
+ });
103
+ }
104
+
105
+ /**
106
+ * 下载文件并返回下载结果。
107
+ */
108
+ function downloadFile(options: DownloadFileOptions): Promise<DownloadFileResult> {
109
+ return new Promise((resolve) => {
110
+ const task = uni.downloadFile({
111
+ url: options.url,
112
+ filePath: options.filePath,
113
+ header: options.header,
114
+ success: (res) => {
115
+ if (res.statusCode === 200) {
116
+ resolve({ success: true, tempFilePath: res.tempFilePath, statusCode: res.statusCode });
117
+ } else {
118
+ resolve({ success: false, statusCode: res.statusCode, errMsg: `下载失败,状态码:${res.statusCode}` });
119
+ }
120
+ },
121
+ fail: (err) => resolve({ success: false, errMsg: err.errMsg }),
122
+ });
123
+
124
+ if (options.onProgress) {
125
+ task.onProgressUpdate((res) => {
126
+ options.onProgress!(res.progress, res.totalBytesWritten, res.totalBytesExpectedToWrite);
127
+ });
128
+ }
129
+ });
130
+ }
131
+
132
+ /**
133
+ * 下载远程图片并直接保存到相册。
134
+ */
135
+ async function downloadAndSaveImage(url: string, onProgress?: (progress: number) => void): Promise<boolean> {
136
+ try {
137
+ uni.showLoading({ title: "下载中...", mask: true });
138
+
139
+ const result = await downloadFile({
140
+ url,
141
+ onProgress: onProgress ? (progress) => onProgress(progress) : undefined,
142
+ });
143
+
144
+ uni.hideLoading();
145
+
146
+ if (!result.success || !result.tempFilePath) {
147
+ uni.showToast({ title: result.errMsg || "下载失败", icon: "none" });
148
+ return false;
149
+ }
150
+
151
+ return await saveImage(result.tempFilePath);
152
+ } catch {
153
+ uni.hideLoading();
154
+ uni.showToast({ title: "操作失败", icon: "none" });
155
+ return false;
156
+ }
157
+ }
158
+
159
+ return { copy, copyFromEvent, paste, saveImage, downloadFile, downloadAndSaveImage };
160
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * useValidate - 校验工具 composable
3
+ */
4
+ export function useValidate() {
5
+ /** 中国大陆手机号格式校验。 */
6
+ function phone(value: string): boolean {
7
+ return /^1[3-9]\d{9}$/.test(value);
8
+ }
9
+
10
+ /** 校验邮箱地址格式。 */
11
+ function email(value: string): boolean {
12
+ return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
13
+ }
14
+
15
+ /** 校验是否为合法 URL。 */
16
+ function url(value: string): boolean {
17
+ try {
18
+ new URL(value);
19
+ return true;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ /** 18 位身份证号格式校验。 */
26
+ function idCard(value: string): boolean {
27
+ return /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(value);
28
+ }
29
+
30
+ /** 普通民用车牌号格式校验。 */
31
+ function carNumber(value: string): boolean {
32
+ return /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{5}$/.test(value);
33
+ }
34
+
35
+ /** 至少 8 位且同时包含字母和数字的密码校验。 */
36
+ function password(value: string): boolean {
37
+ return /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/.test(value);
38
+ }
39
+
40
+ /** 判断值是否为空字符串、空数组、空对象或 null/undefined。 */
41
+ function empty(value: unknown): boolean {
42
+ if (value == null) return true;
43
+ if (typeof value === "string") return value.trim() === "";
44
+ if (Array.isArray(value)) return value.length === 0;
45
+ if (typeof value === "object") return Object.keys(value).length === 0;
46
+ return false;
47
+ }
48
+
49
+ return {
50
+ phone,
51
+ email,
52
+ url,
53
+ idCard,
54
+ carNumber,
55
+ password,
56
+ empty,
57
+ };
58
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * v-copy 指令 - 点击自动复制
3
+ *
4
+ * 用法:
5
+ * <view v-copy="text">...</view>
6
+ * <text v-copy="userId">{{ userId }}</text>
7
+ */
8
+ import type { Directive, DirectiveBinding, VNode } from 'vue'
9
+
10
+ /**
11
+ * 将文本复制到剪贴板,并显示成功提示。
12
+ */
13
+ function copyText(data: string) {
14
+ uni.setClipboardData({
15
+ data,
16
+ showToast: false,
17
+ success: () => uni.showToast({ title: '复制成功', icon: 'none', duration: 1500 }),
18
+ })
19
+ }
20
+
21
+ /**
22
+ * 向 vnode 注入 onTap 事件,在点击时执行复制逻辑。
23
+ */
24
+ function injectTap(vnode: VNode, binding: DirectiveBinding) {
25
+ if (!vnode.props) (vnode as any).props = {}
26
+ const props = vnode.props as Record<string, any>
27
+ const prev = props.onTap
28
+
29
+ props.onTap = (e: any) => {
30
+ prev?.(e)
31
+ const value = binding.value
32
+ if (value == null || value === '') return
33
+ copyText(String(value))
34
+ }
35
+ }
36
+
37
+ export const vCopy: Directive = {
38
+ /**
39
+ * 在指令创建时注入点击事件。
40
+ */
41
+ created(el: any, binding: DirectiveBinding, vnode: VNode) {
42
+ injectTap(vnode, binding)
43
+ },
44
+ /**
45
+ * 在绑定值更新前重新注入点击事件。
46
+ */
47
+ beforeUpdate(el: any, binding: DirectiveBinding, vnode: VNode) {
48
+ injectTap(vnode, binding)
49
+ },
50
+ }
@@ -0,0 +1 @@
1
+ export { vCopy } from './copy'
package/src/hlw.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * hlw - 全局命名空间工厂
3
+ * 提供 $msg、$device、$http、$utils、$color 的统一访问入口。
4
+ *
5
+ * 注意:广告能力请直接 `import { useAd } from "@hlw-uni/mp-vue"`,不再通过 hlw.$ad 暴露。
6
+ */
7
+ import { useMsg } from '@/composables/msg';
8
+ import { useDevice, type DeviceInfo } from '@/composables/device';
9
+ import { http } from '@/composables/http';
10
+ import { useUtils } from '@/composables/utils';
11
+ import { useColor } from '@/composables/color';
12
+
13
+ export interface HlwInstance {
14
+ $msg: ReturnType<typeof useMsg>;
15
+ $device: DeviceInfo;
16
+ $http: typeof http;
17
+ $utils: ReturnType<typeof useUtils>;
18
+ $color: ReturnType<typeof useColor>;
19
+ }
20
+
21
+ let _msg: ReturnType<typeof useMsg> | null = null;
22
+ let _device: ReturnType<typeof useDevice> | null = null;
23
+ let _utils: ReturnType<typeof useUtils> | null = null;
24
+ let _color: ReturnType<typeof useColor> | null = null;
25
+
26
+ export const hlw: HlwInstance = {
27
+ /** 延迟创建消息提示实例。 */
28
+ get $msg() { return (_msg ??= useMsg()); },
29
+ /** 延迟读取并缓存设备信息。 */
30
+ get $device() { return (_device ??= useDevice()).value!; },
31
+ /** 复用全局 HTTP 实例。 */
32
+ $http: http,
33
+ /** 延迟创建通用工具实例。 */
34
+ get $utils() { return (_utils ??= useUtils()); },
35
+ /** 延迟创建颜色工具实例。 */
36
+ get $color() { return (_color ??= useColor()); },
37
+ };
package/src/index.ts CHANGED
@@ -1,27 +1,28 @@
1
1
  /**
2
- * @hlw-uni/mp-vue package root exports
2
+ * @hlw-uni/mp-vue 统一导出
3
3
  *
4
- * Note:
5
- * Components are resolved through easycom using `@hlw-uni/mp-vue/src/components/...`.
6
- * The package root only exports plain TS modules so uni-app does not try to bundle
7
- * compiled SFC runtime helpers from the library entry.
4
+ * 2.0 起合并了原 @hlw-uni/mp-core 全部内容。
5
+ * 业务方一处 import,无需再分包:
6
+ * import { useAd, useMsg, useColor, useThemePageStyle, ... } from "@hlw-uni/mp-vue";
7
+ *
8
+ * UI 组件(hlw-page / hlw-button / hlw-ad 等)走 easycom 自动注册,不在这里 export。
8
9
  */
9
10
 
10
- export type { FontScale, FontPreset, ThemeColor } from "./composables/theme";
11
+ // Composables / 工具 / Theme
12
+ export * from "./composables";
13
+
14
+ // 类型
11
15
  export type { HlwMenuItem } from "./components/hlw-menu/types";
12
16
  export type { HlwPagingRef, HlwPagingInstance } from "./components/hlw-paging/types";
13
- export {
14
- FONT_PRESETS,
15
- FONT_SCALE_KEY,
16
- DEFAULT_THEMES,
17
- THEME_COLOR_KEY,
18
- THEME_SEMANTIC_COLORS,
19
- THEME_CHANGE_EVENT,
20
- getCurrentFontScale,
21
- getCurrentFontVars,
22
- getCurrentThemeColor,
23
- getCurrentThemeVars,
24
- buildThemeStyle,
25
- useThemePageStyle,
26
- } from "./composables/theme";
17
+
18
+ // Pinia store
27
19
  export { useThemeStore } from "./stores/theme";
20
+
21
+ // App 根上下文
22
+ export { useApp, setupDefaultInterceptors } from "./app";
23
+
24
+ // hlw 全局命名空间
25
+ export { hlw, type HlwInstance } from "./hlw";
26
+
27
+ // 指令
28
+ export { vCopy } from "./directives";