skill-base 2.0.4 → 2.0.7
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/README.md +177 -115
- package/bin/skill-base.js +29 -3
- package/package.json +4 -1
- package/src/cappy.js +416 -0
- package/src/database.js +11 -0
- package/src/index.js +125 -25
- package/src/middleware/auth.js +96 -32
- package/src/routes/auth.js +1 -1
- package/src/routes/skills.js +10 -5
- package/src/utils/zip.js +15 -4
- package/static/android-chrome-192x192.png +0 -0
- package/static/android-chrome-512x512.png +0 -0
- package/static/apple-touch-icon.png +0 -0
- package/static/assets/index-BkwByEEp.css +1 -0
- package/static/assets/index-CB4Diul3.js +209 -0
- package/static/favicon-16x16.png +0 -0
- package/static/favicon-32x32.png +0 -0
- package/static/favicon.ico +0 -0
- package/static/favicon.svg +14 -0
- package/static/index.html +18 -248
- package/static/site.webmanifest +1 -0
- package/static/admin/users.html +0 -593
- package/static/cli-code.html +0 -203
- package/static/css/.gitkeep +0 -0
- package/static/css/style.css +0 -1567
- package/static/diff.html +0 -466
- package/static/file.html +0 -443
- package/static/js/.gitkeep +0 -0
- package/static/js/admin/users.js +0 -346
- package/static/js/app.js +0 -508
- package/static/js/auth.js +0 -151
- package/static/js/cli-code.js +0 -184
- package/static/js/collaborators.js +0 -283
- package/static/js/diff.js +0 -540
- package/static/js/file.js +0 -619
- package/static/js/i18n.js +0 -739
- package/static/js/index.js +0 -168
- package/static/js/publish.js +0 -718
- package/static/js/settings.js +0 -124
- package/static/js/setup.js +0 -157
- package/static/js/skill.js +0 -808
- package/static/login.html +0 -82
- package/static/publish.html +0 -459
- package/static/settings.html +0 -163
- package/static/setup.html +0 -101
- package/static/skill.html +0 -851
package/static/admin/users.html
DELETED
|
@@ -1,593 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title data-i18n="admin.title">用户管理 - Skill Base</title>
|
|
7
|
-
<link rel="stylesheet" href="/css/style.css">
|
|
8
|
-
<style>
|
|
9
|
-
/* 页面标题区域 */
|
|
10
|
-
.page-header {
|
|
11
|
-
display: flex;
|
|
12
|
-
align-items: center;
|
|
13
|
-
justify-content: space-between;
|
|
14
|
-
margin-bottom: var(--spacing-lg);
|
|
15
|
-
flex-wrap: wrap;
|
|
16
|
-
gap: var(--spacing-md);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.page-title {
|
|
20
|
-
font-size: 1.75rem;
|
|
21
|
-
font-weight: 700;
|
|
22
|
-
color: var(--text-color);
|
|
23
|
-
margin: 0;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* 搜索和筛选栏 */
|
|
27
|
-
.filter-bar {
|
|
28
|
-
display: flex;
|
|
29
|
-
gap: var(--spacing-md);
|
|
30
|
-
margin-bottom: var(--spacing-lg);
|
|
31
|
-
flex-wrap: wrap;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.filter-bar .search-container {
|
|
35
|
-
flex: 1;
|
|
36
|
-
min-width: 200px;
|
|
37
|
-
max-width: 400px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.filter-bar select {
|
|
41
|
-
min-width: 140px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* 用户表格 */
|
|
45
|
-
.users-table-container {
|
|
46
|
-
background-color: var(--white);
|
|
47
|
-
border-radius: var(--radius);
|
|
48
|
-
box-shadow: var(--shadow);
|
|
49
|
-
overflow: hidden;
|
|
50
|
-
border: 1px solid var(--border-color);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.users-table {
|
|
54
|
-
width: 100%;
|
|
55
|
-
border-collapse: collapse;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.users-table th,
|
|
59
|
-
.users-table td {
|
|
60
|
-
padding: var(--spacing-md);
|
|
61
|
-
text-align: left;
|
|
62
|
-
border-bottom: 1px solid var(--border-color);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.users-table th {
|
|
66
|
-
background-color: var(--bg-color);
|
|
67
|
-
font-weight: 600;
|
|
68
|
-
font-size: 0.875rem;
|
|
69
|
-
color: var(--text-secondary);
|
|
70
|
-
white-space: nowrap;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.users-table td {
|
|
74
|
-
font-size: 0.875rem;
|
|
75
|
-
color: var(--text-color);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.users-table tr:last-child td {
|
|
79
|
-
border-bottom: none;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.users-table tr:hover td {
|
|
83
|
-
background-color: rgba(125, 211, 252, 0.05);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* 角色和状态标签 */
|
|
87
|
-
.role-badge {
|
|
88
|
-
display: inline-flex;
|
|
89
|
-
align-items: center;
|
|
90
|
-
gap: var(--spacing-xs);
|
|
91
|
-
padding: 0.125rem 0.5rem;
|
|
92
|
-
font-size: 0.75rem;
|
|
93
|
-
font-weight: 500;
|
|
94
|
-
border-radius: var(--radius-full);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.role-badge.admin {
|
|
98
|
-
background-color: var(--primary-light);
|
|
99
|
-
color: var(--primary-color);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.role-badge.developer {
|
|
103
|
-
background-color: var(--info-light);
|
|
104
|
-
color: var(--info-color);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.status-badge {
|
|
108
|
-
font-size: 0.875rem;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.status-badge.active {
|
|
112
|
-
color: var(--success-color);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.status-badge.disabled {
|
|
116
|
-
color: var(--error-color);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/* 分页控件 */
|
|
120
|
-
.pagination {
|
|
121
|
-
display: flex;
|
|
122
|
-
align-items: center;
|
|
123
|
-
justify-content: center;
|
|
124
|
-
gap: var(--spacing-md);
|
|
125
|
-
padding: var(--spacing-lg);
|
|
126
|
-
border-top: 1px solid var(--border-color);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.pagination-info {
|
|
130
|
-
color: var(--text-secondary);
|
|
131
|
-
font-size: 0.875rem;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/* 空状态 */
|
|
135
|
-
.empty-state {
|
|
136
|
-
text-align: center;
|
|
137
|
-
padding: var(--spacing-xl) var(--spacing-md);
|
|
138
|
-
color: var(--text-secondary);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.empty-state-icon {
|
|
142
|
-
font-size: 4rem;
|
|
143
|
-
margin-bottom: var(--spacing-md);
|
|
144
|
-
opacity: 0.5;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.empty-state-text {
|
|
148
|
-
font-size: 1rem;
|
|
149
|
-
margin-bottom: var(--spacing-md);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/* Modal 弹窗 */
|
|
153
|
-
.modal-overlay {
|
|
154
|
-
position: fixed;
|
|
155
|
-
top: 0;
|
|
156
|
-
left: 0;
|
|
157
|
-
right: 0;
|
|
158
|
-
bottom: 0;
|
|
159
|
-
background-color: rgba(0, 0, 0, 0.6);
|
|
160
|
-
display: flex;
|
|
161
|
-
align-items: center;
|
|
162
|
-
justify-content: center;
|
|
163
|
-
z-index: 2000;
|
|
164
|
-
opacity: 0;
|
|
165
|
-
visibility: hidden;
|
|
166
|
-
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.modal-overlay.visible {
|
|
170
|
-
opacity: 1;
|
|
171
|
-
visibility: visible;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.modal {
|
|
175
|
-
background-color: var(--white);
|
|
176
|
-
border-radius: var(--radius-lg);
|
|
177
|
-
box-shadow: var(--shadow-lg);
|
|
178
|
-
width: 100%;
|
|
179
|
-
max-width: 480px;
|
|
180
|
-
max-height: 90vh;
|
|
181
|
-
overflow-y: auto;
|
|
182
|
-
transform: scale(0.95);
|
|
183
|
-
transition: transform 0.2s ease;
|
|
184
|
-
border: 1px solid var(--border-color);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.modal-overlay.visible .modal {
|
|
188
|
-
transform: scale(1);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.modal-header {
|
|
192
|
-
display: flex;
|
|
193
|
-
align-items: center;
|
|
194
|
-
justify-content: space-between;
|
|
195
|
-
padding: var(--spacing-lg);
|
|
196
|
-
border-bottom: 1px solid var(--border-color);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.modal-title {
|
|
200
|
-
font-size: 1.125rem;
|
|
201
|
-
font-weight: 600;
|
|
202
|
-
color: var(--text-color);
|
|
203
|
-
margin: 0;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.modal-close {
|
|
207
|
-
background: none;
|
|
208
|
-
border: none;
|
|
209
|
-
color: var(--text-muted);
|
|
210
|
-
cursor: pointer;
|
|
211
|
-
padding: var(--spacing-xs);
|
|
212
|
-
display: flex;
|
|
213
|
-
align-items: center;
|
|
214
|
-
justify-content: center;
|
|
215
|
-
border-radius: var(--radius-sm);
|
|
216
|
-
transition: var(--transition);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.modal-close:hover {
|
|
220
|
-
background-color: var(--bg-color);
|
|
221
|
-
color: var(--text-color);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.modal-body {
|
|
225
|
-
padding: var(--spacing-lg);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.modal-footer {
|
|
229
|
-
display: flex;
|
|
230
|
-
align-items: center;
|
|
231
|
-
justify-content: flex-end;
|
|
232
|
-
gap: var(--spacing-md);
|
|
233
|
-
padding: var(--spacing-lg);
|
|
234
|
-
border-top: 1px solid var(--border-color);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/* 单选按钮组 */
|
|
238
|
-
.radio-group {
|
|
239
|
-
display: flex;
|
|
240
|
-
gap: var(--spacing-lg);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.radio-label {
|
|
244
|
-
display: flex;
|
|
245
|
-
align-items: center;
|
|
246
|
-
gap: var(--spacing-sm);
|
|
247
|
-
cursor: pointer;
|
|
248
|
-
font-size: 0.875rem;
|
|
249
|
-
color: var(--text-color);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
.radio-label input[type="radio"] {
|
|
253
|
-
width: 18px;
|
|
254
|
-
height: 18px;
|
|
255
|
-
accent-color: var(--primary-color);
|
|
256
|
-
cursor: pointer;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/* 切换开关 */
|
|
260
|
-
.toggle-group {
|
|
261
|
-
display: flex;
|
|
262
|
-
align-items: center;
|
|
263
|
-
gap: var(--spacing-md);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.toggle-switch {
|
|
267
|
-
position: relative;
|
|
268
|
-
width: 48px;
|
|
269
|
-
height: 26px;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
.toggle-switch input {
|
|
273
|
-
opacity: 0;
|
|
274
|
-
width: 0;
|
|
275
|
-
height: 0;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.toggle-slider {
|
|
279
|
-
position: absolute;
|
|
280
|
-
cursor: pointer;
|
|
281
|
-
top: 0;
|
|
282
|
-
left: 0;
|
|
283
|
-
right: 0;
|
|
284
|
-
bottom: 0;
|
|
285
|
-
background-color: var(--border-color);
|
|
286
|
-
transition: 0.3s;
|
|
287
|
-
border-radius: var(--radius-full);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
.toggle-slider:before {
|
|
291
|
-
position: absolute;
|
|
292
|
-
content: "";
|
|
293
|
-
height: 20px;
|
|
294
|
-
width: 20px;
|
|
295
|
-
left: 3px;
|
|
296
|
-
bottom: 3px;
|
|
297
|
-
background-color: var(--text-color);
|
|
298
|
-
transition: 0.3s;
|
|
299
|
-
border-radius: 50%;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.toggle-switch input:checked + .toggle-slider {
|
|
303
|
-
background-color: var(--success-color);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.toggle-switch input:checked + .toggle-slider:before {
|
|
307
|
-
transform: translateX(22px);
|
|
308
|
-
background-color: #fff;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.toggle-label {
|
|
312
|
-
font-size: 0.875rem;
|
|
313
|
-
color: var(--text-secondary);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/* 分隔线 */
|
|
317
|
-
.divider {
|
|
318
|
-
height: 1px;
|
|
319
|
-
background-color: var(--border-color);
|
|
320
|
-
margin: var(--spacing-lg) 0;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/* 重置密码区域 */
|
|
324
|
-
.reset-password-section {
|
|
325
|
-
display: flex;
|
|
326
|
-
align-items: center;
|
|
327
|
-
justify-content: space-between;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
.reset-password-section .section-label {
|
|
331
|
-
font-size: 0.875rem;
|
|
332
|
-
color: var(--text-secondary);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/* Loading 状态 */
|
|
336
|
-
.table-loading {
|
|
337
|
-
display: flex;
|
|
338
|
-
align-items: center;
|
|
339
|
-
justify-content: center;
|
|
340
|
-
padding: var(--spacing-xl);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
@media (max-width: 768px) {
|
|
344
|
-
.page-header {
|
|
345
|
-
flex-direction: column;
|
|
346
|
-
align-items: flex-start;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
.filter-bar {
|
|
350
|
-
flex-direction: column;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
.filter-bar .search-container {
|
|
354
|
-
max-width: none;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
.users-table-container {
|
|
358
|
-
overflow-x: auto;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.users-table {
|
|
362
|
-
min-width: 600px;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
.modal {
|
|
366
|
-
margin: var(--spacing-md);
|
|
367
|
-
max-width: calc(100% - var(--spacing-lg));
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
</style>
|
|
371
|
-
</head>
|
|
372
|
-
<body class="app-devtools">
|
|
373
|
-
<!-- 导航栏 -->
|
|
374
|
-
<nav class="navbar">
|
|
375
|
-
<div class="container">
|
|
376
|
-
<a href="/" class="navbar-brand">
|
|
377
|
-
<svg class="navbar-brand-icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
|
|
378
|
-
<span>Skill Base</span>
|
|
379
|
-
</a>
|
|
380
|
-
<div class="navbar-nav">
|
|
381
|
-
<a href="/" data-i18n="nav.home">首页</a>
|
|
382
|
-
<a href="/publish.html" class="hide-mobile" data-i18n="nav.publish">发布</a>
|
|
383
|
-
</div>
|
|
384
|
-
<!-- 用户区域由 JS 动态渲染 -->
|
|
385
|
-
</div>
|
|
386
|
-
</nav>
|
|
387
|
-
|
|
388
|
-
<!-- 页面内容 -->
|
|
389
|
-
<main class="page-content">
|
|
390
|
-
<div class="container">
|
|
391
|
-
<!-- 页面标题 -->
|
|
392
|
-
<div class="page-header">
|
|
393
|
-
<h1 class="page-title" data-i18n="admin.heading">用户管理</h1>
|
|
394
|
-
<button class="btn btn-primary" onclick="showAddUserModal()">
|
|
395
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
396
|
-
<line x1="12" y1="5" x2="12" y2="19"/>
|
|
397
|
-
<line x1="5" y1="12" x2="19" y2="12"/>
|
|
398
|
-
</svg>
|
|
399
|
-
<span data-i18n="admin.addUser">添加用户</span>
|
|
400
|
-
</button>
|
|
401
|
-
</div>
|
|
402
|
-
|
|
403
|
-
<!-- 搜索和筛选 -->
|
|
404
|
-
<div class="filter-bar">
|
|
405
|
-
<div class="search-container">
|
|
406
|
-
<div class="search-bar">
|
|
407
|
-
<input
|
|
408
|
-
type="search"
|
|
409
|
-
id="searchInput"
|
|
410
|
-
data-i18n-placeholder="admin.searchPlaceholder"
|
|
411
|
-
placeholder="搜索用户名..."
|
|
412
|
-
autocomplete="off"
|
|
413
|
-
>
|
|
414
|
-
<span class="search-icon">
|
|
415
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
416
|
-
<circle cx="11" cy="11" r="8"/>
|
|
417
|
-
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
|
|
418
|
-
</svg>
|
|
419
|
-
</span>
|
|
420
|
-
<button type="button" class="clear-btn" id="clearSearch">
|
|
421
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
422
|
-
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
423
|
-
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
424
|
-
</svg>
|
|
425
|
-
</button>
|
|
426
|
-
</div>
|
|
427
|
-
</div>
|
|
428
|
-
<select id="statusFilter">
|
|
429
|
-
<option value="" data-i18n="admin.allStatus">全部状态</option>
|
|
430
|
-
<option value="active" data-i18n="admin.active">启用</option>
|
|
431
|
-
<option value="disabled" data-i18n="admin.disabled">禁用</option>
|
|
432
|
-
</select>
|
|
433
|
-
</div>
|
|
434
|
-
|
|
435
|
-
<!-- 用户列表 -->
|
|
436
|
-
<div class="users-table-container">
|
|
437
|
-
<table class="users-table">
|
|
438
|
-
<thead>
|
|
439
|
-
<tr>
|
|
440
|
-
<th data-i18n="admin.thUsername">用户名</th>
|
|
441
|
-
<th data-i18n="admin.thName">姓名</th>
|
|
442
|
-
<th data-i18n="admin.thRole">角色</th>
|
|
443
|
-
<th data-i18n="admin.thStatus">状态</th>
|
|
444
|
-
<th data-i18n="admin.thCreatedAt">创建时间</th>
|
|
445
|
-
<th data-i18n="admin.thActions">操作</th>
|
|
446
|
-
</tr>
|
|
447
|
-
</thead>
|
|
448
|
-
<tbody id="usersTableBody">
|
|
449
|
-
<!-- 由 JS 动态渲染 -->
|
|
450
|
-
</tbody>
|
|
451
|
-
</table>
|
|
452
|
-
<div id="pagination" class="pagination hidden">
|
|
453
|
-
<button class="btn btn-secondary btn-sm" id="prevPage" disabled data-i18n="admin.prevPage">上一页</button>
|
|
454
|
-
<span class="pagination-info" id="pageInfo">1 / 1</span>
|
|
455
|
-
<button class="btn btn-secondary btn-sm" id="nextPage" disabled data-i18n="admin.nextPage">下一页</button>
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
459
|
-
</main>
|
|
460
|
-
|
|
461
|
-
<!-- 添加用户弹窗 -->
|
|
462
|
-
<div class="modal-overlay" id="addUserModal">
|
|
463
|
-
<div class="modal">
|
|
464
|
-
<div class="modal-header">
|
|
465
|
-
<h3 class="modal-title" data-i18n="admin.addModal">添加用户</h3>
|
|
466
|
-
<button class="modal-close" onclick="closeModal()">
|
|
467
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
468
|
-
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
469
|
-
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
470
|
-
</svg>
|
|
471
|
-
</button>
|
|
472
|
-
</div>
|
|
473
|
-
<div class="modal-body">
|
|
474
|
-
<div class="form-group">
|
|
475
|
-
<label class="form-label required" data-i18n="admin.addUsernameLabel">用户名</label>
|
|
476
|
-
<input type="text" id="addUsername" data-i18n-placeholder="admin.addUsernamePlaceholder" placeholder="请输入用户名">
|
|
477
|
-
</div>
|
|
478
|
-
<div class="form-group">
|
|
479
|
-
<label class="form-label required" data-i18n="admin.addPasswordLabel">初始密码</label>
|
|
480
|
-
<input type="password" id="addPassword" data-i18n-placeholder="admin.addPasswordPlaceholder" placeholder="请输入初始密码">
|
|
481
|
-
</div>
|
|
482
|
-
<div class="form-group">
|
|
483
|
-
<label class="form-label required" data-i18n="admin.addRoleLabel">角色</label>
|
|
484
|
-
<div class="radio-group">
|
|
485
|
-
<label class="radio-label">
|
|
486
|
-
<input type="radio" name="addRole" value="developer" checked>
|
|
487
|
-
<span data-i18n="admin.roleDeveloperLabel">开发者</span>
|
|
488
|
-
</label>
|
|
489
|
-
<label class="radio-label">
|
|
490
|
-
<input type="radio" name="addRole" value="admin">
|
|
491
|
-
<span data-i18n="admin.roleAdminLabel">管理员</span>
|
|
492
|
-
</label>
|
|
493
|
-
</div>
|
|
494
|
-
</div>
|
|
495
|
-
</div>
|
|
496
|
-
<div class="modal-footer">
|
|
497
|
-
<button class="btn btn-secondary" onclick="closeModal()" data-i18n="btn.cancel">取消</button>
|
|
498
|
-
<button class="btn btn-primary" id="submitAddUser" onclick="submitAddUser()" data-i18n="btn.add">添加</button>
|
|
499
|
-
</div>
|
|
500
|
-
</div>
|
|
501
|
-
</div>
|
|
502
|
-
|
|
503
|
-
<!-- 编辑用户弹窗 -->
|
|
504
|
-
<div class="modal-overlay" id="editUserModal">
|
|
505
|
-
<div class="modal">
|
|
506
|
-
<div class="modal-header">
|
|
507
|
-
<h3 class="modal-title" data-i18n="admin.editModal">编辑用户</h3>
|
|
508
|
-
<button class="modal-close" onclick="closeModal()">
|
|
509
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
510
|
-
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
511
|
-
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
512
|
-
</svg>
|
|
513
|
-
</button>
|
|
514
|
-
</div>
|
|
515
|
-
<div class="modal-body">
|
|
516
|
-
<input type="hidden" id="editUserId">
|
|
517
|
-
<div class="form-group">
|
|
518
|
-
<label class="form-label" data-i18n="admin.editUsernameLabel">用户名</label>
|
|
519
|
-
<input type="text" id="editUsername" disabled>
|
|
520
|
-
</div>
|
|
521
|
-
<div class="form-group">
|
|
522
|
-
<label class="form-label" data-i18n="admin.editNameLabel">姓名</label>
|
|
523
|
-
<input type="text" id="editName" data-i18n-placeholder="admin.editNamePlaceholder" placeholder="请输入姓名">
|
|
524
|
-
</div>
|
|
525
|
-
<div class="form-group">
|
|
526
|
-
<label class="form-label" data-i18n="admin.editRoleLabel">角色</label>
|
|
527
|
-
<div class="radio-group">
|
|
528
|
-
<label class="radio-label">
|
|
529
|
-
<input type="radio" name="editRole" value="developer">
|
|
530
|
-
<span data-i18n="admin.roleDeveloperLabel">开发者</span>
|
|
531
|
-
</label>
|
|
532
|
-
<label class="radio-label">
|
|
533
|
-
<input type="radio" name="editRole" value="admin">
|
|
534
|
-
<span data-i18n="admin.roleAdminLabel">管理员</span>
|
|
535
|
-
</label>
|
|
536
|
-
</div>
|
|
537
|
-
</div>
|
|
538
|
-
<div class="form-group">
|
|
539
|
-
<label class="form-label" data-i18n="admin.editStatusLabel">状态</label>
|
|
540
|
-
<div class="toggle-group">
|
|
541
|
-
<label class="toggle-switch">
|
|
542
|
-
<input type="checkbox" id="editStatus">
|
|
543
|
-
<span class="toggle-slider"></span>
|
|
544
|
-
</label>
|
|
545
|
-
<span class="toggle-label" id="editStatusLabel">启用</span>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
<div class="divider"></div>
|
|
549
|
-
<div class="reset-password-section">
|
|
550
|
-
<span class="section-label" data-i18n="admin.resetPasswordSection">重置用户密码</span>
|
|
551
|
-
<button class="btn btn-secondary btn-sm" id="resetPasswordBtn" data-i18n="admin.resetPasswordBtn">重置密码</button>
|
|
552
|
-
</div>
|
|
553
|
-
</div>
|
|
554
|
-
<div class="modal-footer">
|
|
555
|
-
<button class="btn btn-secondary" onclick="closeModal()" data-i18n="btn.cancel">取消</button>
|
|
556
|
-
<button class="btn btn-primary" id="submitEditUser" onclick="submitEditUser()" data-i18n="btn.save">保存</button>
|
|
557
|
-
</div>
|
|
558
|
-
</div>
|
|
559
|
-
</div>
|
|
560
|
-
|
|
561
|
-
<!-- 重置密码弹窗 -->
|
|
562
|
-
<div class="modal-overlay" id="resetPasswordModal">
|
|
563
|
-
<div class="modal">
|
|
564
|
-
<div class="modal-header">
|
|
565
|
-
<h3 class="modal-title" data-i18n="admin.resetModal">重置密码</h3>
|
|
566
|
-
<button class="modal-close" onclick="closeModal()">
|
|
567
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
568
|
-
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
569
|
-
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
570
|
-
</svg>
|
|
571
|
-
</button>
|
|
572
|
-
</div>
|
|
573
|
-
<div class="modal-body">
|
|
574
|
-
<input type="hidden" id="resetPasswordUserId">
|
|
575
|
-
<p class="text-secondary mb-2"><span data-i18n="admin.resetDesc">为用户 </span><strong id="resetPasswordUsername"></strong><span data-i18n="admin.resetDescEnd"> 设置新密码:</span></p>
|
|
576
|
-
<div class="form-group">
|
|
577
|
-
<label class="form-label required" data-i18n="admin.resetPasswordLabel">新密码</label>
|
|
578
|
-
<input type="password" id="newPassword" data-i18n-placeholder="admin.resetPasswordPlaceholder" placeholder="请输入新密码">
|
|
579
|
-
</div>
|
|
580
|
-
</div>
|
|
581
|
-
<div class="modal-footer">
|
|
582
|
-
<button class="btn btn-secondary" onclick="closeModal()" data-i18n="btn.cancel">取消</button>
|
|
583
|
-
<button class="btn btn-primary" id="submitResetPassword" onclick="submitResetPassword()" data-i18n="btn.reset">确认重置</button>
|
|
584
|
-
</div>
|
|
585
|
-
</div>
|
|
586
|
-
</div>
|
|
587
|
-
|
|
588
|
-
<!-- 引入 JS -->
|
|
589
|
-
<script src="/js/i18n.js"></script>
|
|
590
|
-
<script src="/js/app.js"></script>
|
|
591
|
-
<script src="/js/admin/users.js"></script>
|
|
592
|
-
</body>
|
|
593
|
-
</html>
|