@kevisual/kv-login 0.0.1 → 0.0.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.
@@ -3,7 +3,7 @@ import { createMessage } from '../pages/kv-message.ts';
3
3
  import { WX_MP_APP_ID } from '../pages/kv-login.ts';
4
4
  export const message = createMessage();
5
5
  type LoginOpts = {
6
- loginMethod: 'password' | 'phone' | 'wechat' | 'wechat-mp',
6
+ loginMethod: 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket',
7
7
  data: any,
8
8
  el: HTMLElement
9
9
  }
@@ -38,7 +38,11 @@ export const loginHandle = async (opts: LoginOpts) => {
38
38
  console.warn('未知的登录方式:', loginMethod)
39
39
  }
40
40
  }
41
-
41
+ /**
42
+ * 使用用户名和密码登录
43
+ * @param data
44
+ * @returns
45
+ */
42
46
  const loginByPassword = async (data: { username: string, password: string }) => {
43
47
  console.log('使用用户名密码登录:', data)
44
48
  let needLogin = true; // 这里可以根据实际情况决定是否需要登录, 只能判断密码登录和手机号登录
@@ -185,4 +189,49 @@ const checkMpWechatInWx = async () => {
185
189
 
186
190
  setTimeout(() => {
187
191
  checkMpWechat();
188
- }, 100);
192
+ }, 100);
193
+
194
+ export const getQrCode = async () => {
195
+ const res = await query.post({
196
+ path: 'wx',
197
+ key: 'get-qrcode-ticket'
198
+ })
199
+ if (res.code !== 200) {
200
+ message.error('获取二维码失败');
201
+ return null;
202
+ }
203
+ return res?.data as { ticket: string, url: string }
204
+ }
205
+
206
+ export const checkMpQrCodeLogin = (ticket: string) => {
207
+ let run = true;
208
+ const fetchLoginStatus = async () => {
209
+ const res = await query.post({
210
+ path: 'wx',
211
+ key: 'check-qrcode-login',
212
+ payload: { ticket }
213
+ })
214
+ if (res.code === 200) {
215
+ message.success('登录成功');
216
+ clearTimeout(timer);
217
+ redirectHome();
218
+ } else {
219
+ // message.error(res.message || '登录失败');
220
+ if (res.code === 401) {
221
+ console.log('等待扫码登录...');
222
+ } else {
223
+ console.log('扫码登录状态:', res);
224
+ }
225
+ if (run) {
226
+ setTimeout(fetchLoginStatus, 2000);
227
+ }
228
+ }
229
+ }
230
+ const timer = setTimeout(fetchLoginStatus, 2000);
231
+ const close = () => {
232
+ console.log('停止检测扫码登录状态');
233
+ clearTimeout(timer);
234
+ run = false
235
+ }
236
+ return close;
237
+ }
@@ -1,21 +1,35 @@
1
1
  import { render, html } from 'lit-html'
2
- import { loginHandle, checkWechat } from '../modules/login-handle.ts'
2
+ import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'
3
+ import { loginHandle, checkWechat, getQrCode, checkMpQrCodeLogin } from '../modules/login-handle.ts'
3
4
  import { setWxerwma } from '../modules/wx/ws-login.ts';
4
5
  import { useCreateLoginQRCode } from '../modules/wx-mp/qr.ts';
5
6
  export const WX_MP_APP_ID = "wxff97d569b1db16b6";
6
7
  interface LoginMethod {
7
8
  id: LoginMethods
8
9
  name: string
9
- icon: string
10
+ icon: any
10
11
  appid?: string
11
12
  }
