uview-pro 0.0.3 → 0.0.4

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 (74) hide show
  1. package/changelog.md +25 -1
  2. package/components/u-action-sheet/u-action-sheet.vue +4 -4
  3. package/components/u-avatar/u-avatar.vue +1 -1
  4. package/components/u-badge/u-badge.vue +1 -1
  5. package/components/u-button/u-button.vue +1 -1
  6. package/components/u-card/u-card.vue +1 -1
  7. package/components/u-cell-group/u-cell-group.vue +1 -1
  8. package/components/u-cell-item/u-cell-item.vue +1 -1
  9. package/components/u-checkbox/u-checkbox.vue +1 -1
  10. package/components/u-checkbox-group/u-checkbox-group.vue +1 -1
  11. package/components/u-circle-progress/u-circle-progress.vue +1 -1
  12. package/components/u-col/u-col.vue +1 -1
  13. package/components/u-collapse/u-collapse.vue +1 -1
  14. package/components/u-collapse-item/u-collapse-item.vue +2 -2
  15. package/components/u-count-down/u-count-down.vue +1 -1
  16. package/components/u-count-to/u-count-to.vue +1 -1
  17. package/components/u-divider/u-divider.vue +1 -1
  18. package/components/u-empty/u-empty.vue +1 -1
  19. package/components/u-field/u-field.vue +1 -1
  20. package/components/u-gap/u-gap.vue +1 -1
  21. package/components/u-grid/u-grid.vue +1 -1
  22. package/components/u-grid-item/u-grid-item.vue +1 -1
  23. package/components/u-icon/u-icon.vue +29 -23
  24. package/components/u-index-anchor/u-index-anchor.vue +1 -1
  25. package/components/u-index-list/u-index-list.vue +1 -1
  26. package/components/u-keyboard/u-keyboard.vue +1 -1
  27. package/components/u-lazy-load/u-lazy-load.vue +1 -1
  28. package/components/u-line/u-line.vue +1 -1
  29. package/components/u-line-progress/u-line-progress.vue +1 -1
  30. package/components/u-link/u-link.vue +1 -1
  31. package/components/u-loading/u-loading.vue +1 -1
  32. package/components/u-loadmore/u-loadmore.vue +1 -1
  33. package/components/u-mask/u-mask.vue +1 -1
  34. package/components/u-message-input/u-message-input.vue +1 -1
  35. package/components/u-modal/u-modal.vue +1 -1
  36. package/components/u-navbar/u-navbar.vue +1 -1
  37. package/components/u-no-network/u-no-network.vue +1 -1
  38. package/components/u-notice-bar/u-notice-bar.vue +1 -1
  39. package/components/u-number-box/u-number-box.vue +1 -1
  40. package/components/u-picker/u-picker.vue +1 -1
  41. package/components/u-popup/u-popup.vue +1 -1
  42. package/components/u-radio/u-radio.vue +1 -1
  43. package/components/u-radio-group/u-radio-group.vue +1 -1
  44. package/components/u-rate/u-rate.vue +1 -1
  45. package/components/u-read-more/u-read-more.vue +1 -1
  46. package/components/u-row/u-row.vue +1 -1
  47. package/components/u-search/u-search.vue +1 -1
  48. package/components/u-section/u-section.vue +1 -1
  49. package/components/u-skeleton/u-skeleton.vue +1 -1
  50. package/components/u-steps/u-steps.vue +1 -1
  51. package/components/u-sticky/u-sticky.vue +1 -1
  52. package/components/u-subsection/u-subsection.vue +1 -1
  53. package/components/u-swipe-action/u-swipe-action.vue +1 -1
  54. package/components/u-swiper/u-swiper.vue +1 -1
  55. package/components/u-switch/u-switch.vue +1 -1
  56. package/components/u-table/u-table.vue +1 -1
  57. package/components/u-tabs/u-tabs.vue +1 -1
  58. package/components/u-tabs-swiper/u-tabs-swiper.vue +1 -1
  59. package/components/u-tag/u-tag.vue +1 -1
  60. package/components/u-td/u-td.vue +1 -1
  61. package/components/u-th/u-th.vue +1 -1
  62. package/components/u-time-line/u-time-line.vue +1 -1
  63. package/components/u-time-line-item/u-time-line-item.vue +1 -1
  64. package/components/u-toast/u-toast.vue +1 -1
  65. package/components/u-top-tips/u-top-tips.vue +1 -1
  66. package/components/u-tr/u-tr.vue +1 -1
  67. package/components/u-upload/u-upload.vue +1 -1
  68. package/components/u-verification-code/u-verification-code.vue +1 -1
  69. package/components/u-waterfall/u-waterfall.vue +1 -1
  70. package/libs/function/md5.ts +3 -1
  71. package/libs/request/uni-http.md +156 -0
  72. package/libs/request/uni-http.ts +373 -0
  73. package/package.json +1 -1
  74. package/readme.md +24 -10
