scipious commited on
Commit
e28ac0d
·
verified ·
1 Parent(s): 7eb4c01

Upload chat_v03.html

Browse files
Files changed (1) hide show
  1. templates/chat_v03.html +1810 -0
templates/chat_v03.html ADDED
@@ -0,0 +1,1810 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>LexiMind - 자동차 인증 법규를 더 쉽게</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
8
+ <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
9
+ <style>
10
+ :root {
11
+ --primary-color: #0066FF;
12
+ --primary-hover: #4da8ff;
13
+ --bg-primary: #1a1a1a;
14
+ --bg-secondary: #2c2c2c;
15
+ --bg-tertiary: #333;
16
+ --bg-quaternary: #444;
17
+ --text-primary: #e0e0e0;
18
+ --text-secondary: #b0b0b0;
19
+ --text-muted: #888;
20
+ --border-color: #444;
21
+ --shadow: 0 2px 8px rgba(0,0,0,0.2);
22
+ --radius: 8px;
23
+ --success-color: #4caf50;
24
+ --warning-color: #ff9800;
25
+ }
26
+
27
+ * { box-sizing: border-box; }
28
+
29
+ body {
30
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans KR', sans-serif;
31
+ margin: 0; padding: 0;
32
+ background-color: var(--bg-primary);
33
+ color: var(--text-primary);
34
+ line-height: 1.6;
35
+ }
36
+
37
+ /* ===== 헤더 ===== */
38
+ .header {
39
+ background: var(--bg-secondary);
40
+ padding: 16px 24px;
41
+ box-shadow: var(--shadow);
42
+ display: flex; justify-content: space-between; align-items: center;
43
+ position: sticky; top: 0; z-index: 100;
44
+ }
45
+
46
+ .logo {
47
+ font-size: 28px; font-weight: 700; color: var(--primary-color); letter-spacing: -0.5px;
48
+ }
49
+
50
+ .nav {
51
+ display: flex; list-style: none; gap: 32px; margin: 0; padding: 0;
52
+ }
53
+
54
+ .nav a {
55
+ text-decoration: none; color: var(--text-secondary); font-weight: 500;
56
+ padding: 8px 12px; border-radius: var(--radius); transition: all 0.2s ease;
57
+ }
58
+
59
+ .nav a:hover {
60
+ color: var(--primary-hover); background: rgba(77, 168, 255, 0.1);
61
+ }
62
+
63
+ /* ===== 사이드바 컨트롤 ===== */
64
+ .sidebar-toggle {
65
+ position: fixed;
66
+ top: 100px;
67
+ left: 30px;
68
+ width: 40px;
69
+ height: 40px;
70
+ background: rgba(0, 102, 255, 0.7);
71
+ border: 1px solid rgba(255, 255, 255, 0.2);
72
+ border-radius: 50%;
73
+ cursor: pointer;
74
+ z-index: 1001;
75
+ transition: all 0.3s ease;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ backdrop-filter: blur(10px);
80
+ box-shadow: 0 8px 32px rgba(0, 102, 255, 0.3);
81
+ }
82
+
83
+ .sidebar-toggle:hover {
84
+ background: rgba(77, 168, 255, 0.8);
85
+ transform: scale(1.05);
86
+ }
87
+
88
+ .hamburger {
89
+ width: 15px;
90
+ height: 2px;
91
+ background: white;
92
+ position: relative;
93
+ transition: all 0.3s ease;
94
+ transform: translateX(-7px);
95
+ }
96
+
97
+ .hamburger::before,
98
+ .hamburger::after {
99
+ content: '';
100
+ position: absolute;
101
+ width: 15px;
102
+ height: 2px;
103
+ background: white;
104
+ transition: all 0.3s ease;
105
+ }
106
+
107
+ .hamburger::before { top: -6px; }
108
+ .hamburger::after { top: 6px; }
109
+
110
+ .sidebar-toggle.active .hamburger { background: transparent; }
111
+ .sidebar-toggle.active .hamburger::before { transform: rotate(45deg); top: 0; }
112
+ .sidebar-toggle.active .hamburger::after { transform: rotate(-45deg); top: 0; }
113
+
114
+ .new-page-btn {
115
+ position: fixed;
116
+ top: 100px;
117
+ left: 85px;
118
+ min-width: 120px;
119
+ height: 40px;
120
+ padding: 8px 16px;
121
+ background: rgba(255, 255, 255, 1);
122
+ border: 2px solid rgba(0, 102, 255, 0.2);
123
+ border-radius: 12px;
124
+ cursor: pointer;
125
+ z-index: 1001;
126
+ transition: all 0.3s ease;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ gap: 8px;
131
+ opacity: 0;
132
+ visibility: hidden;
133
+ transform: translateX(-20px);
134
+ }
135
+
136
+ .new-page-btn.show {
137
+ opacity: 1;
138
+ visibility: visible;
139
+ transform: translateX(0);
140
+ }
141
+
142
+ .new-page-btn:hover {
143
+ background: rgba(255, 255, 255, 0.8);
144
+ transform: translateY(-2px);
145
+ }
146
+
147
+ .plus-icon {
148
+ color: #0066FF;
149
+ font-size: 16px;
150
+ font-weight: 700;
151
+ }
152
+
153
+ /* ===== 사이드바 ===== */
154
+ .sidebar {
155
+ position: fixed; top: 76px; left: -300px; width: 300px;
156
+ height: calc(100vh - 76px); background: #2c2c2c;
157
+ transition: left 0.3s ease; z-index: 1000; overflow-y: auto;
158
+ }
159
+ .sidebar.open { left: 0; }
160
+
161
+ .sidebar-content {
162
+ padding: 75px 30px 30px 30px;
163
+ }
164
+
165
+ .sidebar-overlay {
166
+ position: fixed; top: 76px; left: 0; width: 100%;
167
+ height: calc(100vh - 76px); background: rgba(0, 0, 0, 0.5);
168
+ opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 999;
169
+ }
170
+ .sidebar-overlay.active { opacity: 1; visibility: visible; }
171
+
172
+ .date-ranges {
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: 12px;
176
+ }
177
+
178
+ .date-range-item {
179
+ display: block;
180
+ padding: 16px;
181
+ background: var(--bg-tertiary);
182
+ border: 2px solid transparent;
183
+ border-radius: var(--radius);
184
+ text-decoration: none;
185
+ color: var(--text-primary);
186
+ transition: all 0.3s ease;
187
+ }
188
+
189
+ .date-range-item:hover {
190
+ background: var(--bg-quaternary);
191
+ border-color: var(--primary-color);
192
+ transform: translateY(-2px);
193
+ }
194
+
195
+ .date-period {
196
+ display: block;
197
+ font-weight: 600;
198
+ font-size: 14px;
199
+ color: var(--primary-color);
200
+ margin-bottom: 4px;
201
+ }
202
+
203
+ .date-count {
204
+ display: block;
205
+ font-size: 12px;
206
+ color: var(--text-muted);
207
+ }
208
+
209
+ /* ===== 메인 레이아웃 ===== */
210
+ .main {
211
+ display: flex;
212
+ height: calc(100vh - 76px);
213
+ max-width: 100%;
214
+ margin: 0;
215
+ padding: 0;
216
+ }
217
+
218
+ /* ===== 필터 패널 ===== */
219
+ .filter-panel {
220
+ width: 350px;
221
+ background: var(--bg-secondary);
222
+ border-right: 1px solid var(--border-color);
223
+ display: flex;
224
+ flex-direction: column;
225
+ overflow: hidden;
226
+ }
227
+
228
+ .filter-header {
229
+ padding: 100px 20px 20px 20px;
230
+ border-bottom: 1px solid var(--border-color);
231
+ background: var(--bg-tertiary);
232
+ }
233
+ .filter-title {
234
+ font-size: 20px;
235
+ font-weight: 700;
236
+ color: var(--text-primary);
237
+ margin: 0 0 16px 0;
238
+ }
239
+
240
+ /* 지역 선택 토글 */
241
+ .toggle-group { margin-bottom: 24px; }
242
+ .toggle-label {
243
+ display: block;
244
+ font-size: 14px;
245
+ font-weight: 600;
246
+ color: var(--text-secondary);
247
+ margin-bottom: 12px;
248
+ }
249
+ .toggle-options {
250
+ display: flex;
251
+ gap: 8px;
252
+ flex-wrap: wrap;
253
+ }
254
+ .toggle-btn {
255
+ padding: 8px 16px;
256
+ background: var(--bg-quaternary);
257
+ border: 2px solid transparent;
258
+ border-radius: 20px;
259
+ color: var(--text-secondary);
260
+ cursor: pointer;
261
+ transition: all 0.2s ease;
262
+ font-size: 13px;
263
+ font-weight: 500;
264
+ }
265
+ .toggle-btn:hover {
266
+ background: #3a3a3a;
267
+ color: var(--text-primary);
268
+ }
269
+ .toggle-btn.active {
270
+ background: var(--primary-color);
271
+ border-color: var(--primary-hover);
272
+ color: white;
273
+ }
274
+
275
+ /* 법규 목록 스타일 */
276
+ .regulation-list-container {
277
+ border-bottom: 1px solid var(--border-color);
278
+ padding: 24px;
279
+ max-height: 250px;
280
+ overflow-y: auto;
281
+ }
282
+
283
+ .regulation-header {
284
+ display: flex;
285
+ justify-content: space-between;
286
+ align-items: center;
287
+ margin-bottom: 12px;
288
+ }
289
+
290
+ .selected-count {
291
+ font-size: 12px;
292
+ color: var(--primary-color);
293
+ background: rgba(77, 168, 255, 0.1);
294
+ padding: 4px 8px;
295
+ border-radius: 4px;
296
+ }
297
+
298
+ .regulation-item {
299
+ padding: 12px;
300
+ margin: 8px 0;
301
+ background: var(--bg-quaternary);
302
+ border-radius: var(--radius);
303
+ cursor: pointer;
304
+ transition: all 0.2s ease;
305
+ border: 2px solid transparent;
306
+ user-select: none;
307
+ }
308
+ .regulation-item:hover {
309
+ background: #3a3a3a;
310
+ border-color: var(--primary-color);
311
+ }
312
+ .regulation-item.selected {
313
+ background: var(--primary-color);
314
+ color: white;
315
+ border-color: var(--primary-hover);
316
+ }
317
+
318
+ /* ===== 상세 법규 리스트 ===== */
319
+ .regulation-details-container {
320
+ flex: 1;
321
+ display: flex;
322
+ flex-direction: column;
323
+ overflow: hidden;
324
+ }
325
+
326
+ .regulation-details-header {
327
+ display: flex;
328
+ justify-content: space-between;
329
+ align-items: center;
330
+ padding: 16px 24px;
331
+ border-bottom: 1px solid var(--border-color);
332
+ }
333
+
334
+ .regulation-header-content {
335
+ display: flex;
336
+ flex-direction: column;
337
+ gap: 4px;
338
+ }
339
+
340
+ .selected-count {
341
+ font-size: 12px;
342
+ color: var(--primary-color);
343
+ background: rgba(77, 168, 255, 0.1);
344
+ padding: 4px 8px;
345
+ border-radius: 4px;
346
+ width: fit-content;
347
+ border: 1px solid rgba(77, 168, 255, 0.2);
348
+ font-weight: 600;
349
+ }
350
+
351
+ .selected-count.has-selection {
352
+ background: rgba(77, 168, 255, 0.2);
353
+ border-color: var(--primary-color);
354
+ animation: pulse 2s infinite;
355
+ }
356
+
357
+ @keyframes pulse {
358
+ 0% {
359
+ box-shadow: 0 0 0 0 rgba(77, 168, 255, 0.4);
360
+ }
361
+ 70% {
362
+ box-shadow: 0 0 0 4px rgba(77, 168, 255, 0);
363
+ }
364
+ 100% {
365
+ box-shadow: 0 0 0 0 rgba(77, 168, 255, 0);
366
+ }
367
+ }
368
+
369
+ .btn {
370
+ padding: 8px 16px;
371
+ border: none;
372
+ border-radius: var(--radius);
373
+ background: var(--primary-color);
374
+ color: white;
375
+ cursor: pointer;
376
+ font-size: 13px;
377
+ font-weight: 600;
378
+ transition: all 0.2s ease;
379
+ }
380
+
381
+ .btn:hover {
382
+ background: var(--primary-hover);
383
+ transform: translateY(-1px);
384
+ }
385
+
386
+ .btn-small {
387
+ padding: 6px 12px;
388
+ font-size: 12px;
389
+ }
390
+
391
+ .btn-load {
392
+ background: var(--success-color);
393
+ }
394
+
395
+ .btn-load:hover {
396
+ background: #45a049;
397
+ }
398
+
399
+ .btn-secondary {
400
+ background: var(--bg-quaternary);
401
+ }
402
+
403
+ .btn-secondary:hover {
404
+ background: #555;
405
+ }
406
+
407
+ .btn-danger {
408
+ background: #ff4757;
409
+ }
410
+
411
+ .btn-danger:hover {
412
+ background: #ff3838;
413
+ }
414
+
415
+ .regulation-search {
416
+ padding: 12px 24px;
417
+ background: var(--bg-tertiary);
418
+ border-bottom: 1px solid var(--border-color);
419
+ }
420
+ .regulation-search-input {
421
+ width: 100%;
422
+ padding: 8px 12px;
423
+ border: 1px solid var(--border-color);
424
+ border-radius: var(--radius);
425
+ background: var(--bg-quaternary);
426
+ color: var(--text-primary);
427
+ font-size: 13px;
428
+ transition: border-color 0.2s ease;
429
+ }
430
+ .regulation-search-input:focus {
431
+ outline: none;
432
+ border-color: var(--primary-color);
433
+ }
434
+ .regulation-search-input::placeholder {
435
+ color: var(--text-muted);
436
+ }
437
+ .regulation-details-list {
438
+ flex: 1;
439
+ overflow-y: auto;
440
+ padding: 12px 24px;
441
+ }
442
+ .regulation-detail-item {
443
+ padding: 10px 12px;
444
+ margin: 6px 0;
445
+ background: var(--bg-quaternary);
446
+ border-radius: var(--radius);
447
+ cursor: pointer;
448
+ transition: all 0.2s ease;
449
+ border: 2px solid transparent;
450
+ user-select: none;
451
+ font-size: 13px;
452
+ line-height: 1.4;
453
+ }
454
+ .regulation-detail-item:hover {
455
+ background: #3a3a3a;
456
+ border-color: var(--primary-color);
457
+ }
458
+ .regulation-detail-item.selected {
459
+ background: var(--primary-color);
460
+ color: white;
461
+ border-color: var(--primary-hover);
462
+ }
463
+ .regulation-detail-item.hidden {
464
+ display: none;
465
+ }
466
+
467
+ .action-buttons {
468
+ display: flex;
469
+ gap: 12px;
470
+ padding: 16px 24px;
471
+ border-top: 1px solid var(--border-color);
472
+ background: var(--bg-secondary);
473
+ }
474
+
475
+ /* ===== 채팅 패널 ===== */
476
+ .chat-panel {
477
+ flex: 1;
478
+ display: flex;
479
+ flex-direction: column;
480
+ background: var(--bg-primary);
481
+ }
482
+ .chat-header {
483
+ padding: 20px 24px;
484
+ background: var(--bg-secondary);
485
+ border-bottom: 1px solid var(--border-color);
486
+ }
487
+ .chat-title {
488
+ font-size: 18px;
489
+ font-weight: 600;
490
+ color: var(--text-primary);
491
+ margin: 0;
492
+ display: flex;
493
+ align-items: baseline;
494
+ gap: 10px;
495
+ }
496
+ .title-subtitle {
497
+ font-size: 14px;
498
+ font-weight: 400;
499
+ color: var(--text-muted);
500
+ }
501
+
502
+ .status-text {
503
+ margin-top: 12px;
504
+ padding: 16px 20px;
505
+ background: linear-gradient(135deg, var(--bg-tertiary) 0%, var(--bg-quaternary) 100%);
506
+ border: 2px solid var(--border-color);
507
+ border-radius: 12px;
508
+ font-size: 16px;
509
+ font-weight: 600;
510
+ color: var(--primary-color);
511
+ position: relative;
512
+ box-shadow: 0 4px 12px rgba(0, 102, 255, 0.15);
513
+ min-height: 60px;
514
+ display: flex;
515
+ align-items: center;
516
+ transition: all 0.3s ease;
517
+ }
518
+
519
+ .status-text:hover {
520
+ border-color: var(--primary-color);
521
+ box-shadow: 0 6px 20px rgba(0, 102, 255, 0.25);
522
+ }
523
+
524
+
525
+ /* 수정된 progress-bar 스타일 - 더 두껍게 */
526
+ .progress-bar {
527
+ position: absolute;
528
+ bottom: 0;
529
+ left: 0;
530
+ height: 6px;
531
+ background: linear-gradient(90deg, var(--primary-color), var(--primary-hover));
532
+ border-radius: 0 0 10px 10px;
533
+ transition: width 0.3s ease;
534
+ width: 0%;
535
+ box-shadow: 0 2px 8px rgba(0, 102, 255, 0.4);
536
+ }
537
+
538
+ .cancel-search-btn {
539
+ position: absolute;
540
+ right: 16px;
541
+ top: 50%;
542
+ transform: translateY(-50%);
543
+ padding: 8px 16px;
544
+ font-size: 13px;
545
+ font-weight: 600;
546
+ background: var(--warning-color);
547
+ border: 2px solid transparent;
548
+ border-radius: 8px;
549
+ color: white;
550
+ cursor: pointer;
551
+ display: none;
552
+ transition: all 0.3s ease;
553
+ box-shadow: 0 2px 8px rgba(255, 152, 0, 0.3);
554
+ }
555
+
556
+ .cancel-search-btn:hover {
557
+ background: #e68900;
558
+ border-color: #ff9800;
559
+ transform: translateY(-50%) scale(1.05);
560
+ box-shadow: 0 4px 12px rgba(255, 152, 0, 0.4);
561
+ }
562
+
563
+ .cancel-search-btn:active {
564
+ transform: translateY(-50%) scale(0.95);
565
+ }
566
+
567
+ .chat-messages {
568
+ flex: 1;
569
+ overflow-y: auto;
570
+ padding: 24px;
571
+ display: flex;
572
+ flex-direction: column;
573
+ gap: 16px;
574
+ }
575
+
576
+ /* 메시지 버블 */
577
+ .message {
578
+ display: flex;
579
+ gap: 12px;
580
+ max-width: 80%;
581
+ animation: slideIn 0.3s ease;
582
+ }
583
+ @keyframes slideIn {
584
+ from { opacity: 0; transform: translateY(10px); }
585
+ to { opacity: 1; transform: translateY(0); }
586
+ }
587
+ .message.user {
588
+ align-self: flex-end;
589
+ flex-direction: row-reverse;
590
+ }
591
+ .message.assistant {
592
+ align-self: flex-start;
593
+ }
594
+ .message-avatar {
595
+ width: 36px;
596
+ height: 36px;
597
+ border-radius: 50%;
598
+ background: var(--primary-color);
599
+ display: flex;
600
+ align-items: center;
601
+ justify-content: center;
602
+ color: white;
603
+ font-weight: 700;
604
+ font-size: 14px;
605
+ flex-shrink: 0;
606
+ }
607
+ .message.user .message-avatar {
608
+ background: var(--success-color);
609
+ }
610
+ .message-content {
611
+ background: var(--bg-secondary);
612
+ padding: 12px 16px;
613
+ border-radius: 16px;
614
+ color: var(--text-primary);
615
+ line-height: 1.5;
616
+ word-wrap: break-word;
617
+ }
618
+ .message.user .message-content {
619
+ background: var(--primary-color);
620
+ color: white;
621
+ }
622
+ .message-time {
623
+ font-size: 11px;
624
+ color: var(--text-muted);
625
+ margin-top: 4px;
626
+ }
627
+
628
+ /* 메시지 콘텐츠 내 HTML 스타일링 */
629
+ .message-content h1,
630
+ .message-content h2 {
631
+ color: var(--primary-color);
632
+ margin: 12px 0 8px 0;
633
+ font-weight: 600;
634
+ }
635
+
636
+ .message-content h1 { font-size: 18px; }
637
+ .message-content h2 {
638
+ font-size: 16px;
639
+ border-bottom: 1px solid var(--border-color);
640
+ padding-bottom: 4px;
641
+ }
642
+
643
+ .message-content ul,
644
+ .message-content ol {
645
+ margin: 8px 0;
646
+ padding-left: 20px;
647
+ }
648
+
649
+ .message-content li {
650
+ margin: 4px 0;
651
+ line-height: 1.4;
652
+ }
653
+
654
+ .message-content strong {
655
+ color: var(--primary-color);
656
+ }
657
+
658
+ .message-content p {
659
+ margin: 8px 0;
660
+ line-height: 1.5;
661
+ }
662
+
663
+ .message.user .message-content h1,
664
+ .message.user .message-content h2,
665
+ .message.user .message-content strong {
666
+ color: white;
667
+ }
668
+
669
+ /* 채팅 입력 영역 */
670
+ .chat-input-container {
671
+ padding: 20px 24px;
672
+ background: var(--bg-secondary);
673
+ border-top: 1px solid var(--border-color);
674
+ }
675
+ .chat-input-wrapper {
676
+ display: flex;
677
+ gap: 12px;
678
+ align-items: flex-end;
679
+ }
680
+ .chat-input {
681
+ flex: 1;
682
+ padding: 12px 16px;
683
+ background: var(--bg-tertiary);
684
+ border: 2px solid var(--border-color);
685
+ border-radius: 24px;
686
+ color: var(--text-primary);
687
+ font-size: 14px;
688
+ resize: none;
689
+ max-height: 120px;
690
+ min-height: 44px;
691
+ font-family: inherit;
692
+ transition: border-color 0.2s ease;
693
+ }
694
+ .chat-input:focus {
695
+ outline: none;
696
+ border-color: var(--primary-color);
697
+ }
698
+ .chat-input::placeholder {
699
+ color: var(--text-muted);
700
+ }
701
+ .send-btn {
702
+ width: 44px;
703
+ height: 44px;
704
+ border-radius: 50%;
705
+ background: var(--primary-color);
706
+ border: none;
707
+ color: white;
708
+ cursor: pointer;
709
+ display: flex;
710
+ align-items: center;
711
+ justify-content: center;
712
+ transition: all 0.2s ease;
713
+ flex-shrink: 0;
714
+ }
715
+ .send-btn:hover {
716
+ background: var(--primary-hover);
717
+ transform: scale(1.05);
718
+ }
719
+ .send-btn:active {
720
+ transform: scale(0.95);
721
+ }
722
+ .send-btn:disabled {
723
+ background: var(--bg-quaternary);
724
+ cursor: not-allowed;
725
+ transform: none;
726
+ }
727
+
728
+ /* 로딩 인디케이터 */
729
+ .typing-indicator {
730
+ display: flex;
731
+ gap: 4px;
732
+ padding: 12px 16px;
733
+ background: var(--bg-secondary);
734
+ border-radius: 16px;
735
+ width: fit-content;
736
+ }
737
+ .typing-dot {
738
+ width: 8px;
739
+ height: 8px;
740
+ border-radius: 50%;
741
+ background: var(--text-muted);
742
+ animation: typing 1.4s infinite;
743
+ }
744
+ .typing-dot:nth-child(2) { animation-delay: 0.2s; }
745
+ .typing-dot:nth-child(3) { animation-delay: 0.4s; }
746
+
747
+ @keyframes typing {
748
+ 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
749
+ 30% { opacity: 1; transform: translateY(-10px); }
750
+ }
751
+
752
+ /* 스크롤바 스타일 */
753
+ .chat-messages::-webkit-scrollbar,
754
+ .filter-panel::-webkit-scrollbar,
755
+ .regulation-list-container::-webkit-scrollbar,
756
+ .regulation-details-list::-webkit-scrollbar {
757
+ width: 8px;
758
+ }
759
+
760
+ .chat-messages::-webkit-scrollbar-track,
761
+ .filter-panel::-webkit-scrollbar-track,
762
+ .regulation-list-container::-webkit-scrollbar-track,
763
+ .regulation-details-list::-webkit-scrollbar-track {
764
+ background: var(--bg-tertiary);
765
+ }
766
+
767
+ .chat-messages::-webkit-scrollbar-thumb,
768
+ .filter-panel::-webkit-scrollbar-thumb,
769
+ .regulation-list-container::-webkit-scrollbar-thumb,
770
+ .regulation-details-list::-webkit-scrollbar-thumb {
771
+ background: var(--bg-quaternary);
772
+ border-radius: 4px;
773
+ }
774
+
775
+ .chat-messages::-webkit-scrollbar-thumb:hover,
776
+ .filter-panel::-webkit-scrollbar-thumb:hover,
777
+ .regulation-list-container::-webkit-scrollbar-thumb:hover,
778
+ .regulation-details-list::-webkit-scrollbar-thumb:hover {
779
+ background: #555;
780
+ }
781
+
782
+ .search-mode-group {
783
+ margin-bottom: 20px;
784
+ padding: 16px;
785
+ background: var(--bg-quaternary);
786
+ border-radius: var(--radius);
787
+ border: 1px solid var(--border-color);
788
+ }
789
+
790
+ .search-mode-toggle {
791
+ position: relative;
792
+ display: inline-block;
793
+ width: 60px;
794
+ height: 34px;
795
+ }
796
+
797
+ .search-mode-toggle input {
798
+ opacity: 0;
799
+ width: 0;
800
+ height: 0;
801
+ }
802
+
803
+ .slider {
804
+ position: absolute;
805
+ cursor: pointer;
806
+ top: 0;
807
+ left: 0;
808
+ right: 0;
809
+ bottom: 0;
810
+ background-color: var(--bg-tertiary);
811
+ transition: 0.4s;
812
+ border-radius: 34px;
813
+ border: 2px solid var(--border-color);
814
+ }
815
+
816
+ .slider:before {
817
+ position: absolute;
818
+ content: "";
819
+ height: 24px;
820
+ width: 24px;
821
+ left: 3px;
822
+ bottom: 3px;
823
+ background-color: var(--text-secondary);
824
+ transition: 0.4s;
825
+ border-radius: 50%;
826
+ }
827
+
828
+ input:checked + .slider {
829
+ background-color: var(--primary-color);
830
+ border-color: var(--primary-hover);
831
+ }
832
+
833
+ input:checked + .slider:before {
834
+ transform: translateX(24px);
835
+ background-color: white;
836
+ }
837
+
838
+ .search-mode-label {
839
+ display: flex;
840
+ align-items: center;
841
+ gap: 12px;
842
+ margin-bottom: 8px;
843
+ color: var(--text-secondary);
844
+ font-weight: 600;
845
+ font-size: 14px;
846
+ }
847
+
848
+ .search-mode-description {
849
+ font-size: 12px;
850
+ color: var(--text-muted);
851
+ line-height: 1.4;
852
+ margin-top: 8px;
853
+ }
854
+
855
+ .mode-indicator {
856
+ font-size: 13px;
857
+ font-weight: 600;
858
+ color: var(--primary-color);
859
+ }
860
+
861
+ .regulation-type-tabs {
862
+ display: flex;
863
+ background: var(--bg-tertiary);
864
+ border-bottom: 1px solid var(--border-color);
865
+ padding: 8px 12px;
866
+ gap: 4px;
867
+ }
868
+
869
+ .type-tab {
870
+ padding: 8px 16px;
871
+ background: var(--bg-quaternary);
872
+ border: 1px solid var(--border-color);
873
+ border-radius: var(--radius);
874
+ color: var(--text-secondary);
875
+ cursor: pointer;
876
+ font-size: 12px;
877
+ font-weight: 600;
878
+ transition: all 0.2s ease;
879
+ flex: 1;
880
+ text-align: center;
881
+ }
882
+
883
+ .type-tab:hover {
884
+ background: var(--bg-tertiary);
885
+ color: var(--text-primary);
886
+ }
887
+
888
+ .type-tab.active {
889
+ background: var(--primary-color);
890
+ border-color: var(--primary-hover);
891
+ color: white;
892
+ }
893
+
894
+ /* 기존 스타일에 타입별 구분을 위한 스타일 추가 */
895
+ .regulation-detail-item[data-type="part"]::before,
896
+ .regulation-detail-item[data-level="level1"]::before {
897
+ content: "[L1] ";
898
+ color: var(--primary-color);
899
+ font-weight: 700;
900
+ font-size: 11px;
901
+ }
902
+
903
+ .regulation-detail-item[data-type="section"]::before,
904
+ .regulation-detail-item[data-type="chapter"]::before,
905
+ .regulation-detail-item[data-level="level2"]::before {
906
+ content: "[L2] ";
907
+ color: var(--success-color);
908
+ font-weight: 700;
909
+ font-size: 11px;
910
+ }
911
+
912
+ .regulation-detail-item[data-type="jo"]::before,
913
+ .regulation-detail-item[data-level="level3"]::before {
914
+ content: "[L3] ";
915
+ color: var(--warning-color);
916
+ font-weight: 700;
917
+ font-size: 11px;
918
+ }
919
+ </style>
920
+ </head>
921
+
922
+ <body>
923
+ <header class="header">
924
+ <div class="logo">LexiMind</div>
925
+ <nav>
926
+ <ul class="nav">
927
+ <li><a href="#">법규 검색</a></li>
928
+ <li><a href="#">체크리스트 생성</a></li>
929
+ <li><a href="#">유권해석</a></li>
930
+ <li><a href="#">사용문의</a></li>
931
+ </ul>
932
+ </nav>
933
+ </header>
934
+
935
+ <!-- 햄버거 버튼 -->
936
+ <button class="sidebar-toggle" id="sidebarToggle">
937
+ <span class="hamburger"></span>
938
+ </button>
939
+
940
+ <!-- 새 페이지 버튼 -->
941
+ <button class="new-page-btn" id="newPageBtn">
942
+ <span class="plus-icon">+ 새 대화 생성</span>
943
+ </button>
944
+
945
+ <!-- 사이드바 오버레이 -->
946
+ <div class="sidebar-overlay" id="sidebarOverlay"></div>
947
+
948
+ <!-- 사이드바 -->
949
+ <nav class="sidebar" id="sidebar">
950
+ <div class="sidebar-content">
951
+ <h3>과거 이력</h3>
952
+ <div class="date-ranges">
953
+ <a href="/history/202511" class="date-range-item">
954
+ <span class="date-period">2025.11.01 ~ 2025.11.30</span>
955
+ <span class="date-count">검색 15건</span>
956
+ </a>
957
+ <a href="/history/202510" class="date-range-item">
958
+ <span class="date-period">2025.10.01 ~ 2025.10.31</span>
959
+ <span class="date-count">검색 8건</span>
960
+ </a>
961
+ <a href="/history/202509" class="date-range-item">
962
+ <span class="date-period">2025.09.01 ~ 2025.09.30</span>
963
+ <span class="date-count">검색 12건</span>
964
+ </a>
965
+ </div>
966
+ </div>
967
+ </nav>
968
+
969
+ <main class="main">
970
+ <!-- 필터 패널 -->
971
+ <aside class="filter-panel">
972
+ <div class="filter-header">
973
+ <h2 class="filter-title">검색 필터</h2>
974
+ <div class="toggle-group">
975
+ <span class="toggle-label">지역</span>
976
+ <div class="toggle-options">
977
+ <button class="toggle-btn region-toggle" data-value="국내">국내</button>
978
+ <button class="toggle-btn region-toggle" data-value="북미">북미</button>
979
+ <button class="toggle-btn region-toggle" data-value="유럽">유럽</button>
980
+ <button class="toggle-btn region-toggle active" data-value="전체">전체</button>
981
+ </div>
982
+ </div>
983
+
984
+ <!-- 검색 모드 토글 추가 -->
985
+ <div class="search-mode-group">
986
+ <div class="search-mode-label">
987
+ <span>선택된 법규 각각에서 검색하기</span>
988
+ <label class="search-mode-toggle">
989
+ <input type="checkbox" id="searchEachModeToggle">
990
+ <span class="slider"></span>
991
+ </label>
992
+ </div>
993
+ <div class="mode-indicator" id="searchModeIndicator">각각 검색 모드</div>
994
+ <div class="search-mode-description" id="searchModeDescription">
995
+ 선택된 각 법규별로 개별 검색을 수행하고 결과를 따로 표시합니다.
996
+ </div>
997
+ </div>
998
+ </div>
999
+
1000
+ <!-- 상세 법규 리스트 -->
1001
+ <div class="regulation-details-container">
1002
+ <div class="regulation-details-header">
1003
+ <div class="regulation-header-content">
1004
+ <span class="toggle-label">상세 법규 리스트</span>
1005
+ <span class="selected-count" id="selectedCount">선택됨: 0</span>
1006
+ </div>
1007
+ <button class="btn btn-load btn-small" onclick="loadDetailedRegulationList()">리스트 불러오기</button>
1008
+ </div>
1009
+
1010
+ <!-- 법규 타입 선택 탭 추가 -->
1011
+ <div class="regulation-type-tabs" id="regulationTypeTabs" style="display: none;">
1012
+ <button class="type-tab active" data-type="level1" data-original-types="part">Level 1</button>
1013
+ <button class="type-tab" data-type="level2" data-original-types="section,chapter">Level 2</button>
1014
+ <button class="type-tab" data-type="level3" data-original-types="jo">Level 3</button>
1015
+ </div>
1016
+
1017
+ <div class="regulation-search" id="regulationSearchContainer" style="display: none;">
1018
+ <input type="text" id="regulationSearchInput" class="regulation-search-input" placeholder="법규 검색...">
1019
+ </div>
1020
+ <div class="regulation-details-list" id="regulationDetailsList">
1021
+ <p style="color: var(--text-muted); padding: 20px; text-align: center; margin: 0;">
1022
+ 리스트 불러오기를 눌러 상세 법규를 확인하세요.
1023
+ </p>
1024
+ </div>
1025
+ </div>
1026
+
1027
+ <div class="action-buttons">
1028
+ <button class="btn btn-secondary" onclick="clearAllSelections()">선택 초기화</button>
1029
+ </div>
1030
+ </aside>
1031
+
1032
+ <!-- 채팅 패널 -->
1033
+ <section class="chat-panel">
1034
+ <div class="chat-header">
1035
+ <h1 class="chat-title">자동차 인증 법규 검색
1036
+ <span class="title-subtitle">&nbsp&nbsp관련 법규 내용을 검색으로 편리하게 찾아보세요! ※ 모든 결과물은 AI에 의해 생성된 것으로 오류가 있을 수 있습니다</span>
1037
+ </h1>
1038
+ <div id="statusText" class="status-text">
1039
+ 시스템 준비 중...
1040
+ <div class="progress-bar" id="progressBar"></div>
1041
+ <button class="cancel-search-btn" id="cancelSearchBtn" onclick="cancelSearch()">취소</button>
1042
+ </div>
1043
+ </div>
1044
+
1045
+ <div class="chat-messages" id="chatMessages">
1046
+ <div class="message assistant">
1047
+ <div class="message-avatar">Lexi</div>
1048
+ <div>
1049
+ <div class="message-content">
1050
+ 안녕하세요! 자동차 인증 법규 검색 도우미입니다.<br>
1051
+ 궁금하신 법규 내용을 검색해보세요.<br><br>
1052
+ (ex : ISA의 작동 요건을 알려주고, 표로 정리해줘)
1053
+ </div>
1054
+ <div class="message-time" id="welcomeTime"></div>
1055
+ </div>
1056
+ </div>
1057
+ </div>
1058
+
1059
+ <!-- 채팅 입력 영역 -->
1060
+ <div class="chat-input-container">
1061
+ <div class="chat-input-wrapper">
1062
+ <textarea
1063
+ id="chatInput"
1064
+ class="chat-input"
1065
+ placeholder="검색하고 싶은 내용을 입력하세요..."
1066
+ rows="1"
1067
+ ></textarea>
1068
+ <button class="send-btn" id="sendBtn" title="전송">
1069
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1070
+ <path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/>
1071
+ </svg>
1072
+ </button>
1073
+ </div>
1074
+ </div>
1075
+ </section>
1076
+ </main>
1077
+
1078
+ <script>
1079
+ // ===== 전역 변수 =====
1080
+ let selectedRegulations = [];
1081
+ let selectedRegions = [];
1082
+ let socket;
1083
+ let currentSessionId = null;
1084
+ let isSearching = false;
1085
+ let searchEachMode = false;
1086
+ let regulationData = {}; // 모든 법규 데이터 저장
1087
+ let currentRegulationType = 'level1'; // 기본값을 level1로 변경
1088
+
1089
+ // ===== 초기화 =====
1090
+ document.addEventListener('DOMContentLoaded', function() {
1091
+ initializeSocket();
1092
+ initializeSidebar();
1093
+ initializeToggles();
1094
+ initializeChat();
1095
+ initializeRegulationList();
1096
+ initializeSearchModeToggle();
1097
+ initializeRegulationTypeTabs(); // 탭 초기화 추가
1098
+ setWelcomeTime();
1099
+ updateSelectedCount();
1100
+ });
1101
+
1102
+ // ===== 법규 타입 탭 초기화 수정 =====
1103
+ function initializeRegulationTypeTabs() {
1104
+ const tabs = document.querySelectorAll('.type-tab');
1105
+ tabs.forEach(tab => {
1106
+ tab.addEventListener('click', function() {
1107
+ const type = this.getAttribute('data-type');
1108
+ switchRegulationType(type);
1109
+ });
1110
+ });
1111
+ }
1112
+
1113
+ function switchRegulationType(type) {
1114
+ currentRegulationType = type;
1115
+
1116
+ // 탭 활성화 상태 변경
1117
+ document.querySelectorAll('.type-tab').forEach(tab => {
1118
+ tab.classList.remove('active');
1119
+ });
1120
+ document.querySelector(`.type-tab[data-type="${type}"]`).classList.add('active');
1121
+
1122
+ // 해당 타입의 데이터 표시
1123
+ displayRegulationDataByLevel(type);
1124
+
1125
+ console.log('법규 레벨 변경:', type);
1126
+ }
1127
+
1128
+ function displayRegulationDataByLevel(level) {
1129
+ let dataToDisplay = [];
1130
+
1131
+ if (level === 'level1') {
1132
+ // Part 데이터만 표시
1133
+ if (regulationData.reg_list_part) {
1134
+ dataToDisplay = parseRegulationData(regulationData.reg_list_part, 'part');
1135
+ }
1136
+ } else if (level === 'level2') {
1137
+ // Section과 Chapter 데이터를 합쳐서 표시
1138
+ const sectionData = regulationData.reg_list_section ?
1139
+ parseRegulationData(regulationData.reg_list_section, 'section') : [];
1140
+ const chapterData = regulationData.reg_list_chapter ?
1141
+ parseRegulationData(regulationData.reg_list_chapter, 'chapter') : [];
1142
+
1143
+ dataToDisplay = [...sectionData, ...chapterData].sort((a, b) => a.title.localeCompare(b.title));
1144
+ } else if (level === 'level3') {
1145
+ // Jo 데이터만 표시
1146
+ if (regulationData.reg_list_jo) {
1147
+ dataToDisplay = parseRegulationData(regulationData.reg_list_jo, 'jo');
1148
+ }
1149
+ }
1150
+
1151
+ displayDetailedRegulationList(dataToDisplay, level);
1152
+ }
1153
+
1154
+ function parseRegulationData(data, originalType) {
1155
+ const result = [];
1156
+
1157
+ if (typeof data === 'string' && data.trim()) {
1158
+ const lines = data.split('\n').filter(line => line.trim());
1159
+ lines.forEach((line, index) => {
1160
+ result.push({
1161
+ id: `detail_reg_${originalType}_${Date.now()}_${index}`,
1162
+ title: line.trim(),
1163
+ originalType: originalType,
1164
+ searchText: line.trim().toLowerCase()
1165
+ });
1166
+ });
1167
+ } else if (Array.isArray(data)) {
1168
+ data.forEach((item, index) => {
1169
+ const title = item.title || item.name || item.toString();
1170
+ result.push({
1171
+ id: item.id || `detail_reg_${originalType}_${Date.now()}_${index}`,
1172
+ title: title,
1173
+ originalType: originalType,
1174
+ searchText: title.toLowerCase()
1175
+ });
1176
+ });
1177
+ }
1178
+
1179
+ return result;
1180
+ }
1181
+
1182
+ // ===== 검색 모드 토글 초기화 =====
1183
+ function initializeSearchModeToggle() {
1184
+ const searchModeToggle = document.getElementById('searchEachModeToggle');
1185
+ const modeIndicator = document.getElementById('searchModeIndicator');
1186
+ const modeDescription = document.getElementById('searchModeDescription');
1187
+
1188
+ searchModeToggle.addEventListener('change', function() {
1189
+ searchEachMode = this.checked;
1190
+ updateSearchModeDisplay();
1191
+ });
1192
+
1193
+ updateSearchModeDisplay(); // 초기 상태 설정
1194
+ }
1195
+
1196
+ function updateSearchModeDisplay() {
1197
+ const modeIndicator = document.getElementById('searchModeIndicator');
1198
+ const modeDescription = document.getElementById('searchModeDescription');
1199
+
1200
+ if (searchEachMode) {
1201
+ modeIndicator.textContent = '각각 검색 모드';
1202
+ modeDescription.textContent = '선택된 각 법규별로 개별 검색을 수행하고 결과를 따로 표시합니다.';
1203
+ } else {
1204
+ modeIndicator.textContent = '통합 검색 모드';
1205
+ modeDescription.textContent = '선택된 모든 법규를 통합하여 한 번에 검색하고 결과를 종합하여 표시합니다.';
1206
+ }
1207
+
1208
+ console.log('검색 모드 변경:', searchEachMode ? '각각 검색' : '통합 검색');
1209
+ }
1210
+
1211
+ // 환영 메시지 시간 설정
1212
+ function setWelcomeTime() {
1213
+ const timeElement = document.getElementById('welcomeTime');
1214
+ if (timeElement) {
1215
+ const now = new Date();
1216
+ timeElement.textContent = formatTime(now);
1217
+ }
1218
+ }
1219
+
1220
+ // 시간 포맷팅
1221
+ function formatTime(date) {
1222
+ const hours = date.getHours().toString().padStart(2, '0');
1223
+ const minutes = date.getMinutes().toString().padStart(2, '0');
1224
+ return `${hours}:${minutes}`;
1225
+ }
1226
+
1227
+ // ===== Socket.IO 초기화 =====
1228
+ function initializeSocket() {
1229
+ socket = io();
1230
+
1231
+ // 기존 시스템 메시지
1232
+ socket.on('message', function(data) {
1233
+ updateSearchStatus(data.message);
1234
+ });
1235
+
1236
+ // 검색 시작 - session_id 받기 (추가됨)
1237
+ socket.on('search_started', function(data) {
1238
+ currentSessionId = data.session_id;
1239
+ console.log('Search started with session ID:', currentSessionId);
1240
+ });
1241
+
1242
+ // 검색 상태 업데이트
1243
+ socket.on('search_status', function(data) {
1244
+ updateSearchStatus(data.message);
1245
+ if (data.progress !== undefined) {
1246
+ updateProgressBar(data.progress);
1247
+ }
1248
+ });
1249
+
1250
+ // 법규별 결과 수신 (여러 법규 선택 시)
1251
+ socket.on('regulation_result', function(data) {
1252
+ const message = `**${data.regulation_title} (${data.regulation_index}/${data.total_regulations})**\n\n${data.result}`;
1253
+ addMessage(message, 'assistant');
1254
+ });
1255
+
1256
+ // 단일 검색 결과 수신
1257
+ socket.on('search_result', function(data) {
1258
+ addMessage(data.result, 'assistant');
1259
+ });
1260
+
1261
+ // 검색 완료
1262
+ socket.on('search_complete', function(data) {
1263
+ hideTypingIndicator();
1264
+ updateSearchStatus(data.message);
1265
+ enableChatInput();
1266
+ hideCancelButton();
1267
+ isSearching = false;
1268
+ currentSessionId = null; // 세션 ID 초기화
1269
+ });
1270
+
1271
+ // 검색 오류
1272
+ socket.on('search_error', function(data) {
1273
+ hideTypingIndicator();
1274
+ addMessage(`죄송합니다. ${data.message}\n오류 내용: ${data.error}`, 'assistant');
1275
+ enableChatInput();
1276
+ hideCancelButton();
1277
+ isSearching = false;
1278
+ currentSessionId = null; // 세션 ID 초기화
1279
+ });
1280
+
1281
+ // 검색 취소
1282
+ socket.on('search_cancelled', function(data) {
1283
+ hideTypingIndicator();
1284
+ addMessage('검색이 취소되었습니다.', 'assistant');
1285
+ enableChatInput();
1286
+ hideCancelButton();
1287
+ isSearching = false;
1288
+ currentSessionId = null; // 세션 ID 초기화
1289
+ });
1290
+ }
1291
+
1292
+ function updateSearchStatus(message) {
1293
+ const statusElement = document.getElementById('statusText');
1294
+ if (statusElement) {
1295
+ // 첫 번째 텍스트 노드 업데이트
1296
+ const textNode = statusElement.childNodes[0];
1297
+ if (textNode && textNode.nodeType === Node.TEXT_NODE) {
1298
+ textNode.textContent = message;
1299
+ } else {
1300
+ // 텍스트 노드가 없으면 새로 생성
1301
+ statusElement.insertBefore(document.createTextNode(message), statusElement.firstChild);
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ function updateProgressBar(progress) {
1307
+ const progressBar = document.getElementById('progressBar');
1308
+ if (progressBar) {
1309
+ progressBar.style.width = `${progress}%`;
1310
+ }
1311
+ }
1312
+
1313
+ function showCancelButton() {
1314
+ const cancelBtn = document.getElementById('cancelSearchBtn');
1315
+ if (cancelBtn) {
1316
+ cancelBtn.style.display = 'block';
1317
+ console.log('Cancel button shown');
1318
+ }
1319
+ }
1320
+
1321
+ function hideCancelButton() {
1322
+ const cancelBtn = document.getElementById('cancelSearchBtn');
1323
+ if (cancelBtn) {
1324
+ cancelBtn.style.display = 'none';
1325
+ console.log('Cancel button hidden');
1326
+ }
1327
+ updateProgressBar(0);
1328
+ }
1329
+
1330
+ function enableChatInput() {
1331
+ const chatInput = document.getElementById('chatInput');
1332
+ const sendBtn = document.getElementById('sendBtn');
1333
+
1334
+ chatInput.disabled = false;
1335
+ sendBtn.disabled = false;
1336
+ chatInput.placeholder = '검색하고 싶은 내용을 입력하세요...';
1337
+ }
1338
+
1339
+ function disableChatInput() {
1340
+ const chatInput = document.getElementById('chatInput');
1341
+ const sendBtn = document.getElementById('sendBtn');
1342
+
1343
+ chatInput.disabled = true;
1344
+ sendBtn.disabled = true;
1345
+ chatInput.placeholder = '검색 진행 중...';
1346
+ }
1347
+
1348
+ // ===== 사이드바 초기화 =====
1349
+ function initializeSidebar() {
1350
+ const sidebarToggle = document.getElementById('sidebarToggle');
1351
+ const sidebar = document.getElementById('sidebar');
1352
+ const sidebarOverlay = document.getElementById('sidebarOverlay');
1353
+ const newPageBtn = document.getElementById('newPageBtn');
1354
+
1355
+ sidebarToggle.addEventListener('click', function() {
1356
+ const isOpen = sidebar.classList.contains('open');
1357
+ if (isOpen) {
1358
+ closeSidebar();
1359
+ } else {
1360
+ openSidebar();
1361
+ }
1362
+ });
1363
+
1364
+ sidebarOverlay.addEventListener('click', closeSidebar);
1365
+
1366
+ document.addEventListener('keydown', function(e) {
1367
+ if (e.key === 'Escape') {
1368
+ closeSidebar();
1369
+ }
1370
+ });
1371
+
1372
+ if (newPageBtn) {
1373
+ newPageBtn.addEventListener('click', function() {
1374
+ window.open('/', '_blank');
1375
+ });
1376
+ }
1377
+ }
1378
+
1379
+ function openSidebar() {
1380
+ const sidebar = document.getElementById('sidebar');
1381
+ const sidebarToggle = document.getElementById('sidebarToggle');
1382
+ const sidebarOverlay = document.getElementById('sidebarOverlay');
1383
+ const newPageBtn = document.getElementById('newPageBtn');
1384
+
1385
+ sidebar.classList.add('open');
1386
+ sidebarToggle.classList.add('active');
1387
+ sidebarOverlay.classList.add('active');
1388
+ if (newPageBtn) newPageBtn.classList.add('show');
1389
+ }
1390
+
1391
+ function closeSidebar() {
1392
+ const sidebar = document.getElementById('sidebar');
1393
+ const sidebarToggle = document.getElementById('sidebarToggle');
1394
+ const sidebarOverlay = document.getElementById('sidebarOverlay');
1395
+ const newPageBtn = document.getElementById('newPageBtn');
1396
+
1397
+ sidebar.classList.remove('open');
1398
+ sidebarToggle.classList.remove('active');
1399
+ sidebarOverlay.classList.remove('active');
1400
+ if (newPageBtn) newPageBtn.classList.remove('show');
1401
+ }
1402
+
1403
+ // ===== 토글 버튼 초기화 =====
1404
+ function initializeToggles() {
1405
+ document.querySelectorAll('.region-toggle').forEach(btn => {
1406
+ btn.addEventListener('click', function() {
1407
+ handleRegionToggle(this);
1408
+ });
1409
+ });
1410
+ }
1411
+
1412
+ function handleRegionToggle(clickedBtn) {
1413
+ const value = clickedBtn.getAttribute('data-value');
1414
+ const allButtons = document.querySelectorAll('.region-toggle');
1415
+
1416
+ if (value === '전체') {
1417
+ // 전체 선택 - 다른 모든 버튼 비활성화
1418
+ allButtons.forEach(btn => btn.classList.remove('active'));
1419
+ clickedBtn.classList.add('active');
1420
+ selectedRegions.length = 0;
1421
+ } else {
1422
+ // 개별 선택 - 전체 버튼 비활성화
1423
+ const allBtn = document.querySelector('.region-toggle[data-value="전체"]');
1424
+ if (allBtn) allBtn.classList.remove('active');
1425
+
1426
+ clickedBtn.classList.toggle('active');
1427
+
1428
+ if (clickedBtn.classList.contains('active')) {
1429
+ if (!selectedRegions.includes(value)) {
1430
+ selectedRegions.push(value);
1431
+ }
1432
+ } else {
1433
+ selectedRegions = selectedRegions.filter(region => region !== value);
1434
+ }
1435
+
1436
+ // 아무것도 선택되지 않았으면 전체 활성화
1437
+ if (selectedRegions.length === 0 && allBtn) {
1438
+ allBtn.classList.add('active');
1439
+ }
1440
+ }
1441
+
1442
+ console.log('선택된 지역:', selectedRegions);
1443
+ }
1444
+
1445
+ function getSelectedRegions() {
1446
+ return selectedRegions.length > 0 ? selectedRegions : [];
1447
+ }
1448
+
1449
+ // ===== 법규 리스트 초기화 =====
1450
+ function initializeRegulationList() {
1451
+ // 이미 상세 법규 리스트에서 처리되므로 여기서는 빈 함수로 유지
1452
+ }
1453
+
1454
+ // ===== 채팅 초기화 =====
1455
+ function initializeChat() {
1456
+ const chatInput = document.getElementById('chatInput');
1457
+ const sendBtn = document.getElementById('sendBtn');
1458
+
1459
+ // 자동 높이 조절
1460
+ chatInput.addEventListener('input', function() {
1461
+ this.style.height = 'auto';
1462
+ this.style.height = Math.min(this.scrollHeight, 120) + 'px';
1463
+ });
1464
+
1465
+ // Enter 키로 전송
1466
+ chatInput.addEventListener('keydown', function(e) {
1467
+ if (e.key === 'Enter' && !e.shiftKey && !isSearching) {
1468
+ e.preventDefault();
1469
+ sendMessage();
1470
+ }
1471
+ });
1472
+
1473
+ // 전송 버튼 클릭
1474
+ sendBtn.addEventListener('click', function() {
1475
+ if (!isSearching) {
1476
+ sendMessage();
1477
+ }
1478
+ });
1479
+ }
1480
+
1481
+ // ===== 메시지 전송 함수 수정 - 원래 타입 전송 =====
1482
+ function sendMessage() {
1483
+ const chatInput = document.getElementById('chatInput');
1484
+ const message = chatInput.value.trim();
1485
+ if (!message || isSearching) return;
1486
+
1487
+ // 사용자 메시지 추가
1488
+ addMessage(message, 'user');
1489
+
1490
+ // 입력창 초기화 및 비활성화
1491
+ chatInput.value = '';
1492
+ chatInput.style.height = 'auto';
1493
+ disableChatInput();
1494
+ isSearching = true;
1495
+
1496
+ // 로딩 표시
1497
+ showTypingIndicator();
1498
+ showCancelButton();
1499
+
1500
+ // 서버에 소켓으로 요청 (원래 타입 정보로 전송)
1501
+ const requestData = {
1502
+ query: message,
1503
+ regions: getSelectedRegions(),
1504
+ searchEachMode: searchEachMode,
1505
+ selectedRegulations: selectedRegulations.map(reg => {
1506
+ return {
1507
+ id: reg.id,
1508
+ title: reg.title,
1509
+ type: reg.originalType // 원래 타입(part/section/chapter/jo) 전송
1510
+ };
1511
+ })
1512
+ };
1513
+
1514
+ console.log('전송 데이터 (Original Type):', requestData); // 디버깅용
1515
+
1516
+ // 소켓으로 검색 요청 전송
1517
+ socket.emit('search_query', requestData);
1518
+ }
1519
+
1520
+ // 검색 취소 함수
1521
+ function cancelSearch() {
1522
+ console.log('Cancel search clicked. Session ID:', currentSessionId, 'Is searching:', isSearching);
1523
+
1524
+ if (currentSessionId && isSearching) {
1525
+ socket.emit('cancel_search', { session_id: currentSessionId });
1526
+ console.log('Cancel request sent with session ID:', currentSessionId);
1527
+ } else {
1528
+ console.log('Cannot cancel: no session ID or not searching');
1529
+ // 로컬에서 검색 상태 초기화
1530
+ hideTypingIndicator();
1531
+ enableChatInput();
1532
+ hideCancelButton();
1533
+ isSearching = false;
1534
+ currentSessionId = null;
1535
+ updateSearchStatus('검색이 취소되었습니다.');
1536
+ }
1537
+ }
1538
+
1539
+ function addMessage(text, type) {
1540
+ const chatMessages = document.getElementById('chatMessages');
1541
+ const messageDiv = document.createElement('div');
1542
+ messageDiv.className = `message ${type}`;
1543
+
1544
+ const avatar = document.createElement('div');
1545
+ avatar.className = 'message-avatar';
1546
+ avatar.textContent = type === 'user' ? 'Me' : 'Lexi';
1547
+
1548
+ const contentWrapper = document.createElement('div');
1549
+ const content = document.createElement('div');
1550
+ content.className = 'message-content';
1551
+
1552
+ if (type === 'assistant') {
1553
+ // 마크다운 스타일 텍스트를 HTML로 변환
1554
+ //const formattedText = formatMarkdownToHtml(text);
1555
+ content.innerHTML = text;
1556
+ } else {
1557
+ content.textContent = text;
1558
+ }
1559
+
1560
+ const time = document.createElement('div');
1561
+ time.className = 'message-time';
1562
+ time.textContent = formatTime(new Date());
1563
+
1564
+ contentWrapper.appendChild(content);
1565
+ contentWrapper.appendChild(time);
1566
+ messageDiv.appendChild(avatar);
1567
+ messageDiv.appendChild(contentWrapper);
1568
+
1569
+ // 타이핑 인디케이터가 있으면 그 위에 추가
1570
+ const typingIndicator = document.getElementById('typingIndicator');
1571
+ if (typingIndicator) {
1572
+ chatMessages.insertBefore(messageDiv, typingIndicator);
1573
+ } else {
1574
+ chatMessages.appendChild(messageDiv);
1575
+ }
1576
+
1577
+ chatMessages.scrollTop = chatMessages.scrollHeight;
1578
+ }
1579
+
1580
+ function formatMarkdownToHtml(text) {
1581
+ // 간단한 마크다운 변환
1582
+ let html = text;
1583
+
1584
+ // **굵은 글씨** 변환
1585
+ html = html.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
1586
+
1587
+ // 줄바꿈 변환
1588
+ html = html.replace(/\n/g, '<br>');
1589
+
1590
+ return html;
1591
+ }
1592
+
1593
+ function showTypingIndicator() {
1594
+ // 기존 타이핑 인디케이터 제거
1595
+ hideTypingIndicator();
1596
+
1597
+ const chatMessages = document.getElementById('chatMessages');
1598
+ const indicator = document.createElement('div');
1599
+ indicator.className = 'message assistant';
1600
+ indicator.id = 'typingIndicator';
1601
+
1602
+ const avatar = document.createElement('div');
1603
+ avatar.className = 'message-avatar';
1604
+ avatar.textContent = 'Lexi';
1605
+
1606
+ const typing = document.createElement('div');
1607
+ typing.className = 'typing-indicator';
1608
+ typing.innerHTML = '<div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div>';
1609
+
1610
+ indicator.appendChild(avatar);
1611
+ indicator.appendChild(typing);
1612
+ chatMessages.appendChild(indicator);
1613
+ chatMessages.scrollTop = chatMessages.scrollHeight;
1614
+ }
1615
+
1616
+ function hideTypingIndicator() {
1617
+ const indicator = document.getElementById('typingIndicator');
1618
+ if (indicator) {
1619
+ indicator.remove();
1620
+ }
1621
+ }
1622
+
1623
+ function decodeHtmlEntities(text) {
1624
+ const textarea = document.createElement('textarea');
1625
+ textarea.innerHTML = text;
1626
+ return textarea.value;
1627
+ }
1628
+
1629
+ // ===== 상세 법규 리스트 관련 함수 =====
1630
+ function loadDetailedRegulationList() {
1631
+ const selectedRegions = getSelectedRegions();
1632
+ const detailsListDiv = document.getElementById('regulationDetailsList');
1633
+ const searchContainer = document.getElementById('regulationSearchContainer');
1634
+ const typeTabs = document.getElementById('regulationTypeTabs');
1635
+
1636
+ detailsListDiv.innerHTML = '<p style="color: var(--text-muted); padding: 20px; text-align: center; margin: 0;">상세 법규 리스트 로딩 중...</p>';
1637
+
1638
+ fetch('/get_reg_list', {
1639
+ method: 'POST',
1640
+ headers: {
1641
+ 'Content-Type': 'application/json'
1642
+ },
1643
+ body: JSON.stringify({ regions: selectedRegions })
1644
+ })
1645
+ .then(response => response.json())
1646
+ .then(data => {
1647
+ // 모든 법규 데이터 저장
1648
+ regulationData = data;
1649
+
1650
+ if (data.reg_list_part || data.reg_list_section || data.reg_list_chapter || data.reg_list_jo) {
1651
+ // 탭과 검색창 표시
1652
+ typeTabs.style.display = 'flex';
1653
+ searchContainer.style.display = 'block';
1654
+
1655
+ // 기본적으로 level1 표시
1656
+ switchRegulationType('level1');
1657
+ initializeRegulationSearch();
1658
+ } else {
1659
+ detailsListDiv.innerHTML = '<p style="color: var(--text-muted); padding: 20px; text-align: center; margin: 0;">상세 법규 리스트를 불러올 수 없습니다.</p>';
1660
+ }
1661
+ })
1662
+ .catch(error => {
1663
+ console.error('상세 법규 리스트 로딩 오류:', error);
1664
+ detailsListDiv.innerHTML = '<p style="color: #ff6b6b; padding: 20px; text-align: center; margin: 0;">리스트 로딩 중 오류가 발생했습니다.</p>';
1665
+ });
1666
+ }
1667
+
1668
+ // ===== 상세 법규 리스트 표시 함수 수정 =====
1669
+ function displayDetailedRegulationList(data, level) {
1670
+ const detailsListDiv = document.getElementById('regulationDetailsList');
1671
+
1672
+ if (!data || data.length === 0) {
1673
+ detailsListDiv.innerHTML = '<p style="color: var(--text-muted); padding: 20px; text-align: center; margin: 0;">해당 레벨의 법규 데이터가 없습니다.</p>';
1674
+ updateSelectedCount(); // 빈 상태일 때도 카운트 업데이트
1675
+ return;
1676
+ }
1677
+
1678
+ let listHTML = '';
1679
+ data.forEach(item => {
1680
+ const isSelected = selectedRegulations.find(reg => reg.id === item.id);
1681
+ listHTML += `
1682
+ <div class="regulation-detail-item ${isSelected ? 'selected' : ''}"
1683
+ data-id="${item.id}"
1684
+ data-title="${item.title}"
1685
+ data-type="${item.originalType}"
1686
+ data-level="${level}"
1687
+ data-search-text="${item.searchText}">
1688
+ ${item.title}
1689
+ </div>
1690
+ `;
1691
+ });
1692
+
1693
+ detailsListDiv.innerHTML = listHTML;
1694
+ updateSelectedCount(); // 리스트 표시 후 카운트 업데이트
1695
+
1696
+ // 이벤트 리스너 재설정
1697
+ detailsListDiv.removeEventListener('click', handleRegulationClick);
1698
+ detailsListDiv.addEventListener('click', handleRegulationClick);
1699
+ }
1700
+
1701
+ function handleRegulationClick(e) {
1702
+ const item = e.target.closest('.regulation-detail-item');
1703
+ if (item) {
1704
+ toggleRegulationSelection(item);
1705
+ }
1706
+ }
1707
+
1708
+ // ===== 법규 선택 토글 함수 수정 - 원래 타입 저장 =====
1709
+ function toggleRegulationSelection(element) {
1710
+ const id = element.getAttribute('data-id');
1711
+ const isSelected = selectedRegulations.find(reg => reg.id === id);
1712
+
1713
+ if (isSelected) {
1714
+ selectedRegulations = selectedRegulations.filter(reg => reg.id !== id);
1715
+ element.classList.remove('selected');
1716
+ } else {
1717
+ const regulationData = {
1718
+ id: id,
1719
+ title: element.getAttribute('data-title') || element.textContent.trim(),
1720
+ originalType: element.getAttribute('data-type'), // 원래 타입 저장 (part/section/chapter/jo)
1721
+ displayLevel: element.getAttribute('data-level') // 표시용 레벨 정보
1722
+ };
1723
+ selectedRegulations.push(regulationData);
1724
+ element.classList.add('selected');
1725
+ }
1726
+
1727
+ // 선택 개수 즉시 업데이트
1728
+ updateSelectedCount();
1729
+
1730
+ // 선택 상태 로깅
1731
+ console.log(`법규 선택 변경: ${element.getAttribute('data-title')} - ${isSelected ? '해제' : '선택'}됨`);
1732
+ console.log(`현재 선택된 법규 수: ${selectedRegulations.length}`);
1733
+ }
1734
+
1735
+ // ===== 선택 개수 업데이트 함수 수정 =====
1736
+ function updateSelectedCount() {
1737
+ const countElement = document.getElementById('selectedCount');
1738
+ if (countElement) {
1739
+ // 원래 타입별 선택 개수 표시
1740
+ const partCount = selectedRegulations.filter(reg => reg.originalType === 'part').length;
1741
+ const sectionCount = selectedRegulations.filter(reg => reg.originalType === 'section').length;
1742
+ const chapterCount = selectedRegulations.filter(reg => reg.originalType === 'chapter').length;
1743
+ const joCount = selectedRegulations.filter(reg => reg.originalType === 'jo').length;
1744
+
1745
+ const level1Count = partCount;
1746
+ const level2Count = sectionCount + chapterCount;
1747
+ const level3Count = joCount;
1748
+ const totalCount = selectedRegulations.length;
1749
+
1750
+ if (totalCount === 0) {
1751
+ countElement.textContent = '선택됨: 0';
1752
+ countElement.classList.remove('has-selection');
1753
+ } else {
1754
+ countElement.textContent = `선택됨: ${totalCount} (L1: ${level1Count}, L2: ${level2Count}, L3: ${level3Count})`;
1755
+ countElement.classList.add('has-selection');
1756
+ }
1757
+ }
1758
+ }
1759
+
1760
+ function clearAllSelections() {
1761
+ selectedRegulations = [];
1762
+ document.querySelectorAll('.regulation-item').forEach(item => {
1763
+ item.classList.remove('selected');
1764
+ });
1765
+ document.querySelectorAll('.regulation-detail-item').forEach(item => {
1766
+ item.classList.remove('selected');
1767
+ });
1768
+
1769
+ // 선택 개수 업데이트
1770
+ updateSelectedCount();
1771
+
1772
+ // 검색창 초기화
1773
+ const searchInput = document.getElementById('regulationSearchInput');
1774
+ if (searchInput) {
1775
+ searchInput.value = '';
1776
+ filterRegulationList('');
1777
+ }
1778
+
1779
+ console.log('모든 법규 선택이 초기화되었습니다.');
1780
+ }
1781
+
1782
+ function initializeRegulationSearch() {
1783
+ const searchInput = document.getElementById('regulationSearchInput');
1784
+
1785
+ // 기존 이벤트 리스너 제거 후 새로 추가
1786
+ searchInput.removeEventListener('input', handleSearchInput);
1787
+ searchInput.addEventListener('input', handleSearchInput);
1788
+ }
1789
+
1790
+ function handleSearchInput() {
1791
+ const searchTerm = this.value.toLowerCase().trim();
1792
+ filterRegulationList(searchTerm);
1793
+ }
1794
+
1795
+ function filterRegulationList(searchTerm) {
1796
+ const detailItems = document.querySelectorAll('.regulation-detail-item');
1797
+
1798
+ detailItems.forEach(item => {
1799
+ const searchText = item.getAttribute('data-search-text') || '';
1800
+
1801
+ if (searchTerm === '' || searchText.includes(searchTerm)) {
1802
+ item.classList.remove('hidden');
1803
+ } else {
1804
+ item.classList.add('hidden');
1805
+ }
1806
+ });
1807
+ }
1808
+ </script>
1809
+ </body>
1810
+ </html>