@kevisual/kv-login 0.0.1
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/kv-login.es.js +3288 -0
- package/dist/kv-login.umd.js +429 -0
- package/index.html +84 -0
- package/package.json +31 -0
- package/src/main.ts +2 -0
- package/src/modules/login-handle.ts +188 -0
- package/src/modules/query.ts +10 -0
- package/src/modules/wx/load-js.ts +21 -0
- package/src/modules/wx/tencent-captcha.ts +70 -0
- package/src/modules/wx/ws-login.ts +61 -0
- package/src/modules/wx-mp/qr.ts +57 -0
- package/src/pages/kv-login.ts +466 -0
- package/src/pages/kv-message.ts +351 -0
- package/vite-lib.config.ts +12 -0
- package/vite.config.ts +15 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { html, render, TemplateResult } from 'lit-html'
|
|
2
|
+
|
|
3
|
+
export interface KvMessageOptions {
|
|
4
|
+
type?: 'success' | 'error' | 'loading'
|
|
5
|
+
message: string
|
|
6
|
+
duration?: number
|
|
7
|
+
closable?: boolean
|
|
8
|
+
position?: 'center' | 'right'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class KvMessage extends HTMLElement {
|
|
12
|
+
private options: KvMessageOptions
|
|
13
|
+
private timer: number | null = null
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super()
|
|
17
|
+
this.options = {
|
|
18
|
+
type: 'success',
|
|
19
|
+
message: '',
|
|
20
|
+
duration: 2000,
|
|
21
|
+
closable: true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
connectedCallback() {
|
|
26
|
+
this.render()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setOptions(options: KvMessageOptions) {
|
|
30
|
+
this.options = { ...this.options, ...options }
|
|
31
|
+
this.render()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private render() {
|
|
35
|
+
const { type, message, closable } = this.options
|
|
36
|
+
|
|
37
|
+
const getTypeIcon = () => {
|
|
38
|
+
switch (type) {
|
|
39
|
+
case 'success':
|
|
40
|
+
return '✓'
|
|
41
|
+
case 'error':
|
|
42
|
+
return '✕'
|
|
43
|
+
case 'loading':
|
|
44
|
+
return html`<div class="loading-spinner"></div>`
|
|
45
|
+
default:
|
|
46
|
+
return ''
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const template: TemplateResult = html`
|
|
51
|
+
<style>
|
|
52
|
+
:host {
|
|
53
|
+
display: block;
|
|
54
|
+
margin-bottom: 12px;
|
|
55
|
+
animation: slideIn 0.3s ease-out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.message-container {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
gap: 8px;
|
|
62
|
+
padding: 12px 16px;
|
|
63
|
+
border-radius: 6px;
|
|
64
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
65
|
+
background: white;
|
|
66
|
+
position: relative;
|
|
67
|
+
min-width: 300px;
|
|
68
|
+
max-width: 500px;
|
|
69
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
70
|
+
font-size: 14px;
|
|
71
|
+
line-height: 1.4;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.message-container.success {
|
|
75
|
+
border-left: 4px solid #52c41a;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.message-container.error {
|
|
79
|
+
border-left: 4px solid #ff4d4f;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.message-container.loading {
|
|
83
|
+
border-left: 4px solid #1890ff;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.message-icon {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
width: 16px;
|
|
91
|
+
height: 16px;
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.success .message-icon {
|
|
96
|
+
color: #52c41a;
|
|
97
|
+
font-weight: bold;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.error .message-icon {
|
|
101
|
+
color: #ff4d4f;
|
|
102
|
+
font-weight: bold;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.loading .message-icon {
|
|
106
|
+
color: #1890ff;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.loading-spinner {
|
|
110
|
+
width: 14px;
|
|
111
|
+
height: 14px;
|
|
112
|
+
border: 2px solid #f3f3f3;
|
|
113
|
+
border-top: 2px solid #1890ff;
|
|
114
|
+
border-radius: 50%;
|
|
115
|
+
animation: spin 1s linear infinite;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.message-content {
|
|
119
|
+
flex: 1;
|
|
120
|
+
color: #333;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.message-close {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
width: 16px;
|
|
128
|
+
height: 16px;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
color: #999;
|
|
131
|
+
background: none;
|
|
132
|
+
border: none;
|
|
133
|
+
font-size: 12px;
|
|
134
|
+
border-radius: 50%;
|
|
135
|
+
transition: all 0.2s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.message-close:hover {
|
|
139
|
+
color: #666;
|
|
140
|
+
background: #f0f0f0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@keyframes slideIn {
|
|
144
|
+
from {
|
|
145
|
+
transform: translateX(100%);
|
|
146
|
+
opacity: 0;
|
|
147
|
+
}
|
|
148
|
+
to {
|
|
149
|
+
transform: translateX(0);
|
|
150
|
+
opacity: 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@keyframes slideOut {
|
|
155
|
+
from {
|
|
156
|
+
transform: translateX(0);
|
|
157
|
+
opacity: 1;
|
|
158
|
+
}
|
|
159
|
+
to {
|
|
160
|
+
transform: translateX(100%);
|
|
161
|
+
opacity: 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@keyframes spin {
|
|
166
|
+
0% { transform: rotate(0deg); }
|
|
167
|
+
100% { transform: rotate(360deg); }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.removing {
|
|
171
|
+
animation: slideOut 0.3s ease-out forwards;
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
174
|
+
|
|
175
|
+
<div class="message-container ${type}">
|
|
176
|
+
<div class="message-icon">
|
|
177
|
+
${getTypeIcon()}
|
|
178
|
+
</div>
|
|
179
|
+
<div class="message-content">${message}</div>
|
|
180
|
+
${closable ? html`
|
|
181
|
+
<button class="message-close" @click=${() => this.remove()}>×</button>
|
|
182
|
+
` : ''}
|
|
183
|
+
</div>
|
|
184
|
+
`
|
|
185
|
+
|
|
186
|
+
render(template, this)
|
|
187
|
+
|
|
188
|
+
if (type !== 'loading' && this.options.duration && this.options.duration > 0) {
|
|
189
|
+
this.setTimer()
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private setTimer() {
|
|
194
|
+
if (this.timer) {
|
|
195
|
+
clearTimeout(this.timer)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
this.timer = window.setTimeout(() => {
|
|
199
|
+
this.remove()
|
|
200
|
+
}, this.options.duration)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
remove() {
|
|
204
|
+
if (this.timer) {
|
|
205
|
+
clearTimeout(this.timer)
|
|
206
|
+
this.timer = null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.classList.add('removing')
|
|
210
|
+
|
|
211
|
+
setTimeout(() => {
|
|
212
|
+
if (this.parentNode) {
|
|
213
|
+
this.parentNode.removeChild(this)
|
|
214
|
+
}
|
|
215
|
+
}, 300)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
disconnectedCallback() {
|
|
219
|
+
if (this.timer) {
|
|
220
|
+
clearTimeout(this.timer)
|
|
221
|
+
this.timer = null
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
customElements.define('kv-message', KvMessage)
|
|
227
|
+
|
|
228
|
+
export class KvMessageManager {
|
|
229
|
+
private static instance: KvMessageManager
|
|
230
|
+
private container: HTMLElement | null = null
|
|
231
|
+
private defaultPosition: 'center' | 'right' = 'center'
|
|
232
|
+
|
|
233
|
+
static getInstance(): KvMessageManager {
|
|
234
|
+
if (!KvMessageManager.instance) {
|
|
235
|
+
KvMessageManager.instance = new KvMessageManager()
|
|
236
|
+
}
|
|
237
|
+
return KvMessageManager.instance
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
setDefaultPosition(position: 'center' | 'right') {
|
|
241
|
+
this.defaultPosition = position
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private getContainer(position?: 'center' | 'right'): HTMLElement {
|
|
245
|
+
const finalPosition = position || this.defaultPosition
|
|
246
|
+
|
|
247
|
+
if (!this.container) {
|
|
248
|
+
this.container = document.getElementById('messages')
|
|
249
|
+
if (!this.container) {
|
|
250
|
+
this.container = document.createElement('div')
|
|
251
|
+
this.container.id = 'messages'
|
|
252
|
+
|
|
253
|
+
if (finalPosition === 'center') {
|
|
254
|
+
this.container.style.cssText = `
|
|
255
|
+
position: fixed;
|
|
256
|
+
top: 20px;
|
|
257
|
+
left: 50%;
|
|
258
|
+
transform: translateX(-50%);
|
|
259
|
+
z-index: 9999;
|
|
260
|
+
display: flex;
|
|
261
|
+
gap: 8px;
|
|
262
|
+
flex-direction: column;
|
|
263
|
+
align-items: center;
|
|
264
|
+
pointer-events: none;
|
|
265
|
+
`
|
|
266
|
+
} else {
|
|
267
|
+
this.container.style.cssText = `
|
|
268
|
+
position: fixed;
|
|
269
|
+
top: 20px;
|
|
270
|
+
right: 20px;
|
|
271
|
+
z-index: 9999;
|
|
272
|
+
display: flex;
|
|
273
|
+
gap: 8px;
|
|
274
|
+
flex-direction: column;
|
|
275
|
+
align-items: flex-end;
|
|
276
|
+
pointer-events: none;
|
|
277
|
+
`
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
document.body.appendChild(this.container)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return this.container
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
show(options: KvMessageOptions): KvMessage {
|
|
287
|
+
const container = this.getContainer(options.position)
|
|
288
|
+
|
|
289
|
+
const message = document.createElement('kv-message') as KvMessage
|
|
290
|
+
message.setOptions(options)
|
|
291
|
+
|
|
292
|
+
message.style.cssText = 'pointer-events: auto;'
|
|
293
|
+
|
|
294
|
+
container.appendChild(message)
|
|
295
|
+
|
|
296
|
+
return message
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
success(message: string, options?: { duration?: number; position?: 'center' | 'right'; closable?: boolean }): KvMessage {
|
|
300
|
+
return this.show({
|
|
301
|
+
type: 'success',
|
|
302
|
+
message,
|
|
303
|
+
duration: options?.duration || 2000,
|
|
304
|
+
position: options?.position,
|
|
305
|
+
closable: options?.closable
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
error(message: string, options?: { duration?: number; position?: 'center' | 'right'; closable?: boolean }): KvMessage {
|
|
310
|
+
return this.show({
|
|
311
|
+
type: 'error',
|
|
312
|
+
message,
|
|
313
|
+
duration: options?.duration || 3000,
|
|
314
|
+
position: options?.position,
|
|
315
|
+
closable: options?.closable
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
loading(message: string, options?: { position?: 'center' | 'right'; closable?: boolean }): KvMessage {
|
|
320
|
+
return this.show({
|
|
321
|
+
type: 'loading',
|
|
322
|
+
message,
|
|
323
|
+
duration: 0,
|
|
324
|
+
position: options?.position,
|
|
325
|
+
closable: options?.closable
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
remove(message: KvMessage) {
|
|
330
|
+
message.remove()
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
clear() {
|
|
334
|
+
const container = this.getContainer()
|
|
335
|
+
const messages = container.querySelectorAll('kv-message')
|
|
336
|
+
messages.forEach(message => {
|
|
337
|
+
(message as KvMessage).remove()
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export const createMessage = () => KvMessageManager.getInstance()
|
|
343
|
+
|
|
344
|
+
// 将 createMessage 暴露到全局,以便 HTML 中的 JavaScript 可以使用
|
|
345
|
+
declare global {
|
|
346
|
+
interface Window {
|
|
347
|
+
createMessage: typeof createMessage
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
window.createMessage = createMessage
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
const idDev = process.env.NODE_ENV === 'development';
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
base: idDev ? '/' : '/root/kv-login-test/',
|
|
6
|
+
server: {
|
|
7
|
+
proxy: {
|
|
8
|
+
'/api': {
|
|
9
|
+
target: 'https://kevisual.xiongxiao.me',
|
|
10
|
+
changeOrigin: true,
|
|
11
|
+
secure: false,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
});
|