@@ -0,0 +1,373 @@
1
+ /**
2
+ * 通用 uni-app 网络请求,uni.request
3
+ * 基于 Promise 对象实现更简单的 request 使用方式,支持请求和响应拦截
4
+ * @author anyup
5
+ */
6
+
7
+ // 请求内容类型枚举
8
+ export enum ContentType {
9
+ JSON = 'application/json;charset=UTF-8',
10
+ URLENCODED = 'application/x-www-form-urlencoded',
11
+ FORMDATA = 'multipart/form-data'
12
+ }
13
+
14
+ // 请求方法类型
15
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'HEAD' | 'DELETE' | 'UPLOAD';
16
+
17
+ // 请求头类型
18
+ export type HttpHeaderType = Record<string, string>;
19
+
20
+ // 请求配置类型
21
+ export interface HttpRequestConfig {
22
+ baseURL?: string;
23
+ url?: string;
24
+ header?: HttpHeaderType;
25
+ data?: any;
26
+ method?: HttpMethod;
27
+ dataType?: string;
28
+ responseType?: string;
29
+ success?: (res: any) => void;
30
+ fail?: (err: any) => void;
31
+ complete?: (res: any) => void;
32
+ [key: string]: any;
33
+ }
34
+
35
+ // 拦截器类型
36
+ export interface Interceptor<T = any> {
37
+ handler?: (arg: T, P: typeof Promise) => any;
38
+ onerror?: (arg: T, P: typeof Promise) => any;
39
+ complete?: (arg: T, P: typeof Promise) => any;
40
+ use: (...args: any[]) => void;
41
+ lock?: () => void;
42
+ unlock?: () => void;
43
+ clear?: () => void;
44
+ p?: Promise<any> | null;
45
+ }
46
+
47
+ /**
48
+ * HttpHeader 构造器,自动处理 Content-Type
49
+ */
50
+ export class HttpHeader {
51
+ [key: string]: string;
52
+ constructor(params: HttpHeaderType) {
53
+ Object.keys(params).forEach(key => {
54
+ if (key === 'Content-Type') {
55
+ this[key] = ContentType[params[key] as keyof typeof ContentType] || params[key];
56
+ } else {
57
+ this[key] = params[key];
58
+ }
59
+ });
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Builder 用于批量生成 API 方法
65
+ */
66
+ export class Builder {
67
+ private http: Http;
68
+ constructor(http: Http) {
69
+ this.http = http;
70
+ }
71
+ /**
72
+ * 根据 url 配置表批量生成 API 方法
73
+ */
74
+ dispatch(urls: Record<string, any>) {
75
+ const obj: Record<string, any> = {};
76
+ Object.keys(urls).forEach(name => {
77
+ obj[name] = this.use.bind(this, urls[name]);
78
+ });
79
+ return obj;
80
+ }
81
+ /**
82
+ * 发送请求
83
+ */
84
+ use(urlConfig: Record<string, any>, data?: any, config: HttpRequestConfig = {}) {
85
+ let url: string = config.url || urlConfig.url;
86
+ const append: string = config.append || '';
87
+ url = url + append;
88
+ const defaultFn = (res: any) => res;
89
+ const successFn: (res: any) => any = config.success || defaultFn;
90
+ // 只传递一个参数,避免类型不符
91
+ const callbackFn = (res: any) => successFn(res);
92
+ return this.http.request({ url, data, ...urlConfig, ...config }).then(callbackFn);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Http 主类,支持拦截器、链式配置、类型完善
98
+ */
99
+ export class Http {
100
+ static Builder = Builder;
101
+ config: HttpRequestConfig;
102
+ interceptors: {
103
+ response: Interceptor;
104
+ request: Interceptor;
105
+ };
106
+
107
+ constructor(options: HttpRequestConfig = {}) {
108
+ this.config = {
109
+ baseURL: '',
110
+ header: new HttpHeader({ 'Content-Type': 'JSON' }),
111
+ data: {},
112
+ method: 'GET',
113
+ dataType: 'json',
114
+ responseType: 'text',
115
+ success() {},
116
+ fail() {},
117
+ complete() {},
118
+ ...options
119
+ };
120
+ this.interceptors = {
121
+ response: {
122
+ use(handler, onerror, complete) {
123
+ this.handler = handler;
124
+ this.onerror = onerror;
125
+ this.complete = complete;
126
+ }
127
+ },
128
+ request: {
129
+ use(handler) {
130
+ this.handler = handler;
131
+ }
132
+ }
133
+ };
134
+ wrap(this.interceptors.request);
135
+ wrap(this.interceptors.response);
136
+ }
137
+
138
+ /**
139
+ * 设置 baseURL
140
+ */
141
+ setBaseURL(baseURL: string) {
142
+ this.config.baseURL = baseURL;
143
+ return this;
144
+ }
145
+
146
+ /**
147
+ * 设置 header
148
+ */
149
+ setHeader(header: HttpHeaderType) {
150
+ this.config.header = { ...this.config.header, ...header };
151
+ return this;
152
+ }
153
+
154
+ /**
155
+ * 设置 data
156
+ */
157
+ setData(data: any) {
158
+ if (isArray(data)) {
159
+ this.config.data = data;
160
+ } else {
161
+ this.config.data = { ...this.config.data, ...data };
162
+ }
163
+ return this;
164
+ }
165
+
166
+ /**
167
+ * 设置其他 options
168
+ */
169
+ setOptions(options: HttpRequestConfig) {
170
+ this.config = { ...this.config, ...options };
171
+ }
172
+
173
+ /**
174
+ * 请求主方法
175
+ * @param options 实时传递的配置
176
+ * @returns Promise
177
+ * 说明:配置优先级 实时传递的 options > 公共配置的 config
178
+ */
179
+ request<T = any>(options: HttpRequestConfig = {}): Promise<T> {
180
+ if (!options) options = {};
181
+ // 请求体
182
+ const data = options.data || {};
183
+ // 请求baseURL:优先级为:实时传递的 > 公共配置的
184
+ options.baseURL = options.baseURL !== undefined ? options.baseURL : this.config.baseURL;
185
+ // 请求头:合并公共配置与实时设置的header, 且优先级实时设置会覆盖公共配置的
186
+ options.header = { ...this.config.header, ...options.header };
187
+ // 请求方式:优先级为:实时传递的 > 公共配置的
188
+ options.method = options.method || this.config.method;
189
+ // 数据格式:默认json
190
+ options.dataType = options.dataType || this.config.dataType;
191
+ // 请求体:优先级为:实时传递的 > 公共配置的
192
+ if (isArray(data)) {
193
+ options.data = data;
194
+ } else {
195
+ options.data = { ...this.config.data, ...data };
196
+ }
197
+
198
+ // 拦截器处理
199
+ const interceptors = this.interceptors;
200
+ const requestInterceptor = interceptors.request;
201
+ const responseInterceptor = interceptors.response;
202
+ const requestInterceptorHandler = requestInterceptor.handler;
203
+
204
+ return new Promise((resolve: (value: T) => void, reject: (reason?: any) => void) => {
205
+ function isPromise(p: any): p is Promise<any> {
206
+ return p && typeof p.then === 'function' && typeof p.catch === 'function';
207
+ }
208
+ function enqueueIfLocked(promise: Promise<any> | null | undefined, callback: () => void) {
209
+ if (promise) {
210
+ promise.then(() => {
211
+ callback();
212
+ });
213
+ } else {
214
+ callback();
215
+ }
216
+ }
217
+ function onresult(
218
+ handler: ((arg: any, P: typeof Promise) => any) | undefined,
219
+ response: any,
220
+ type: number
221
+ ) {
222
+ enqueueIfLocked(responseInterceptor.p, function () {
223
+ if (handler) {
224
+ response.request = options;
225
+ const ret = handler.call(responseInterceptor, response, Promise);
226
+ response = ret === undefined ? response : ret;
227
+ }
228
+ if (!isPromise(response)) {
229
+ response = Promise[type === 0 ? 'resolve' : 'reject'](response);
230
+ }
231
+ response
232
+ .then((d: any) => {
233
+ resolve(d.data);
234
+ })
235
+ .catch((e: any) => {
236
+ reject(e);
237
+ });
238
+ });
239
+ }
240
+ options.complete = (response: any) => {
241
+ const statusCode: number = response.statusCode;
242
+ let type = 0;
243
+ if ((statusCode >= 200 && statusCode < 300) || statusCode === 304) {
244
+ type = 0;
245
+ onresult(responseInterceptor.handler, response, type);
246
+ } else {
247
+ type = -1;
248
+ onresult(responseInterceptor.onerror, response, type);
249
+ }
250
+ onresult(responseInterceptor.complete, response, type);
251
+ };
252
+ enqueueIfLocked(requestInterceptor.p, () => {
253
+ options = Object.assign({}, this.config, options);
254
+ options.requestId = new Date().getTime();
255
+ let ret: any = options;
256
+ if (requestInterceptorHandler) {
257
+ ret = requestInterceptorHandler.call(requestInterceptor, options, Promise) || options;
258
+ }
259
+ if (!isPromise(ret)) {
260
+ ret = Promise.resolve(ret);
261
+ }
262
+ ret.then(
263
+ (d: any) => {
264
+ if (d === options) {
265
+ d.url = d.url && d.url.indexOf('http') !== 0 ? d.baseURL + d.url : d.url;
266
+ d.url = d.restURL ? d.url + d.restURL : d.url;
267
+ d.method = d.method.toUpperCase();
268
+ d.method === 'UPLOAD' ? uni.uploadFile(d) : uni.request(d);
269
+ } else {
270
+ resolve(d);
271
+ }
272
+ },
273
+ (err: any) => {
274
+ reject(err);
275
+ }
276
+ );
277
+ });
278
+ });
279
+ }
280
+
281
+ /**
282
+ * 并发请求
283
+ */
284
+ all<T = any>(promises: Promise<T>[]): Promise<T[]> {
285
+ return Promise.all(promises);
286
+ }
287
+
288
+ // 动态方法扩展:get/post/put/patch/head/delete/upload
289
+ [key: string]: any;
290
+ }
291
+
292
+ ['get', 'post', 'put', 'patch', 'head', 'delete', 'upload'].forEach(e => {
293
+ Http.prototype[e] = function (url: string, data?: any, option?: HttpRequestConfig) {
294
+ return this.request(merge({ url, data, method: e.toUpperCase() }, option));
295
+ };
296
+ });
297
+
298
+ ['lock', 'unlock', 'clear'].forEach(e => {
299
+ Http.prototype[e] = function () {
300
+ const fn = this.interceptors.request[e as keyof Interceptor];
301
+ if (typeof fn === 'function') {
302
+ // 只传递 this 作为上下文,不传参数,适配所有类型
303
+ (fn as () => void).call(this.interceptors.request);
304
+ }
305
+ };
306
+ });
307
+
308
+ // 数据合并
309
+ function merge(a: any, b: any): any {
310
+ for (const key in b) {
311
+ if (!a.hasOwnProperty(key)) {
312
+ a[key] = b[key];
313
+ } else if (isObject(b[key], 1) && isObject(a[key], 1)) {
314
+ merge(a[key], b[key]);
315
+ }
316
+ }
317
+ return a;
318
+ }
319
+
320
+ function isObject(ob: any, real?: number): boolean {
321
+ if (real) {
322
+ return Object.prototype.toString.call(ob).slice(8, -1).toLowerCase() === 'object';
323
+ } else {
324
+ return ob && typeof ob === 'object';
325
+ }
326
+ }
327
+
328
+ function isArray(value: any): value is any[] {
329
+ return Array.isArray(value);
330
+ }
331
+
332
+ function wrap(interceptor: Interceptor) {
333
+ let resolve: ((value?: unknown) => void) | null;
334
+ let reject: ((reason?: any) => void) | null;
335
+ function _clear() {
336
+ interceptor.p = resolve = reject = null;
337
+ }
338
+ merge(interceptor, {
339
+ lock() {
340
+ if (!resolve) {
341
+ interceptor.p = new Promise((_resolve, _reject) => {
342
+ resolve = _resolve;
343
+ reject = _reject;
344
+ });
345
+ }
346
+ },
347
+ unlock() {
348
+ if (resolve) {
349
+ resolve();
350
+ _clear();
351
+ }
352
+ },
353
+ clear() {
354
+ if (reject) {
355
+ reject('cancel');
356
+ _clear();
357
+ }
358
+ }
359
+ });
360
+ }
361
+
362
+ /**
363
+ * useHttp hooks 工厂函数,推荐唯一入口
364
+ * @param options 可选的全局配置
365
+ * @returns http 实例(包含 get/post/put/delete 等方法和拦截器)
366
+ */
367
+ export function useHttp(options: HttpRequestConfig = {}) {
368
+ const http = new Http(options);
369
+ return http;
370
+ }
371
+
372
+ // 只导出 useHttp,不再导出 Http 类实例化方式
373
+ export default useHttp;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "uview-pro",
3
3
  "name": "uview-pro",
4
4
  "displayName": "uView Pro是uni-app全面兼容Vue3+TS的uni-app生态框架,70+精选组件",
5
- "version": "0.0.3",
5
+ "version": "0.0.4",
6
6
  "description": "uView Pro,是uni-app全面兼容Vue3的uni-app生态框架,70+精选组件已使用TypeScript重构,已全面支持uni-app Vue3.0",
7
7
  "main": "index.ts",
8
8
  "module": "index.ts",
package/readme.md CHANGED
@@ -9,6 +9,10 @@
9
9
  [![stars](https://img.shields.io/github/stars/anyup/uView-Pro?style=flat-square&logo=GitHub)](https://github.com/anyup/uView-Pro)
10
10
  [![forks](https://img.shields.io/github/forks/anyup/uView-Pro?style=flat-square&logo=GitHub)](https://github.com/anyup/uView-Pro)
11
11
  [![issues](https://img.shields.io/github/issues/anyup/uView-Pro?style=flat-square&logo=GitHub)](https://github.com/anyup/uView-Pro/issues)
12
+ [![npm version](https://img.shields.io/npm/v/uview-pro)](https://www.npmjs.com/package/uview-pro)
13
+ [![Website](https://img.shields.io/badge/uView%20Pro-docs-blue?style=flat-square)](https://uview-pro.anyup.cn/)
14
+ [![node version](https://img.shields.io/badge/node-%3E%3D18-green)](https://nodejs.org/)
15
+ [![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green)](https://pnpm.io/)
12
16
  [![license](https://img.shields.io/github/license/anyup/uView-Pro?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
13
17
 
14
18
  ## 说明
@@ -17,12 +21,12 @@ uView UI,是 [uni-app](https://uniapp.dcloud.io/) 生态优秀的 UI 框架,
17
21
 
18
22
  uView Pro,是全面支持 Vue3.0、TypeScript 的 uni-app 生态框架,uView Pro 的基线版本是基于 uView 1.8.8 修改,使用 TypeScript 完全重构,目前已全面支持 uni-app Vue3.0。
19
23
 
20
- ## [官方文档:https://uview-pro.anyup.cn/](https://uview-pro.anyup.cn/)
24
+ ## [官方文档:https://uview-pro.netlify.app/](https://uview-pro.netlify.app/)
21
25
 
22
26
  ## 特性
23
27
 
24
28
  - 兼容安卓,iOS,微信小程序,H5,QQ 小程序,百度小程序,支付宝小程序,头条小程序
25
- - 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
29
+ - 70+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
26
30
  - 众多贴心的 JS 利器,让您飞镖在手,召之即来,百步穿杨
27
31
  - 众多的常用页面和布局,让您专注逻辑,事半功倍
28
32
  - 详尽的文档支持,现代化的演示效果
@@ -52,13 +56,11 @@ pnpm install
52
56
  pnpm dev
53
57
  ```
54
58
 
55
-
56
-
57
59
  ## 链接
58
60
 
59
61
  - [Github](https://github.com/anyup/uview-pro)
60
62
  - [Gitee](https://gitee.com/anyup/uview-pro)
61
- - [官方文档](https://uview-pro.anyup.cn/)
63
+ - [官方文档](https://uview-pro.netlify.app/)
62
64
  - [更新日志](https://github.com/anyup/uView-Pro/blob/master/src/uni_modules/uview-pro/changelog.md)
63
65
 
64
66
  ## 交流反馈
@@ -99,7 +101,7 @@ pnpm add uview-pro
99
101
 
100
102
  #### **插件市场下载**
101
103
 
102
- [https://p.dcloud.net.cn/plugin?name=uview-pro](https://p.dcloud.net.cn/plugin?name=uview-pro)
104
+ [https://ext.dcloud.net.cn/plugin?id=24633](https://ext.dcloud.net.cn/plugin?id=24633)
103
105
 
104
106
  ## 快速上手
105
107
 
@@ -108,7 +110,10 @@ pnpm add uview-pro
108
110
  ```js
109
111
  // main.ts
110
112
  import { createSSRApp } from 'vue';
113
+ // npm安装方式
111
114
  import uViewPro from 'uview-pro';
115
+ // uni_modules安装方式
116
+ // import uViewPro from '@/uni_modules/uview-pro';
112
117
 
113
118
  export function createApp() {
114
119
  const app = createSSRApp(App);
@@ -125,15 +130,22 @@ export function createApp() {
125
130
  ```css
126
131
  /* App.vue */
127
132
  <style lang="scss">
133
+ /* npm安装方式 */
128
134
  @import "uview-pro/index.scss";
135
+
136
+ /* uni_modules安装方式 */
137
+ /* @import "@/uni_modules/uview-pro/index.scss"; */
129
138
  </style>
130
139
  ```
131
140
 
132
141
  3. `uni.scss`引入全局 scss 变量文件
133
142
 
134
143
  ```css
135
- /* uni.scss */
144
+ /* npm安装方式 */
136
145
  @import 'uview-pro/theme.scss';
146
+
147
+ /* uni_modules安装方式 */
148
+ /* @import '@/uni_modules/uview-pro/theme.scss'; */
137
149
  ```
138
150
 
139
151
  4. `pages.json`配置 easycom 规则(按需引入)
@@ -142,7 +154,7 @@ export function createApp() {
142
154
  // pages.json
143
155
  {
144
156
  "easycom": {
145
- // uni_modules安装的方式需要前面的"@/",npm安装的方式无需"@/"
157
+ // uni_modules安装的方式需要前面的"@/uni_modules/",npm安装的方式无需"@/",以下方式任选其一
146
158
  // npm安装方式
147
159
  "^u-(.*)": "uview-pro/components/u-$1/u-$1.vue"
148
160
  // uni_modules安装方式
@@ -155,19 +167,21 @@ export function createApp() {
155
167
  }
156
168
  ```
157
169
 
158
- 请通过[快速上手](https://www.anyup.cn/docs/components/quickstart.html)了解更详细的内容
170
+ 请通过[快速上手](https://uview-pro.netlify.app/components/quickstart.html)了解更详细的内容
159
171
 
160
172
  ## 使用方法
161
173
 
162
174
  配置 easycom 规则后,自动按需引入,无需`import`组件,直接引用即可。
163
175
 
176
+ > 注意:配置完以上规则后,一定要重新运行 uni-app 项目,否则不会生效
177
+
164
178
  ```html
165
179
  <template>
166
180
  <u-button>按钮</u-button>
167
181
  </template>
168
182
  ```
169
183
 
170
- 请通过[快速上手](https://www.anyup.cn/docs/components/quickstart.html)了解更详细的内容
184
+ 请通过[快速上手](https://uview-pro.netlify.app/components/quickstart.html)了解更详细的内容
171
185
 
172
186
  ## 捐赠 uView Pro
173
187