diff --git a/package.json b/package.json index c16e952..baec1a3 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@astrojs/sitemap": "^3.6.0", "@floating-ui/dom": "^1.7.4", "@kevisual/context": "^0.0.4", + "@kevisual/kv-login": "^0.0.1", "@kevisual/query": "0.0.29", "@kevisual/query-login": "^0.0.6", "@kevisual/registry": "^0.0.1", diff --git a/packages/kv-login/package.json b/packages/kv-login/package.json index 461aa53..49f7283 100644 --- a/packages/kv-login/package.json +++ b/packages/kv-login/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/kv-login", - "version": "0.0.1", + "version": "0.0.2", "description": "", "main": "src/main.ts", "scripts": { @@ -8,7 +8,7 @@ "build": "vite build --config vite-lib.config.ts", "build:test": "vite build", "prepub": "rm -rf ./dist && pnpm run build:test", - "pub": "ev deploy ./dist -k kv-login-test -v 0.0.1 -u -y yes" + "pub": "ev deploy ./dist -k kv-login-test -v 0.0.2 -u -y yes" }, "keywords": [], "author": "abearxiong (https://www.xiongxiao.me)", diff --git a/packages/kv-login/src/modules/login-handle.ts b/packages/kv-login/src/modules/login-handle.ts index c3b1751..7c7a4ff 100644 --- a/packages/kv-login/src/modules/login-handle.ts +++ b/packages/kv-login/src/modules/login-handle.ts @@ -3,7 +3,7 @@ import { createMessage } from '../pages/kv-message.ts'; import { WX_MP_APP_ID } from '../pages/kv-login.ts'; export const message = createMessage(); type LoginOpts = { - loginMethod: 'password' | 'phone' | 'wechat' | 'wechat-mp', + loginMethod: 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket', data: any, el: HTMLElement } @@ -38,7 +38,11 @@ export const loginHandle = async (opts: LoginOpts) => { console.warn('未知的登录方式:', loginMethod) } } - +/** + * 使用用户名和密码登录 + * @param data + * @returns + */ const loginByPassword = async (data: { username: string, password: string }) => { console.log('使用用户名密码登录:', data) let needLogin = true; // 这里可以根据实际情况决定是否需要登录, 只能判断密码登录和手机号登录 @@ -185,4 +189,49 @@ const checkMpWechatInWx = async () => { setTimeout(() => { checkMpWechat(); -}, 100); \ No newline at end of file +}, 100); + +export const getQrCode = async () => { + const res = await query.post({ + path: 'wx', + key: 'get-qrcode-ticket' + }) + if (res.code !== 200) { + message.error('获取二维码失败'); + return null; + } + return res?.data as { ticket: string, url: string } +} + +export const checkMpQrCodeLogin = (ticket: string) => { + let run = true; + const fetchLoginStatus = async () => { + const res = await query.post({ + path: 'wx', + key: 'check-qrcode-login', + payload: { ticket } + }) + if (res.code === 200) { + message.success('登录成功'); + clearTimeout(timer); + redirectHome(); + } else { + // message.error(res.message || '登录失败'); + if (res.code === 401) { + console.log('等待扫码登录...'); + } else { + console.log('扫码登录状态:', res); + } + if (run) { + setTimeout(fetchLoginStatus, 2000); + } + } + } + const timer = setTimeout(fetchLoginStatus, 2000); + const close = () => { + console.log('停止检测扫码登录状态'); + clearTimeout(timer); + run = false + } + return close; +} diff --git a/packages/kv-login/src/pages/kv-login.ts b/packages/kv-login/src/pages/kv-login.ts index c809b9c..b57fec0 100644 --- a/packages/kv-login/src/pages/kv-login.ts +++ b/packages/kv-login/src/pages/kv-login.ts @@ -1,5 +1,5 @@ import { render, html } from 'lit-html' -import { loginHandle, checkWechat } from '../modules/login-handle.ts' +import { loginHandle, checkWechat, getQrCode, checkMpQrCodeLogin } from '../modules/login-handle.ts' import { setWxerwma } from '../modules/wx/ws-login.ts'; import { useCreateLoginQRCode } from '../modules/wx-mp/qr.ts'; export const WX_MP_APP_ID = "wxff97d569b1db16b6"; @@ -13,9 +13,10 @@ const DefaultLoginMethods: LoginMethod[] = [ { id: 'password', name: '密码登录', icon: '🔒' }, { id: 'wechat', name: '微信登录', icon: '💬', appid: "wx9378885c8390e09b" }, { id: 'wechat-mp', name: '微信公众号登录', icon: '💬', appid: WX_MP_APP_ID }, + { id: 'wechat-mp-ticket', name: '微信公众号登录', icon: '💬' }, { id: 'phone', name: '手机号登录', icon: '📱' } ] -type LoginMethods = 'password' | 'phone' | 'wechat' | 'wechat-mp' +type LoginMethods = 'password' | 'phone' | 'wechat' | 'wechat-mp' | 'wechat-mp-ticket'; const getLoginMethodByDomain = (): LoginMethod[] => { const domain = window.location.hostname let methods: LoginMethods[] = [] @@ -24,10 +25,10 @@ const getLoginMethodByDomain = (): LoginMethod[] => { methods = ['password', 'wechat-mp'] break; case 'kevisual.cn': - methods = ['password', 'wechat'] + methods = ['password', 'wechat', 'wechat-mp-ticket'] break; default: - methods = ['password', 'phone', 'wechat', 'wechat-mp'] + methods = ['password', 'phone', 'wechat', 'wechat-mp', 'wechat-mp-ticket'] break; } return DefaultLoginMethods.filter(method => methods.includes(method.id)) @@ -224,6 +225,31 @@ class KvLogin extends HTMLElement { ` } + private renderWechatMpTicketForm() { + const that = this; + setTimeout(async () => { + const data = await getQrCode(); + if (!data) return; + const imgEl = that.shadowRoot!.querySelector('.qrcode') as HTMLImageElement; + if (data.url) { + imgEl.src = data.url; + // TODO: 轮询检测登录状态 + const clear = checkMpQrCodeLogin(data.ticket) + // 当切换登录方式时,停止轮询 + that.#clearTimer = clear + } + }, 0) + return html` +
+
+
+ +

请使用微信扫描二维码登录

+
+
+
+ ` + } private sendVerificationCode() { console.log('发送验证码') @@ -248,6 +274,8 @@ class KvLogin extends HTMLElement { return this.renderWechatForm() case 'wechat-mp': return this.renderWechatMpForm() + case 'wechat-mp-ticket': + return this.renderWechatMpTicketForm() default: return this.renderPasswordForm() } diff --git a/packages/user-login/package.json b/packages/user-login/package.json index 97969a3..c414856 100644 --- a/packages/user-login/package.json +++ b/packages/user-login/package.json @@ -19,7 +19,6 @@ "@kevisual/query": "0.0.29", "@kevisual/query-login": "^0.0.6", "@kevisual/system-lib": "^0.0.22", - "@kevisual/system-ui": "^0.0.3", "clsx": "^2.1.1", "dayjs": "^1.11.19", "lodash-es": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52e73ff..af130fc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@kevisual/context': specifier: ^0.0.4 version: 0.0.4 + '@kevisual/kv-login': + specifier: ^0.0.1 + version: 0.0.1(@kevisual/query@0.0.29(ws@8.18.0)(zod@3.25.76))(rollup@4.52.5)(tslib@2.8.1)(typescript@5.8.3) '@kevisual/query': specifier: 0.0.29 version: 0.0.29(ws@8.18.0)(zod@3.25.76) @@ -141,9 +144,6 @@ importers: '@kevisual/system-lib': specifier: ^0.0.22 version: 0.0.22 - '@kevisual/system-ui': - specifier: ^0.0.3 - version: 0.0.3 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -701,92 +701,78 @@ packages: resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.3': resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.3': resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.3': resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.3': resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.3': resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.3': resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.4': resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.4': resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.4': resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.4': resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.4': resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.4': resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.4': resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.4': resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} @@ -850,6 +836,9 @@ packages: '@kevisual/context@0.0.4': resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==} + '@kevisual/kv-login@0.0.1': + resolution: {integrity: sha512-xbZ0jcVOdgu8YngoqjL4C3QJ9lkWjwkRTVQc4Nk3R90iCfoBoQEUIjpC2YSUDZ1WdLpEVMP2NNsYIHpEN2+X6Q==} + '@kevisual/query-login@0.0.6': resolution: {integrity: sha512-ZdX+sxeQaM3PV9fZXofMlxFz1RmpYIkoi47exzUgw6DADjEryBAQKRXe2/oL20NsBTV8owqaagRqffAVjq5c5g==} peerDependencies: @@ -876,9 +865,6 @@ packages: '@kevisual/system-lib@0.0.22': resolution: {integrity: sha512-kdzYlWLH+TGnNe4BfzB4Lk7jRdQE/KMQnMguWvPXdOb/aRiwJFVjlfYoNtA6BXgNC9MOpJ59CzFRc+EsMx1HRw==} - '@kevisual/system-ui@0.0.3': - resolution: {integrity: sha512-zRtUnL6wNe6R1W7X6eirDADZWeTmxZCNpLwxCLu30yeNuIhpFJdxHyOg0nX9aOZn6F0Kb6lB3Li2fZpKwdpk0w==} - '@kevisual/types@0.0.10': resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==} @@ -1142,28 +1128,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.17': resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.17': resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.17': resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.17': resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} @@ -1825,9 +1807,6 @@ packages: inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} - inline-style-parser@0.2.6: - resolution: {integrity: sha512-gtGXVaBdl5mAes3rPcMedEBm12ibjt1kDMFfheul1wUAOVEJW60voNdMVzVkfLN06O7ZaD/rxhfKgtlgtTbMjg==} - iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -1938,28 +1917,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -2621,9 +2596,6 @@ packages: style-to-object@1.0.11: resolution: {integrity: sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow==} - style-to-object@1.0.12: - resolution: {integrity: sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw==} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -3561,6 +3533,17 @@ snapshots: '@kevisual/context@0.0.4': {} + '@kevisual/kv-login@0.0.1(@kevisual/query@0.0.29(ws@8.18.0)(zod@3.25.76))(rollup@4.52.5)(tslib@2.8.1)(typescript@5.8.3)': + dependencies: + '@kevisual/query-login': 0.0.6(@kevisual/query@0.0.29(ws@8.18.0)(zod@3.25.76))(rollup@4.52.5)(tslib@2.8.1)(typescript@5.8.3) + lit-html: 3.3.1 + qrcode: 1.5.4 + transitivePeerDependencies: + - '@kevisual/query' + - rollup + - tslib + - typescript + '@kevisual/query-login@0.0.6(@kevisual/query@0.0.29(ws@8.18.0)(zod@3.25.76))(rollup@4.52.5)(tslib@2.8.1)(typescript@5.8.3)': dependencies: '@kevisual/cache': 0.0.2(rollup@4.52.5)(tslib@2.8.1)(typescript@5.8.3) @@ -3618,12 +3601,6 @@ snapshots: '@kevisual/system-lib@0.0.22': {} - '@kevisual/system-ui@0.0.3': - dependencies: - dayjs: 1.11.19 - lodash-es: 4.17.21 - style-to-object: 1.0.12 - '@kevisual/types@0.0.10': {} '@mdx-js/mdx@3.1.1': @@ -4730,8 +4707,6 @@ snapshots: inline-style-parser@0.2.4: {} - inline-style-parser@0.2.6: {} - iron-webcrypto@1.2.1: {} is-alphabetical@2.0.1: {} @@ -5846,10 +5821,6 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - style-to-object@1.0.12: - dependencies: - inline-style-parser: 0.2.6 - supports-preserve-symlinks-flag@1.0.0: {} tailwind-merge@3.4.0: {} diff --git a/src/apps/web-command/index.tsx b/src/apps/web-command/index.tsx index 16467ef..af0110e 100644 --- a/src/apps/web-command/index.tsx +++ b/src/apps/web-command/index.tsx @@ -1,6 +1,7 @@ import { app } from '../ai'; import { useEffect, useState } from 'react'; import { local } from '@/modules/query'; +import '@kevisual/kv-login' const getAppRoutes = () => { const appRoutes = app.routes.map((route) => { return { @@ -52,5 +53,18 @@ export const App = () => { setAppRoutes(getAppRoutes()); } }>{JSON.stringify(appRoutes, null, 2)} + + +
+
; +} + +// Add custom element to JSX namespace for TypeScript +declare global { + namespace JSX { + interface IntrinsicElements { + 'kv-login': React.DetailedHTMLProps, HTMLElement>; + } + } } \ No newline at end of file