af-mobile-client-vue3 1.3.40 → 1.3.42
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/certs/127.0.0.1+2-key.pem +28 -0
- package/certs/127.0.0.1+2.pem +27 -0
- package/package.json +3 -2
- package/src/api/user/index.ts +40 -40
- package/src/components/core/ImageUploader/index.vue +7 -5
- package/src/router/routes.ts +1 -1
- package/src/services/api/Login.ts +6 -6
- package/src/stores/modules/user.ts +16 -0
- package/src/styles/login.less +109 -109
- package/src/utils/environment.ts +129 -0
- package/src/utils/platform-auth.ts +24 -8
- package/src/utils/queryFormDefaultRangePicker.ts +57 -57
- package/src/utils/wechat.ts +297 -0
- package/src/views/component/XCellListView/index.vue +6 -27
- package/src/views/component/XFormGroupView/index.vue +7 -11
- package/src/views/component/XFormView/index.vue +2 -2
- package/src/views/loading/AuthLoading.vue +20 -5
- package/src/views/user/register/index.vue +13 -9
- package/vite.config.ts +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChKsPmzaqY3iw4
|
|
3
|
+
nugwJIdl/Xf4HA33hxiNs1u5VnL/DceCz/6uOfj/pi1w3N4Zzn8j58aY5Oh2HTDJ
|
|
4
|
+
laaDEHQmq7suBgeAVIJoplr4SDQEyecehqH5bHt4MnJ5ize1ldNxzXgO5a2XwfPz
|
|
5
|
+
YxWw90jZk1QEQIgS1Ip90amJk7al+M/+dIb61uoET/xLIrcVXtc9lzglPyZpNYQd
|
|
6
|
+
LB0hkjd+Ed8c5Hx90/gc/JJh3Ur1YfWREr4SJwfz1+KbUGbADEFwaLX6G5Hma6qi
|
|
7
|
+
gC3OZ13M1+bxpxT01+TGtPzUhFADFF+ychj8v4U4UbypgsiW9Wya7LHRNUfODmXc
|
|
8
|
+
UT2M5O/pAgMBAAECggEAUtmDH3D2k+MSZID751O/7uQf+gGiBG8EZkOfkWUpdIgG
|
|
9
|
+
2e5GhBX1NKaekXhZDHck0LZjV1HFVoKnA9nUYWfh7cc2T/B1hrjq2RU7iorDgvqv
|
|
10
|
+
vveC6I+l4SI9ytGQb953dfckErRrSqo/2AxFqFVWs9KSzCTITrXIA+n1921h5Wtz
|
|
11
|
+
2UGsiyt7SR9ASOQ9o16QlDBNan7SulQyIam/NHaiDuyoB8bBxrewPGIx12vESbeK
|
|
12
|
+
NlpZhWd9jzcdkfLudIiCkp2XQ3lQsQHHNIgTij2GsYEE6hb4jLIfRsuUz6IHdFcE
|
|
13
|
+
gnqnXtUJPUMMmaoz6sFG3yLjHrsMUfSShDzMp19ViQKBgQDJzZ1fL+ZhQd7kTR4N
|
|
14
|
+
zDexXHcuHFXhXJ8VuXKcCgc5K4wt88yVQTNWwWRw27RFIh75DHQhm3FQiGydf+HM
|
|
15
|
+
8k7riKA0ab3/AO5u9JYNf+Pbz0k/+rthWk/qA4N/New2eJaJMZcguwCRtg7h1Ecr
|
|
16
|
+
JvcVxKkxwdCvPNwq8IKeyOyS1wKBgQDMc1Uok5sPhn/LSjqnUCRlyzv1tbgJPRsZ
|
|
17
|
+
1RU2wouRJc5b0usPJi9bX4642O2eTfd4mwQpPS4WcYnXVA2+qVG+rs6WAvMN10LI
|
|
18
|
+
SIICIzFrah1GyXs8baILE9bfJamB+YFAOF7DPK6dDHLlEg/ZhUqKr/PwoU1Cjro6
|
|
19
|
+
Xiwy7Gz7PwKBgQC44TgBAbg1eAyE6iXTjDmlssm5I9qGGb3hQEHAtOtDNCM74jSW
|
|
20
|
+
tOIc5BZp0s6H26e2kPM/6tHYbvPbI1Kx2Xf2Dvh+rDWVjrviSQ/DlFwjf/ditwm+
|
|
21
|
+
Oegmw0tQWw1qJfX8AMOtB8WQuNNPj5QX853AgqhjXmYadU5bxHZWlEswhwKBgCMP
|
|
22
|
+
uE/wGExuTWYogayFwuguFUdK9ZeoAgjJEQ1GCbdHm38FycfcTYzG82vhz8YxKrpl
|
|
23
|
+
Iy6LTmcM642g3YaP9PPVeJojQVljTBGa1ajWLjh0hzbHgLnZN0vdCCFWjR48Ep1X
|
|
24
|
+
zXB/7JYEN4PvOAaepCzqhdQDZYN/hJJT6hKFlx7zAoGAC2wxKt0MdQCX8f9B8Lhj
|
|
25
|
+
3zl6ehRrfM0Ah/4Bf8845AQcS1K8FeDgU7glacz8EAKX2XUx+y2KqOb2Wiw+LwVi
|
|
26
|
+
kAl60oJBZxpuK/upjlOykWP9wOrpWtEYgqlu3ilOFLNQUb0h/7oL9fvfinUzij/V
|
|
27
|
+
PkQrsv2j4+R8OHWD5VN1IiA=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIEkTCCAvmgAwIBAgIQcMK+bOM3fXEWrBMEL3//XDANBgkqhkiG9w0BAQsFADCB
|
|
3
|
+
pTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMT0wOwYDVQQLDDRMQVBU
|
|
4
|
+
T1AtOUxOR0xKQktc5ZSQ5qKT54OoQExBUFRPUC05TE5HTEpCSyAodGFuZ3ppeWUp
|
|
5
|
+
MUQwQgYDVQQDDDtta2NlcnQgTEFQVE9QLTlMTkdMSkJLXOWUkOaik+eDqEBMQVBU
|
|
6
|
+
T1AtOUxOR0xKQksgKHRhbmd6aXllKTAeFw0yNDA5MDQwNjI4MThaFw0yNjEyMDQw
|
|
7
|
+
NjI4MThaMGgxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0
|
|
8
|
+
ZTE9MDsGA1UECww0TEFQVE9QLTlMTkdMSkJLXOWUkOaik+eDqEBMQVBUT1AtOUxO
|
|
9
|
+
R0xKQksgKHRhbmd6aXllKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
|
10
|
+
AKEqw+bNqpjeLDie6DAkh2X9d/gcDfeHGI2zW7lWcv8Nx4LP/q45+P+mLXDc3hnO
|
|
11
|
+
fyPnxpjk6HYdMMmVpoMQdCaruy4GB4BUgmimWvhINATJ5x6Goflse3gycnmLN7WV
|
|
12
|
+
03HNeA7lrZfB8/NjFbD3SNmTVARAiBLUin3RqYmTtqX4z/50hvrW6gRP/EsitxVe
|
|
13
|
+
1z2XOCU/Jmk1hB0sHSGSN34R3xzkfH3T+Bz8kmHdSvVh9ZESvhInB/PX4ptQZsAM
|
|
14
|
+
QXBotfobkeZrqqKALc5nXczX5vGnFPTX5Ma0/NSEUAMUX7JyGPy/hThRvKmCyJb1
|
|
15
|
+
bJrssdE1R84OZdxRPYzk7+kCAwEAAaN5MHcwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
|
16
|
+
JQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFChzYGTua1EmLuS4rXqUekjNK40r
|
|
17
|
+
MC8GA1UdEQQoMCaCCWxvY2FsaG9zdIITd3d3LmFvZmVuZ2Nsb3VkLmNvbYcEfwAA
|
|
18
|
+
ATANBgkqhkiG9w0BAQsFAAOCAYEAhVvhN3eEEw2jmJ+ey2h7eLoZkuTIlJpJymPj
|
|
19
|
+
pXea4LBj+q3MHNXO5SRjc5QzB6As5GOLld++JDLOUkL/4IA+E6IFNWyDS7pS2EdP
|
|
20
|
+
G61nc3v7Os4g/ZElXA3xePYEfHewTURe5NagEHx+jdXEwK4nEChrJxmlbNgk6VEL
|
|
21
|
+
TYDLhA0bWWm7/CMv1oPOXWPLI5BDi56HnjJVXem6JpOwiHRmiZcj1DvP9m52+8f9
|
|
22
|
+
g94Q9zMBvwpNneaNAcUgATxykMjZoLJBCe1EdqmO0xXEJI6Cz8nJEp6CJBl5Vi/t
|
|
23
|
+
deKITXWe7ZP2/temIHG3Tv62l3/XQqdCvztgk50aW8YGyci243k7YDgWuULPvDf1
|
|
24
|
+
N0cUEC3PYKnkhhSWyy91aMyrsorWGpsjrb6xgla+0SpHNb+ZAl1SEY5VqTOsWxE/
|
|
25
|
+
qAQ+5xHN1EnrIqtNX7Lzp/7ekq0OQTP/U9D2soLpX7jlnWgQPnoBrNmOYr26UpzB
|
|
26
|
+
os3c4GV0Cr9AChbLjbWPn7D9+cA1
|
|
27
|
+
-----END CERTIFICATE-----
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "af-mobile-client-vue3",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.42",
|
|
5
5
|
"packageManager": "pnpm@10.13.1",
|
|
6
6
|
"description": "Vue + Vite component lib",
|
|
7
7
|
"engines": {
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"vue": "^3.5.17",
|
|
44
44
|
"vue-i18n": "^11.1.10",
|
|
45
45
|
"vue-router": "^4.5.1",
|
|
46
|
-
"vue3-hash-calendar": "^1.1.3"
|
|
46
|
+
"vue3-hash-calendar": "^1.1.3",
|
|
47
|
+
"weixin-js-sdk": "^1.6.5"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@antfu/eslint-config": "4.17.0",
|
package/src/api/user/index.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { loginApi } from '@af-mobile-client-vue3/services/api/Login'
|
|
2
|
-
|
|
3
|
-
import { get, post } from '@af-mobile-client-vue3/services/restTools'
|
|
4
|
-
import { http } from '@af-mobile-client-vue3/utils/http'
|
|
5
|
-
|
|
6
|
-
export interface BasicResponseModel<T = any> {
|
|
7
|
-
code: number
|
|
8
|
-
msg: string
|
|
9
|
-
data: T
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function login(data: any) {
|
|
13
|
-
return post(
|
|
14
|
-
loginApi.Login,
|
|
15
|
-
data,
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function OALogin(data: any) {
|
|
20
|
-
return get(`/af-system/user/${data.username}/${data.password}/智慧OA`)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @description: 获取用户信息
|
|
25
|
-
*/
|
|
26
|
-
export function getUserInfo() {
|
|
27
|
-
return get(
|
|
28
|
-
'/getUserInfo',
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @description: 用户登出
|
|
34
|
-
*/
|
|
35
|
-
export function doLogout() {
|
|
36
|
-
return http.request({
|
|
37
|
-
url: loginApi.Logout,
|
|
38
|
-
method: 'DELETE',
|
|
39
|
-
})
|
|
40
|
-
}
|
|
1
|
+
import { loginApi } from '@af-mobile-client-vue3/services/api/Login'
|
|
2
|
+
|
|
3
|
+
import { get, post } from '@af-mobile-client-vue3/services/restTools'
|
|
4
|
+
import { http } from '@af-mobile-client-vue3/utils/http'
|
|
5
|
+
|
|
6
|
+
export interface BasicResponseModel<T = any> {
|
|
7
|
+
code: number
|
|
8
|
+
msg: string
|
|
9
|
+
data: T
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function login(data: any) {
|
|
13
|
+
return post(
|
|
14
|
+
loginApi.Login,
|
|
15
|
+
data,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function OALogin(data: any) {
|
|
20
|
+
return get(`/af-system/user/${data.username}/${data.password}/智慧OA`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @description: 获取用户信息
|
|
25
|
+
*/
|
|
26
|
+
export function getUserInfo() {
|
|
27
|
+
return get(
|
|
28
|
+
'/getUserInfo',
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @description: 用户登出
|
|
34
|
+
*/
|
|
35
|
+
export function doLogout() {
|
|
36
|
+
return http.request({
|
|
37
|
+
url: loginApi.Logout,
|
|
38
|
+
method: 'DELETE',
|
|
39
|
+
})
|
|
40
|
+
}
|
|
@@ -228,15 +228,16 @@ function handleActionSelect(option: any) {
|
|
|
228
228
|
.uploader-container {
|
|
229
229
|
display: flex;
|
|
230
230
|
flex-direction: column;
|
|
231
|
+
// 默认图片上传区域高度会影响布局
|
|
232
|
+
width: 100%;
|
|
233
|
+
height: 100%;
|
|
231
234
|
// 该属性会影响表单布局
|
|
232
235
|
// gap: 16px;
|
|
233
236
|
}
|
|
234
237
|
.custom-upload-area {
|
|
235
238
|
width: 100%;
|
|
236
|
-
|
|
237
|
-
min-height:
|
|
238
|
-
// 该属性会影响表单布局
|
|
239
|
-
// margin: 0 auto 12px auto;
|
|
239
|
+
height: 100%;
|
|
240
|
+
min-height: 80px;
|
|
240
241
|
box-sizing: border-box;
|
|
241
242
|
border: 1px dashed #d9d9d9;
|
|
242
243
|
border-radius: 10px;
|
|
@@ -246,7 +247,8 @@ function handleActionSelect(option: any) {
|
|
|
246
247
|
align-items: center;
|
|
247
248
|
justify-content: center;
|
|
248
249
|
cursor: pointer;
|
|
249
|
-
padding:
|
|
250
|
+
padding: 8px 4px;
|
|
251
|
+
flex: 1;
|
|
250
252
|
.upload-camera-img {
|
|
251
253
|
width: 28px;
|
|
252
254
|
height: 28px;
|
package/src/router/routes.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const loginApi = {
|
|
2
|
-
Login: '/af-auth/login',
|
|
3
|
-
Logout: '/af-auth/logout',
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export { loginApi }
|
|
1
|
+
const loginApi = {
|
|
2
|
+
Login: '/af-auth/login',
|
|
3
|
+
Logout: '/af-auth/logout',
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export { loginApi }
|
|
@@ -250,6 +250,21 @@ export const useUserStore = defineStore('app-user', () => {
|
|
|
250
250
|
return Promise.reject(error)
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
+
const loginExternalMini = async (data: any) => {
|
|
254
|
+
try {
|
|
255
|
+
// 设置Token
|
|
256
|
+
setToken(data.access_token)
|
|
257
|
+
|
|
258
|
+
// 加密存储登录票据
|
|
259
|
+
const LoginTicket = crypto.AESEncrypt(JSON.stringify(data), '3KMKqvgwR8ULbR8Z')
|
|
260
|
+
Storage.set('LoginTicket', LoginTicket)
|
|
261
|
+
|
|
262
|
+
return Promise.resolve(data)
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
return Promise.reject(error)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
253
268
|
|
|
254
269
|
const logout = async () => {
|
|
255
270
|
if (getToken()) {
|
|
@@ -294,6 +309,7 @@ export const useUserStore = defineStore('app-user', () => {
|
|
|
294
309
|
Login,
|
|
295
310
|
loginUnified,
|
|
296
311
|
loginExternal,
|
|
312
|
+
loginExternalMini,
|
|
297
313
|
getToken,
|
|
298
314
|
getLastUpdateTime,
|
|
299
315
|
logout,
|
package/src/styles/login.less
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
html:not(.dark) {
|
|
2
|
-
.form {
|
|
3
|
-
.form_field {
|
|
4
|
-
:deep(.van-field__label) {
|
|
5
|
-
color: rgb(88, 88, 88);
|
|
6
|
-
}
|
|
7
|
-
:deep(.van-field__body) {
|
|
8
|
-
background: rgb(251, 251, 251);
|
|
9
|
-
box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.1);
|
|
10
|
-
color: rgb(71, 71, 71);
|
|
11
|
-
}
|
|
12
|
-
:deep(.van-cell) {
|
|
13
|
-
background: #ffffff;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
.extra_setting {
|
|
17
|
-
.extra_setting_for_remember_password {
|
|
18
|
-
color: rgb(88, 88, 88);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
.form {
|
|
24
|
-
width: 100%;
|
|
25
|
-
padding: 0 40px;
|
|
26
|
-
.form_field {
|
|
27
|
-
padding-right: 0;
|
|
28
|
-
padding-left: 0;
|
|
29
|
-
:deep(.van-field__label) {
|
|
30
|
-
opacity: 0.7;
|
|
31
|
-
font-size: 16px;
|
|
32
|
-
font-weight: 400;
|
|
33
|
-
line-height: 23px;
|
|
34
|
-
text-transform: uppercase;
|
|
35
|
-
text-indent: 10px;
|
|
36
|
-
}
|
|
37
|
-
:deep(.van-field__body) {
|
|
38
|
-
height: 40px;
|
|
39
|
-
border-radius: 5px;
|
|
40
|
-
font-size: 16px;
|
|
41
|
-
font-weight: 400;
|
|
42
|
-
padding: 8px 10px;
|
|
43
|
-
opacity: 0.6;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
.extra_setting {
|
|
47
|
-
font-size: 12px;
|
|
48
|
-
font-weight: 400;
|
|
49
|
-
line-height: 12px;
|
|
50
|
-
.extra_setting_for_remember_password {
|
|
51
|
-
opacity: 0.7;
|
|
52
|
-
span {
|
|
53
|
-
position: relative;
|
|
54
|
-
bottom: 3px;
|
|
55
|
-
left: 5px;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
.extra_setting_for_reset_password {
|
|
59
|
-
position: relative;
|
|
60
|
-
top: 2px;
|
|
61
|
-
opacity: 0.7;
|
|
62
|
-
color: rgb(56, 149, 250);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
.btn {
|
|
66
|
-
height: 50px;
|
|
67
|
-
:deep(.van-button__text) {
|
|
68
|
-
color: rgb(255, 255, 255);
|
|
69
|
-
font-size: 16px;
|
|
70
|
-
font-weight: 700;
|
|
71
|
-
line-height: 23px;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
.login_btn {
|
|
75
|
-
background: rgb(56, 149, 250);
|
|
76
|
-
margin-top: 104px;
|
|
77
|
-
}
|
|
78
|
-
.reset_btn {
|
|
79
|
-
margin: 24px 0;
|
|
80
|
-
}
|
|
81
|
-
.back_btn {
|
|
82
|
-
:deep(.van-button__text) {
|
|
83
|
-
color: rgb(56, 149, 250);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
:deep(.van-cell:after) {
|
|
87
|
-
border-bottom: none;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
.login_form {
|
|
91
|
-
margin-top: 65px;
|
|
92
|
-
}
|
|
93
|
-
.forget_password_form {
|
|
94
|
-
margin-top: 15px;
|
|
95
|
-
}
|
|
96
|
-
/* 使图标垂直居中 */
|
|
97
|
-
.wechat-login-btn .van-icon {
|
|
98
|
-
vertical-align: middle;
|
|
99
|
-
}
|
|
100
|
-
/* 悬停效果 */
|
|
101
|
-
.wechat-login-btn:hover {
|
|
102
|
-
background-color: #06ad56 !important;
|
|
103
|
-
border-color: #06ad56 !important;
|
|
104
|
-
}
|
|
105
|
-
/* 点击效果 */
|
|
106
|
-
.wechat-login-btn:active {
|
|
107
|
-
background-color: #05994c !important;
|
|
108
|
-
border-color: #05994c !important;
|
|
109
|
-
}
|
|
1
|
+
html:not(.dark) {
|
|
2
|
+
.form {
|
|
3
|
+
.form_field {
|
|
4
|
+
:deep(.van-field__label) {
|
|
5
|
+
color: rgb(88, 88, 88);
|
|
6
|
+
}
|
|
7
|
+
:deep(.van-field__body) {
|
|
8
|
+
background: rgb(251, 251, 251);
|
|
9
|
+
box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.1);
|
|
10
|
+
color: rgb(71, 71, 71);
|
|
11
|
+
}
|
|
12
|
+
:deep(.van-cell) {
|
|
13
|
+
background: #ffffff;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
.extra_setting {
|
|
17
|
+
.extra_setting_for_remember_password {
|
|
18
|
+
color: rgb(88, 88, 88);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
.form {
|
|
24
|
+
width: 100%;
|
|
25
|
+
padding: 0 40px;
|
|
26
|
+
.form_field {
|
|
27
|
+
padding-right: 0;
|
|
28
|
+
padding-left: 0;
|
|
29
|
+
:deep(.van-field__label) {
|
|
30
|
+
opacity: 0.7;
|
|
31
|
+
font-size: 16px;
|
|
32
|
+
font-weight: 400;
|
|
33
|
+
line-height: 23px;
|
|
34
|
+
text-transform: uppercase;
|
|
35
|
+
text-indent: 10px;
|
|
36
|
+
}
|
|
37
|
+
:deep(.van-field__body) {
|
|
38
|
+
height: 40px;
|
|
39
|
+
border-radius: 5px;
|
|
40
|
+
font-size: 16px;
|
|
41
|
+
font-weight: 400;
|
|
42
|
+
padding: 8px 10px;
|
|
43
|
+
opacity: 0.6;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
.extra_setting {
|
|
47
|
+
font-size: 12px;
|
|
48
|
+
font-weight: 400;
|
|
49
|
+
line-height: 12px;
|
|
50
|
+
.extra_setting_for_remember_password {
|
|
51
|
+
opacity: 0.7;
|
|
52
|
+
span {
|
|
53
|
+
position: relative;
|
|
54
|
+
bottom: 3px;
|
|
55
|
+
left: 5px;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
.extra_setting_for_reset_password {
|
|
59
|
+
position: relative;
|
|
60
|
+
top: 2px;
|
|
61
|
+
opacity: 0.7;
|
|
62
|
+
color: rgb(56, 149, 250);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
.btn {
|
|
66
|
+
height: 50px;
|
|
67
|
+
:deep(.van-button__text) {
|
|
68
|
+
color: rgb(255, 255, 255);
|
|
69
|
+
font-size: 16px;
|
|
70
|
+
font-weight: 700;
|
|
71
|
+
line-height: 23px;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
.login_btn {
|
|
75
|
+
background: rgb(56, 149, 250);
|
|
76
|
+
margin-top: 104px;
|
|
77
|
+
}
|
|
78
|
+
.reset_btn {
|
|
79
|
+
margin: 24px 0;
|
|
80
|
+
}
|
|
81
|
+
.back_btn {
|
|
82
|
+
:deep(.van-button__text) {
|
|
83
|
+
color: rgb(56, 149, 250);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
:deep(.van-cell:after) {
|
|
87
|
+
border-bottom: none;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
.login_form {
|
|
91
|
+
margin-top: 65px;
|
|
92
|
+
}
|
|
93
|
+
.forget_password_form {
|
|
94
|
+
margin-top: 15px;
|
|
95
|
+
}
|
|
96
|
+
/* 使图标垂直居中 */
|
|
97
|
+
.wechat-login-btn .van-icon {
|
|
98
|
+
vertical-align: middle;
|
|
99
|
+
}
|
|
100
|
+
/* 悬停效果 */
|
|
101
|
+
.wechat-login-btn:hover {
|
|
102
|
+
background-color: #06ad56 !important;
|
|
103
|
+
border-color: #06ad56 !important;
|
|
104
|
+
}
|
|
105
|
+
/* 点击效果 */
|
|
106
|
+
.wechat-login-btn:active {
|
|
107
|
+
background-color: #05994c !important;
|
|
108
|
+
border-color: #05994c !important;
|
|
109
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 环境检测工具类
|
|
3
|
+
* 用于检测当前运行环境:微信服务号、浏览器、小程序、App等
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface EnvironmentInfo {
|
|
7
|
+
isWechat: boolean
|
|
8
|
+
isMiniprogram: boolean
|
|
9
|
+
isApp: boolean
|
|
10
|
+
isBrowser: boolean
|
|
11
|
+
userAgent: string
|
|
12
|
+
platform: string
|
|
13
|
+
isAlipayClient: boolean
|
|
14
|
+
isDingTalk: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 从 UA-CH 或 UA 推断平台,避免使用已弃用的 navigator.platform
|
|
19
|
+
*/
|
|
20
|
+
function getPlatformFromClient(): string {
|
|
21
|
+
// 优先使用 UA-CH(Chromium 等支持)
|
|
22
|
+
const navAny = navigator as any
|
|
23
|
+
const uaData = navAny && navAny.userAgentData
|
|
24
|
+
const uaDataPlatform = typeof uaData?.platform === 'string' ? uaData.platform : ''
|
|
25
|
+
|
|
26
|
+
const platform = uaDataPlatform || inferPlatformFromUserAgent(navigator.userAgent)
|
|
27
|
+
return (platform || 'unknown').toLowerCase()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function inferPlatformFromUserAgent(userAgent: string): string {
|
|
31
|
+
const ua = (userAgent || '').toLowerCase()
|
|
32
|
+
if (ua.includes('windows'))
|
|
33
|
+
return 'windows'
|
|
34
|
+
if (ua.includes('mac os x') || ua.includes('macintosh') || ua.includes('mac os'))
|
|
35
|
+
return 'macos'
|
|
36
|
+
if (ua.includes('android'))
|
|
37
|
+
return 'android'
|
|
38
|
+
if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod') || ua.includes('ios'))
|
|
39
|
+
return 'ios'
|
|
40
|
+
if (ua.includes('cros'))
|
|
41
|
+
return 'chrome os'
|
|
42
|
+
if (ua.includes('linux'))
|
|
43
|
+
return 'linux'
|
|
44
|
+
return 'unknown'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 检测当前运行环境
|
|
49
|
+
*/
|
|
50
|
+
export function detectEnvironment(): EnvironmentInfo {
|
|
51
|
+
const userAgent = navigator.userAgent.toLowerCase()
|
|
52
|
+
const platform = getPlatformFromClient()
|
|
53
|
+
|
|
54
|
+
// 检测微信环境
|
|
55
|
+
const isWechat = /micromessenger/i.test(userAgent)
|
|
56
|
+
|
|
57
|
+
// 检测支付宝环境
|
|
58
|
+
const isAlipayClient = /alipayclient/i.test(userAgent)
|
|
59
|
+
|
|
60
|
+
// 检测抖音环境
|
|
61
|
+
const isDingTalk = /dingtalk/i.test(userAgent)
|
|
62
|
+
|
|
63
|
+
// 检测微信小程序环境
|
|
64
|
+
const isMiniprogram = isWechat && /miniprogram/i.test(userAgent)
|
|
65
|
+
|
|
66
|
+
// 检测App环境 - 使用括号明确优先级
|
|
67
|
+
const isApp = (
|
|
68
|
+
/myapp|customapp|nativeapp/.test(userAgent)
|
|
69
|
+
|| (Object.prototype.hasOwnProperty.call(window, 'webkit') && !!(window as any).webkit?.messageHandlers)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
// 检测浏览器环境
|
|
73
|
+
const isBrowser = !isWechat && !isApp
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
isWechat,
|
|
77
|
+
isMiniprogram,
|
|
78
|
+
isApp,
|
|
79
|
+
isBrowser,
|
|
80
|
+
userAgent,
|
|
81
|
+
platform,
|
|
82
|
+
isAlipayClient,
|
|
83
|
+
isDingTalk,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 获取当前场景类型
|
|
88
|
+
*/
|
|
89
|
+
export function getCurrentScene(): 'wechat' | 'browser' | 'miniprogram' | 'app' | 'unknown' {
|
|
90
|
+
const env = detectEnvironment()
|
|
91
|
+
|
|
92
|
+
if (env.isMiniprogram)
|
|
93
|
+
return 'miniprogram'
|
|
94
|
+
if (env.isWechat)
|
|
95
|
+
return 'wechat'
|
|
96
|
+
if (env.isApp)
|
|
97
|
+
return 'app'
|
|
98
|
+
if (env.isBrowser)
|
|
99
|
+
return 'browser'
|
|
100
|
+
|
|
101
|
+
return 'unknown'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 检查是否支持特定功能
|
|
106
|
+
*/
|
|
107
|
+
export function checkFeatureSupport() {
|
|
108
|
+
const env = detectEnvironment()
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
// 摄像头支持
|
|
112
|
+
camera: 'mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices,
|
|
113
|
+
|
|
114
|
+
// NFC支持
|
|
115
|
+
nfc: 'NDEFReader' in window || 'nfc' in navigator,
|
|
116
|
+
|
|
117
|
+
// 文件系统支持
|
|
118
|
+
fileSystem: 'showOpenFilePicker' in window,
|
|
119
|
+
|
|
120
|
+
// 振动支持
|
|
121
|
+
vibration: 'vibrate' in navigator,
|
|
122
|
+
|
|
123
|
+
// 地理位置支持
|
|
124
|
+
geolocation: 'geolocation' in navigator,
|
|
125
|
+
|
|
126
|
+
// 微信JS-SDK支持
|
|
127
|
+
wechatJSSDK: env.isWechat && typeof window !== 'undefined' && 'WeixinJSBridge' in window,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { RouteLocationNormalized } from 'vue-router'
|
|
7
7
|
import { PLATFORM_ROUTE_MAP, PlatformType } from '@af-mobile-client-vue3/types/platform'
|
|
8
|
-
|
|
8
|
+
import { detectEnvironment } from '@af-mobile-client-vue3/utils/environment'
|
|
9
9
|
/**
|
|
10
10
|
* 认证参数接口
|
|
11
11
|
*/
|
|
@@ -58,7 +58,7 @@ export function isExternalUser(to: RouteLocationNormalized): ExternalUserResult
|
|
|
58
58
|
|
|
59
59
|
// 第一层检测:URL参数检测(最高优先级)判断公众号登录逻辑
|
|
60
60
|
// 检查路由查询参数中是否有授权参数(code + state)
|
|
61
|
-
const { code, state } = to.query
|
|
61
|
+
const { code, state, appData } = to.query
|
|
62
62
|
if (code && state) {
|
|
63
63
|
// 解析认证参数
|
|
64
64
|
const authParams = {
|
|
@@ -77,10 +77,21 @@ export function isExternalUser(to: RouteLocationNormalized): ExternalUserResult
|
|
|
77
77
|
|
|
78
78
|
// 第二层检测:User-Agent环境检测
|
|
79
79
|
// 检查浏览器环境是否为第三方平台
|
|
80
|
-
const
|
|
81
|
-
|
|
80
|
+
const env = detectEnvironment()
|
|
81
|
+
// 微信小程序
|
|
82
|
+
if (env.isMiniprogram && appData) {
|
|
83
|
+
const authParams = {
|
|
84
|
+
platformType: PlatformType.WECHAT_MINI,
|
|
85
|
+
appData,
|
|
86
|
+
}
|
|
87
|
+
// 暂未实现 后续需要增加登陆参数
|
|
88
|
+
return {
|
|
89
|
+
isExternal: true,
|
|
90
|
+
authParams,
|
|
91
|
+
}
|
|
92
|
+
}
|
|
82
93
|
// 微信环境检测
|
|
83
|
-
if (
|
|
94
|
+
if (env.isWechat) {
|
|
84
95
|
console.log('[Platform Detection] 检测到微信环境,判定为外部用户(无授权参数)')
|
|
85
96
|
return {
|
|
86
97
|
isExternal: true,
|
|
@@ -92,7 +103,7 @@ export function isExternalUser(to: RouteLocationNormalized): ExternalUserResult
|
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
// 支付宝环境检测
|
|
95
|
-
if (
|
|
106
|
+
if (env.isAlipayClient) {
|
|
96
107
|
// 暂未实现 后续需要增加登陆参数
|
|
97
108
|
return {
|
|
98
109
|
isExternal: true,
|
|
@@ -103,9 +114,14 @@ export function isExternalUser(to: RouteLocationNormalized): ExternalUserResult
|
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
// 钉钉环境检测
|
|
106
|
-
if (
|
|
117
|
+
if (env.isDingTalk) {
|
|
107
118
|
// 暂未实现 后续需要增加登陆参数
|
|
108
|
-
return {
|
|
119
|
+
return {
|
|
120
|
+
isExternal: true,
|
|
121
|
+
authParams: {
|
|
122
|
+
platformType: PlatformType.DINGTALK,
|
|
123
|
+
},
|
|
124
|
+
}
|
|
109
125
|
}
|
|
110
126
|
|
|
111
127
|
// 第三层检测:路由前缀检测
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 根据类型获取日期区间字符串
|
|
3
|
-
* @param type '当年' | 'curMonth' | '当日'
|
|
4
|
-
* @param show 区分实际值还是显示值, true为实际值, false为显示值
|
|
5
|
-
* @returns [start, end] 例:['2024-01-01 00:00:00', '2024-12-31 23:59:59']
|
|
6
|
-
*/
|
|
7
|
-
export function getRangeByType(type: string, show: boolean): [string, string] {
|
|
8
|
-
const now = new Date()
|
|
9
|
-
const year = now.getFullYear()
|
|
10
|
-
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
|
11
|
-
const day = now.getDate().toString().padStart(2, '0')
|
|
12
|
-
|
|
13
|
-
if (!show) {
|
|
14
|
-
if (type === 'curYear') {
|
|
15
|
-
return [
|
|
16
|
-
`${year}-01-01 00:00:00`,
|
|
17
|
-
`${year}-12-31 23:59:59`,
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
if (type === 'curMonth') {
|
|
21
|
-
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
22
|
-
return [
|
|
23
|
-
`${year}-${month}-01 00:00:00`,
|
|
24
|
-
`${year}-${month}-${lastDay.toString().padStart(2, '0')} 23:59:59`,
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
if (type === 'curDay') {
|
|
28
|
-
return [
|
|
29
|
-
`${year}-${month}-${day} 00:00:00`,
|
|
30
|
-
`${year}-${month}-${day} 23:59:59`,
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (show) {
|
|
35
|
-
if (type === 'curYear') {
|
|
36
|
-
return [
|
|
37
|
-
`${year}-01-01`,
|
|
38
|
-
`${year}-12-31`,
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
if (type === 'curMonth') {
|
|
42
|
-
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
43
|
-
return [
|
|
44
|
-
`${year}-${month}-01`,
|
|
45
|
-
`${year}-${month}-${lastDay.toString().padStart(2, '0')}`,
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
if (type === 'curDay') {
|
|
49
|
-
return [
|
|
50
|
-
`${year}-${month}-${day}`,
|
|
51
|
-
`${year}-${month}-${day}`,
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// 兜底返回空字符串数组
|
|
56
|
-
return ['', '']
|
|
57
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 根据类型获取日期区间字符串
|
|
3
|
+
* @param type '当年' | 'curMonth' | '当日'
|
|
4
|
+
* @param show 区分实际值还是显示值, true为实际值, false为显示值
|
|
5
|
+
* @returns [start, end] 例:['2024-01-01 00:00:00', '2024-12-31 23:59:59']
|
|
6
|
+
*/
|
|
7
|
+
export function getRangeByType(type: string, show: boolean): [string, string] {
|
|
8
|
+
const now = new Date()
|
|
9
|
+
const year = now.getFullYear()
|
|
10
|
+
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
|
11
|
+
const day = now.getDate().toString().padStart(2, '0')
|
|
12
|
+
|
|
13
|
+
if (!show) {
|
|
14
|
+
if (type === 'curYear') {
|
|
15
|
+
return [
|
|
16
|
+
`${year}-01-01 00:00:00`,
|
|
17
|
+
`${year}-12-31 23:59:59`,
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
if (type === 'curMonth') {
|
|
21
|
+
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
22
|
+
return [
|
|
23
|
+
`${year}-${month}-01 00:00:00`,
|
|
24
|
+
`${year}-${month}-${lastDay.toString().padStart(2, '0')} 23:59:59`,
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
if (type === 'curDay') {
|
|
28
|
+
return [
|
|
29
|
+
`${year}-${month}-${day} 00:00:00`,
|
|
30
|
+
`${year}-${month}-${day} 23:59:59`,
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (show) {
|
|
35
|
+
if (type === 'curYear') {
|
|
36
|
+
return [
|
|
37
|
+
`${year}-01-01`,
|
|
38
|
+
`${year}-12-31`,
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
if (type === 'curMonth') {
|
|
42
|
+
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
43
|
+
return [
|
|
44
|
+
`${year}-${month}-01`,
|
|
45
|
+
`${year}-${month}-${lastDay.toString().padStart(2, '0')}`,
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
if (type === 'curDay') {
|
|
49
|
+
return [
|
|
50
|
+
`${year}-${month}-${day}`,
|
|
51
|
+
`${year}-${month}-${day}`,
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// 兜底返回空字符串数组
|
|
56
|
+
return ['', '']
|
|
57
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { get } from '@af-mobile-client-vue3/services/restTools'
|
|
2
|
+
import { detectEnvironment } from '@af-mobile-client-vue3/utils/environment'
|
|
3
|
+
import wx from 'weixin-js-sdk'
|
|
4
|
+
// 微信JS-SDK配置接口
|
|
5
|
+
export interface WechatConfig {
|
|
6
|
+
debug: boolean
|
|
7
|
+
appId: string
|
|
8
|
+
timestamp: string
|
|
9
|
+
nonceStr: string
|
|
10
|
+
signature: string
|
|
11
|
+
jsApiList: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 微信扫码配置
|
|
15
|
+
export interface WechatScanConfig {
|
|
16
|
+
needResult: 0 | 1
|
|
17
|
+
scanType: string[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 微信扫码结果
|
|
21
|
+
export interface WechatScanResult {
|
|
22
|
+
resultStr: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 检查是否在微信环境中
|
|
26
|
+
export function isWechatBrowser(): boolean {
|
|
27
|
+
const env = detectEnvironment()
|
|
28
|
+
return env.isWechat
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 检查是否在小程序环境中
|
|
32
|
+
export function isMiniprogram(): boolean {
|
|
33
|
+
const env = detectEnvironment()
|
|
34
|
+
return env.isMiniprogram
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 配置微信JS-SDK
|
|
38
|
+
export function configWechatSDK(config: WechatConfig): Promise<void> {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
if (!isWechatBrowser()) {
|
|
41
|
+
reject(new Error('非微信环境,无法使用微信JS-SDK'))
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
wx.config({
|
|
46
|
+
debug: config.debug,
|
|
47
|
+
appId: config.appId,
|
|
48
|
+
timestamp: config.timestamp,
|
|
49
|
+
nonceStr: config.nonceStr,
|
|
50
|
+
signature: config.signature,
|
|
51
|
+
jsApiList: config.jsApiList,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
wx.ready(() => {
|
|
55
|
+
console.log('微信JS-SDK配置成功')
|
|
56
|
+
resolve()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
wx.error((res: any) => {
|
|
60
|
+
console.error('微信JS-SDK配置失败:', res)
|
|
61
|
+
reject(new Error(`微信JS-SDK配置失败: ${res.errMsg}`))
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 微信扫码
|
|
67
|
+
export function scanQRCode(config: WechatScanConfig): Promise<WechatScanResult> {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
if (!isWechatBrowser()) {
|
|
70
|
+
reject(new Error('非微信环境,无法使用微信扫码'))
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
wx.scanQRCode({
|
|
75
|
+
needResult: config.needResult,
|
|
76
|
+
scanType: config.scanType,
|
|
77
|
+
success: (res: WechatScanResult) => {
|
|
78
|
+
console.log('微信扫码成功:', res)
|
|
79
|
+
resolve(res)
|
|
80
|
+
},
|
|
81
|
+
fail: (res: any) => {
|
|
82
|
+
console.error('微信扫码失败:', res)
|
|
83
|
+
reject(new Error(`微信扫码失败: ${res.errMsg}`))
|
|
84
|
+
},
|
|
85
|
+
cancel: () => {
|
|
86
|
+
reject(new Error('用户取消扫码'))
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 获取微信签名(模拟)
|
|
93
|
+
export async function getWechatSignature(url: string): Promise<{
|
|
94
|
+
appId: string
|
|
95
|
+
timestamp: string
|
|
96
|
+
nonceStr: string
|
|
97
|
+
signature: string
|
|
98
|
+
}> {
|
|
99
|
+
// 这里应该调用后端接口获取微信签名
|
|
100
|
+
// 现在使用模拟数据
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
get(`/af-wechat/weixin/getJsSdk?path=${url}`).then((res) => {
|
|
103
|
+
resolve({
|
|
104
|
+
appId: res.appId,
|
|
105
|
+
timestamp: res.timeStamp,
|
|
106
|
+
nonceStr: res.nonceStr,
|
|
107
|
+
signature: res.sign,
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 初始化微信环境
|
|
114
|
+
export async function initWechatEnvironment(): Promise<void> {
|
|
115
|
+
if (!isWechatBrowser()) {
|
|
116
|
+
console.log('非微信环境,跳过微信初始化')
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const currentUrl = window.location.href.split('#')[0]
|
|
122
|
+
const signatureData = await getWechatSignature(currentUrl)
|
|
123
|
+
|
|
124
|
+
await configWechatSDK({
|
|
125
|
+
debug: false,
|
|
126
|
+
appId: signatureData.appId,
|
|
127
|
+
timestamp: signatureData.timestamp,
|
|
128
|
+
nonceStr: signatureData.nonceStr,
|
|
129
|
+
signature: signatureData.signature,
|
|
130
|
+
jsApiList: [
|
|
131
|
+
'onMenuShareTimeline',
|
|
132
|
+
'onMenuShareAppMessage',
|
|
133
|
+
'onMenuShareQQ',
|
|
134
|
+
'onMenuShareWeibo',
|
|
135
|
+
'onMenuShareQZone',
|
|
136
|
+
'startRecord',
|
|
137
|
+
'stopRecord',
|
|
138
|
+
'onVoiceRecordEnd',
|
|
139
|
+
'playVoice',
|
|
140
|
+
'pauseVoice',
|
|
141
|
+
'stopVoice',
|
|
142
|
+
'onVoicePlayEnd',
|
|
143
|
+
'uploadVoice',
|
|
144
|
+
'downloadVoice',
|
|
145
|
+
'chooseImage',
|
|
146
|
+
'previewImage',
|
|
147
|
+
'uploadImage',
|
|
148
|
+
'downloadImage',
|
|
149
|
+
'translateVoice',
|
|
150
|
+
'getNetworkType',
|
|
151
|
+
'openLocation',
|
|
152
|
+
'getLocation',
|
|
153
|
+
'hideOptionMenu',
|
|
154
|
+
'showOptionMenu',
|
|
155
|
+
'hideMenuItems',
|
|
156
|
+
'showMenuItems',
|
|
157
|
+
'hideAllNonBaseMenuItem',
|
|
158
|
+
'showAllNonBaseMenuItem',
|
|
159
|
+
'closeWindow',
|
|
160
|
+
'scanQRCode',
|
|
161
|
+
'chooseWXPay',
|
|
162
|
+
'openProductSpecificView',
|
|
163
|
+
'addCard',
|
|
164
|
+
'chooseCard',
|
|
165
|
+
'openCard',
|
|
166
|
+
],
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
console.log('微信环境初始化成功')
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
console.error('微信环境初始化失败:', error)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 小程序扫码(在小程序环境中)
|
|
177
|
+
export function miniprogramScanCode(): Promise<string> {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
if (!isMiniprogram()) {
|
|
180
|
+
reject(new Error('非小程序环境,无法使用小程序扫码'))
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 在小程序环境中,通过 postMessage 与小程序通信
|
|
185
|
+
const mp = (window as any).wx && (window as any).wx.miniProgram
|
|
186
|
+
const sendMessage = (payload: any) => {
|
|
187
|
+
if (mp && typeof mp.postMessage === 'function') {
|
|
188
|
+
mp.postMessage({ data: payload })
|
|
189
|
+
}
|
|
190
|
+
else if (window.parent && window.parent !== window) {
|
|
191
|
+
window.parent.postMessage(payload, '*')
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new Error('无法与小程序通信')
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
sendMessage({ type: 'scanCode', data: {} })
|
|
200
|
+
|
|
201
|
+
// 监听小程序返回的扫码结果
|
|
202
|
+
const handleMessage = (event: MessageEvent) => {
|
|
203
|
+
const raw = (event as any).data
|
|
204
|
+
const msg = raw && typeof raw === 'object' && 'data' in raw ? (raw as any).data : raw
|
|
205
|
+
if (msg && msg.type === 'scanCodeResult') {
|
|
206
|
+
window.removeEventListener('message', handleMessage)
|
|
207
|
+
if (msg.success) {
|
|
208
|
+
resolve(msg.result)
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
reject(new Error(msg.error || '扫码失败'))
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
window.addEventListener('message', handleMessage)
|
|
217
|
+
|
|
218
|
+
// 设置超时
|
|
219
|
+
setTimeout(() => {
|
|
220
|
+
window.removeEventListener('message', handleMessage)
|
|
221
|
+
reject(new Error('扫码超时'))
|
|
222
|
+
}, 30000)
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
reject(err)
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 小程序NFC读取(在小程序环境中)
|
|
231
|
+
export function miniprogramNfcRead(): Promise<string> {
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
if (!isMiniprogram()) {
|
|
234
|
+
reject(new Error('非小程序环境,无法使用小程序NFC'))
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const mp = (window as any).wx && (window as any).wx.miniProgram
|
|
239
|
+
const sendMessage = (payload: any) => {
|
|
240
|
+
if (mp && typeof mp.postMessage === 'function') {
|
|
241
|
+
mp.postMessage({ data: payload })
|
|
242
|
+
}
|
|
243
|
+
else if (window.parent && window.parent !== window) {
|
|
244
|
+
window.parent.postMessage(payload, '*')
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
throw new Error('无法与小程序通信')
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
sendMessage({ type: 'nfcRead', data: {} })
|
|
253
|
+
|
|
254
|
+
const handleMessage = (event: MessageEvent) => {
|
|
255
|
+
const raw = (event as any).data
|
|
256
|
+
const msg = raw && typeof raw === 'object' && 'data' in raw ? (raw as any).data : raw
|
|
257
|
+
if (msg && msg.type === 'nfcResult') {
|
|
258
|
+
window.removeEventListener('message', handleMessage)
|
|
259
|
+
if (msg.success) {
|
|
260
|
+
resolve(msg.result || '')
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
reject(new Error(msg.error || 'NFC读取失败'))
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
window.addEventListener('message', handleMessage)
|
|
269
|
+
|
|
270
|
+
setTimeout(() => {
|
|
271
|
+
window.removeEventListener('message', handleMessage)
|
|
272
|
+
reject(new Error('NFC读取超时'))
|
|
273
|
+
}, 30000)
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
reject(err)
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
// H5:仅监听小程序主动回传
|
|
281
|
+
export function waitAuthFromMiniProgram(timeout = 15000) {
|
|
282
|
+
return new Promise<{ token: string, resources?: any, expireTime?: number }>((resolve, reject) => {
|
|
283
|
+
const handle = (event: MessageEvent) => {
|
|
284
|
+
const raw = (event as any).data
|
|
285
|
+
const msg = raw && typeof raw === 'object' && 'data' in raw ? (raw as any).data : raw
|
|
286
|
+
if (msg && msg.type === 'auth') {
|
|
287
|
+
window.removeEventListener('message', handle)
|
|
288
|
+
return msg ? resolve(msg) : reject(new Error('未获取到授权信息'))
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
window.addEventListener('message', handle)
|
|
292
|
+
setTimeout(() => {
|
|
293
|
+
window.removeEventListener('message', handle)
|
|
294
|
+
reject(new Error('获取授权信息超时'))
|
|
295
|
+
}, timeout)
|
|
296
|
+
})
|
|
297
|
+
}
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import XCellList from '@af-mobile-client-vue3/components/data/XCellList/index.vue'
|
|
3
3
|
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
4
|
-
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
|
|
5
4
|
import { defineEmits, ref } from 'vue'
|
|
6
5
|
import { useRouter } from 'vue-router'
|
|
7
6
|
|
|
8
7
|
// 定义事件
|
|
9
8
|
const emit = defineEmits(['deleteRow'])
|
|
10
|
-
|
|
11
|
-
// 多选操作配置
|
|
12
|
-
const multiSelectActions = ref([
|
|
13
|
-
{ name: '批量审核', key: 'batchAudit', color: '#000000', icon: 'passed' },
|
|
14
|
-
])
|
|
15
|
-
|
|
16
|
-
const userInfo = useUserStore().getUserInfo()
|
|
17
9
|
// 访问路由
|
|
18
10
|
const router = useRouter()
|
|
19
11
|
// 获取默认值
|
|
@@ -56,7 +48,7 @@ const serviceName = ref('af-gaslink')
|
|
|
56
48
|
// 跳转到表单——以表单组来渲染纯表单
|
|
57
49
|
function toDetail(item) {
|
|
58
50
|
router.push({
|
|
59
|
-
name: '
|
|
51
|
+
name: 'XFormGroupView',
|
|
60
52
|
query: {
|
|
61
53
|
id: item[idKey.value],
|
|
62
54
|
// id: item.rr_id,
|
|
@@ -95,31 +87,18 @@ function toDetail(item) {
|
|
|
95
87
|
function deleteRow(result) {
|
|
96
88
|
emit('deleteRow', result.o_id)
|
|
97
89
|
}
|
|
98
|
-
|
|
99
|
-
// 多选操作处理
|
|
100
|
-
function handleMultiSelectAction(action: string, selectedItems: any[], selectedItemsArray: any[]) {
|
|
101
|
-
console.log('多选操作:', action, selectedItems, selectedItemsArray)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 选择变化处理
|
|
105
|
-
function handleSelectionChange(selectedItems: any[]) {
|
|
106
|
-
console.log('选择变化,当前选中:', selectedItems.length, '个项目')
|
|
107
|
-
// 可以在这里更新UI状态,比如显示选中数量等
|
|
108
|
-
}
|
|
109
90
|
</script>
|
|
110
91
|
|
|
111
92
|
<template>
|
|
112
93
|
<NormalDataLayout id="XCellListView" title="工作计划">
|
|
113
94
|
<template #layout_content>
|
|
114
95
|
<XCellList
|
|
115
|
-
config-name="
|
|
116
|
-
service-name="
|
|
117
|
-
:
|
|
118
|
-
id-key="
|
|
119
|
-
:multi-select-actions="multiSelectActions"
|
|
96
|
+
:config-name="configName"
|
|
97
|
+
:service-name="serviceName"
|
|
98
|
+
:fix-query-form="{ o_f_oper_name: 'edu_test' }"
|
|
99
|
+
:id-key="idKey"
|
|
120
100
|
@to-detail="toDetail"
|
|
121
|
-
@
|
|
122
|
-
@selection-change="handleSelectionChange"
|
|
101
|
+
@delete-row="deleteRow"
|
|
123
102
|
/>
|
|
124
103
|
</template>
|
|
125
104
|
</NormalDataLayout>
|
|
@@ -5,19 +5,16 @@ import { showDialog } from 'vant'
|
|
|
5
5
|
import { ref } from 'vue'
|
|
6
6
|
import { useRoute } from 'vue-router'
|
|
7
7
|
|
|
8
|
-
// const configName = ref('reviewFormGroup')
|
|
9
|
-
// const serviceName = ref('af-revenue')
|
|
10
|
-
|
|
11
8
|
// 纯表单
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const configName = ref('form_check_test')
|
|
10
|
+
const serviceName = ref('af-system')
|
|
14
11
|
|
|
15
12
|
// const configName = ref("计划下发Form")
|
|
16
13
|
// const serviceName = ref("af-linepatrol")
|
|
17
14
|
|
|
18
15
|
// 表单组
|
|
19
|
-
const configName = ref('lngChargeAuditMobileFormGroup')
|
|
20
|
-
const serviceName = ref('af-gaslink')
|
|
16
|
+
// const configName = ref('lngChargeAuditMobileFormGroup')
|
|
17
|
+
// const serviceName = ref('af-gaslink')
|
|
21
18
|
|
|
22
19
|
const formData = ref({})
|
|
23
20
|
const formGroup = ref(null)
|
|
@@ -25,8 +22,7 @@ const route = useRoute()
|
|
|
25
22
|
const isInit = ref(false)
|
|
26
23
|
function submit(_result) {
|
|
27
24
|
showDialog({ message: '提交成功' }).then(() => {
|
|
28
|
-
|
|
29
|
-
// history.back()
|
|
25
|
+
history.back()
|
|
30
26
|
})
|
|
31
27
|
}
|
|
32
28
|
|
|
@@ -67,8 +63,8 @@ function submit(_result) {
|
|
|
67
63
|
<!-- v-if="isInit" -->
|
|
68
64
|
<XFormGroup
|
|
69
65
|
ref="formGroup"
|
|
70
|
-
config-name="
|
|
71
|
-
service-name="
|
|
66
|
+
:config-name="configName"
|
|
67
|
+
:service-name="serviceName"
|
|
72
68
|
:group-form-data="formData"
|
|
73
69
|
mode="新增"
|
|
74
70
|
@submit="submit"
|
|
@@ -3,8 +3,8 @@ import XForm from '@af-mobile-client-vue3/components/data/XForm/index.vue'
|
|
|
3
3
|
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
|
|
6
|
-
const configName = ref('
|
|
7
|
-
const serviceName = ref('af-
|
|
6
|
+
const configName = ref('AddConstructionForm')
|
|
7
|
+
const serviceName = ref('af-linepatrol')
|
|
8
8
|
|
|
9
9
|
const formGroupAddConstruction = ref(null)
|
|
10
10
|
</script>
|
|
@@ -24,8 +24,16 @@ async function handleAuth() {
|
|
|
24
24
|
const authParam = route.query as Record<string, string>
|
|
25
25
|
|
|
26
26
|
if (authParam.platformType) {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
switch (authParam.platformType) {
|
|
28
|
+
case PlatformType.WECHAT_OFFICIAL:
|
|
29
|
+
case PlatformType.WECHAT_MINI:
|
|
30
|
+
// 微信公众号,微信小程序授权登录参数
|
|
31
|
+
await handleExternalLogin(authParam)
|
|
32
|
+
break
|
|
33
|
+
default:
|
|
34
|
+
// 其他环境使用原生扫码(需要页面跳转或调用原生API)
|
|
35
|
+
throw new Error('当前环境不支持授权登录')
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
else {
|
|
31
39
|
// 无授权参数,检查是否已登录或等待授权
|
|
@@ -49,9 +57,16 @@ async function handleAuth() {
|
|
|
49
57
|
|
|
50
58
|
// 处理外部用户登录
|
|
51
59
|
async function handleExternalLogin(loginParams: any) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
let data: any
|
|
61
|
+
if (loginParams.platformType === PlatformType.WECHAT_OFFICIAL) {
|
|
62
|
+
data = await userStore.loginExternal(Object.assign(loginParams, {
|
|
63
|
+
isMobile: true,
|
|
64
|
+
}))
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
data = await userStore.loginExternalMini(JSON.parse(loginParams.appData))
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
const loginInfo = {
|
|
56
71
|
f: data,
|
|
57
72
|
jwt: data.id,
|
|
@@ -310,10 +310,14 @@ async function submitRegistration(): Promise<void> {
|
|
|
310
310
|
try {
|
|
311
311
|
console.log('formData', formData.value)
|
|
312
312
|
const response = await openApiLogic(formData.value, 'registrationUser', 'af-system')
|
|
313
|
-
|
|
313
|
+
if (response.success) {
|
|
314
|
+
showSuccess.value = true
|
|
315
|
+
showSuccessToast('注册成功')
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
showSuccessToast(`注册失败,${response.msg}!`)
|
|
319
|
+
}
|
|
314
320
|
isSubmitting.value = false
|
|
315
|
-
showSuccess.value = true
|
|
316
|
-
showSuccessToast('注册成功')
|
|
317
321
|
}
|
|
318
322
|
catch (error) {
|
|
319
323
|
isSubmitting.value = false
|
|
@@ -705,12 +709,12 @@ onMounted(async () => {
|
|
|
705
709
|
<p><strong>手机号码:</strong>{{ formData.phone }}</p>
|
|
706
710
|
</div>
|
|
707
711
|
<div class="success-actions">
|
|
708
|
-
<VanButton type="default" @click="resetForm">
|
|
709
|
-
继续注册
|
|
710
|
-
</VanButton>
|
|
711
|
-
<VanButton type="primary" @click="goBack">
|
|
712
|
-
去登录
|
|
713
|
-
</VanButton>
|
|
712
|
+
<!-- <VanButton type="default" @click="resetForm"> -->
|
|
713
|
+
<!-- 继续注册 -->
|
|
714
|
+
<!-- </VanButton> -->
|
|
715
|
+
<!-- <VanButton type="primary" @click="goBack"> -->
|
|
716
|
+
<!-- 去登录 -->
|
|
717
|
+
<!-- </VanButton> -->
|
|
714
718
|
</div>
|
|
715
719
|
</div>
|
|
716
720
|
</VanPopup>
|