lgsso-sdk 1.2.7 → 1.3.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/dist/lgsso-sdk.cjs +249 -113
- package/dist/lgsso-sdk.esm.js +249 -113
- package/dist/lgsso-sdk.js +249 -113
- package/dist/lgsso-sdk.min.js +1 -1
- package/package.json +1 -1
- package/src/sso.js +213 -98
- package/src/utils.js +36 -15
package/src/sso.js
CHANGED
|
@@ -1,6 +1,93 @@
|
|
|
1
1
|
import { request } from './request';
|
|
2
2
|
import { isBrowser, getQueryParam, removeQueryParam, getCurrentUrlWithParams, mergeConfigs } from './utils';
|
|
3
3
|
|
|
4
|
+
// ===== Cookie操作工具函数 =====
|
|
5
|
+
/**
|
|
6
|
+
* 获取指定名称的Cookie值
|
|
7
|
+
* @param {string} name Cookie名称
|
|
8
|
+
* @returns {string|null} Cookie值
|
|
9
|
+
*/
|
|
10
|
+
function getCookie(name) {
|
|
11
|
+
if (!isBrowser()) return null;
|
|
12
|
+
const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
|
|
13
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 设置Cookie(支持指定根域名)
|
|
18
|
+
* @param {string} name Cookie名称
|
|
19
|
+
* @param {string} value Cookie值
|
|
20
|
+
* @param {Object} options 配置(expires: 过期天数/Date, path: 路径, domain: 域名)
|
|
21
|
+
*/
|
|
22
|
+
function setCookie(name, value, options = {}) {
|
|
23
|
+
if (!isBrowser()) return;
|
|
24
|
+
let cookieStr = `${name}=${encodeURIComponent(value)}`;
|
|
25
|
+
|
|
26
|
+
// 路径:默认根路径,确保全站可用
|
|
27
|
+
cookieStr += `; path=${options.path || '/'}`;
|
|
28
|
+
|
|
29
|
+
// 域名:指定根域名.zlgx.com(适配你的场景)
|
|
30
|
+
// 优先级:用户传入的domain > 默认根域名.zlgx.com
|
|
31
|
+
const targetDomain = options.domain || '.zlgx.com';
|
|
32
|
+
cookieStr += `; domain=${targetDomain}`;
|
|
33
|
+
|
|
34
|
+
// 过期时间(默认1天)
|
|
35
|
+
if (options.expires) {
|
|
36
|
+
const expires = typeof options.expires === 'number'
|
|
37
|
+
? new Date(Date.now() + options.expires * 86400000)
|
|
38
|
+
: options.expires;
|
|
39
|
+
cookieStr += `; expires=${expires.toUTCString()}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 可选:HTTPS环境下添加Secure(仅HTTPS传输)
|
|
43
|
+
if (options.secure || window.location.protocol === 'https:') {
|
|
44
|
+
cookieStr += '; Secure';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 可选:防止XSS攻击的HttpOnly(注意:HttpOnly的Cookie无法通过JS读取)
|
|
48
|
+
if (options.httpOnly) {
|
|
49
|
+
cookieStr += '; HttpOnly';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
document.cookie = cookieStr;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function removeCookie(name, options = {}) {
|
|
56
|
+
if (!isBrowser()) return;
|
|
57
|
+
setCookie(
|
|
58
|
+
name,
|
|
59
|
+
'',
|
|
60
|
+
{
|
|
61
|
+
expires: -1, // 立即过期
|
|
62
|
+
path: options.path || '/',
|
|
63
|
+
domain: options.domain || '.zlgx.com' // 必须和设置时一致
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 调用示例:删除根域名下的platType
|
|
69
|
+
removeCookie('platType', { domain: '.zlgx.com' });
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 给重定向地址拼接platType参数
|
|
73
|
+
* @param {string} redirectUrl 原始重定向地址
|
|
74
|
+
* @param {string} platType platType值
|
|
75
|
+
* @param {string} platTypeKey 参数名(默认platType)
|
|
76
|
+
* @returns {string} 拼接后的重定向地址
|
|
77
|
+
*/
|
|
78
|
+
function addPlatTypeToRedirectUrl(redirectUrl, platType, platTypeKey = 'platType') {
|
|
79
|
+
if (!redirectUrl || !platType) return redirectUrl;
|
|
80
|
+
try {
|
|
81
|
+
const url = new URL(redirectUrl);
|
|
82
|
+
url.searchParams.set(platTypeKey, platType);
|
|
83
|
+
return url.toString();
|
|
84
|
+
} catch (e) {
|
|
85
|
+
// 兼容非标准URL的情况(比如相对路径)
|
|
86
|
+
const separator = redirectUrl.includes('?') ? '&' : '?';
|
|
87
|
+
return `${redirectUrl}${separator}${platTypeKey}=${platType}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
4
91
|
// 默认配置
|
|
5
92
|
const DEFAULT_CONFIG = {
|
|
6
93
|
accessCodeKey: 'accessCode',
|
|
@@ -11,13 +98,14 @@ const DEFAULT_CONFIG = {
|
|
|
11
98
|
refreshCodeApi: '',
|
|
12
99
|
logoutApi: '',
|
|
13
100
|
logOutUrl: '',
|
|
14
|
-
storage: localStorage,
|
|
101
|
+
storage: localStorage,
|
|
15
102
|
oldPwdKey: 'oldPwd',
|
|
16
103
|
newPwdKey: 'newPwd',
|
|
17
104
|
changePasswordApi: '',
|
|
18
105
|
sendCaptchaCodeApi: '',
|
|
19
106
|
typeKey: 'type',
|
|
20
|
-
codeKey: 'code'
|
|
107
|
+
codeKey: 'code',
|
|
108
|
+
platTypeKey: 'platType' // platType参数名配置
|
|
21
109
|
};
|
|
22
110
|
|
|
23
111
|
let config = null;
|
|
@@ -40,46 +128,35 @@ function validateConfig(options) {
|
|
|
40
128
|
}
|
|
41
129
|
|
|
42
130
|
/**
|
|
43
|
-
* 判断是否是iOS
|
|
131
|
+
* 判断是否是iOS移动端
|
|
44
132
|
* @returns {boolean} 是否为iOS环境
|
|
45
133
|
*/
|
|
46
134
|
function isIOS() {
|
|
47
|
-
|
|
48
|
-
// if (!isBrowser()) return false;
|
|
135
|
+
if (!isBrowser()) return false;
|
|
49
136
|
|
|
50
137
|
const userAgent = navigator.userAgent.toLowerCase();
|
|
51
|
-
const platform = navigator.platform.toLowerCase();
|
|
138
|
+
const platform = navigator.platform.toLowerCase();
|
|
52
139
|
const maxTouchPoints = navigator.maxTouchPoints || 0;
|
|
53
|
-
const screenRatio = screen.width / screen.height;
|
|
140
|
+
const screenRatio = screen.width / screen.height;
|
|
54
141
|
|
|
55
|
-
// ========== 核心检测规则 ==========
|
|
56
|
-
// 1. 基础规则:iPhone/iPod 直接命中(无兼容问题)
|
|
57
142
|
const isIphoneIpod = /iphone|ipod/.test(userAgent) && !window.MSStream;
|
|
58
|
-
|
|
59
|
-
// 2. iPad 专属检测(覆盖所有iPad机型,含iPad Air)
|
|
60
143
|
const isIpad = (
|
|
61
|
-
// 场景1:老版本iPadOS/原生标识(platform含ipad)
|
|
62
144
|
platform.includes('ipad') ||
|
|
63
|
-
// 场景2:iPadOS 13+ 伪装Mac(UA含macintosh + 触摸+ 非Mac平台)
|
|
64
145
|
(
|
|
65
|
-
userAgent.includes('macintosh') &&
|
|
66
|
-
maxTouchPoints > 0 &&
|
|
67
|
-
!platform.includes('mac') &&
|
|
146
|
+
userAgent.includes('macintosh') &&
|
|
147
|
+
maxTouchPoints > 0 &&
|
|
148
|
+
!platform.includes('mac') &&
|
|
68
149
|
!window.MSStream
|
|
69
150
|
) ||
|
|
70
|
-
// 场景3:新版本iPadOS(UA直接含ipados,如iPad Air搭载的iPadOS 15+)
|
|
71
151
|
userAgent.includes('ipados') ||
|
|
72
|
-
// 场景4:极端场景(第三方浏览器如Chrome for iPad Air)
|
|
73
152
|
(
|
|
74
|
-
maxTouchPoints >= 5 &&
|
|
75
|
-
!platform.includes('android') &&
|
|
76
|
-
(screenRatio > 0.7 && screenRatio < 1.4)
|
|
153
|
+
maxTouchPoints >= 5 &&
|
|
154
|
+
!platform.includes('android') &&
|
|
155
|
+
(screenRatio > 0.7 && screenRatio < 1.4)
|
|
77
156
|
)
|
|
78
157
|
);
|
|
79
158
|
|
|
80
|
-
|
|
81
|
-
const result = isIphoneIpod || isIpad;
|
|
82
|
-
return result;
|
|
159
|
+
return isIphoneIpod || isIpad;
|
|
83
160
|
}
|
|
84
161
|
|
|
85
162
|
/**
|
|
@@ -99,9 +176,17 @@ export function createSSO() {
|
|
|
99
176
|
config = mergeConfigs(DEFAULT_CONFIG, options);
|
|
100
177
|
validateConfig(config);
|
|
101
178
|
|
|
179
|
+
// 初始化时检测URL中的platType并存入Cookie
|
|
180
|
+
if (isBrowser()) {
|
|
181
|
+
const platTypeFromUrl = getQueryParam(config.platTypeKey);
|
|
182
|
+
if (platTypeFromUrl) {
|
|
183
|
+
setCookie(config.platTypeKey, platTypeFromUrl);
|
|
184
|
+
// 可选:移除URL中的platType(避免重复显示)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
102
188
|
const accessCode = getQueryParam(config.accessCodeKey);
|
|
103
189
|
|
|
104
|
-
// 验证必要的API配置
|
|
105
190
|
if (!config.tokenApi) {
|
|
106
191
|
return { code: -100, msg: '缺少tokenApi配置', success: false };
|
|
107
192
|
}
|
|
@@ -120,14 +205,25 @@ export function createSSO() {
|
|
|
120
205
|
|
|
121
206
|
if (result.code === 0 && result.data) {
|
|
122
207
|
config.storage.setItem(config.tokenKey, result.data);
|
|
123
|
-
removeQueryParam(config.accessCodeKey);
|
|
208
|
+
removeQueryParam([config.accessCodeKey,config.platTypeKey]);
|
|
124
209
|
}
|
|
125
210
|
return result;
|
|
126
211
|
}
|
|
127
212
|
// 如果没有token,跳转到登录页
|
|
128
213
|
else if (!this.getToken()) {
|
|
129
214
|
if (isBrowser() && config.logOutUrl) {
|
|
130
|
-
|
|
215
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
216
|
+
const platTypeFromCookie = getCookie(config.platTypeKey);
|
|
217
|
+
// 1. 获取原始重定向地址
|
|
218
|
+
let redirectUri = getCurrentUrlWithParams();
|
|
219
|
+
// 2. 给重定向地址加platType参数
|
|
220
|
+
if (platTypeFromCookie) {
|
|
221
|
+
redirectUri = addPlatTypeToRedirectUrl(redirectUri, platTypeFromCookie, config.platTypeKey);
|
|
222
|
+
}
|
|
223
|
+
// 3. 构建登录页URL(仅带redirect_uri参数)
|
|
224
|
+
let loginUrl = new URL(config.logOutUrl);
|
|
225
|
+
loginUrl.searchParams.set('redirect_uri', encodeURIComponent(redirectUri));
|
|
226
|
+
window.location.href = loginUrl.toString();
|
|
131
227
|
}
|
|
132
228
|
}
|
|
133
229
|
|
|
@@ -159,33 +255,21 @@ export function createSSO() {
|
|
|
159
255
|
* @returns {Promise<Object>} 接口返回结果
|
|
160
256
|
*/
|
|
161
257
|
async logout() {
|
|
162
|
-
// 1. 前置校验:初始化状态
|
|
163
258
|
if (!config) {
|
|
164
259
|
return { code: -101, msg: '请先调用init方法初始化', success: false };
|
|
165
260
|
}
|
|
166
261
|
|
|
167
|
-
// 2. 工具函数:统一构建登录跳转URL(确保完整编码当前URL的所有参数/hash)
|
|
168
|
-
const buildLoginUrl = () => {
|
|
169
|
-
if (!config.logOutUrl || !isBrowser()) return '';
|
|
170
|
-
// 关键:获取当前完整URL(含query、hash)并完整编码,避免参数丢失
|
|
171
|
-
const currentFullUrl = window.location.href;
|
|
172
|
-
const encodedRedirectUri = encodeURIComponent(currentFullUrl);
|
|
173
|
-
return `${config.logOutUrl}?redirect_uri=${encodedRedirectUri}`;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// 3. 校验logoutApi配置(仅接口调用时需要,跳转登录页不受此影响)
|
|
177
262
|
if (!config.logoutApi) {
|
|
178
|
-
// 无logoutApi时仍清除token并跳转登录页,保证基础退出逻辑
|
|
179
|
-
this.removeToken();
|
|
180
|
-
const loginUrl = buildLoginUrl();
|
|
181
|
-
if (loginUrl) window.location.href = loginUrl;
|
|
182
263
|
return { code: -102, msg: '未配置logoutApi', success: false };
|
|
183
264
|
}
|
|
184
265
|
|
|
266
|
+
// 获取并删除Cookie中的platType
|
|
267
|
+
const platType = getCookie(config.platTypeKey);
|
|
268
|
+
removeCookie(config.platTypeKey);
|
|
269
|
+
|
|
185
270
|
const token = this.getToken();
|
|
186
271
|
if (token) {
|
|
187
272
|
try {
|
|
188
|
-
// 调用退出接口
|
|
189
273
|
const result = await request(
|
|
190
274
|
config.logoutApi,
|
|
191
275
|
{
|
|
@@ -194,37 +278,48 @@ export function createSSO() {
|
|
|
194
278
|
timeout: config.timeout
|
|
195
279
|
}
|
|
196
280
|
);
|
|
197
|
-
// 无论接口返回结果如何,都清除token
|
|
198
281
|
this.removeToken();
|
|
199
282
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
283
|
+
if (isBrowser() && config.logOutUrl) {
|
|
284
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
285
|
+
// 1. 获取原始重定向地址
|
|
286
|
+
let redirectUri = getCurrentUrlWithParams();
|
|
287
|
+
// 2. 给重定向地址加platType参数
|
|
288
|
+
if (platType) {
|
|
289
|
+
redirectUri = addPlatTypeToRedirectUrl(redirectUri, platType, config.platTypeKey);
|
|
290
|
+
}
|
|
291
|
+
// 3. 构建登录页URL
|
|
292
|
+
let logoutUrl = new URL(config.logOutUrl);
|
|
293
|
+
logoutUrl.searchParams.set('redirect_uri', encodeURIComponent(redirectUri));
|
|
294
|
+
window.location.href = logoutUrl.toString();
|
|
295
|
+
}
|
|
203
296
|
return result;
|
|
204
297
|
} catch (error) {
|
|
205
|
-
// 接口调用失败,仍清除token并跳转登录页
|
|
206
|
-
this.removeToken();
|
|
207
|
-
const loginUrl = buildLoginUrl();
|
|
208
|
-
if (loginUrl) window.location.href = loginUrl;
|
|
209
298
|
return { code: -103, msg: `退出失败: ${error.message}`, success: false };
|
|
210
299
|
}
|
|
211
300
|
} else {
|
|
212
|
-
// 无token时直接清除(兜底)并跳转登录页
|
|
213
301
|
this.removeToken();
|
|
214
|
-
|
|
215
|
-
|
|
302
|
+
if (isBrowser() && config.logOutUrl) {
|
|
303
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
304
|
+
let redirectUri = getCurrentUrlWithParams();
|
|
305
|
+
if (platType) {
|
|
306
|
+
redirectUri = addPlatTypeToRedirectUrl(redirectUri, platType, config.platTypeKey);
|
|
307
|
+
}
|
|
308
|
+
let logoutUrl = new URL(config.logOutUrl);
|
|
309
|
+
logoutUrl.searchParams.set('redirect_uri', encodeURIComponent(redirectUri));
|
|
310
|
+
window.location.href = logoutUrl.toString();
|
|
311
|
+
}
|
|
216
312
|
return { code: 0, msg: '已成功清除token', success: true };
|
|
217
313
|
}
|
|
218
314
|
},
|
|
219
315
|
|
|
220
316
|
/**
|
|
221
317
|
* 用token换取新accessCode并跳转到指定URL
|
|
222
|
-
* @param {string} redirectUrl -
|
|
318
|
+
* @param {string} redirectUrl - 目标跳转地址
|
|
223
319
|
* @param {string} target - 当前页面:_self、新页面打开:_blank,默认当前页_self
|
|
224
320
|
* @returns {Promise<Object>} 接口返回结果
|
|
225
321
|
*/
|
|
226
322
|
async toUrl(redirectUrl, target = '_self') {
|
|
227
|
-
// 1. 前置校验:初始化状态、参数合法性
|
|
228
323
|
if (!config) {
|
|
229
324
|
return { code: -101, msg: '请先调用init方法初始化', success: false };
|
|
230
325
|
}
|
|
@@ -233,45 +328,49 @@ export function createSSO() {
|
|
|
233
328
|
return { code: -104, msg: '请提供跳转地址', success: false };
|
|
234
329
|
}
|
|
235
330
|
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
: (isIOS() ? '_self' : target); // 否则沿用原iOS判断逻辑
|
|
246
|
-
|
|
247
|
-
if (!['_self', '_blank'].includes(finalTarget)) {
|
|
248
|
-
return { code: -108, msg: 'target参数必须是"_self"或"_blank"', success: false };
|
|
331
|
+
// iOS强制_self
|
|
332
|
+
if (isIOS()) {
|
|
333
|
+
target = '_self';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// platType=screen时强制_self
|
|
337
|
+
const platType = getCookie(config.platTypeKey);
|
|
338
|
+
if (platType === 'screen') {
|
|
339
|
+
target = '_self';
|
|
249
340
|
}
|
|
250
341
|
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const encodedRedirectUri = encodeURIComponent(redirectUrl);
|
|
256
|
-
return `${config.logOutUrl}?redirect_uri=${encodedRedirectUri}`;
|
|
257
|
-
};
|
|
342
|
+
// 验证target参数
|
|
343
|
+
if (!['_self', '_blank'].includes(target)) {
|
|
344
|
+
return { code: -108, msg: 'target参数必须是"_self"或"_blank"', success: false };
|
|
345
|
+
}
|
|
258
346
|
|
|
259
|
-
// 4. 校验refreshCodeApi配置
|
|
260
347
|
if (!config.refreshCodeApi) {
|
|
261
348
|
return { code: -105, msg: '未配置refreshCodeApi', success: false };
|
|
262
349
|
}
|
|
263
350
|
|
|
264
|
-
// 5. 获取token,无token则直接跳登录页
|
|
265
351
|
const token = this.getToken();
|
|
266
352
|
if (!token) {
|
|
267
353
|
if (isBrowser() && config.logOutUrl) {
|
|
268
|
-
|
|
269
|
-
|
|
354
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
355
|
+
// 1. 给目标跳转地址加platType
|
|
356
|
+
let newRedirectUrl = redirectUrl;
|
|
357
|
+
if (platType) {
|
|
358
|
+
newRedirectUrl = addPlatTypeToRedirectUrl(newRedirectUrl, platType, config.platTypeKey);
|
|
359
|
+
}
|
|
360
|
+
// 2. 构建登录页URL
|
|
361
|
+
let loginUrl = new URL(config.logOutUrl);
|
|
362
|
+
loginUrl.searchParams.set('redirect_uri', encodeURIComponent(newRedirectUrl));
|
|
363
|
+
const loginUrlStr = loginUrl.toString();
|
|
364
|
+
|
|
365
|
+
if (target === '_blank') {
|
|
366
|
+
window.open(loginUrlStr, '_blank');
|
|
367
|
+
} else {
|
|
368
|
+
window.location.href = loginUrlStr;
|
|
369
|
+
}
|
|
270
370
|
}
|
|
271
371
|
return { code: -106, msg: '未找到有效token', success: false };
|
|
272
372
|
}
|
|
273
373
|
|
|
274
|
-
// 6. 有token则尝试换取accessCode并跳转
|
|
275
374
|
try {
|
|
276
375
|
const result = await request(
|
|
277
376
|
config.refreshCodeApi,
|
|
@@ -283,31 +382,48 @@ export function createSSO() {
|
|
|
283
382
|
);
|
|
284
383
|
|
|
285
384
|
if (result.code === 0 && result.data && isBrowser()) {
|
|
286
|
-
//
|
|
385
|
+
// toUrl跳转目标地址时,仅携带accessCode,不携带platType
|
|
287
386
|
const url = new URL(redirectUrl);
|
|
288
|
-
// 1. 如果当前页面有platType,拼接到目标URL(覆盖原有platType)
|
|
289
|
-
if (currentPlatType) {
|
|
290
|
-
url.searchParams.set('platType', currentPlatType);
|
|
291
|
-
}
|
|
292
|
-
// 2. 拼接accessCode(保留原有逻辑)
|
|
293
387
|
url.searchParams.set(config.accessCodeKey, result.data);
|
|
294
388
|
const targetUrl = url.toString();
|
|
295
389
|
|
|
296
|
-
|
|
390
|
+
if (target === '_blank') {
|
|
391
|
+
window.open(targetUrl, '_blank');
|
|
392
|
+
} else {
|
|
393
|
+
window.location.href = targetUrl;
|
|
394
|
+
}
|
|
297
395
|
} else {
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
396
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
397
|
+
let newRedirectUrl = redirectUrl;
|
|
398
|
+
if (platType) {
|
|
399
|
+
newRedirectUrl = addPlatTypeToRedirectUrl(newRedirectUrl, platType, config.platTypeKey);
|
|
400
|
+
}
|
|
401
|
+
let loginUrl = new URL(config.logOutUrl);
|
|
402
|
+
loginUrl.searchParams.set('redirect_uri', encodeURIComponent(newRedirectUrl));
|
|
403
|
+
const loginUrlStr = loginUrl.toString();
|
|
404
|
+
|
|
405
|
+
if (target === '_blank') {
|
|
406
|
+
window.open(loginUrlStr, '_blank');
|
|
407
|
+
} else {
|
|
408
|
+
window.location.href = loginUrlStr;
|
|
302
409
|
}
|
|
303
410
|
}
|
|
304
411
|
|
|
305
412
|
return result;
|
|
306
413
|
} catch (error) {
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
414
|
+
// ===== 核心修正:platType拼到redirect_uri里 =====
|
|
415
|
+
let newRedirectUrl = redirectUrl;
|
|
416
|
+
if (platType) {
|
|
417
|
+
newRedirectUrl = addPlatTypeToRedirectUrl(newRedirectUrl, platType, config.platTypeKey);
|
|
418
|
+
}
|
|
419
|
+
let loginUrl = new URL(config.logOutUrl);
|
|
420
|
+
loginUrl.searchParams.set('redirect_uri', encodeURIComponent(newRedirectUrl));
|
|
421
|
+
const loginUrlStr = loginUrl.toString();
|
|
422
|
+
|
|
423
|
+
if (target === '_blank') {
|
|
424
|
+
window.open(loginUrlStr, '_blank');
|
|
425
|
+
} else {
|
|
426
|
+
window.location.href = loginUrlStr;
|
|
311
427
|
}
|
|
312
428
|
return { code: -107, msg: `跳转失败: ${error.message}`, success: false };
|
|
313
429
|
}
|
|
@@ -346,7 +462,7 @@ export function createSSO() {
|
|
|
346
462
|
* @returns {Object|null} 当前配置
|
|
347
463
|
*/
|
|
348
464
|
getConfig() {
|
|
349
|
-
return { ...config };
|
|
465
|
+
return { ...config };
|
|
350
466
|
},
|
|
351
467
|
|
|
352
468
|
async changePassword(fromData = {}) {
|
|
@@ -375,7 +491,6 @@ export function createSSO() {
|
|
|
375
491
|
|
|
376
492
|
async getPhoneCode() {
|
|
377
493
|
const token = this.getToken();
|
|
378
|
-
// 修复笔误:sendCaptchaCode → sendCaptchaCodeApi
|
|
379
494
|
return request(
|
|
380
495
|
config.sendCaptchaCodeApi,
|
|
381
496
|
{
|
package/src/utils.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @Author: Robin LEI
|
|
3
3
|
* @Date: 2025-08-21 15:09:15
|
|
4
|
-
* @LastEditTime:
|
|
5
|
-
* @FilePath: \
|
|
4
|
+
* @LastEditTime: 2026-01-23 11:28:26
|
|
5
|
+
* @FilePath: \lims-frontd:\业务代码\中联钢信\五服一管\lg-ssosdk\src\utils.js
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
8
|
* 检查是否在浏览器环境
|
|
@@ -38,38 +38,58 @@ export function getQueryParam(name, url) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* 移除URL
|
|
42
|
-
* @param {string}
|
|
41
|
+
* 移除URL中的指定参数(支持单个或多个)
|
|
42
|
+
* @param {string|string[]} names - 要删除的参数名(单个字符串或字符串数组)
|
|
43
43
|
*/
|
|
44
|
-
export function removeQueryParam(
|
|
44
|
+
export function removeQueryParam(names) {
|
|
45
45
|
if (!isBrowser()) return;
|
|
46
46
|
|
|
47
|
+
// 统一转为数组,兼容单个参数的调用方式
|
|
48
|
+
const paramNames = Array.isArray(names) ? names : [names];
|
|
49
|
+
if (paramNames.length === 0) return; // 无参数需删除时直接返回
|
|
50
|
+
|
|
47
51
|
const url = new URL(window.location.href);
|
|
48
|
-
let
|
|
52
|
+
let newUrl;
|
|
49
53
|
|
|
50
54
|
// 处理hash模式(参数在#之后)
|
|
51
55
|
if (url.hash.includes('?')) {
|
|
52
56
|
const [hashPath, hashQuery] = url.hash.split('?');
|
|
53
|
-
params = new URLSearchParams(hashQuery);
|
|
57
|
+
const params = new URLSearchParams(hashQuery);
|
|
58
|
+
|
|
59
|
+
// 批量删除参数
|
|
60
|
+
paramNames.forEach(name => {
|
|
61
|
+
if (params.has(name)) {
|
|
62
|
+
params.delete(name);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
// 重构hash部分
|
|
67
|
+
const newHash = params.toString() ? `${hashPath}?${params.toString()}` : hashPath;
|
|
68
|
+
if (newHash !== url.hash) { // 只有hash变化时才更新URL
|
|
58
69
|
url.hash = newHash;
|
|
59
70
|
newUrl = url.toString();
|
|
60
71
|
}
|
|
61
72
|
}
|
|
62
73
|
// 处理history模式(参数在?之后)
|
|
63
74
|
else {
|
|
64
|
-
params = new URLSearchParams(url.search);
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
const params = new URLSearchParams(url.search);
|
|
76
|
+
let hasChanged = false;
|
|
77
|
+
|
|
78
|
+
// 批量删除参数
|
|
79
|
+
paramNames.forEach(name => {
|
|
80
|
+
if (params.has(name)) {
|
|
81
|
+
params.delete(name);
|
|
82
|
+
hasChanged = true;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// 只有参数变化时才更新URL
|
|
87
|
+
if (hasChanged) {
|
|
67
88
|
url.search = params.toString();
|
|
68
89
|
newUrl = url.toString();
|
|
69
90
|
}
|
|
70
91
|
}
|
|
71
|
-
|
|
72
|
-
// 更新URL
|
|
92
|
+
// 更新URL(仅当URL有变化时)
|
|
73
93
|
if (newUrl && newUrl !== window.location.href) {
|
|
74
94
|
window.location.replace(newUrl);
|
|
75
95
|
}
|
|
@@ -92,6 +112,7 @@ export function getCurrentUrlWithParams() {
|
|
|
92
112
|
*/
|
|
93
113
|
export function mergeConfigs(defaults, options) {
|
|
94
114
|
if (!options) return { ...defaults };
|
|
115
|
+
|
|
95
116
|
const merged = { ...defaults };
|
|
96
117
|
for (const key in options) {
|
|
97
118
|
if (options.hasOwnProperty(key)) {
|