jmash-core-mp 0.1.1 → 0.1.3
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 +14 -3
- package/package.json +3 -1
- package/src/api/auth/index.ts +62 -16
- package/src/api/auth/types.ts +52 -1
- package/src/api/files/index.ts +37 -55
- package/src/app.mpx +16 -10
- package/src/components/auth-user/jmash-logout.mpx +91 -0
- package/src/components/auth-user/jmash-update-user.mpx +381 -0
- package/src/components/auth-user/jmash-update-user.web.mpx +365 -0
- package/src/components/auth-user/jmash-user.mpx +256 -46
- package/src/components/common/jmash-menu.mpx +129 -0
- package/src/components/common/jmash-tab-bar.mpx +2 -2
- package/src/components/core/jmash-login.ali.mpx +284 -0
- package/src/components/core/jmash-login.mpx +20 -15
- package/src/components/core/jmash-login.web.mpx +421 -0
- package/src/components/core/jmash-popup-login.ali.mpx +311 -0
- package/src/components/core/jmash-popup-login.mpx +6 -4
- package/src/components/core/jmash-popup-login.web.mpx +389 -0
- package/src/custom-tab-bar/index.mpx +0 -1
- package/src/global.d.ts +10 -3
- package/src/index.ts +2 -1
- package/src/packages/index.mpx +1 -0
- package/src/packages/pages/auth/cms-protocol.mpx +1 -1
- package/src/packages/pages/auth/login.mpx +10 -14
- package/src/packages/pages/auth/update-user.mpx +18 -0
- package/src/pages/half-home.mpx +3 -2
- package/src/pages/home.mpx +14 -11
- package/src/pages/index.mpx +0 -1
- package/src/pages/tabbar/home.mpx +7 -4
- package/src/pages/tabbar/my.mpx +53 -13
- package/src/store/user.ts +268 -0
- package/src/styles/index.scss +24 -5
- package/src/utils/config.ts +1 -1
- package/src/utils/db.ts +1 -1
- package/src/utils/net.ts +18 -0
- package/src/utils/request.ts +20 -9
- package/src/components/auth-user/jmash-update-user/index.mpx +0 -31
- package/src/components/common/auth-avatar/avatar-edit/index.mpx +0 -31
- package/src/stores/setup.js +0 -15
- package/src/utils/auth.ts +0 -270
- /package/src/components/common/{auth-search/index.mpx → auth-search.mpx} +0 -0
package/README.md
CHANGED
|
@@ -34,10 +34,21 @@ npm run build -- --targets=wx,ali,web
|
|
|
34
34
|
|
|
35
35
|
登录
|
|
36
36
|
minidev login
|
|
37
|
-
预览
|
|
38
|
-
minidev preview --app-id 2021006137629651
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
调试开发
|
|
39
|
+
minidev dev
|
|
40
|
+
|
|
41
|
+
本地 IP 调试
|
|
42
|
+
minidev dev --host 192.168.1.154
|
|
43
|
+
|
|
44
|
+
真机调试
|
|
45
|
+
minidev remote-debug -a 2021006137629651
|
|
46
|
+
|
|
47
|
+
Web 端调试
|
|
48
|
+
minidev dev
|
|
49
|
+
web -a 2021006137629651
|
|
50
|
+
真机预览
|
|
51
|
+
minidev preview -a 2021006137629651
|
|
41
52
|
|
|
42
53
|
# pnpm publish --no-git-checks
|
|
43
54
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jmash-core-mp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"dependencies": {
|
|
6
|
+
"sm-crypto": "^0.4.0",
|
|
6
7
|
"@mpxjs/api-proxy": "^2.10.19",
|
|
7
8
|
"@mpxjs/core": "^2.10.19",
|
|
8
9
|
"@mpxjs/fetch": "^2.10.19",
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
"@babel/plugin-transform-runtime": "^7.10.4",
|
|
23
24
|
"@babel/preset-env": "^7.10.4",
|
|
24
25
|
"@babel/runtime-corejs3": "^7.10.4",
|
|
26
|
+
"@mini-types/global": "^1.0.33",
|
|
25
27
|
"@mpxjs/babel-plugin-inject-page-events": "^2.9.0",
|
|
26
28
|
"@mpxjs/eslint-config": "^2.0.3",
|
|
27
29
|
"@mpxjs/miniprogram-simulate": "^1.4.17",
|
package/src/api/auth/index.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ResponseData } from "../../types/core";
|
|
2
|
+
import { OpensType } from "./types";
|
|
2
3
|
import type {
|
|
3
4
|
LoginReq,
|
|
4
5
|
LoginRes,
|
|
5
6
|
RolesPerms,
|
|
7
|
+
WebLoginReq,
|
|
6
8
|
TokenModel,
|
|
7
|
-
|
|
9
|
+
PhoneRegisterReq,
|
|
10
|
+
PhoneReplaceReq,
|
|
8
11
|
UpdateUserReq,
|
|
9
12
|
UserInfoReq,
|
|
10
13
|
UserInfo,
|
|
@@ -15,23 +18,77 @@ import { config } from "../../utils/config";
|
|
|
15
18
|
import mpx from "@mpxjs/core";
|
|
16
19
|
|
|
17
20
|
class AuthApi {
|
|
18
|
-
//
|
|
19
|
-
|
|
21
|
+
// 小程序静默登录
|
|
22
|
+
mpLogin(data: LoginReq): Promise<ResponseData<LoginRes>> {
|
|
23
|
+
if (__mpx_mode__ === "wx") {
|
|
24
|
+
data.opensType = OpensType.wechat;
|
|
25
|
+
}
|
|
26
|
+
if (__mpx_mode__ === "ali") {
|
|
27
|
+
data.opensType = OpensType.ali_pay;
|
|
28
|
+
}
|
|
20
29
|
return mpx.xfetch.fetch({
|
|
21
30
|
url: "/v1/front/rbac/miniapp_login/" + config.tenant,
|
|
22
31
|
method: "POST",
|
|
23
32
|
data,
|
|
24
|
-
header: {
|
|
33
|
+
header: {
|
|
34
|
+
"content-type": "application/json",
|
|
35
|
+
Authorization: false,
|
|
36
|
+
},
|
|
25
37
|
});
|
|
26
38
|
}
|
|
39
|
+
|
|
27
40
|
// 手机号注册登录
|
|
28
|
-
|
|
41
|
+
mpPhoneRegister(data: PhoneRegisterReq): Promise<ResponseData<LoginRes>> {
|
|
42
|
+
if (__mpx_mode__ === "wx") {
|
|
43
|
+
data.opensType = OpensType.wechat;
|
|
44
|
+
}
|
|
45
|
+
if (__mpx_mode__ === "ali") {
|
|
46
|
+
data.opensType = OpensType.ali_pay;
|
|
47
|
+
}
|
|
29
48
|
return mpx.xfetch.fetch({
|
|
30
49
|
url: "/v1/front/rbac/miniapp_phonenumber/" + config.tenant,
|
|
31
50
|
method: "POST",
|
|
32
51
|
data: data,
|
|
52
|
+
header: {
|
|
53
|
+
Authorization: false,
|
|
54
|
+
},
|
|
33
55
|
});
|
|
34
56
|
}
|
|
57
|
+
|
|
58
|
+
// 已登陆状态小程序更换绑定手机号
|
|
59
|
+
replaceBindphone(data: PhoneReplaceReq): Promise<ResponseData<string>> {
|
|
60
|
+
data.tenant = config.tenant;
|
|
61
|
+
if (__mpx_mode__ === "wx") {
|
|
62
|
+
data.opensType = OpensType.wechat;
|
|
63
|
+
}
|
|
64
|
+
if (__mpx_mode__ === "ali") {
|
|
65
|
+
data.opensType = OpensType.ali_pay;
|
|
66
|
+
}
|
|
67
|
+
grpc.clearEmpty(data);
|
|
68
|
+
return mpx.xfetch.fetch({
|
|
69
|
+
url: "/v1/front/rbac/miniapp_bindphone",
|
|
70
|
+
method: "POST",
|
|
71
|
+
data: data,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//web登录.
|
|
76
|
+
webLogin(data: WebLoginReq): Promise<ResponseData<TokenModel>> {
|
|
77
|
+
data.tenant = config.tenant;
|
|
78
|
+
data.directoryId = "user";
|
|
79
|
+
data.clientId = config.appId ? config.appId : "h5";
|
|
80
|
+
data.captchaId = "1";
|
|
81
|
+
data.captchaCode = "1";
|
|
82
|
+
return mpx.xfetch.fetch({
|
|
83
|
+
url: "/v1/rbac/auth/login",
|
|
84
|
+
method: "POST",
|
|
85
|
+
data: data,
|
|
86
|
+
header: {
|
|
87
|
+
Authorization: false,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
35
92
|
// 刷新token
|
|
36
93
|
refreshToken(): Promise<ResponseData<TokenModel>> {
|
|
37
94
|
return mpx.xfetch.fetch({
|
|
@@ -141,17 +198,6 @@ class AuthApi {
|
|
|
141
198
|
});
|
|
142
199
|
}
|
|
143
200
|
|
|
144
|
-
// 已登陆状态小程序更换绑定手机号
|
|
145
|
-
replaceBindphone(data: PhoneNumberReq): Promise<ResponseData<string>> {
|
|
146
|
-
data.tenant = config.tenant;
|
|
147
|
-
grpc.clearEmpty(data);
|
|
148
|
-
return mpx.xfetch.fetch({
|
|
149
|
-
url: "/v1/front/rbac/miniapp_bindphone",
|
|
150
|
-
method: "POST",
|
|
151
|
-
data: data,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
201
|
// 获取当前会话用户的信息
|
|
156
202
|
findUserInfo(data: UserInfoReq): Promise<ResponseData<UserInfo>> {
|
|
157
203
|
data.tenant = config.tenant;
|
package/src/api/auth/types.ts
CHANGED
|
@@ -10,6 +10,15 @@ export interface TokenModel {
|
|
|
10
10
|
tokenType: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export enum OpensType {
|
|
14
|
+
//微信
|
|
15
|
+
wechat,
|
|
16
|
+
//支付宝
|
|
17
|
+
ali_pay,
|
|
18
|
+
//云闪付
|
|
19
|
+
union_pay,
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
// 登录接口传参定义
|
|
14
23
|
export interface LoginReq {
|
|
15
24
|
// 小程序APPID
|
|
@@ -18,6 +27,30 @@ export interface LoginReq {
|
|
|
18
27
|
loginCode: string;
|
|
19
28
|
// 小程序托管微信第三方平台(可选)
|
|
20
29
|
componentAppid?: string;
|
|
30
|
+
//登录类型
|
|
31
|
+
opensType?: OpensType;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 登录请求参数
|
|
36
|
+
*/
|
|
37
|
+
export interface WebLoginReq {
|
|
38
|
+
// 租户
|
|
39
|
+
tenant?: string;
|
|
40
|
+
// 目录ID
|
|
41
|
+
directoryId?: string;
|
|
42
|
+
//互斥角色
|
|
43
|
+
scope?: string;
|
|
44
|
+
//用户名
|
|
45
|
+
userName: string;
|
|
46
|
+
//加密密钥
|
|
47
|
+
encodePwd: string;
|
|
48
|
+
//验证码缓存key
|
|
49
|
+
captchaId?: string;
|
|
50
|
+
//验证码
|
|
51
|
+
captchaCode?: string;
|
|
52
|
+
// 客户ID
|
|
53
|
+
clientId?: string;
|
|
21
54
|
}
|
|
22
55
|
|
|
23
56
|
// 登录接口接收参数定义
|
|
@@ -33,7 +66,7 @@ export interface LoginRes {
|
|
|
33
66
|
}
|
|
34
67
|
|
|
35
68
|
// 获取手机号定义
|
|
36
|
-
export interface
|
|
69
|
+
export interface PhoneRegisterReq {
|
|
37
70
|
// 租户
|
|
38
71
|
tenant?: string;
|
|
39
72
|
// 小程序APPID
|
|
@@ -44,8 +77,26 @@ export interface PhoneNumberReq {
|
|
|
44
77
|
phoneCode: string;
|
|
45
78
|
// 昵称
|
|
46
79
|
nickName?: string;
|
|
80
|
+
// 头像
|
|
81
|
+
avatar?: string;
|
|
82
|
+
// 小程序托管微信第三方平台(可选)
|
|
83
|
+
componentAppid?: string;
|
|
84
|
+
//登录类型
|
|
85
|
+
opensType?: OpensType;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 手机号绑定接口
|
|
89
|
+
export interface PhoneReplaceReq {
|
|
90
|
+
// 租户
|
|
91
|
+
tenant?: string;
|
|
92
|
+
// 小程序APPID
|
|
93
|
+
appId: string;
|
|
94
|
+
// 获取手机号码
|
|
95
|
+
phoneCode: string;
|
|
47
96
|
// 小程序托管微信第三方平台(可选)
|
|
48
97
|
componentAppid?: string;
|
|
98
|
+
//登录类型
|
|
99
|
+
opensType?: OpensType;
|
|
49
100
|
}
|
|
50
101
|
|
|
51
102
|
// 刷新token
|
package/src/api/files/index.ts
CHANGED
|
@@ -88,66 +88,48 @@ class FileApi {
|
|
|
88
88
|
|
|
89
89
|
// 上传文件
|
|
90
90
|
uploadFile(file: string): Promise<FileInfo> {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
duration: 2000,
|
|
117
|
-
});
|
|
118
|
-
resolve({
|
|
119
|
-
code: response.statusCode,
|
|
120
|
-
message: response.errMsg,
|
|
121
|
-
data: JSON.parse(response.data),
|
|
122
|
-
} as any);
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
fail(error) {
|
|
126
|
-
reject(error);
|
|
127
|
-
},
|
|
128
|
-
});
|
|
91
|
+
const p = mpx.uploadFile({
|
|
92
|
+
url: this.uploadUrl(),
|
|
93
|
+
filePath: file,
|
|
94
|
+
name: "file",
|
|
95
|
+
header: {
|
|
96
|
+
"Content-Type": "multipart/form-data",
|
|
97
|
+
Authorization: db.getBearerToken(),
|
|
98
|
+
},
|
|
99
|
+
} as WechatMiniprogram.UploadFileOption) as any;
|
|
100
|
+
return p.then((res: any) => {
|
|
101
|
+
console.log("uploadFile", res);
|
|
102
|
+
if (res.statusCode === 200) {
|
|
103
|
+
return JSON.parse(res.data) as FileInfo;
|
|
104
|
+
} else if (res.statusCode === 401) {
|
|
105
|
+
// 清理登录信息
|
|
106
|
+
mpx.clearStorage();
|
|
107
|
+
throw new Error("登录过期,请重新登录");
|
|
108
|
+
} else {
|
|
109
|
+
mpx.showToast({
|
|
110
|
+
title: res.errMsg,
|
|
111
|
+
icon: "none",
|
|
112
|
+
duration: 2000,
|
|
113
|
+
});
|
|
114
|
+
return JSON.parse(res.data) as FileInfo;
|
|
115
|
+
}
|
|
129
116
|
});
|
|
130
117
|
}
|
|
131
118
|
|
|
132
119
|
// 上传文件
|
|
133
120
|
downloadFile(url: string): Promise<FileDownInfo> {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
},
|
|
147
|
-
fail(error) {
|
|
148
|
-
reject(error);
|
|
149
|
-
},
|
|
150
|
-
});
|
|
121
|
+
const p = mpx.downloadFile({
|
|
122
|
+
url: url,
|
|
123
|
+
header: {
|
|
124
|
+
Authorization: db.getBearerToken(),
|
|
125
|
+
},
|
|
126
|
+
}) as any;
|
|
127
|
+
return p.then((res: any) => {
|
|
128
|
+
return {
|
|
129
|
+
statusCode: res.statusCode,
|
|
130
|
+
tempFilePath: res.tempFilePath,
|
|
131
|
+
filePath: res.tempFilePath,
|
|
132
|
+
} as FileDownInfo;
|
|
151
133
|
});
|
|
152
134
|
}
|
|
153
135
|
|
package/src/app.mpx
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import mpx, { createApp } from '@mpxjs/core';
|
|
3
|
+
//api代理
|
|
4
|
+
import apiProxy from '@mpxjs/api-proxy';
|
|
5
|
+
mpx.use(apiProxy, { usePromise: true })
|
|
3
6
|
//状态管理
|
|
4
7
|
import { createPinia } from '@mpxjs/pinia';
|
|
5
8
|
createPinia();
|
|
6
9
|
//网络请求和App配置
|
|
7
10
|
import { mpxFetch, config } from "./index";
|
|
8
11
|
mpx.use(mpxFetch);
|
|
9
|
-
|
|
10
|
-
import apiProxy from '@mpxjs/api-proxy';
|
|
11
|
-
mpx.use(apiProxy, { usePromise: true })
|
|
12
|
+
|
|
12
13
|
createApp({
|
|
13
14
|
globalData: {
|
|
14
15
|
config: config
|
|
15
16
|
}
|
|
16
17
|
})
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if (__mpx_mode__ !== "web") {
|
|
19
|
+
// 只有运行时才能调用
|
|
20
|
+
const accountInfo = mpx.getAccountInfoSync();
|
|
21
|
+
// 微信
|
|
22
|
+
config.appId = accountInfo.miniProgram.appId;
|
|
23
|
+
}
|
|
21
24
|
</script>
|
|
22
25
|
|
|
23
26
|
<style></style>
|
|
@@ -39,15 +42,18 @@ config.appId = accountInfo.miniProgram.appId;
|
|
|
39
42
|
"custom": true,
|
|
40
43
|
"color": "#86909C",
|
|
41
44
|
"selectedColor": "#EA4C3B",
|
|
42
|
-
"borderStyle": "white",
|
|
43
45
|
"list": [
|
|
44
46
|
{
|
|
45
47
|
"pagePath": "pages/tabbar/home",
|
|
46
|
-
"text": "首页"
|
|
48
|
+
"text": "首页",
|
|
49
|
+
"activeIcon": "",
|
|
50
|
+
"icon": ""
|
|
47
51
|
},
|
|
48
52
|
{
|
|
49
53
|
"pagePath": "pages/tabbar/my",
|
|
50
|
-
"text": "我的"
|
|
54
|
+
"text": "我的",
|
|
55
|
+
"activeIcon": "",
|
|
56
|
+
"icon": ""
|
|
51
57
|
}
|
|
52
58
|
]
|
|
53
59
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="logout-section">
|
|
3
|
+
<!-- 登录状态才显示退出按钮 -->
|
|
4
|
+
<button class="logout-btn" bind:tap="handleLogout" wx:if="{{ isLogin }}">退出登录</button>
|
|
5
|
+
<text class="version-text">当前版本 V{{ version }}</text>
|
|
6
|
+
</view>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import mpx, { createComponent, computed } from '@mpxjs/core'
|
|
11
|
+
import { useUserStore } from '../../store/user'
|
|
12
|
+
|
|
13
|
+
createComponent({
|
|
14
|
+
properties: {
|
|
15
|
+
// 自定义版本号,默认读配置
|
|
16
|
+
version: {
|
|
17
|
+
type: String,
|
|
18
|
+
value: '1.0.0'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
setup() {
|
|
22
|
+
let userStore = useUserStore();
|
|
23
|
+
const isLogin = computed(() => userStore.accessToken !== '');
|
|
24
|
+
return {
|
|
25
|
+
isLogin, userStore
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
methods: {
|
|
29
|
+
// 退出登录逻辑
|
|
30
|
+
handleLogout() {
|
|
31
|
+
mpx.showModal({
|
|
32
|
+
title: '提示',
|
|
33
|
+
content: '确定要退出登录吗?',
|
|
34
|
+
success: (res) => {
|
|
35
|
+
if (res.confirm) {
|
|
36
|
+
this.userStore.logout() // 调用退出接口
|
|
37
|
+
mpx.showToast({ title: '已退出登录', icon: 'success' })
|
|
38
|
+
// 通知父组件退出成功
|
|
39
|
+
this.triggerEvent('logoutSuccess');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<style lang="scss">
|
|
49
|
+
$primary: #07c160;
|
|
50
|
+
$text-3: #999999;
|
|
51
|
+
|
|
52
|
+
.logout-section {
|
|
53
|
+
padding: 40rpx 16rpx 80rpx; // 底部留空适配tabbar
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
align-items: center;
|
|
57
|
+
|
|
58
|
+
.logout-btn {
|
|
59
|
+
width: 300rpx;
|
|
60
|
+
height: 72rpx;
|
|
61
|
+
border-radius: 36rpx;
|
|
62
|
+
border: 2rpx solid #ff4d4f;
|
|
63
|
+
background: #fff;
|
|
64
|
+
color: #ff4d4f;
|
|
65
|
+
font-size: 28rpx;
|
|
66
|
+
font-weight: 500;
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
margin-bottom: 24rpx;
|
|
71
|
+
transition: all 0.2s;
|
|
72
|
+
|
|
73
|
+
&:active {
|
|
74
|
+
background: #fff1f0;
|
|
75
|
+
transform: scale(0.98);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.version-text {
|
|
80
|
+
font-size: 24rpx;
|
|
81
|
+
color: $text-3;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
85
|
+
|
|
86
|
+
<script type="application/json">
|
|
87
|
+
{
|
|
88
|
+
"component": true,
|
|
89
|
+
"usingComponents": {}
|
|
90
|
+
}
|
|
91
|
+
</script>
|