@hlw-uni/mp-core 1.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.
- package/README.md +229 -0
- package/dist/app.d.ts +26 -0
- package/dist/assets/index.css +191 -0
- package/dist/composables/device/index.d.ts +67 -0
- package/dist/composables/format/index.d.ts +9 -0
- package/dist/composables/http/adapters/alist.d.ts +3 -0
- package/dist/composables/http/adapters/base.d.ts +19 -0
- package/dist/composables/http/adapters/cos.d.ts +3 -0
- package/dist/composables/http/adapters/index.d.ts +13 -0
- package/dist/composables/http/adapters/oss.d.ts +3 -0
- package/dist/composables/http/adapters/qiniu.d.ts +3 -0
- package/dist/composables/http/client.d.ts +48 -0
- package/dist/composables/http/index.d.ts +8 -0
- package/dist/composables/http/types.d.ts +51 -0
- package/dist/composables/http/useRequest.d.ts +36 -0
- package/dist/composables/index.d.ts +12 -0
- package/dist/composables/loading/index.d.ts +7 -0
- package/dist/composables/msg/index.d.ts +33 -0
- package/dist/composables/page-meta/index.d.ts +15 -0
- package/dist/composables/refs/index.d.ts +4 -0
- package/dist/composables/storage/index.d.ts +13 -0
- package/dist/composables/validate/index.d.ts +12 -0
- package/dist/hlw.d.ts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +310 -0
- package/dist/index.mjs +309 -0
- package/package.json +39 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { http } from './client';
|
|
2
|
+
import { RequestConfig, ApiResponse } from './types';
|
|
3
|
+
|
|
4
|
+
export interface UseRequestOptions<T = unknown> {
|
|
5
|
+
/** 初始数据 */
|
|
6
|
+
initialData?: T | null;
|
|
7
|
+
/** 手动触发(不自动请求) */
|
|
8
|
+
manual?: boolean;
|
|
9
|
+
/** 成功回调 */
|
|
10
|
+
onSuccess?: (data: T, res: ApiResponse<T>) => void;
|
|
11
|
+
/** 失败回调 */
|
|
12
|
+
onError?: (err: Error) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* useRequest — 组件内请求 composable
|
|
16
|
+
* @example
|
|
17
|
+
* const { loading, data, error, run } = useRequest<User>();
|
|
18
|
+
* run({ url: '/user/info', method: 'GET' });
|
|
19
|
+
*/
|
|
20
|
+
export declare function useRequest<T = unknown>(options?: UseRequestOptions<T>): {
|
|
21
|
+
loading: any;
|
|
22
|
+
data: any;
|
|
23
|
+
error: any;
|
|
24
|
+
run: (config: RequestConfig) => Promise<ApiResponse<T>>;
|
|
25
|
+
get: (url: string, data?: unknown) => Promise<ApiResponse<T>>;
|
|
26
|
+
post: (url: string, data?: unknown) => Promise<ApiResponse<T>>;
|
|
27
|
+
put: (url: string, data?: unknown) => Promise<ApiResponse<T>>;
|
|
28
|
+
del: (url: string, data?: unknown) => Promise<ApiResponse<T>>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* useUpload — 上传文件 composable
|
|
32
|
+
*/
|
|
33
|
+
export declare function useUpload(): {
|
|
34
|
+
uploading: any;
|
|
35
|
+
upload: (options: import('./types').UploadConfig) => Promise<import('./types').UploadResult>;
|
|
36
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composables 统一导出
|
|
3
|
+
*/
|
|
4
|
+
export * from './http';
|
|
5
|
+
export { useLoading } from './loading';
|
|
6
|
+
export { useMsg, type HlwMsg, type ToastOptions, type ModalOptions, type ToastIcon } from './msg';
|
|
7
|
+
export { useDevice, deviceToQuery, clearDeviceCache, type DeviceInfo } from './device';
|
|
8
|
+
export { useRefs } from './refs';
|
|
9
|
+
export { usePageMeta } from './page-meta';
|
|
10
|
+
export { useStorage, type StorageInstance } from './storage';
|
|
11
|
+
export { useValidate } from './validate';
|
|
12
|
+
export { useFormat } from './format';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useMsg — 消息提示 composable
|
|
3
|
+
*/
|
|
4
|
+
export type ToastIcon = "success" | "fail" | "exception" | "none";
|
|
5
|
+
export type ToastDuration = "short" | "long";
|
|
6
|
+
export interface ToastOptions {
|
|
7
|
+
message: string;
|
|
8
|
+
icon?: ToastIcon;
|
|
9
|
+
image?: string;
|
|
10
|
+
duration?: number;
|
|
11
|
+
mask?: boolean;
|
|
12
|
+
position?: "top" | "center" | "bottom";
|
|
13
|
+
}
|
|
14
|
+
export interface ModalOptions {
|
|
15
|
+
title?: string;
|
|
16
|
+
content: string;
|
|
17
|
+
confirmText?: string;
|
|
18
|
+
cancelText?: string;
|
|
19
|
+
confirmColor?: string;
|
|
20
|
+
cancelColor?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface HlwMsg {
|
|
23
|
+
toast(opts: ToastOptions): void;
|
|
24
|
+
success(message: string): void;
|
|
25
|
+
error(message: string): void;
|
|
26
|
+
fail(message: string): void;
|
|
27
|
+
showLoading(message?: string): void;
|
|
28
|
+
hideLoading(): void;
|
|
29
|
+
confirm(opts: ModalOptions): Promise<boolean>;
|
|
30
|
+
modal(opts: ModalOptions): Promise<boolean>;
|
|
31
|
+
setLoadingBar(progress: number): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function useMsg(): HlwMsg;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usePageMeta — 页面元信息 composable
|
|
3
|
+
*/
|
|
4
|
+
export interface PageMeta {
|
|
5
|
+
title?: string;
|
|
6
|
+
navigationBarTitleText?: string;
|
|
7
|
+
navigationBarBackgroundColor?: string;
|
|
8
|
+
navigationBarTextStyle?: "white" | "black";
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
enablePullDownRefresh?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function usePageMeta(): {
|
|
13
|
+
setTitle: (title: string) => void;
|
|
14
|
+
setOptions: (options: PageMeta) => void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="@dcloudio/types" />
|
|
2
|
+
/// <reference types="@dcloudio/types" />
|
|
3
|
+
/**
|
|
4
|
+
* useStorage — 本地存储 composable
|
|
5
|
+
*/
|
|
6
|
+
export interface StorageInstance {
|
|
7
|
+
get: <T = unknown>(key: string) => T | null;
|
|
8
|
+
set: <T>(key: string, value: T) => boolean;
|
|
9
|
+
remove: (key: string) => boolean;
|
|
10
|
+
clear: () => boolean;
|
|
11
|
+
info: () => UniApp.GetStorageInfoSuccess | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function useStorage(): StorageInstance;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useValidate — 校验工具 composable
|
|
3
|
+
*/
|
|
4
|
+
export declare function useValidate(): {
|
|
5
|
+
phone: (value: string) => boolean;
|
|
6
|
+
email: (value: string) => boolean;
|
|
7
|
+
url: (value: string) => boolean;
|
|
8
|
+
idCard: (value: string) => boolean;
|
|
9
|
+
carNumber: (value: string) => boolean;
|
|
10
|
+
password: (value: string) => boolean;
|
|
11
|
+
empty: (value: unknown) => boolean;
|
|
12
|
+
};
|
package/dist/hlw.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useMsg } from './composables/msg';
|
|
2
|
+
import { useDevice } from './composables/device';
|
|
3
|
+
import { http } from './composables/http';
|
|
4
|
+
|
|
5
|
+
export interface HlwInstance {
|
|
6
|
+
$msg: ReturnType<typeof useMsg>;
|
|
7
|
+
$device: ReturnType<typeof useDevice>;
|
|
8
|
+
$http: typeof http;
|
|
9
|
+
}
|
|
10
|
+
export declare const hlw: HlwInstance;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hlw-uni/mp-core 统一导出
|
|
3
|
+
*/
|
|
4
|
+
export * from './composables';
|
|
5
|
+
export { useApp, setupDefaultInterceptors } from './app';
|
|
6
|
+
export { hlw, type HlwInstance } from './hlw';
|
|
7
|
+
export { default as Avatar } from './components/Avatar.vue';
|
|
8
|
+
export { default as Empty } from './components/Empty.vue';
|
|
9
|
+
export { default as Loading } from './components/Loading.vue';
|
|
10
|
+
export { default as MenuList, type MenuItem } from './components/MenuList.vue';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => {
|
|
5
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
const vue = require("vue");
|
|
9
|
+
const cosAdapter = {
|
|
10
|
+
name: "cos",
|
|
11
|
+
buildFormData(ctx) {
|
|
12
|
+
const c = ctx.credentials ?? {};
|
|
13
|
+
return {
|
|
14
|
+
"q-ak": c["ak"] ?? "",
|
|
15
|
+
policy: c["policy"] ?? "",
|
|
16
|
+
"q-key-time": c["key-time"] ?? "",
|
|
17
|
+
"q-signature": c["signature"] ?? "",
|
|
18
|
+
"Content-Disposition": `inline;filename=${encodeURIComponent(ctx.fileName)}`,
|
|
19
|
+
success_action_status: 200,
|
|
20
|
+
...ctx.extraData ?? {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const ossAdapter = {
|
|
25
|
+
name: "oss",
|
|
26
|
+
buildFormData(ctx) {
|
|
27
|
+
const c = ctx.credentials ?? {};
|
|
28
|
+
return {
|
|
29
|
+
policy: c["policy"] ?? "",
|
|
30
|
+
signature: c["signature"] ?? "",
|
|
31
|
+
OSSAccessKeyId: c["accessKeyId"] ?? "",
|
|
32
|
+
success_action_status: 200,
|
|
33
|
+
"Content-Disposition": `inline;filename=${encodeURIComponent(ctx.fileName)}`,
|
|
34
|
+
...ctx.extraData ?? {}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const qiniuAdapter = {
|
|
39
|
+
name: "qiniu",
|
|
40
|
+
buildFormData(ctx) {
|
|
41
|
+
const c = ctx.credentials ?? {};
|
|
42
|
+
return {
|
|
43
|
+
token: c["token"] ?? "",
|
|
44
|
+
key: c["key"] ?? ctx.fileName,
|
|
45
|
+
...ctx.extraData ?? {}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const alistAdapter = {
|
|
50
|
+
name: "alist",
|
|
51
|
+
buildFormData(ctx) {
|
|
52
|
+
const c = ctx.credentials ?? {};
|
|
53
|
+
return {
|
|
54
|
+
"file-path": c["file-path"] ?? ctx.fileName,
|
|
55
|
+
authorization: c["token"] ?? "",
|
|
56
|
+
...ctx.extraData ?? {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const adapters = {
|
|
61
|
+
cos: cosAdapter,
|
|
62
|
+
oss: ossAdapter,
|
|
63
|
+
qiniu: qiniuAdapter,
|
|
64
|
+
alist: alistAdapter
|
|
65
|
+
};
|
|
66
|
+
function getAdapter(name) {
|
|
67
|
+
const adapter = adapters[name];
|
|
68
|
+
if (!adapter)
|
|
69
|
+
throw new Error(`[hlw] Unknown upload adapter: ${name}`);
|
|
70
|
+
return adapter;
|
|
71
|
+
}
|
|
72
|
+
var define_import_meta_env_default = {};
|
|
73
|
+
class HttpClient {
|
|
74
|
+
constructor(options = {}) {
|
|
75
|
+
__publicField(this, "_reqInterceptors", []);
|
|
76
|
+
__publicField(this, "_resInterceptors", []);
|
|
77
|
+
__publicField(this, "_errInterceptors", []);
|
|
78
|
+
__publicField(this, "_baseURL");
|
|
79
|
+
__publicField(this, "_defaultHeaders");
|
|
80
|
+
this._baseURL = options.baseURL ?? "";
|
|
81
|
+
this._defaultHeaders = {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
...options.headers
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** 添加请求拦截器,返回取消函数 */
|
|
87
|
+
onRequest(fn) {
|
|
88
|
+
this._reqInterceptors.push(fn);
|
|
89
|
+
return () => {
|
|
90
|
+
const idx = this._reqInterceptors.indexOf(fn);
|
|
91
|
+
if (idx > -1)
|
|
92
|
+
this._reqInterceptors.splice(idx, 1);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** 添加响应拦截器 */
|
|
96
|
+
onResponse(fn) {
|
|
97
|
+
this._resInterceptors.push(fn);
|
|
98
|
+
return () => {
|
|
99
|
+
const idx = this._resInterceptors.indexOf(fn);
|
|
100
|
+
if (idx > -1)
|
|
101
|
+
this._resInterceptors.splice(idx, 1);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** 添加错误拦截器 */
|
|
105
|
+
onError(fn) {
|
|
106
|
+
this._errInterceptors.push(fn);
|
|
107
|
+
return () => {
|
|
108
|
+
const idx = this._errInterceptors.indexOf(fn);
|
|
109
|
+
if (idx > -1)
|
|
110
|
+
this._errInterceptors.splice(idx, 1);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 全局请求
|
|
115
|
+
*/
|
|
116
|
+
async request(config) {
|
|
117
|
+
let cfg = {
|
|
118
|
+
method: "GET",
|
|
119
|
+
...config,
|
|
120
|
+
headers: { ...this._defaultHeaders, ...config.headers }
|
|
121
|
+
};
|
|
122
|
+
for (const fn of this._reqInterceptors) {
|
|
123
|
+
cfg = await fn(cfg);
|
|
124
|
+
}
|
|
125
|
+
const fullUrl = this._buildUrl(cfg.url);
|
|
126
|
+
const res = await this._doRequest(fullUrl, cfg);
|
|
127
|
+
for (const fn of this._resInterceptors) {
|
|
128
|
+
const modified = await fn(res);
|
|
129
|
+
if (modified !== void 0)
|
|
130
|
+
return modified;
|
|
131
|
+
}
|
|
132
|
+
return res;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 组件内请求,返回带状态的 composable
|
|
136
|
+
*/
|
|
137
|
+
useRequest() {
|
|
138
|
+
const loading = vue.ref(false);
|
|
139
|
+
const data = vue.ref(null);
|
|
140
|
+
const error = vue.ref(null);
|
|
141
|
+
async function run(cfg) {
|
|
142
|
+
loading.value = true;
|
|
143
|
+
error.value = null;
|
|
144
|
+
try {
|
|
145
|
+
const res = await this.request(cfg);
|
|
146
|
+
data.value = res.data;
|
|
147
|
+
return res;
|
|
148
|
+
} catch (e) {
|
|
149
|
+
error.value = e;
|
|
150
|
+
await this._applyErrorInterceptors(e);
|
|
151
|
+
throw e;
|
|
152
|
+
} finally {
|
|
153
|
+
loading.value = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const get = (url, d) => run({ url, method: "GET", data: d });
|
|
157
|
+
const post = (url, d) => run({ url, method: "POST", data: d });
|
|
158
|
+
const put = (url, d) => run({ url, method: "PUT", data: d });
|
|
159
|
+
const del = (url, d) => run({ url, method: "DELETE", data: d });
|
|
160
|
+
return { loading, data, error, run: run.bind(this), get, post, put, del };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 上传文件(策略模式)
|
|
164
|
+
*/
|
|
165
|
+
upload(config) {
|
|
166
|
+
const adapter = getAdapter(config.type);
|
|
167
|
+
const fileName = config.fileName ?? config.filePath.split("/").pop() ?? "file";
|
|
168
|
+
let server = config.server;
|
|
169
|
+
if (config.type === "local" && config.url)
|
|
170
|
+
server = config.url;
|
|
171
|
+
const formData = adapter.buildFormData({
|
|
172
|
+
filePath: config.filePath,
|
|
173
|
+
fileName,
|
|
174
|
+
credentials: config.credentials
|
|
175
|
+
});
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
uni.uploadFile({
|
|
178
|
+
url: server,
|
|
179
|
+
filePath: config.filePath,
|
|
180
|
+
name: "file",
|
|
181
|
+
formData,
|
|
182
|
+
header: config.header,
|
|
183
|
+
success: (res) => {
|
|
184
|
+
if (res.statusCode === 200) {
|
|
185
|
+
try {
|
|
186
|
+
const body = JSON.parse(res.data);
|
|
187
|
+
resolve({ code: body.code ?? 1, msg: body.message ?? "上传成功", data: body.data ?? "" });
|
|
188
|
+
} catch {
|
|
189
|
+
resolve({ code: 1, msg: "上传成功", data: res.data });
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
reject(new Error("上传失败"));
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
fail: (err) => reject(new Error(err.errMsg || "上传失败"))
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
_buildUrl(url) {
|
|
200
|
+
if (/^https?:\/\//.test(url))
|
|
201
|
+
return url;
|
|
202
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
203
|
+
return `${this._baseURL}${url}${sep}_t=${Date.now()}`;
|
|
204
|
+
}
|
|
205
|
+
async _doRequest(url, cfg) {
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
uni.request({
|
|
208
|
+
url,
|
|
209
|
+
method: cfg.method,
|
|
210
|
+
data: cfg.data,
|
|
211
|
+
header: cfg.headers,
|
|
212
|
+
success: (res) => {
|
|
213
|
+
var _a;
|
|
214
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
215
|
+
resolve(res.data);
|
|
216
|
+
} else {
|
|
217
|
+
const msg = ((_a = res.data) == null ? void 0 : _a.message) ?? `请求失败: ${res.statusCode}`;
|
|
218
|
+
reject(new Error(msg));
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
fail: (err) => reject(new Error(err.errMsg || "网络请求失败"))
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
async _applyErrorInterceptors(err) {
|
|
226
|
+
for (const fn of this._errInterceptors) {
|
|
227
|
+
await fn(err);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
new HttpClient({
|
|
232
|
+
baseURL: define_import_meta_env_default.VITE_API_BASE_URL ?? ""
|
|
233
|
+
});
|
|
234
|
+
const _info = vue.ref(null);
|
|
235
|
+
function collect() {
|
|
236
|
+
var _a;
|
|
237
|
+
const sys = uni.getSystemInfoSync();
|
|
238
|
+
let appid = "";
|
|
239
|
+
try {
|
|
240
|
+
const accountInfo = uni.getAccountInfoSync();
|
|
241
|
+
appid = ((_a = accountInfo == null ? void 0 : accountInfo.miniProgram) == null ? void 0 : _a.appId) || "";
|
|
242
|
+
} catch {
|
|
243
|
+
appid = sys.appId || "";
|
|
244
|
+
}
|
|
245
|
+
let appName = "";
|
|
246
|
+
let appVersion = "";
|
|
247
|
+
let appVersionCode = "";
|
|
248
|
+
let hostName = "";
|
|
249
|
+
let hostVersion = "";
|
|
250
|
+
let hostLanguage = "";
|
|
251
|
+
let hostTheme = "";
|
|
252
|
+
try {
|
|
253
|
+
const appInfo = uni.getAppBaseInfo();
|
|
254
|
+
appName = appInfo.appName || "";
|
|
255
|
+
appVersion = appInfo.appVersion || "";
|
|
256
|
+
appVersionCode = appInfo.appVersionCode || "";
|
|
257
|
+
hostName = appInfo.hostName || "";
|
|
258
|
+
hostVersion = appInfo.hostVersion || "";
|
|
259
|
+
hostLanguage = appInfo.hostLanguage || "";
|
|
260
|
+
hostTheme = appInfo.hostTheme || "";
|
|
261
|
+
} catch {
|
|
262
|
+
appVersion = sys.appVersion || "";
|
|
263
|
+
}
|
|
264
|
+
const deviceBrand = sys.deviceBrand || "";
|
|
265
|
+
const deviceModel = sys.deviceModel || "";
|
|
266
|
+
const deviceId = sys.deviceId || "";
|
|
267
|
+
const deviceType = sys.deviceType || "";
|
|
268
|
+
const deviceOrientation = sys.deviceOrientation || "portrait";
|
|
269
|
+
const system = sys.system || "";
|
|
270
|
+
return {
|
|
271
|
+
appid,
|
|
272
|
+
app_name: appName,
|
|
273
|
+
app_version: appVersion,
|
|
274
|
+
app_version_code: appVersionCode,
|
|
275
|
+
app_channel: sys.appChannel || "",
|
|
276
|
+
device_brand: deviceBrand,
|
|
277
|
+
device_model: deviceModel,
|
|
278
|
+
device_id: deviceId,
|
|
279
|
+
device_type: deviceType,
|
|
280
|
+
device_orientation: deviceOrientation,
|
|
281
|
+
brand: sys.brand || "",
|
|
282
|
+
model: sys.model || "",
|
|
283
|
+
system,
|
|
284
|
+
os: system.split(" ")[0] || "",
|
|
285
|
+
pixel_ratio: sys.pixelRatio || 0,
|
|
286
|
+
screen_width: sys.screenWidth || 0,
|
|
287
|
+
screen_height: sys.screenHeight || 0,
|
|
288
|
+
window_width: sys.windowWidth || 0,
|
|
289
|
+
window_height: sys.windowHeight || 0,
|
|
290
|
+
status_bar_height: sys.statusBarHeight || 0,
|
|
291
|
+
sdk_version: sys.SDKVersion || "",
|
|
292
|
+
host_name: hostName,
|
|
293
|
+
host_version: hostVersion,
|
|
294
|
+
host_language: hostLanguage,
|
|
295
|
+
host_theme: hostTheme,
|
|
296
|
+
platform: sys.platform || "",
|
|
297
|
+
language: sys.language || "",
|
|
298
|
+
version: sys.version || ""
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function ensure() {
|
|
302
|
+
if (!_info.value) {
|
|
303
|
+
_info.value = collect();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function useDevice() {
|
|
307
|
+
ensure();
|
|
308
|
+
return _info;
|
|
309
|
+
}
|
|
310
|
+
useDevice();
|