13
+ const wxmpSvg = `<svg t="1764510467010" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1958" width="32" height="32"><path d="M615.904 388.48c8.8 0 17.536 0.64 26.176 1.6-23.52-109.536-140.608-190.912-274.272-190.912C218.4 199.2 96 301.056 96 430.4c0 74.656 40.736 135.936 108.768 183.488l-27.2 81.792 95.04-47.648c33.984 6.72 61.28 13.632 95.2 13.632 8.544 0 16.992-0.416 25.376-1.088a202.496 202.496 0 0 1-8.384-56.96c0-118.752 101.984-215.136 231.104-215.136zM469.76 314.784c20.48 0 34.016 13.472 34.016 33.92 0 20.352-13.536 34.016-34.016 34.016-20.384 0-40.832-13.664-40.832-34.016 0-20.448 20.448-33.92 40.832-33.92zM279.52 382.72c-20.384 0-40.928-13.664-40.928-34.016 0-20.448 20.544-33.92 40.928-33.92 20.352 0 33.92 13.472 33.92 33.92 0 20.384-13.568 34.016-33.92 34.016z" fill="" p-id="1959"></path><path d="M864 600.352c0-108.672-108.736-197.28-230.88-197.28-129.344 0-231.2 88.576-231.2 197.28 0 108.864 101.856 197.248 231.2 197.248 27.072 0 54.368-6.816 81.568-13.632l74.56 40.8-20.448-67.904C823.328 715.936 864 661.664 864 600.352z m-305.856-34.016c-13.536 0-27.2-13.44-27.2-27.2 0-13.568 13.664-27.2 27.2-27.2 20.576 0 34.016 13.632 34.016 27.2 0 13.76-13.44 27.2-34.016 27.2z m149.536 0c-13.44 0-27.008-13.44-27.008-27.2 0-13.568 13.568-27.2 27.008-27.2 20.352 0 34.016 13.632 34.016 27.2 0 13.76-13.664 27.2-34.016 27.2z" fill="" p-id="1960"></path></svg>`
14
+ const wxOpenSvg = `<svg t="1764511395617" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3882" width="32" height="32"><path d="M256 259.584c-29.184 0-51.2 14.848-51.2 44.032s29.184 44.032 51.2 44.032c29.184 0 44.032-14.848 44.032-44.032s-22.016-44.032-44.032-44.032zM541.184 303.616c0-29.184-14.848-44.032-44.032-44.032-29.184 0-51.2 14.848-51.2 44.032s29.184 44.032 51.2 44.032c29.696 0 44.032-22.016 44.032-44.032zM614.4 508.416c-14.848 0-36.352 14.848-36.352 36.352 0 14.848 14.848 36.352 36.352 36.352 29.184 0 44.032-14.848 44.032-36.352 0-14.336-14.848-36.352-44.032-36.352z" p-id="3883"></path><path d="M1024 625.152c0-138.752-124.416-256-285.184-270.848-29.184-153.6-189.952-263.168-373.248-263.168C160.768 91.648 0 230.4 0 406.016c0 95.232 44.032 175.616 138.752 241.152L109.568 742.4c0 7.168 0 14.848 7.168 22.016h14.848l117.248-58.368h14.848c36.352 7.168 66.048 14.848 109.568 14.848 14.848 0 44.032-7.168 44.032-7.168C460.8 822.784 578.048 896 716.8 896c36.352 0 73.216-7.168 102.4-14.848l87.552 51.2h14.848c7.168-7.168 7.168-7.168 7.168-14.848l-22.016-87.552c80.896-58.368 117.248-131.584 117.248-204.8z m-621.568 51.2h-36.352c-36.352 0-66.048-7.168-95.232-14.848l-22.016-7.168h-7.168L153.6 698.368l22.016-66.048c0-7.168 0-14.848-7.168-14.848C80.384 559.616 36.352 486.4 36.352 398.848 36.352 245.248 182.784 128 358.4 128c160.768 0 300.032 95.232 329.216 226.816-168.448 0-300.032 117.248-300.032 263.168 7.168 22.016 14.848 44.032 14.848 58.368z m467.968 132.096c-7.168 7.168-7.168 7.168-7.168 14.848l14.848 51.2L819.2 844.8h-14.848c-29.184 7.168-66.048 14.848-95.232 14.848-146.432 0-270.848-102.4-270.848-226.816 0-131.584 124.416-233.984 270.848-233.984s270.848 102.4 270.848 226.816c0 65.536-36.352 123.904-109.568 182.784z" p-id="3884"></path><path d="M804.352 508.416c-14.848 0-36.352 14.848-36.352 36.352 0 14.848 14.848 36.352 36.352 36.352 29.184 0 44.032-14.848 44.032-36.352 0-14.336-14.336-36.352-44.032-36.352z" p-id="3885"></path></svg>`
15
+ const phone = `<svg t="1764511425462" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5097" width="32" height="32"><path d="M820.409449 797.228346q0 25.19685-10.07874 46.866142t-27.716535 38.299213-41.322835 26.204724-50.897638 9.574803l-357.795276 0q-27.212598 0-50.897638-9.574803t-41.322835-26.204724-27.716535-38.299213-10.07874-46.866142l0-675.275591q0-25.19685 10.07874-47.370079t27.716535-38.80315 41.322835-26.204724 50.897638-9.574803l357.795276 0q27.212598 0 50.897638 9.574803t41.322835 26.204724 27.716535 38.80315 10.07874 47.370079l0 675.275591zM738.771654 170.330709l-455.559055 0 0 577.511811 455.559055 0 0-577.511811zM510.992126 776.062992q-21.165354 0-36.787402 15.11811t-15.622047 37.291339q0 21.165354 15.622047 36.787402t36.787402 15.622047q22.173228 0 37.291339-15.622047t15.11811-36.787402q0-22.173228-15.11811-37.291339t-37.291339-15.11811zM591.622047 84.661417q0-8.062992-5.03937-12.598425t-11.086614-4.535433l-128 0q-5.03937 0-10.582677 4.535433t-5.543307 12.598425 5.03937 12.598425 11.086614 4.535433l128 0q6.047244 0 11.086614-4.535433t5.03937-12.598425z" p-id="5098"></path></svg>`
16
+ const pwd = `<svg t="1764511500570" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10511" width="32" height="32"><path d="M768.9216 422.72768 372.06016 422.72768C378.88 365.21984 329.37984 131.42016 512.2048 125.72672c173.83424-6.59456 146.78016 213.34016 146.78016 213.34016l85.13536 0.57344c0 0 24.73984-294.4-231.91552-295.8336C232.09984 58.01984 297.82016 377.18016 289.28 422.72768c1.98656 0 4.56704 0 7.29088 0-55.88992 0-101.21216 45.34272-101.21216 101.21216l0 337.38752c0 55.88992 45.34272 101.21216 101.21216 101.21216l472.35072 0c55.88992 0 101.21216-45.34272 101.21216-101.21216L870.13376 523.93984C870.13376 468.0704 824.79104 422.72768 768.9216 422.72768zM566.4768 717.02528l0 76.84096c0 18.57536-15.1552 33.73056-33.73056 33.73056-18.57536 0-33.73056-15.1552-33.73056-33.73056l0-76.84096c-20.09088-11.69408-33.73056-33.21856-33.73056-58.12224 0-37.2736 30.208-67.4816 67.4816-67.4816 37.2736 0 67.4816 30.208 67.4816 67.4816C600.22784 683.80672 586.58816 705.3312 566.4768 717.02528z" fill="#272636" p-id="10512"></path></svg>`
17
+
18
+ const icons: any = {
19
+ pwd,
20
+ phone,
21
+ wxmpSvg,
22
+ wxOpenSvg
23
+ }
12
24
  const DefaultLoginMethods: LoginMethod[] = [
13
- { id: 'password', name: '密码登录', icon: '🔒' },
14
- { id: 'wechat', name: '微信登录', icon: '💬', appid: "wx9378885c8390e09b" },
15
- { id: 'wechat-mp', name: '微信公众号登录', icon: '💬', appid: WX_MP_APP_ID },
16
- { id: 'phone', name: '手机号登录', icon: '📱' }
25
+ { id: 'password', name: '密码登录', icon: 'pwd' },
26
+ { id: 'wechat', name: '微信登录', icon: 'wxmpSvg', appid: "wx9378885c8390e09b" },
27
+ { id: 'wechat-mp', name: '微信公众号', icon: 'wxOpenSvg', appid: WX_MP_APP_ID },
28
+ { id: 'wechat-mp-ticket', name: '微信公众号', icon: 'wxOpenSvg' },
29
+ { id: 'phone', name: '手机号登录', icon: 'phone' }
17
30
  ]
