-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproject-builder.html
More file actions
738 lines (666 loc) · 30.7 KB
/
project-builder.html
File metadata and controls
738 lines (666 loc) · 30.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI 自动构建 - 创页 创作台</title>
<style>
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Noto+Serif+SC:wght@600;700;900&display=swap");
:root {
/* 统一的数字工坊配色体系 */
--bg: #f7f7f5;
--surface: rgba(255, 255, 255, 0.72);
--surface-strong: #ffffff;
--brand-light: #f0f0ec;
--text-primary: #111111;
--text-secondary: #686868;
--border: rgba(17, 17, 17, 0.08);
--radius-xl: 28px;
--radius-lg: 20px;
--radius-md: 16px;
--primary: #111111;
--primary-soft: #f0f0ec;
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-serif: 'Noto Serif SC', serif;
--ease: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out: cubic-bezier(0.33, 1, 0.68, 1);
}
* { box-sizing: border-box; -webkit-font-smoothing: antialiased; }
body {
margin: 0;
background: var(--bg);
color: var(--text-primary);
font-family: var(--font-sans);
min-height: 100vh;
overflow-x: hidden;
}
/* 统一环境漫反射光 */
#ambient-glow {
position: fixed;
width: 600px; height: 600px;
background: radial-gradient(circle, rgba(17, 17, 17, 0.03) 0%, transparent 70%);
border-radius: 50%;
pointer-events: none;
z-index: -1;
transform: translate(-50%, -50%);
filter: blur(72px);
transition: transform 0.8s var(--ease-out);
}
/* 极简导航 - 胶囊风格 */
nav {
display: flex; justify-content: space-between; align-items: center;
padding: 18px 6%; position: sticky; width: 100%; top: 0; z-index: 100;
background: rgba(247, 247, 245, 0.78);
backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
border-bottom: 1px solid rgba(17, 17, 17, 0.05);
}
.logo {
font-family: var(--font-serif); font-size: 24px; font-weight: 700;
color: var(--text-primary); letter-spacing: -0.03em;
text-decoration: none; transition: opacity 0.3s ease;
}
.logo:hover { opacity: 0.8; }
.nav-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.btn-ghost {
border: 1px solid var(--border); background: rgba(255, 255, 255, 0.6);
color: var(--text-primary); height: 36px; padding: 0 16px; border-radius: 999px;
font-size: 13px; font-weight: 500; cursor: pointer; text-decoration: none;
display: inline-flex; align-items: center; justify-content: center;
transition: background 0.2s, border-color 0.2s, transform 0.2s;
}
.btn-ghost:hover {
background: rgba(255, 255, 255, 0.92);
border-color: rgba(17, 17, 17, 0.16); transform: translateY(-1px);
}
.container {
max-width: 1240px;
margin: 36px auto 96px;
padding: 0 6%;
display: grid;
grid-template-columns: 220px minmax(0, 1fr) 340px;
gap: 36px;
}
.header-area {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
align-items: flex-end;
gap: 20px;
}
.header-area h1 {
font-family: var(--font-serif);
font-size: clamp(30px, 4vw, 38px);
margin: 0 0 10px;
letter-spacing: -0.02em;
}
.header-area p { margin: 0; color: var(--text-secondary); line-height: 1.7; font-size: 15px;}
.step-tag {
padding: 6px 14px;
border-radius: 999px;
background: var(--brand-light);
color: var(--text-primary);
border: 1px solid var(--border);
font-size: 11px;
font-weight: 700;
white-space: nowrap;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.builder-sidebar {
grid-column: 1;
position: sticky;
top: 100px;
align-self: start;
}
.sidebar-title {
font-size: 12px;
font-weight: 700;
color: var(--text-secondary);
margin: 0 0 12px;
padding: 0 4px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.builder-nav {
display: grid;
gap: 8px;
padding: 16px;
border-radius: var(--radius-xl);
background: var(--surface);
border: 1px solid var(--border);
box-shadow: 0 4px 20px rgba(0,0,0,0.015);
backdrop-filter: blur(24px);
}
.builder-nav-btn {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
width: 100%;
padding: 12px 16px;
border-radius: var(--radius-md);
border: 1px solid rgba(17, 17, 17, 0.04);
background: var(--surface-strong);
color: var(--text-primary);
text-align: left;
cursor: pointer;
transition: 0.2s var(--ease);
}
.builder-nav-btn:hover {
border-color: rgba(17, 17, 17, 0.15);
transform: translateY(-1px);
}
.builder-nav-btn.is-active {
border-color: var(--text-primary);
background: var(--text-primary);
color: white;
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
}
.builder-nav-copy { display: grid; gap: 2px; }
.builder-nav-copy span { font-size: 14px; font-weight: 600; }
.builder-nav-copy small { font-size: 11px; font-weight: 500; color: var(--text-secondary); }
.builder-nav-btn.is-active .builder-nav-copy small { color: rgba(255, 255, 255, 0.7); }
.builder-nav-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(17, 17, 17, 0.1);
flex-shrink: 0;
}
.builder-nav-btn.is-active .builder-nav-dot { background: white; }
.builder-main { grid-column: 2; display: grid; gap: 26px; }
.builder-panel.is-hidden { display: none; }
.card, .side-card {
background: var(--surface-strong);
border: 1px solid var(--border);
border-radius: var(--radius-xl);
padding: 32px;
box-shadow: 0 4px 20px rgba(0,0,0,0.015);
}
.section-title { font-size: 20px; font-family: var(--font-serif); font-weight: 700; margin-bottom: 8px; color: var(--text-primary); }
.section-subtitle { color: var(--text-secondary); font-size: 14px; line-height: 1.7; margin: 0 0 24px; }
.form-group { margin-bottom: 24px; }
.form-group label { display: block; margin-bottom: 8px; font-size: 13px; font-weight: 600; color: var(--text-primary); }
.form-control {
width: 100%;
padding: 14px 16px;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--bg);
font: inherit;
font-size: 14px;
outline: none;
transition: 0.2s;
color: var(--text-primary);
}
.form-control:focus { border-color: var(--text-primary); box-shadow: 0 0 0 1px var(--text-primary); background: white; }
.form-control::placeholder { color: #a1a1aa; }
textarea.form-control { resize: vertical; min-height: 100px; }
.style-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.style-card {
position: relative;
padding: 14px;
border-radius: var(--radius-md);
border: 1px solid var(--border);
background: var(--bg);
cursor: pointer;
transition: 0.25s var(--ease);
text-align: left;
}
.style-card:hover { transform: translateY(-2px); border-color: rgba(17,17,17,0.15); box-shadow: 0 8px 24px rgba(0,0,0,0.04); }
.style-card.active { border-color: var(--text-primary); background: white; box-shadow: 0 0 0 1px var(--text-primary); }
.style-card.locked { opacity: 0.6; cursor: not-allowed; filter: grayscale(50%); }
.style-card.locked:hover { transform: none; border-color: var(--border); box-shadow: none; }
.style-lock {
position: absolute; top: 10px; right: 10px;
padding: 4px 8px; border-radius: 999px;
background: rgba(9, 9, 11, 0.85); backdrop-filter: blur(4px);
color: #fff; border: 1px solid rgba(255,255,255,0.1);
font-size: 10px; font-weight: 600; letter-spacing: 0.5px;
}
.style-card h4 { margin: 12px 0 4px; font-size: 14px; font-weight: 600; }
.style-card p { margin: 0; color: var(--text-secondary); font-size: 12px; line-height: 1.6; }
.style-thumb {
height: 74px;
border-radius: 8px;
border: 1px solid rgba(0,0,0,0.06);
}
/* 对齐 project-new.html 风格预览颜色 */
.thumb-1 { background: #fafafa; }
.thumb-2 { background: #09090b; }
.thumb-3 { background: #fff; border: 1px solid #000; border-radius: 0; }
.thumb-4 { background: linear-gradient(90deg, #27272a 0 6px, #fff 6px 100%); }
.thumb-5 { background: #fdfdfd; }
.thumb-6 { background: radial-gradient(circle at top right, #27272a, #09090b); }
.thumb-7 { background: #fdfbf7; }
.thumb-8 { background: #09090b; box-shadow: inset 0 0 10px rgba(0,255,255,0.2); }
.thumb-9 { background: #f5f5f0; }
.readonly-box, .info-box, .status-box {
border-radius: var(--radius-md); padding: 16px 20px;
}
.readonly-box { background: var(--brand-light); border: 1px solid var(--border); color: var(--text-secondary); font-size: 13px; line-height: 1.7; }
.info-box { background: var(--brand-light); border: 1px solid var(--border); color: var(--text-secondary); font-size: 13px; line-height: 1.7; }
.status-box { display: none; font-size: 13px; line-height: 1.6; margin-top: 16px;}
.status-box.show { display: block; }
.status-box.error { background: #fef2f2; border: 1px solid #fecaca; color: #dc2626; }
.status-box.success { background: #ecfdf5; border: 1px solid #bbf7d0; color: #047857; }
/* AI 正在生成覆盖层 */
.builder-generating-overlay {
position: fixed; inset: 0; display: none; align-items: center; justify-content: center;
padding: 24px; background: rgba(247, 247, 245, 0.85); backdrop-filter: blur(12px); z-index: 1000;
}
.builder-generating-overlay.is-active { display: flex; }
.builder-generating-card {
width: min(100%, 460px); padding: 48px; border-radius: var(--radius-xl);
background: var(--surface-strong); border: 1px solid var(--border);
box-shadow: 0 32px 64px -16px rgba(0, 0, 0, 0.1); text-align: center;
}
.builder-generating-orbit {
width: 64px; height: 64px; margin: 0 auto 32px; border-radius: 50%;
border: 2px solid var(--brand-light); border-top-color: var(--text-primary);
animation: builder-orbit-spin 0.8s linear infinite;
}
.builder-generating-title { margin: 0 0 12px; font-family: var(--font-serif); font-size: 24px; font-weight: 700; color: var(--text-primary); }
.builder-generating-phase { margin: 0 0 24px; color: var(--text-secondary); font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; }
.builder-generating-progress { height: 4px; background: var(--brand-light); border-radius: 999px; overflow: hidden; margin-bottom: 24px; }
.builder-generating-progress::before {
content: ""; display: block; height: 100%; width: 40%; background: var(--text-primary);
border-radius: inherit; animation: builder-progress-slide 1.5s infinite var(--ease-out);
}
.builder-generating-tips { color: var(--text-secondary); font-size: 13px; line-height: 1.8; }
.builder-actions { display: flex; gap: 12px; margin-top: 12px;}
.btn {
padding: 12px 24px; border-radius: 999px; border: 1px solid var(--border);
background: var(--surface-strong); color: var(--text-primary); font-size: 13px; font-weight: 600;
cursor: pointer; text-decoration: none; transition: 0.2s var(--ease);
display: inline-flex; align-items: center; justify-content: center;
}
.btn-primary { background: var(--text-primary); color: white; border: 1px solid transparent; box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
.btn-primary:hover:not(:disabled) { background: #27272a; transform: translateY(-1px); box-shadow: 0 8px 20px rgba(0,0,0,0.12); }
.btn:hover:not(.btn-primary) { background: var(--brand-light); border-color: rgba(17,17,17,0.15); }
.metrics { display: grid; gap: 14px; }
.metric-row { display: flex; justify-content: space-between; gap: 14px; padding-bottom: 12px; border-bottom: 1px solid rgba(17,17,17,0.04); }
.metric-row:last-child { border-bottom: none; }
.metric-row span { color: var(--text-secondary); font-size: 13px; font-weight: 500; }
.metric-row strong { font-size: 14px; color: var(--text-primary); font-weight: 700; }
.rule-list { margin: 20px 0 0; padding-left: 20px; list-style: square; }
.rule-list li { margin-bottom: 10px; color: var(--text-secondary); font-size: 13px; line-height: 1.7; }
@keyframes builder-orbit-spin { to { transform: rotate(360deg); } }
@keyframes builder-progress-slide {
0% { transform: translateX(-100%); width: 20%; }
50% { width: 50%; }
100% { transform: translateX(400%); width: 20%; }
}
@keyframes builder-dots { 0%, 20% { content: ""; } 40% { content: "."; } 60% { content: ".."; } 80%, 100% { content: "..."; } }
.builder-generating-dots::after { content: ""; animation: builder-dots 2s infinite; }
.compat-hidden { display: none !important; }
body.builder-generating-active { overflow: hidden; }
@media (max-width: 1100px) {
.container { grid-template-columns: 1fr; }
.builder-sidebar { position: static; margin-bottom: 24px; }
.builder-nav { grid-template-columns: repeat(2, 1fr); }
.preview-sidebar { grid-column: auto; }
}
@media (max-width: 780px) {
.style-grid { grid-template-columns: repeat(2, 1fr); }
.header-area { flex-direction: column; align-items: stretch; gap: 12px; }
.container { padding: 0 20px; margin-top: 24px; }
}
@media (max-width: 560px) {
.style-grid { grid-template-columns: 1fr; }
.builder-nav { grid-template-columns: 1fr; }
.builder-actions { flex-direction: column; }
.btn { width: 100%; }
}
</style>
</head>
<body>
<div id="ambient-glow"></div>
<nav>
<a href="dashboard.html" class="logo">创页</a>
<div class="nav-actions">
<a href="dashboard.html" class="btn-ghost">返回工坊</a>
<a href="templates.html" class="btn-ghost">灵感广场</a>
<button class="btn-ghost" type="button" data-action="logout">退出账号</button>
</div>
</nav>
<main class="container">
<header class="header-area">
<div>
<h1>AI 自动构建项目</h1>
<p>输入你的核心构想,大模型将自动编排首版页面、交互逻辑与内容结构。</p>
</div>
<span class="step-tag">Initial起草 / 算力驱动</span>
</header>
<aside class="builder-sidebar">
<div class="sidebar-title">构建协议</div>
<div class="builder-nav">
<button class="builder-nav-btn is-active" type="button" data-builder-nav="direction">
<div class="builder-nav-copy"><span>业务方向</span><small>受众与评估模型</small></div>
<span class="builder-nav-dot"></span>
</button>
<button class="builder-nav-btn" type="button" data-builder-nav="style">
<div class="builder-nav-copy"><span>视觉基调</span><small>前端渲染效果</small></div>
<span class="builder-nav-dot"></span>
</button>
<button class="builder-nav-btn" type="button" data-builder-nav="base">
<div class="builder-nav-copy"><span>元数据</span><small>标识与摘要</small></div>
<span class="builder-nav-dot"></span>
</button>
<button class="builder-nav-btn" type="button" data-builder-nav="prompt">
<div class="builder-nav-copy"><span>逻辑提示词</span><small>算力引导参数</small></div>
<span class="builder-nav-dot"></span>
</button>
</div>
</aside>
<section class="builder-main">
<section class="card builder-panel" data-builder-section="direction">
<h2 class="section-title">确立评估模型</h2>
<p class="section-subtitle">定义您数字产品的核心评估逻辑。AI 将根据此处描述的方向来生成算法逻辑。</p>
<div class="form-group">
<label for="direction-tag">领域分类</label>
<input id="direction-tag" class="form-control" type="text" placeholder="例如:商业战略 / 心理健康" />
</div>
<div class="form-group">
<label for="direction-title">评估标题</label>
<input id="direction-title" class="form-control" type="text" placeholder="例如:职场领导力潜能扫描" />
</div>
<div class="form-group">
<label for="direction-desc">逻辑描述</label>
<textarea id="direction-desc" class="form-control" placeholder="简述该方向的评估深度。例如:关注沟通风格、决策偏好与压力容忍度。"></textarea>
</div>
</section>
<section class="card builder-panel is-hidden" data-builder-section="style">
<h2 class="section-title">选择视觉基调</h2>
<p class="section-subtitle">决定终端受众的视觉感官体验。体验版本可调用前 3 个渲染节点。</p>
<div class="style-grid" id="style-grid"></div>
<div class="info-box" id="style-note" style="margin-top: 20px;">系统将根据您的权限级别自动匹配渲染资源池。</div>
</section>
<section class="card builder-panel is-hidden" data-builder-section="base">
<h2 class="section-title">项目元数据</h2>
<p class="section-subtitle">设定数字项目落库时的正式标识。生成后可在编辑器中进一步精细化调整。</p>
<div class="form-group">
<label for="project-title">项目正式标题</label>
<input id="project-title" class="form-control" type="text" placeholder="例如:深度领导力:解码你的商业格局" />
</div>
<div class="form-group">
<label for="project-subtitle">项目正式副标题</label>
<textarea id="project-subtitle" class="form-control" placeholder="用于开场屏与分享摘要..."></textarea>
</div>
<div class="readonly-box">
<strong>输出模型验证:</strong> 情感共鸣型 (Healing)<br />
AI 将优先构建具备温度的反馈矩阵,您可以于生成后的编辑器中切换至其他高级模型。
</div>
</section>
<section class="card builder-panel is-hidden" data-builder-section="prompt">
<h2 class="section-title">注入算力指令</h2>
<p class="section-subtitle">提交核心引导参数。AI 引擎将接管底层代码逻辑与文案骨架的生成任务。</p>
<div class="form-group">
<label for="test-direction">评估逻辑核心</label>
<textarea id="test-direction" class="form-control" placeholder="详细描述评估准则。例如:通过行为偏好推导职场冲突处理能力。"></textarea>
</div>
<div class="form-group">
<label for="target-audience">目标受众画像</label>
<textarea id="target-audience" class="form-control" placeholder="描述您的最终用户。例如:具备 3-5 年经验的中层管理人员。"></textarea>
</div>
<div class="form-group">
<label for="selling-point">交付价值主张</label>
<textarea id="selling-point" class="form-control" placeholder="描述生成结果的收获感。例如:提供可落地的团队协作优化建议。"></textarea>
</div>
<div class="status-box" id="status-box"></div>
<div class="builder-actions">
<button id="generate-btn" class="btn btn-primary" type="button">执行构建协议</button>
<a href="project-new.html" class="btn">手动配置架构</a>
</div>
</section>
</section>
<aside class="builder-side">
<div class="side-card">
<h3 class="section-title">构建状态监视</h3>
<div class="metrics">
<div class="metric-row"><span>AI 引擎算力池</span><strong id="token-text">连接中...</strong></div>
<div class="metric-row"><span>已选视觉基调</span><strong id="style-text">Healing Platinum</strong></div>
<div class="metric-row"><span>预设输出模型</span><strong>情感共鸣型</strong></div>
</div>
<ul class="rule-list">
<li>引擎将自动校准分数区间,确保逻辑严密性。</li>
<li>构建过程将消耗分配的 AI 算力额度。</li>
<li>生成的项目将作为草稿存入您的数字资产库。</li>
<li>生成后将自动建立预览通道并引导至配置台。</li>
</ul>
</div>
</aside>
</main>
<!-- AI 生成动画覆盖层 -->
<div class="builder-generating-overlay" id="builder-generating-overlay" aria-hidden="true">
<div class="builder-generating-card" role="status" aria-live="polite">
<div class="builder-generating-orbit" aria-hidden="true"></div>
<h3 class="builder-generating-title" id="builder-generating-title">正在调度 AI 算力</h3>
<p class="builder-generating-phase builder-generating-dots" id="builder-generating-phase">正在执行预处理</p>
<div class="builder-generating-progress" aria-hidden="true"></div>
<p class="builder-generating-tips" id="builder-generating-tips">系统正在初始化逻辑节点,请保持网络连接稳定。</p>
</div>
</div>
<script src="seller-session.js"></script>
<script>
// 环境漫反射光引擎
const glow = document.getElementById('ambient-glow');
let targetX = window.innerWidth / 2, targetY = window.innerHeight / 2;
let currentX = targetX, currentY = targetY;
window.addEventListener('mousemove', e => { targetX = e.clientX; targetY = e.clientY; });
function animateGlow() {
currentX += (targetX - currentX) * 0.05; currentY += (targetY - currentY) * 0.05;
glow.style.transform = `translate(calc(-50% + ${currentX}px), calc(-50% + ${currentY}px))`;
requestAnimationFrame(animateGlow);
}
animateGlow();
const STYLE_OPTIONS = [
{ name: 'Healing Platinum', label: '治愈白金', desc: '柔和感官体验', thumb: 'thumb-1', premium: false },
{ name: 'Night Emotion', label: '极夜情绪', desc: '沉浸式暗色模式', thumb: 'thumb-2', premium: false },
{ name: 'French Relationship', label: '高定黑白', desc: '法式简约网格', thumb: 'thumb-3', premium: false },
{ name: 'Urban Magazine', label: '商业图鉴', desc: '专业杂志质感', thumb: 'thumb-4', premium: true },
{ name: 'Minimal Pro', label: '实验数据', desc: '极致克制的数据感', thumb: 'thumb-5', premium: true },
{ name: 'Spiritual Starmap', label: '暗物质', desc: '深空神秘学氛围', thumb: 'thumb-6', premium: true },
{ name: 'Diary Handbook', label: '复古档案', desc: '纸质记录质感', thumb: 'thumb-7', premium: true },
{ name: 'Neon High-Energy', label: '高能霓光', desc: '强交互反差视觉', thumb: 'thumb-8', premium: true },
{ name: 'Oriental Elegance', label: '东方留白', desc: '素雅人文气息', thumb: 'thumb-9', premium: true }
];
const state = {
membershipTier: 'free',
tokenBalance: null,
selectedStyle: STYLE_OPTIONS[0].name,
builderGeneratingPhaseTimer: null,
builderGeneratingTipsTimer: null
};
const el = {
navButtons: Array.from(document.querySelectorAll('[data-builder-nav]')),
panels: Array.from(document.querySelectorAll('[data-builder-section]')),
styleGrid: document.getElementById('style-grid'),
styleNote: document.getElementById('style-note'),
tokenText: document.getElementById('token-text'),
styleText: document.getElementById('style-text'),
directionTag: document.getElementById('direction-tag'),
directionTitle: document.getElementById('direction-title'),
directionDesc: document.getElementById('direction-desc'),
projectTitle: document.getElementById('project-title'),
projectSubtitle: document.getElementById('project-subtitle'),
testDirection: document.getElementById('test-direction'),
targetAudience: document.getElementById('target-audience'),
sellingPoint: document.getElementById('selling-point'),
statusBox: document.getElementById('status-box'),
generateBtn: document.getElementById('generate-btn'),
builderGeneratingOverlay: document.getElementById('builder-generating-overlay'),
builderGeneratingTitle: document.getElementById('builder-generating-title'),
builderGeneratingPhase: document.getElementById('builder-generating-phase'),
builderGeneratingTips: document.getElementById('builder-generating-tips')
};
const BUILDER_GENERATING_PHASES = [
'正在注入算力参数',
'正在编排逻辑架构',
'正在渲染文案矩阵',
'正在执行最终部署'
];
const BUILDER_GENERATING_TIPS = [
'正在先整理方向,再搭建题目结构,请稍等几秒。',
'正在校准分数梯度,确保低分答案和高分答案方向一致。',
'正在生成可编辑普通项目链接,完成后会自动跳转。'
];
function formatTokenStatus(balance) {
const total = Number(balance?.total || 0);
const remaining = Number(balance?.remaining || 0);
if (total <= 0) return '未开通算力';
if (remaining <= 0) return '算力已耗尽';
const ratio = remaining / total;
if (ratio <= 0.2) return '负载紧张';
return '运力充足';
}
function isLockedStyle(option) {
return option.premium && state.membershipTier === 'free';
}
function showStatus(message, type) {
el.statusBox.textContent = message;
el.statusBox.className = `status-box show ${type}`;
}
function clearStatus() {
el.statusBox.textContent = '';
el.statusBox.className = 'status-box';
}
function stopBuilderGeneratingOverlay() {
if (state.builderGeneratingPhaseTimer) { window.clearInterval(state.builderGeneratingPhaseTimer); state.builderGeneratingPhaseTimer = null; }
if (state.builderGeneratingTipsTimer) { window.clearInterval(state.builderGeneratingTipsTimer); state.builderGeneratingTipsTimer = null; }
document.body.classList.remove('builder-generating-active');
el.builderGeneratingOverlay.classList.remove('is-active');
el.builderGeneratingOverlay.setAttribute('aria-hidden', 'true');
}
function startBuilderGeneratingOverlay() {
stopBuilderGeneratingOverlay();
let phaseIndex = 0; let tipsIndex = 0;
el.builderGeneratingTitle.textContent = '算力处理中';
el.builderGeneratingPhase.textContent = BUILDER_GENERATING_PHASES[phaseIndex];
el.builderGeneratingTips.textContent = BUILDER_GENERATING_TIPS[tipsIndex];
el.builderGeneratingOverlay.classList.add('is-active');
el.builderGeneratingOverlay.setAttribute('aria-hidden', 'false');
document.body.classList.add('builder-generating-active');
state.builderGeneratingPhaseTimer = window.setInterval(() => {
phaseIndex = (phaseIndex + 1) % BUILDER_GENERATING_PHASES.length;
el.builderGeneratingPhase.textContent = BUILDER_GENERATING_PHASES[phaseIndex];
}, 2000);
state.builderGeneratingTipsTimer = window.setInterval(() => {
tipsIndex = (tipsIndex + 1) % BUILDER_GENERATING_TIPS.length;
el.builderGeneratingTips.textContent = BUILDER_GENERATING_TIPS[tipsIndex];
}, 3500);
}
function getRemainingTokenCount() { return Number(state.tokenBalance?.remaining || 0); }
function getSelectedStyleOption() { return STYLE_OPTIONS.find((item) => item.name === state.selectedStyle) || STYLE_OPTIONS[0]; }
function formatBuilderError(err) {
const message = String(err?.message || '').trim();
const remaining = getRemainingTokenCount();
if (remaining > 0 && remaining < 10000) return '算力池水位过低,构建作业已挂起。请注入新的算力包以继续。';
if (/insufficient|token balance/i.test(message)) return 'AI 算力额度不足,无法维持本次构建作业。';
return message || '构建节点响应异常,请稍后重试。';
}
function setActiveSection(section) {
el.navButtons.forEach((button) => { button.classList.toggle('is-active', button.dataset.builderNav === section); });
el.panels.forEach((panel) => { panel.classList.toggle('is-hidden', panel.dataset.builderSection !== section); });
}
function renderStyles() {
el.styleGrid.innerHTML = STYLE_OPTIONS.map((item) => {
const active = item.name === state.selectedStyle;
const locked = isLockedStyle(item);
return `
<button class="style-card${active ? ' active' : ''}${locked ? ' locked' : ''}" type="button" data-style-name="${item.name}" ${locked ? 'data-locked="1"' : ''}>
${locked ? '<span class="style-lock">PRO 级</span>' : ''}
<div class="style-thumb ${item.thumb}"></div>
<h4>${item.label}</h4>
<p>${item.desc}</p>
</button>
`;
}).join('');
el.styleText.textContent = getSelectedStyleOption().label;
el.styleNote.textContent = state.membershipTier === 'free' ? '当前配置受限:高定视觉基调已被锁定,仅能调用基础渲染节点。' : '当前配置全开:您可以调用全量视觉基调资源池。';
}
async function hydrateMembership() {
const currentUser = window.SellerSession.requireUser();
const response = await window.SellerSession.fetchJson(`/api/memberships/${currentUser.id}`);
const membership = response.membership || response;
state.membershipTier = membership.tier || currentUser.membershipTier || 'free';
state.tokenBalance = membership.tokenBalance || null;
el.tokenText.textContent = formatTokenStatus(state.tokenBalance);
renderStyles();
}
function readPayload() {
return {
title: el.projectTitle.value.trim(),
subtitle: el.projectSubtitle.value.trim(),
templateStyle: state.selectedStyle,
templateDirectionMeta: {
tag: el.directionTag.value.trim(),
title: el.directionTitle.value.trim(),
description: el.directionDesc.value.trim()
},
promptContext: {
testDirection: el.testDirection.value.trim(),
targetAudience: el.targetAudience.value.trim(),
sellingPoint: el.sellingPoint.value.trim()
}
};
}
function validatePayload(payload) {
if (!payload.templateDirectionMeta.tag || !payload.templateDirectionMeta.title || !payload.templateDirectionMeta.description) return '参数缺失:业务方向元数据未补全。';
if (!payload.title || !payload.subtitle) return '参数缺失:项目基础标识未填充。';
if (!payload.promptContext.testDirection || !payload.promptContext.targetAudience || !payload.promptContext.sellingPoint) return '参数缺失:逻辑算力提示词未补全。';
return '';
}
async function submitBuilder() {
clearStatus();
const payload = readPayload();
const error = validatePayload(payload);
if (error) { showStatus(error, 'error'); return; }
el.generateBtn.disabled = true;
el.generateBtn.textContent = '数据封包中...';
startBuilderGeneratingOverlay();
try {
const response = await window.SellerSession.fetchJson('/api/projects/ai-builder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const data = response.data || response;
el.builderGeneratingTitle.textContent = '构建作业完成';
el.builderGeneratingPhase.textContent = '正在重定向至编辑器';
el.builderGeneratingTips.textContent = '架构快照已生成。即将跳转至精细化配置台。';
window.setTimeout(() => { window.location.href = `project-editor.html?projectId=${data.project.id}`; }, 1000);
} catch (err) {
stopBuilderGeneratingOverlay();
showStatus(formatBuilderError(err), 'error');
} finally {
el.generateBtn.disabled = false;
el.generateBtn.textContent = '执行构建协议';
}
}
function bindEvents() {
el.navButtons.forEach((button) => { button.addEventListener('click', () => setActiveSection(button.dataset.builderNav)); });
el.styleGrid.addEventListener('click', (event) => {
const target = event.target.closest('[data-style-name]');
if (!target) return;
if (target.dataset.locked === '1') { showStatus('视觉越权:当前方案无法调用该渲染节点。', 'error'); return; }
state.selectedStyle = target.dataset.styleName; clearStatus(); renderStyles();
});
el.generateBtn.addEventListener('click', submitBuilder);
document.querySelector('[data-action="logout"]').addEventListener('click', () => { window.SellerSession.logout(); window.location.href = 'login.html'; });
}
async function init() {
bindEvents(); renderStyles();
try {
window.SellerSession.requireUser();
await hydrateMembership();
} catch (err) {
const message = String(err?.message || '');
if (/登录|auth|401/i.test(message)) { window.location.href = 'login.html'; return; }
showStatus('会话验证失败,无法同步算力池数据。', 'error');
}
}
init();
</script>
</body>
</html>