block-proxy 0.1.12 → 0.1.14
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/.claude/settings.local.json +33 -1
- package/.claude/skills/build-client/skill.md +24 -0
- package/.claude/skills/release-client/skill.md +68 -0
- package/CLAUDE.md +69 -67
- package/Dockerfile +1 -1
- package/README.md +38 -24
- package/build/asset-manifest.json +6 -6
- package/build/index.html +1 -1
- package/build/static/css/main.3f317ce6.css +2 -0
- package/build/static/css/main.3f317ce6.css.map +1 -0
- package/build/static/js/{main.2247fb80.js → main.af1923ea.js} +3 -3
- package/build/static/js/main.af1923ea.js.map +1 -0
- package/client/app.py +312 -0
- package/client/build.sh +84 -0
- package/client/config.py +49 -0
- package/client/config_window.py +155 -0
- package/client/icons/app.icns +0 -0
- package/client/icons/app_example.png +0 -0
- package/client/icons/app_icon.png +0 -0
- package/client/icons/backup/app_example.png +0 -0
- package/client/icons/backup/christmas-sock_dark.png +0 -0
- package/client/icons/backup/christmas-sock_light.png +0 -0
- package/client/icons/backup/socks_on_G.png +0 -0
- package/client/icons/backup/socks_on_M.png +0 -0
- package/client/icons/christmas-sock_dark.png +0 -0
- package/client/icons/christmas-sock_light.png +0 -0
- package/client/icons/christmas-sock_light_bar.png +0 -0
- package/client/icons/socks_on_G.png +0 -0
- package/client/icons/socks_on_G_bar.png +0 -0
- package/client/icons/socks_on_M.png +0 -0
- package/client/icons/socks_on_M_bar.png +0 -0
- package/client/main.py +28 -0
- package/client/proxy_core.py +475 -0
- package/client/requirements.txt +3 -0
- package/client/scripts/download_xray.sh +30 -0
- package/client/setup.py +30 -0
- package/client/system_proxy.py +94 -0
- package/client/tests/__init__.py +0 -0
- package/client/tests/test_config.py +72 -0
- package/client/tests/test_system_proxy.py +69 -0
- package/client/watch-icons.js +31 -0
- package/config.json +4 -199
- package/docs/superpowers/plans/2026-05-27-blockproxyclient.md +1274 -0
- package/docs/superpowers/specs/2026-05-27-blockproxyclient-design.md +264 -0
- package/package.json +11 -5
- package/proxy/proxy.js +19 -34
- package/server/express.js +17 -1
- package/src/App.css +596 -276
- package/src/App.js +25 -32
- package/src/index.css +3 -4
- package/test/lib/mock-server.js +133 -0
- package/test/proxy-tests.js +708 -0
- package/test/run.js +330 -0
- package/build/static/css/main.8bfa3d5f.css +0 -2
- package/build/static/css/main.8bfa3d5f.css.map +0 -1
- package/build/static/js/main.2247fb80.js.map +0 -1
- package/hack-of-anyproxy/lib/requestHandler.js +0 -1060
- /package/build/static/js/{main.2247fb80.js.LICENSE.txt → main.af1923ea.js.LICENSE.txt} +0 -0
package/src/App.css
CHANGED
|
@@ -1,207 +1,261 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/* ===== 基础变量与全局 ===== */
|
|
2
|
+
:root {
|
|
3
|
+
--primary: #4f46e5;
|
|
4
|
+
--primary-hover: #4338ca;
|
|
5
|
+
--primary-light: #eef2ff;
|
|
6
|
+
--success: #059669;
|
|
7
|
+
--success-hover: #047857;
|
|
8
|
+
--danger: #dc2626;
|
|
9
|
+
--danger-hover: #b91c1c;
|
|
10
|
+
--warning: #d97706;
|
|
11
|
+
--warning-hover: #b45309;
|
|
12
|
+
--info: #0284c7;
|
|
13
|
+
--info-hover: #0369a1;
|
|
14
|
+
--gray-50: #f9fafb;
|
|
15
|
+
--gray-100: #f3f4f6;
|
|
16
|
+
--gray-200: #e5e7eb;
|
|
17
|
+
--gray-300: #d1d5db;
|
|
18
|
+
--gray-400: #9ca3af;
|
|
19
|
+
--gray-500: #6b7280;
|
|
20
|
+
--gray-600: #4b5563;
|
|
21
|
+
--gray-700: #374151;
|
|
22
|
+
--gray-800: #1f2937;
|
|
23
|
+
--gray-900: #111827;
|
|
24
|
+
--radius: 8px;
|
|
25
|
+
--radius-sm: 6px;
|
|
26
|
+
--radius-xs: 4px;
|
|
27
|
+
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
|
|
28
|
+
--shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
|
|
29
|
+
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
|
|
30
|
+
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
|
|
31
|
+
--transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
* {
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
body {
|
|
39
|
+
margin: 0;
|
|
40
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
41
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
42
|
+
-webkit-font-smoothing: antialiased;
|
|
43
|
+
-moz-osx-font-smoothing: grayscale;
|
|
8
44
|
}
|
|
9
45
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
46
|
+
/* ===== 布局 ===== */
|
|
47
|
+
.App {
|
|
48
|
+
min-height: 100vh;
|
|
49
|
+
background: linear-gradient(135deg, #f0f4ff 0%, #f8fafc 30%, #f0fdf4 70%, #fefce8 100%);
|
|
50
|
+
padding: 24px 16px 48px;
|
|
14
51
|
}
|
|
15
52
|
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
53
|
+
.config-container {
|
|
54
|
+
max-width: 960px;
|
|
55
|
+
margin: 0 auto;
|
|
56
|
+
position: relative;
|
|
20
57
|
}
|
|
21
58
|
|
|
22
|
-
.
|
|
23
|
-
|
|
59
|
+
.config-container h1 {
|
|
60
|
+
text-align: center;
|
|
61
|
+
font-size: 26px;
|
|
62
|
+
font-weight: 700;
|
|
63
|
+
color: var(--gray-800);
|
|
64
|
+
margin: 0 0 28px;
|
|
65
|
+
letter-spacing: -0.02em;
|
|
24
66
|
}
|
|
25
67
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
68
|
+
/* ===== Section 卡片 ===== */
|
|
69
|
+
.config-section {
|
|
70
|
+
background: white;
|
|
71
|
+
border-radius: 12px;
|
|
72
|
+
padding: 24px 28px;
|
|
73
|
+
margin-bottom: 20px;
|
|
74
|
+
box-shadow: var(--shadow);
|
|
75
|
+
border: 1px solid var(--gray-100);
|
|
76
|
+
transition: box-shadow var(--transition);
|
|
29
77
|
}
|
|
30
78
|
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
font-family: 'Courier New', monospace;
|
|
34
|
-
background-color: #f8f9fa;
|
|
35
|
-
padding: 2px 6px;
|
|
36
|
-
border-radius: 3px;
|
|
79
|
+
.config-section:hover {
|
|
80
|
+
box-shadow: var(--shadow-md);
|
|
37
81
|
}
|
|
38
82
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
padding:
|
|
45
|
-
border-
|
|
46
|
-
color: white;
|
|
47
|
-
font-weight: 500;
|
|
48
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
49
|
-
z-index: 1000;
|
|
83
|
+
.config-section h2 {
|
|
84
|
+
margin: 0 0 18px;
|
|
85
|
+
font-size: 16px;
|
|
86
|
+
font-weight: 600;
|
|
87
|
+
color: var(--gray-800);
|
|
88
|
+
padding-bottom: 12px;
|
|
89
|
+
border-bottom: 2px solid var(--gray-100);
|
|
50
90
|
display: flex;
|
|
51
91
|
align-items: center;
|
|
52
|
-
|
|
53
|
-
min-width: 250px;
|
|
92
|
+
gap: 8px;
|
|
54
93
|
}
|
|
55
94
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
opacity: 1;
|
|
64
|
-
}
|
|
95
|
+
.config-section h2::before {
|
|
96
|
+
content: '';
|
|
97
|
+
display: inline-block;
|
|
98
|
+
width: 4px;
|
|
99
|
+
height: 18px;
|
|
100
|
+
background: var(--primary);
|
|
101
|
+
border-radius: 2px;
|
|
65
102
|
}
|
|
66
103
|
|
|
67
|
-
.
|
|
68
|
-
|
|
69
|
-
|
|
104
|
+
.config-section h3 {
|
|
105
|
+
margin: 0 0 12px;
|
|
106
|
+
font-size: 15px;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
color: var(--gray-700);
|
|
70
109
|
}
|
|
71
110
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
111
|
+
/* ===== 服务器信息 ===== */
|
|
112
|
+
.server-info p {
|
|
113
|
+
margin: 4px 0;
|
|
114
|
+
color: var(--gray-600);
|
|
115
|
+
font-size: 14px;
|
|
75
116
|
}
|
|
76
117
|
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
border-left: 4px solid #117a8b;
|
|
118
|
+
.server-info strong {
|
|
119
|
+
color: var(--gray-800);
|
|
80
120
|
}
|
|
81
121
|
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
border: none;
|
|
85
|
-
color: white;
|
|
86
|
-
font-size: 20px;
|
|
87
|
-
font-weight: bold;
|
|
88
|
-
margin-left: 15px;
|
|
89
|
-
cursor: pointer;
|
|
122
|
+
.ip-list {
|
|
123
|
+
list-style: none;
|
|
90
124
|
padding: 0;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
justify-content: center;
|
|
125
|
+
margin: 12px 0 0;
|
|
126
|
+
display: grid;
|
|
127
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
128
|
+
gap: 8px;
|
|
96
129
|
}
|
|
97
130
|
|
|
98
|
-
.
|
|
99
|
-
|
|
131
|
+
.ip-item {
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
gap: 8px;
|
|
135
|
+
padding: 8px 12px;
|
|
136
|
+
background: var(--gray-50);
|
|
137
|
+
border-radius: var(--radius-sm);
|
|
138
|
+
font-size: 13px;
|
|
139
|
+
border: 1px solid var(--gray-100);
|
|
100
140
|
}
|
|
101
141
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
107
|
-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
108
|
-
sans-serif;
|
|
109
|
-
background-color: #f5f5f5;
|
|
110
|
-
min-height: 100vh;
|
|
142
|
+
.interface-name {
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
color: var(--gray-700);
|
|
145
|
+
white-space: nowrap;
|
|
111
146
|
}
|
|
112
147
|
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
background:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
position: relative;
|
|
148
|
+
.ip-address {
|
|
149
|
+
font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
|
|
150
|
+
font-size: 12px;
|
|
151
|
+
background: var(--primary-light);
|
|
152
|
+
color: var(--primary);
|
|
153
|
+
padding: 2px 8px;
|
|
154
|
+
border-radius: var(--radius-xs);
|
|
155
|
+
font-weight: 500;
|
|
122
156
|
}
|
|
123
157
|
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
.docker-info {
|
|
159
|
+
display: inline-block;
|
|
160
|
+
font-size: 12px;
|
|
161
|
+
font-weight: 500;
|
|
162
|
+
color: var(--info);
|
|
163
|
+
background: #e0f2fe;
|
|
164
|
+
padding: 2px 8px;
|
|
165
|
+
border-radius: 10px;
|
|
166
|
+
margin-left: 6px;
|
|
128
167
|
}
|
|
129
168
|
|
|
130
|
-
.
|
|
131
|
-
margin-
|
|
132
|
-
padding:
|
|
133
|
-
border: 1px solid
|
|
134
|
-
border-radius: 5px;
|
|
135
|
-
background-color: #fafafa;
|
|
169
|
+
.host-ip-info {
|
|
170
|
+
margin-top: 12px;
|
|
171
|
+
padding-top: 12px;
|
|
172
|
+
border-top: 1px solid var(--gray-200);
|
|
136
173
|
}
|
|
137
174
|
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
color:
|
|
141
|
-
border-bottom: 1px solid #eee;
|
|
142
|
-
padding-bottom: 10px;
|
|
175
|
+
.host-ip-info p {
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
color: var(--gray-600);
|
|
143
178
|
}
|
|
144
179
|
|
|
180
|
+
/* ===== 拦截主机列表 ===== */
|
|
145
181
|
.host-input {
|
|
146
182
|
display: flex;
|
|
147
|
-
|
|
183
|
+
flex-wrap: wrap;
|
|
148
184
|
gap: 10px;
|
|
149
|
-
|
|
185
|
+
margin-bottom: 16px;
|
|
186
|
+
align-items: flex-end;
|
|
150
187
|
}
|
|
151
188
|
|
|
152
189
|
.host-input input[type="text"] {
|
|
153
190
|
flex: 1;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
border
|
|
191
|
+
min-width: 180px;
|
|
192
|
+
padding: 10px 14px;
|
|
193
|
+
border: 1.5px solid var(--gray-300);
|
|
194
|
+
border-radius: var(--radius-sm);
|
|
157
195
|
font-size: 14px;
|
|
196
|
+
transition: border-color var(--transition), box-shadow var(--transition);
|
|
197
|
+
background: white;
|
|
158
198
|
}
|
|
159
199
|
|
|
160
|
-
.host-input
|
|
161
|
-
|
|
162
|
-
color:
|
|
163
|
-
|
|
164
|
-
border-radius: 4px;
|
|
165
|
-
cursor: pointer;
|
|
166
|
-
font-size: 14px;
|
|
167
|
-
align-self: flex-start;
|
|
200
|
+
.host-input input[type="text"]:focus {
|
|
201
|
+
outline: none;
|
|
202
|
+
border-color: var(--primary);
|
|
203
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
168
204
|
}
|
|
169
205
|
|
|
170
|
-
.host-input
|
|
171
|
-
|
|
206
|
+
.host-input input[type="text"]::placeholder {
|
|
207
|
+
color: var(--gray-400);
|
|
172
208
|
}
|
|
173
209
|
|
|
174
210
|
.time-inputs {
|
|
175
211
|
display: flex;
|
|
176
212
|
gap: 10px;
|
|
177
213
|
align-items: center;
|
|
214
|
+
flex-wrap: wrap;
|
|
178
215
|
}
|
|
179
216
|
|
|
180
217
|
.time-inputs label {
|
|
181
|
-
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
gap: 4px;
|
|
221
|
+
font-size: 13px;
|
|
222
|
+
color: var(--gray-600);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.time-inputs label span {
|
|
226
|
+
white-space: nowrap;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.host-input button,
|
|
230
|
+
.time-inputs button {
|
|
231
|
+
padding: 10px 20px;
|
|
232
|
+
background: var(--primary);
|
|
233
|
+
color: white;
|
|
234
|
+
border: none;
|
|
235
|
+
border-radius: var(--radius-sm);
|
|
236
|
+
cursor: pointer;
|
|
182
237
|
font-size: 14px;
|
|
238
|
+
font-weight: 500;
|
|
239
|
+
transition: background var(--transition), transform 50ms;
|
|
240
|
+
white-space: nowrap;
|
|
183
241
|
}
|
|
184
242
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
border-width:0px;
|
|
188
|
-
background-color:#e3e3e3
|
|
243
|
+
.host-input button:hover {
|
|
244
|
+
background: var(--primary-hover);
|
|
189
245
|
}
|
|
190
246
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
padding: 4px;
|
|
194
|
-
border: 1px solid #ddd;
|
|
195
|
-
border-radius: 3px;
|
|
196
|
-
background-color: white;
|
|
247
|
+
.host-input button:active {
|
|
248
|
+
transform: scale(0.97);
|
|
197
249
|
}
|
|
198
250
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
border
|
|
202
|
-
|
|
251
|
+
hr.simple-line {
|
|
252
|
+
height: 1px;
|
|
253
|
+
border: none;
|
|
254
|
+
background: var(--gray-200);
|
|
255
|
+
margin: 0 0 12px;
|
|
203
256
|
}
|
|
204
257
|
|
|
258
|
+
/* ===== 域名列表表头 ===== */
|
|
205
259
|
.host-list {
|
|
206
260
|
list-style: none;
|
|
207
261
|
padding: 0;
|
|
@@ -211,9 +265,31 @@ input[type="time"]:focus {
|
|
|
211
265
|
.host-item {
|
|
212
266
|
display: flex;
|
|
213
267
|
justify-content: space-between;
|
|
214
|
-
align-items:
|
|
215
|
-
|
|
216
|
-
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 12px;
|
|
270
|
+
padding: 14px 16px;
|
|
271
|
+
border-radius: var(--radius-sm);
|
|
272
|
+
transition: background var(--transition);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.host-item:first-child {
|
|
276
|
+
background: var(--gray-50);
|
|
277
|
+
border-radius: var(--radius-sm);
|
|
278
|
+
margin-bottom: 4px;
|
|
279
|
+
padding: 10px 16px;
|
|
280
|
+
font-weight: 600;
|
|
281
|
+
font-size: 13px;
|
|
282
|
+
color: var(--gray-500);
|
|
283
|
+
text-transform: uppercase;
|
|
284
|
+
letter-spacing: 0.05em;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.host-item:not(:first-child) {
|
|
288
|
+
border-bottom: 1px solid var(--gray-100);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.host-item:not(:first-child):hover {
|
|
292
|
+
background: var(--gray-50);
|
|
217
293
|
}
|
|
218
294
|
|
|
219
295
|
.host-item:last-child {
|
|
@@ -223,285 +299,529 @@ input[type="time"]:focus {
|
|
|
223
299
|
.host-info {
|
|
224
300
|
display: flex;
|
|
225
301
|
flex-grow: 1;
|
|
226
|
-
align-items:center;
|
|
227
|
-
|
|
302
|
+
align-items: center;
|
|
303
|
+
gap: 12px;
|
|
304
|
+
flex-wrap: wrap;
|
|
228
305
|
}
|
|
229
306
|
|
|
230
307
|
span.host-text {
|
|
231
308
|
font-size: 14px;
|
|
232
|
-
flex
|
|
233
|
-
|
|
309
|
+
flex: 1;
|
|
310
|
+
min-width: 140px;
|
|
311
|
+
line-height: 1.5;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
span.host-text strong {
|
|
315
|
+
color: var(--gray-800);
|
|
316
|
+
font-weight: 600;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* ===== 时间控件 ===== */
|
|
320
|
+
input[type="time"] {
|
|
321
|
+
padding: 6px 8px;
|
|
322
|
+
border: 1.5px solid var(--gray-300);
|
|
323
|
+
border-radius: var(--radius-xs);
|
|
324
|
+
font-size: 13px;
|
|
325
|
+
background: white;
|
|
326
|
+
transition: border-color var(--transition), box-shadow var(--transition);
|
|
327
|
+
font-family: inherit;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
input[type="time"]:focus {
|
|
331
|
+
outline: none;
|
|
332
|
+
border-color: var(--primary);
|
|
333
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
234
334
|
}
|
|
235
335
|
|
|
236
336
|
.time-controls {
|
|
237
337
|
display: flex;
|
|
238
|
-
gap:
|
|
338
|
+
gap: 6px;
|
|
239
339
|
align-items: center;
|
|
240
340
|
}
|
|
241
341
|
|
|
242
342
|
.time-controls label {
|
|
243
343
|
display: flex;
|
|
244
|
-
|
|
245
|
-
font-size:
|
|
344
|
+
align-items: center;
|
|
345
|
+
font-size: 13px;
|
|
346
|
+
color: var(--gray-500);
|
|
246
347
|
}
|
|
247
348
|
|
|
349
|
+
/* ===== 删除按钮 ===== */
|
|
248
350
|
.remove-btn {
|
|
249
|
-
background
|
|
250
|
-
color:
|
|
251
|
-
border:
|
|
252
|
-
|
|
253
|
-
|
|
351
|
+
background: white;
|
|
352
|
+
color: var(--gray-400);
|
|
353
|
+
border: 1.5px solid var(--gray-200);
|
|
354
|
+
width: 30px;
|
|
355
|
+
height: 30px;
|
|
356
|
+
min-width: 30px;
|
|
254
357
|
cursor: pointer;
|
|
255
|
-
border-radius:
|
|
256
|
-
font-size:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
358
|
+
border-radius: var(--radius-xs);
|
|
359
|
+
font-size: 14px;
|
|
360
|
+
font-weight: 600;
|
|
361
|
+
display: flex;
|
|
362
|
+
align-items: center;
|
|
363
|
+
justify-content: center;
|
|
364
|
+
transition: all var(--transition);
|
|
365
|
+
padding: 0;
|
|
260
366
|
}
|
|
261
367
|
|
|
262
368
|
.remove-btn:hover {
|
|
263
|
-
background
|
|
369
|
+
background: var(--danger);
|
|
370
|
+
color: white;
|
|
371
|
+
border-color: var(--danger);
|
|
264
372
|
}
|
|
265
373
|
|
|
374
|
+
/* ===== 设置行 ===== */
|
|
266
375
|
.setting-row {
|
|
267
376
|
display: flex;
|
|
268
377
|
align-items: center;
|
|
269
|
-
margin-bottom:
|
|
270
|
-
gap:
|
|
378
|
+
margin-bottom: 14px;
|
|
379
|
+
gap: 16px;
|
|
271
380
|
}
|
|
272
381
|
|
|
273
382
|
.setting-row label {
|
|
274
|
-
width:
|
|
383
|
+
width: 200px;
|
|
275
384
|
text-align: right;
|
|
276
|
-
font-weight:
|
|
277
|
-
color:
|
|
278
|
-
flex-shrink: 0;
|
|
385
|
+
font-weight: 500;
|
|
386
|
+
color: var(--gray-700);
|
|
387
|
+
flex-shrink: 0;
|
|
388
|
+
font-size: 14px;
|
|
279
389
|
}
|
|
280
390
|
|
|
281
|
-
.setting-row input
|
|
391
|
+
.setting-row input[type="text"],
|
|
392
|
+
.setting-row input[type="number"],
|
|
393
|
+
.setting-row select {
|
|
282
394
|
flex: 1;
|
|
283
|
-
padding:
|
|
284
|
-
border:
|
|
285
|
-
border-radius:
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
.setting-row input[type="number"] {
|
|
289
|
-
padding: 8px;
|
|
290
|
-
border: 1px solid #ddd;
|
|
291
|
-
border-radius: 4px;
|
|
395
|
+
padding: 10px 14px;
|
|
396
|
+
border: 1.5px solid var(--gray-300);
|
|
397
|
+
border-radius: var(--radius-sm);
|
|
292
398
|
font-size: 14px;
|
|
399
|
+
font-family: inherit;
|
|
400
|
+
transition: border-color var(--transition), box-shadow var(--transition);
|
|
401
|
+
background: white;
|
|
293
402
|
}
|
|
294
403
|
|
|
295
|
-
.setting-row input[type="
|
|
404
|
+
.setting-row input[type="text"]:focus,
|
|
405
|
+
.setting-row input[type="number"]:focus,
|
|
406
|
+
.setting-row select:focus {
|
|
296
407
|
outline: none;
|
|
297
|
-
border-color:
|
|
298
|
-
box-shadow: 0 0 0
|
|
408
|
+
border-color: var(--primary);
|
|
409
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
299
410
|
}
|
|
300
411
|
|
|
412
|
+
.setting-row select {
|
|
413
|
+
cursor: pointer;
|
|
414
|
+
appearance: none;
|
|
415
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
|
416
|
+
background-repeat: no-repeat;
|
|
417
|
+
background-position: right 12px center;
|
|
418
|
+
padding-right: 36px;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.setting-row.full-width {
|
|
422
|
+
flex-wrap: wrap;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.setting-row.full-width label {
|
|
426
|
+
width: 200px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.setting-row.full-width input {
|
|
430
|
+
flex: 1;
|
|
431
|
+
min-width: 240px;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.help-text {
|
|
435
|
+
width: 100%;
|
|
436
|
+
margin-left: 216px;
|
|
437
|
+
font-size: 12px;
|
|
438
|
+
color: var(--gray-400);
|
|
439
|
+
line-height: 1.5;
|
|
440
|
+
margin-top: -4px;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* ===== 操作按钮行 ===== */
|
|
301
444
|
.actions {
|
|
302
445
|
display: flex;
|
|
303
|
-
|
|
446
|
+
gap: 12px;
|
|
447
|
+
margin-top: 20px;
|
|
448
|
+
padding-top: 20px;
|
|
449
|
+
border-top: 1px solid var(--gray-100);
|
|
304
450
|
}
|
|
305
451
|
|
|
306
|
-
.save-btn,
|
|
452
|
+
.save-btn,
|
|
453
|
+
.restart-btn,
|
|
454
|
+
.refresh-btn {
|
|
307
455
|
flex: 1;
|
|
308
456
|
padding: 12px 20px;
|
|
309
457
|
border: none;
|
|
310
|
-
border-radius:
|
|
458
|
+
border-radius: var(--radius-sm);
|
|
311
459
|
cursor: pointer;
|
|
312
|
-
font-size:
|
|
313
|
-
font-weight:
|
|
460
|
+
font-size: 14px;
|
|
461
|
+
font-weight: 600;
|
|
462
|
+
transition: all var(--transition);
|
|
463
|
+
letter-spacing: 0.01em;
|
|
314
464
|
}
|
|
315
465
|
|
|
316
466
|
.save-btn {
|
|
317
|
-
background
|
|
467
|
+
background: var(--success);
|
|
318
468
|
color: white;
|
|
319
469
|
}
|
|
320
470
|
|
|
321
471
|
.save-btn:hover:not(:disabled) {
|
|
322
|
-
background
|
|
472
|
+
background: var(--success-hover);
|
|
473
|
+
box-shadow: 0 2px 8px rgba(5, 150, 105, 0.3);
|
|
323
474
|
}
|
|
324
475
|
|
|
325
476
|
.restart-btn {
|
|
326
|
-
background
|
|
327
|
-
color:
|
|
477
|
+
background: var(--warning);
|
|
478
|
+
color: white;
|
|
328
479
|
}
|
|
329
480
|
|
|
330
481
|
.restart-btn:hover:not(:disabled) {
|
|
331
|
-
background
|
|
482
|
+
background: var(--warning-hover);
|
|
483
|
+
box-shadow: 0 2px 8px rgba(217, 119, 6, 0.3);
|
|
332
484
|
}
|
|
333
485
|
|
|
334
|
-
.save-btn:disabled,
|
|
335
|
-
|
|
486
|
+
.save-btn:disabled,
|
|
487
|
+
.restart-btn:disabled,
|
|
488
|
+
.refresh-btn:disabled {
|
|
489
|
+
background: var(--gray-300);
|
|
490
|
+
color: var(--gray-500);
|
|
336
491
|
cursor: not-allowed;
|
|
492
|
+
box-shadow: none;
|
|
337
493
|
}
|
|
338
494
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
transition: background-color 0.2s;
|
|
495
|
+
.save-btn:active:not(:disabled),
|
|
496
|
+
.restart-btn:active:not(:disabled),
|
|
497
|
+
.refresh-btn:active:not(:disabled),
|
|
498
|
+
.refresh-table-btn:active:not(:disabled) {
|
|
499
|
+
transform: scale(0.98);
|
|
345
500
|
}
|
|
346
501
|
|
|
347
|
-
|
|
348
|
-
|
|
502
|
+
.refresh-btn {
|
|
503
|
+
background: var(--info);
|
|
504
|
+
color: white;
|
|
349
505
|
}
|
|
350
506
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
507
|
+
.refresh-btn:hover:not(:disabled) {
|
|
508
|
+
background: var(--info-hover);
|
|
509
|
+
box-shadow: 0 2px 8px rgba(2, 132, 199, 0.3);
|
|
354
510
|
}
|
|
355
511
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
color: #007bff;
|
|
359
|
-
font-size: 0.9em;
|
|
512
|
+
.refresh-table-btn {
|
|
513
|
+
margin-top: 12px;
|
|
360
514
|
}
|
|
361
515
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
516
|
+
/* ===== 代理设置信息区 ===== */
|
|
517
|
+
.config-section p {
|
|
518
|
+
margin: 6px 0;
|
|
519
|
+
font-size: 14px;
|
|
520
|
+
color: var(--gray-600);
|
|
521
|
+
line-height: 1.7;
|
|
366
522
|
}
|
|
367
523
|
|
|
368
|
-
.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
margin: 10px 0;
|
|
524
|
+
.config-section p b {
|
|
525
|
+
color: var(--gray-800);
|
|
526
|
+
font-weight: 600;
|
|
372
527
|
}
|
|
373
528
|
|
|
374
|
-
.
|
|
375
|
-
|
|
376
|
-
|
|
529
|
+
.config-section a {
|
|
530
|
+
color: var(--primary);
|
|
531
|
+
text-decoration: none;
|
|
532
|
+
font-weight: 500;
|
|
533
|
+
transition: color var(--transition);
|
|
377
534
|
}
|
|
378
535
|
|
|
379
|
-
.
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
color: #555;
|
|
536
|
+
.config-section a:hover {
|
|
537
|
+
color: var(--primary-hover);
|
|
538
|
+
text-decoration: underline;
|
|
383
539
|
}
|
|
384
540
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
padding:
|
|
390
|
-
|
|
541
|
+
#qrcode {
|
|
542
|
+
margin-top: 8px;
|
|
543
|
+
border-radius: var(--radius-sm);
|
|
544
|
+
border: 1px solid var(--gray-200);
|
|
545
|
+
padding: 8px;
|
|
546
|
+
background: white;
|
|
391
547
|
}
|
|
392
548
|
|
|
393
|
-
/*
|
|
549
|
+
/* ===== 通用按钮 ===== */
|
|
550
|
+
button {
|
|
551
|
+
font-family: inherit;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.config-section > button {
|
|
555
|
+
padding: 10px 20px;
|
|
556
|
+
background: white;
|
|
557
|
+
color: var(--gray-700);
|
|
558
|
+
border: 1.5px solid var(--gray-300);
|
|
559
|
+
border-radius: var(--radius-sm);
|
|
560
|
+
cursor: pointer;
|
|
561
|
+
font-size: 14px;
|
|
562
|
+
font-weight: 500;
|
|
563
|
+
transition: all var(--transition);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.config-section > button:hover:not(:disabled) {
|
|
567
|
+
background: var(--gray-50);
|
|
568
|
+
border-color: var(--gray-400);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.config-section > button:disabled {
|
|
572
|
+
opacity: 0.5;
|
|
573
|
+
cursor: not-allowed;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/* ===== 星期几按钮 ===== */
|
|
394
577
|
.weekday-controls {
|
|
395
578
|
display: flex;
|
|
396
|
-
|
|
579
|
+
gap: 2px;
|
|
397
580
|
align-items: center;
|
|
398
581
|
}
|
|
399
582
|
|
|
400
583
|
.weekday-btn {
|
|
401
|
-
width:
|
|
402
|
-
height:
|
|
584
|
+
width: 30px;
|
|
585
|
+
height: 30px;
|
|
403
586
|
padding: 0;
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
color: #515b63;
|
|
587
|
+
background: var(--gray-100);
|
|
588
|
+
color: var(--gray-500);
|
|
407
589
|
font-size: 12px;
|
|
408
|
-
|
|
590
|
+
font-weight: 500;
|
|
591
|
+
border-radius: var(--radius-xs);
|
|
409
592
|
cursor: pointer;
|
|
410
593
|
display: flex;
|
|
411
594
|
align-items: center;
|
|
412
595
|
justify-content: center;
|
|
596
|
+
border: 1.5px solid transparent;
|
|
597
|
+
transition: all var(--transition);
|
|
413
598
|
}
|
|
414
599
|
|
|
415
600
|
.weekday-btn:hover {
|
|
416
|
-
background
|
|
417
|
-
|
|
601
|
+
background: var(--gray-200);
|
|
602
|
+
color: var(--gray-700);
|
|
418
603
|
}
|
|
419
604
|
|
|
420
605
|
.weekday-btn.active {
|
|
421
|
-
background
|
|
606
|
+
background: var(--primary);
|
|
422
607
|
color: white;
|
|
608
|
+
border-color: var(--primary);
|
|
609
|
+
box-shadow: 0 1px 3px rgba(79, 70, 229, 0.3);
|
|
423
610
|
}
|
|
424
611
|
|
|
425
612
|
.weekday-btn:focus {
|
|
426
613
|
outline: none;
|
|
427
|
-
box-shadow: 0 0 0 2px rgba(
|
|
614
|
+
box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.3);
|
|
428
615
|
}
|
|
429
616
|
|
|
430
|
-
/* MAC
|
|
617
|
+
/* ===== MAC 地址输入 ===== */
|
|
431
618
|
.mac-input {
|
|
432
619
|
display: flex;
|
|
433
620
|
align-items: center;
|
|
434
|
-
|
|
435
|
-
gap: 5px;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
.mac-input label {
|
|
439
|
-
font-size: 12px;
|
|
440
|
-
color: #555;
|
|
621
|
+
gap: 8px;
|
|
441
622
|
}
|
|
442
623
|
|
|
443
624
|
.mac-input input[type="text"] {
|
|
444
|
-
width:
|
|
445
|
-
padding:
|
|
446
|
-
border:
|
|
447
|
-
border-radius:
|
|
625
|
+
width: 130px;
|
|
626
|
+
padding: 6px 10px;
|
|
627
|
+
border: 1.5px solid var(--gray-300);
|
|
628
|
+
border-radius: var(--radius-xs);
|
|
448
629
|
font-size: 12px;
|
|
630
|
+
font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
|
|
631
|
+
transition: border-color var(--transition), box-shadow var(--transition);
|
|
449
632
|
}
|
|
450
633
|
|
|
451
634
|
.mac-input input[type="text"]:focus {
|
|
452
635
|
outline: none;
|
|
453
|
-
border-color:
|
|
454
|
-
box-shadow: 0 0 0
|
|
636
|
+
border-color: var(--primary);
|
|
637
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.mac-input input[type="text"]::placeholder {
|
|
641
|
+
color: var(--gray-400);
|
|
642
|
+
font-family: inherit;
|
|
455
643
|
}
|
|
456
644
|
|
|
645
|
+
/* ===== 列表表头 ===== */
|
|
457
646
|
.table-right-blank {
|
|
458
|
-
min-width:30px;
|
|
647
|
+
min-width: 30px;
|
|
459
648
|
}
|
|
460
649
|
|
|
461
650
|
.title-mac-input {
|
|
462
|
-
font-size:
|
|
463
|
-
text-align:center;
|
|
464
|
-
min-width:
|
|
651
|
+
font-size: 13px;
|
|
652
|
+
text-align: center;
|
|
653
|
+
min-width: 138px;
|
|
465
654
|
}
|
|
655
|
+
|
|
466
656
|
.title-time-controls {
|
|
467
|
-
font-size:
|
|
468
|
-
text-align:center;
|
|
469
|
-
min-width:
|
|
657
|
+
font-size: 13px;
|
|
658
|
+
text-align: center;
|
|
659
|
+
min-width: 190px;
|
|
470
660
|
}
|
|
661
|
+
|
|
471
662
|
.title-weedkey-controls {
|
|
472
|
-
font-size:
|
|
473
|
-
min-width:
|
|
663
|
+
font-size: 13px;
|
|
664
|
+
min-width: 120px;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/* ===== Toast 通知 ===== */
|
|
668
|
+
.toast {
|
|
669
|
+
position: fixed;
|
|
670
|
+
top: 24px;
|
|
671
|
+
right: 24px;
|
|
672
|
+
padding: 14px 20px;
|
|
673
|
+
border-radius: 10px;
|
|
674
|
+
color: white;
|
|
675
|
+
font-weight: 500;
|
|
676
|
+
font-size: 14px;
|
|
677
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
|
678
|
+
z-index: 1000;
|
|
679
|
+
display: flex;
|
|
680
|
+
align-items: center;
|
|
681
|
+
gap: 12px;
|
|
682
|
+
animation: toastSlideIn 0.35s cubic-bezier(0.16, 1, 0.3, 1);
|
|
683
|
+
min-width: 260px;
|
|
684
|
+
backdrop-filter: blur(8px);
|
|
474
685
|
}
|
|
475
686
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
padding: 20px;
|
|
687
|
+
@keyframes toastSlideIn {
|
|
688
|
+
from {
|
|
689
|
+
transform: translateX(120%);
|
|
690
|
+
opacity: 0;
|
|
481
691
|
}
|
|
482
|
-
|
|
483
|
-
|
|
692
|
+
to {
|
|
693
|
+
transform: translateX(0);
|
|
694
|
+
opacity: 1;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.toast.success {
|
|
699
|
+
background: var(--success);
|
|
700
|
+
box-shadow: 0 8px 20px rgba(5, 150, 105, 0.3);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.toast.error {
|
|
704
|
+
background: var(--danger);
|
|
705
|
+
box-shadow: 0 8px 20px rgba(220, 38, 38, 0.3);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.toast.info {
|
|
709
|
+
background: var(--info);
|
|
710
|
+
box-shadow: 0 8px 20px rgba(2, 132, 199, 0.3);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.toast-close {
|
|
714
|
+
background: rgba(255,255,255,0.2);
|
|
715
|
+
border: none;
|
|
716
|
+
color: white;
|
|
717
|
+
font-size: 18px;
|
|
718
|
+
font-weight: 400;
|
|
719
|
+
cursor: pointer;
|
|
720
|
+
padding: 0;
|
|
721
|
+
width: 24px;
|
|
722
|
+
height: 24px;
|
|
723
|
+
display: flex;
|
|
724
|
+
align-items: center;
|
|
725
|
+
justify-content: center;
|
|
726
|
+
border-radius: 50%;
|
|
727
|
+
transition: background var(--transition);
|
|
728
|
+
margin-left: auto;
|
|
729
|
+
flex-shrink: 0;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.toast-close:hover {
|
|
733
|
+
background: rgba(255,255,255,0.35);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/* ===== 路由表 ===== */
|
|
737
|
+
.config-section .ip-list {
|
|
738
|
+
display: flex;
|
|
739
|
+
flex-direction: column;
|
|
740
|
+
gap: 4px;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.config-section .ip-item {
|
|
744
|
+
background: var(--gray-50);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* ===== 响应式 ===== */
|
|
748
|
+
@media (max-width: 768px) {
|
|
749
|
+
.App {
|
|
750
|
+
padding: 12px 8px 32px;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.config-section {
|
|
754
|
+
padding: 18px 16px;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
.host-info {
|
|
758
|
+
flex-direction: column;
|
|
759
|
+
align-items: flex-start;
|
|
760
|
+
gap: 8px;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.setting-row {
|
|
484
764
|
flex-direction: column;
|
|
485
765
|
align-items: flex-start;
|
|
486
|
-
gap:
|
|
766
|
+
gap: 6px;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.setting-row label {
|
|
770
|
+
width: 100%;
|
|
771
|
+
text-align: left;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.setting-row.full-width label {
|
|
775
|
+
width: 100%;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.help-text {
|
|
779
|
+
margin-left: 0;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.actions {
|
|
783
|
+
flex-direction: column;
|
|
487
784
|
}
|
|
488
785
|
|
|
489
786
|
.host-item {
|
|
490
|
-
|
|
787
|
+
flex-direction: column;
|
|
788
|
+
align-items: flex-start;
|
|
789
|
+
gap: 8px;
|
|
491
790
|
}
|
|
492
|
-
|
|
791
|
+
|
|
493
792
|
.remove-btn {
|
|
494
|
-
align-self: flex-
|
|
495
|
-
|
|
496
|
-
|
|
793
|
+
align-self: flex-end;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.time-controls {
|
|
797
|
+
flex-wrap: wrap;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.host-input {
|
|
801
|
+
flex-direction: column;
|
|
497
802
|
}
|
|
498
803
|
|
|
499
|
-
.
|
|
500
|
-
|
|
804
|
+
.host-input input[type="text"] {
|
|
805
|
+
min-width: 100%;
|
|
501
806
|
}
|
|
502
|
-
|
|
503
|
-
.
|
|
504
|
-
|
|
807
|
+
|
|
808
|
+
.ip-list {
|
|
809
|
+
grid-template-columns: 1fr;
|
|
505
810
|
}
|
|
506
811
|
}
|
|
507
812
|
|
|
813
|
+
@media (max-width: 480px) {
|
|
814
|
+
.config-container h1 {
|
|
815
|
+
font-size: 20px;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.config-section h2 {
|
|
819
|
+
font-size: 14px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.weekday-btn {
|
|
823
|
+
width: 26px;
|
|
824
|
+
height: 26px;
|
|
825
|
+
font-size: 11px;
|
|
826
|
+
}
|
|
827
|
+
}
|