18
- type LoginMethods = 'password' | 'phone' | 'wechat' | 'wechat-mp'
31
+ type LoginMethods = 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket';
32
+
19
33
  const getLoginMethodByDomain = (): LoginMethod[] => {
20
34
  const domain = window.location.hostname
21
35
  let methods: LoginMethods[] = []
@@ -24,10 +38,10 @@ const getLoginMethodByDomain = (): LoginMethod[] => {
24
38
  methods = ['password', 'wechat-mp']
25
39
  break;
26
40
  case 'kevisual.cn':
27
- methods = ['password', 'wechat']
41
+ methods = ['password', 'wechat', 'wechat-mp-ticket']
28
42
  break;
29
43
  default:
30
- methods = ['password', 'phone', 'wechat', 'wechat-mp']
44
+ methods = ['password', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket']
31
45
  break;
32
46
  }
33
47
  return DefaultLoginMethods.filter(method => methods.includes(method.id))
@@ -224,6 +238,31 @@ class KvLogin extends HTMLElement {
224
238
  </div>
225
239
  `
226
240
  }
241
+ private renderWechatMpTicketForm() {
242
+ const that = this;
243
+ setTimeout(async () => {
244
+ const data = await getQrCode();
245
+ if (!data) return;
246
+ const imgEl = that.shadowRoot!.querySelector('.qrcode') as HTMLImageElement;
247
+ if (data.url) {
248
+ imgEl.src = data.url;
249
+ // TODO: 轮询检测登录状态
250
+ const clear = checkMpQrCodeLogin(data.ticket)
251
+ // 当切换登录方式时,停止轮询
252
+ that.#clearTimer = clear
253
+ }
254
+ }, 0)
255
+ return html`
256
+ <div class="wechat-login">
257
+ <div class="qr-container">
258
+ <div class="qr-placeholder">
259
+ <img class="qrcode" width="300" height="300" data-appid="" data-size="200" data-ticket=""></img>
260
+ <p class="qr-desc">请使用微信扫描二维码登录</p>
261
+ </div>
262
+ </div>
263
+ </div>
264
+ `
265
+ }
227
266
 
228
267
  private sendVerificationCode() {
229
268
  console.log('发送验证码')
@@ -248,6 +287,8 @@ class KvLogin extends HTMLElement {
248
287
  return this.renderWechatForm()
249
288
  case 'wechat-mp':
250
289
  return this.renderWechatMpForm()
290
+ case 'wechat-mp-ticket':
291
+ return this.renderWechatMpTicketForm()
251
292
  default:
252
293
  return this.renderPasswordForm()
253
294
  }
@@ -256,6 +297,22 @@ class KvLogin extends HTMLElement {
256
297
  render() {
257
298
  if (!this.shadowRoot) return
258
299
 
300
+ const renderIcon = (icon: any) => {
301
+ // 如果是emoji字符,直接返回
302
+ if (typeof icon === 'string' && !icons[icon]) {
303
+ return html`<span class="method-icon-emoji">${icon}</span>`
304
+ }
305
+ // 如果是SVG引用,从icons对象获取
306
+ if (typeof icon === 'string' && icons[icon]) {
307
+ return html`<span class="method-icon-svg">${unsafeHTML(icons[icon])}</span>`
308
+ }
309
+ // 如果直接是SVG内容
310
+ if (typeof icon === 'string' && (icon.includes('<svg') || icon.includes('<?xml'))) {
311
+ return html`<span class="method-icon-svg">${unsafeHTML(icon)}</span>`
312
+ }
313
+ // 默认情况
314
+ return html`<span class="method-icon-emoji">${icon}</span>`
315
+ }
259
316
  const template = html`
260
317
  <style>
261
318
  :host {
@@ -298,7 +355,7 @@ class KvLogin extends HTMLElement {
298
355
 
299
356
  .login-method.active {
300
357
  background: white;
301
- color: #007bff;
358
+ color: #000000;
302
359
  }
303
360
 
304
361
  .login-method.active::after {
@@ -308,11 +365,33 @@ class KvLogin extends HTMLElement {
308
365
  left: 0;
309
366
  right: 0;
310
367
  height: 2px;
311
- background: #007bff;
368
+ background: #000000;
312
369
  }
313
370
 
314
371
  .method-icon {
315
372
  font-size: 20px;
373
+ display: flex;
374
+ align-items: center;
375
+ justify-content: center;
376
+ width: 24px;
377
+ height: 24px;
378
+ }
379
+
380
+ .method-icon-emoji {
381
+ font-size: 20px;
382
+ line-height: 1;
383
+ }
384
+
385
+ .method-icon-svg {
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: center;
389
+ }
390
+
391
+ .method-icon-svg svg {
392
+ width: 32px;
393
+ height: 32px;
394
+ display: block;
316
395
  }
317
396
 
318
397
  .method-name {
@@ -348,7 +427,7 @@ class KvLogin extends HTMLElement {
348
427
 
349
428
  .form-group input:focus {
350
429
  outline: none;
351
- border-color: #007bff;
430
+ border-color: #000000;
352
431
  }
353
432
 
354
433
  .code-group {
@@ -378,7 +457,7 @@ class KvLogin extends HTMLElement {
378
457
 
379
458
  .login-button {
380
459
  padding: 12px;
381
- background: #007bff;
460
+ background: #000000;
382
461
  color: white;
383
462
  border: none;
384
463
  border-radius: 8px;
@@ -389,7 +468,7 @@ class KvLogin extends HTMLElement {
389
468
  }
390
469
 
391
470
  .login-button:hover {
392
- background: #0056b3;
471
+ background: #333333;
393
472
  }
394
473
 
395
474
  .wechat-login {
@@ -400,9 +479,9 @@ class KvLogin extends HTMLElement {
400
479
  }
401
480
 
402
481
  .qr-container {
403
- width: 400px;
404
- height: 400px;
405
- border: 2px dashed #e9ecef;
482
+ width: 340px;
483
+ height: 340px;
484
+ border: 2px dashed #cccccc;
406
485
  border-radius: 8px;
407
486
  display: flex;
408
487
  align-items: center;
@@ -438,6 +517,10 @@ class KvLogin extends HTMLElement {
438
517
  .refresh-button:hover {
439
518
  background: #5a6268;
440
519
  }
520
+ .method-icon svg {
521
+ width: 24px;
522
+ height: 24px;
523
+ }
441
524
  </style>
442
525
 
443
526
  <div class="login-sidebar">
@@ -447,7 +530,7 @@ class KvLogin extends HTMLElement {
447
530
  class="login-method ${this.selectedMethod === method.id ? 'active' : ''}"
448
531
  data-method="${method.id}"
449
532
  >
450
- <span class="method-icon">${method.icon}</span>
533
+ ${renderIcon(method.icon)}
451
534
  <span class="method-name">${method.name}</span>
452
535
  </button>
453
536
  `)}