diff --git a/index.html b/index.html index ebdf399..f164f39 100644 --- a/index.html +++ b/index.html @@ -74,7 +74,8 @@

登录组件

- + +
diff --git a/package.json b/package.json index 609156d..a8fb6e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/kv-login", - "version": "0.1.1", + "version": "0.1.4", "description": "", "main": "src/main.ts", "scripts": { @@ -9,25 +9,26 @@ "postbuild": "dts -i src/main.ts -o app.d.ts", "build:test": "vite build", "prepub": "rm -rf ./dist && pnpm run build:test", - "pub": "ev deploy ./dist -k kv-login-test -v 0.0.6 -u -y yes" + "pub": "ev deploy ./dist -k login -v 0.1.4 -u -y yes" }, "keywords": [], + "files": [ + "types", + "src", + "dist" + ], "author": "abearxiong (https://www.xiongxiao.me)", "license": "MIT", - "packageManager": "pnpm@10.26.0", + "packageManager": "pnpm@10.26.2", "publishConfig": { "access": "public" }, "type": "module", - "files": [ - "types", - "dist" - ], "dependencies": { "@kevisual/context": "^0.0.4", - "@kevisual/query": "^0.0.32", "@kevisual/query-login": "^0.0.7", - "lit-html": "^3.3.1", + "crypto-js": "^4.2.0", + "lit-html": "^3.3.2", "qrcode": "^1.5.4" }, "exports": { @@ -36,8 +37,7 @@ }, "types": "./types/index.d.ts", "devDependencies": { - "@types/bun": "^1.3.4", - "@types/qrcode": "^1.5.6", - "vite": "^7.3.0" + "@kevisual/api": "^0.0.8", + "@types/bun": "^1.3.5" } } \ No newline at end of file diff --git a/readme.md b/readme.md index 9a006a1..699f2e4 100644 --- a/readme.md +++ b/readme.md @@ -4,24 +4,9 @@ 黑白 + ```html +
-``` - -## 网页 - -```html - - - - -``` +``` \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index b4215c1..43d4853 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,6 @@ import './pages/kv-login' import './pages/kv-message' -export { loginEmitter } from './pages/kv-login' \ No newline at end of file +export { loginEmitter } from './pages/kv-login' + +export { checkPluginLogin, clearCode } from './modules/login-handle'; \ No newline at end of file diff --git a/src/modules/login-handle.ts b/src/modules/login-handle.ts index c559c36..359ecab 100644 --- a/src/modules/login-handle.ts +++ b/src/modules/login-handle.ts @@ -2,9 +2,11 @@ import { query } from './query.ts'; import { createMessage } from '../pages/kv-message.ts'; import { WX_MP_APP_ID } from '../pages/kv-login.ts'; import { emit } from './mitt.ts'; +import { Query } from '@kevisual/query'; +import { QueryLoginBrowser } from '@kevisual/api/login' export const message = createMessage(); type LoginOpts = { - loginMethod: 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket', + loginMethod: 'password' | 'web' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket', data: any, el: HTMLElement } @@ -40,10 +42,28 @@ export const loginHandle = async (opts: LoginOpts) => { case 'wechat': await loginByWeChat(data) break + case 'web': + await loginByWeb(data) + break default: console.warn('未知的登录方式:', loginMethod) } } +const loginByWeb = async (data: {}) => { + const url = new URL("https://kevisual.cn/api/router"); + const query = new Query({ url: "https://kevisual.cn/api/router" }) + const login = new QueryLoginBrowser({ query }) + // @ts-ignore + const res = login.loginWithWeb(url.origin, {}) + console.log('打开网页登录:', res) + window.open(res.url, '_blank'); + const status = await login.pollLoginStatus(res); + if (status) { + redirectHome() + } else { + message.error('网页登录失败,请重试') + } +} /** * 使用用户名和密码登录 * @param data @@ -93,11 +113,13 @@ const loginByWeChatMp = async (data: { wechatMpCode: string }) => { console.log('使用微信公众号登录:', data) } -const clearCode = () => { +export const clearCode = () => { const url = new URL(window.location.href); // 清理 URL 中的 code 参数 url.searchParams.delete('code'); url.searchParams.delete('state'); + url.searchParams.delete('user-check'); + url.searchParams.delete('redirect'); window.history.replaceState({}, document.title, url.toString()); } export const checkWechat = async () => { @@ -146,6 +168,29 @@ export const checkMpWechat = async () => { closePage(); } } +export const checkPluginLogin = async () => { + const userCheck = 'user-check'; + const url = new URL(location.href); + const redirect = url.searchParams.get('redirect'); + const redirectUrl = redirect ? decodeURIComponent(redirect) : ''; + const checkKey = url.searchParams.get(userCheck); + if (redirect && checkKey) { + // 通过refresh_token 刷新token + const me = await query.getMe(); + if (me.code === 200) { + message.success('登录插件中...'); + const token = await query.cacheStore.getAccessToken(); + const newRedirectUrl = new URL(redirectUrl); + newRedirectUrl.searchParams.set('token', token + ''); + setTimeout(() => { + window.open(newRedirectUrl.toString(), '_blank'); + }, 2000); + return; + } + // 刷新token失败,登陆页自己跳转 + } + console.log('checkKey', checkKey, redirectUrl); +} const isWechat = () => { const ua = navigator.userAgent.toLowerCase(); return /micromessenger/i.test(ua); diff --git a/src/pages/kv-login.ts b/src/pages/kv-login.ts index 6379677..2632e14 100644 --- a/src/pages/kv-login.ts +++ b/src/pages/kv-login.ts @@ -1,10 +1,11 @@ import { render, html } from 'lit-html' import { unsafeHTML } from 'lit-html/directives/unsafe-html.js' -import { loginHandle, checkWechat, getQrCode, checkMpQrCodeLogin } from '../modules/login-handle.ts' +import { loginHandle, checkWechat, getQrCode, checkMpQrCodeLogin, redirectHome } from '../modules/login-handle.ts' import { setWxerwma } from '../modules/wx/ws-login.ts'; import { useCreateLoginQRCode } from '../modules/wx-mp/qr.ts'; import { eventEmitter } from '../modules/mitt.ts'; import { useContextKey } from '@kevisual/context' + export const loginEmitter = useContextKey('login-emitter', eventEmitter); export const WX_MP_APP_ID = "wxff97d569b1db16b6"; interface LoginMethod { @@ -17,29 +18,31 @@ const wxmpSvg = `` const phone = `` const pwd = `` - +const web = `` const icons: any = { pwd, + web, phone, wxmpSvg, wxOpenSvg } const DefaultLoginMethods: LoginMethod[] = [ { id: 'password', name: '密码登录', icon: 'pwd' }, + { id: 'web', name: '网页登录', icon: 'web' }, { id: 'wechat', name: '微信登录', icon: 'wxmpSvg', appid: "wx9378885c8390e09b" }, { id: 'wechat-mp', name: '微信公众号', icon: 'wxOpenSvg', appid: WX_MP_APP_ID }, { id: 'wechat-mp-ticket', name: '微信公众号', icon: 'wxOpenSvg' }, { id: 'phone', name: '手机号登录', icon: 'phone' } ] -const LoginMethods = ['password', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket'] as const; -type LoginMethods = 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket'; +const LoginMethods = ['password', 'web', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket'] as const; +type LoginMethods = 'password' | 'web' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket'; const getLoginMethodByDomain = (): LoginMethod[] => { let domain = window.location.host let methods: LoginMethods[] = [] - const has51015 = domain.includes('51015'); - if (has51015) { - domain = 'localhost:51015' + const has51 = domain.includes('localhost') && (domain.endsWith('51515') || domain.endsWith('51015')); + if (has51) { + domain = 'localhost' } switch (domain) { case 'kevisual.xiongxiao.me': @@ -48,11 +51,11 @@ const getLoginMethodByDomain = (): LoginMethod[] => { case 'kevisual.cn': methods = ['password', 'wechat-mp-ticket', 'wechat',] break; - case 'localhost:51015': - methods = ['password'] + case 'localhost': + methods = ['password', 'web'] break default: - methods = ['password', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket'] + methods = ['password', 'web', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket'] break; } return DefaultLoginMethods.filter(method => methods.includes(method.id)) @@ -85,7 +88,6 @@ class KvLogin extends HTMLElement { if (loginMethods.length > 0) { this.loginMethods = getLoginMethod(loginMethods) this.selectedMethod = loginMethods[0] - this.setLoginMethods(this.loginMethods); return; } } @@ -134,6 +136,8 @@ class KvLogin extends HTMLElement { private handleLogin() { const formData = this.getFormData() + // console.log('登录方式:', this.selectedMethod) + // console.log('登录数据:', formData) loginHandle({ loginMethod: this.selectedMethod, data: formData, @@ -160,7 +164,8 @@ class KvLogin extends HTMLElement { username: username?.value || '', password: password?.value || '' } - + case 'web': + return {} case 'phone': const phone = this.shadowRoot.querySelector('#phone') as HTMLInputElement const code = this.shadowRoot.querySelector('#code') as HTMLInputElement @@ -209,7 +214,14 @@ class KvLogin extends HTMLElement { ` } - + private renderWebForm() { + return html` +
+ + +
+ ` + } private renderPhoneForm() { return html`
@@ -307,6 +319,8 @@ class KvLogin extends HTMLElement { switch (this.selectedMethod) { case 'password': return this.renderPasswordForm() + case 'web': + return this.renderWebForm() case 'phone': return this.renderPhoneForm() case 'wechat': @@ -320,18 +334,10 @@ class KvLogin extends HTMLElement { return this.renderPasswordForm() } } - createWeixinEl(){ - const id = 'weixinLogin'; - let el = this.querySelector('#' + id); - if (el) return el; - const weixinEl = document.createElement('div'); - weixinEl.id = 'weixinLogin'; - this.appendChild(weixinEl); - return weixinEl; - } + render() { if (!this.shadowRoot) return - this.createWeixinEl(); + const renderIcon = (icon: any) => { // 如果是emoji字符,直接返回 if (typeof icon === 'string' && !icons[icon]) {