优化APIClient和conversation-service优先使用rawContent提升上下文完整性;调整app-shell.js中对话气泡流式内容渲染逻辑及HTML模块特殊处理;提升STREAM_DEFAULT_OPTIONS maxTokens至30000;重构onepage-prompt.txt交付描述;大幅美化产品画布页面UI,采用Apple和Google风格边框、按钮、气泡,优化配色、阴影、交互效果和模态窗样式,提升整体视觉和交互体验。
This commit is contained in:
@@ -298,7 +298,8 @@ class APIClient {
|
|||||||
.filter(msg => msg.id <= messageId)
|
.filter(msg => msg.id <= messageId)
|
||||||
.map(msg => ({
|
.map(msg => ({
|
||||||
role: msg.type === 'user' ? 'user' : 'assistant',
|
role: msg.type === 'user' ? 'user' : 'assistant',
|
||||||
content: msg.content
|
// 优先使用原始内容,保证上下文完整性
|
||||||
|
content: msg.rawContent || msg.content || ''
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (contextMessages.length === 0) {
|
if (contextMessages.length === 0) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const STREAM_DEFAULT_OPTIONS = {
|
const STREAM_DEFAULT_OPTIONS = {
|
||||||
maxTokens: 13000,
|
maxTokens: 30000,
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -691,7 +691,8 @@
|
|||||||
.filter((msg) => msg.type === 'user' || msg.type === 'ai')
|
.filter((msg) => msg.type === 'user' || msg.type === 'ai')
|
||||||
.map((msg) => ({
|
.map((msg) => ({
|
||||||
role: msg.type === 'user' ? 'user' : 'assistant',
|
role: msg.type === 'user' ? 'user' : 'assistant',
|
||||||
content: msg.content
|
// 使用原始内容作为 LLM 上下文,兼容无 rawContent 的旧记录
|
||||||
|
content: msg.rawContent || msg.content || ''
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.isProcessing = true;
|
this.isProcessing = true;
|
||||||
@@ -836,7 +837,7 @@
|
|||||||
const delta = chunk?.choices?.[0]?.delta?.content || '';
|
const delta = chunk?.choices?.[0]?.delta?.content || '';
|
||||||
if (!delta) return;
|
if (!delta) return;
|
||||||
fullContent += delta;
|
fullContent += delta;
|
||||||
this.updateStreamingContent(container, fullContent);
|
this.updateStreamingContent(container, fullContent, streamState, manifest);
|
||||||
if (manifest.artifact?.type === 'svg') {
|
if (manifest.artifact?.type === 'svg') {
|
||||||
this.processSvgStreamChunk(manifest, fullContent, streamState);
|
this.processSvgStreamChunk(manifest, fullContent, streamState);
|
||||||
} else if (manifest.artifact?.type === 'mermaid') {
|
} else if (manifest.artifact?.type === 'mermaid') {
|
||||||
@@ -893,13 +894,21 @@
|
|||||||
return messageDiv;
|
return messageDiv;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStreamingContent(container, content) {
|
updateStreamingContent(container, content, streamContext = null, manifest = null) {
|
||||||
const cursor = container.querySelector('.typing-cursor');
|
const cursor = container.querySelector('.typing-cursor');
|
||||||
if (!cursor) return;
|
if (!cursor) return;
|
||||||
|
|
||||||
|
// 对于 HTML 模块,HTML 内容已经在右侧预览区域实时渲染,
|
||||||
|
// 为避免在对话气泡中直接注入 <html>/<body> 文档结构,这里不再渲染流式内容。
|
||||||
|
if (manifest?.artifact?.type === 'html') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayContent = content;
|
||||||
if (typeof marked !== 'undefined') {
|
if (typeof marked !== 'undefined') {
|
||||||
cursor.innerHTML = marked.parse(content);
|
cursor.innerHTML = marked.parse(displayContent);
|
||||||
} else {
|
} else {
|
||||||
cursor.textContent = content;
|
cursor.textContent = displayContent;
|
||||||
}
|
}
|
||||||
Utils.scrollToBottom(this.el.chatHistory);
|
Utils.scrollToBottom(this.el.chatHistory);
|
||||||
}
|
}
|
||||||
@@ -994,7 +1003,10 @@
|
|||||||
const messageRecord = {
|
const messageRecord = {
|
||||||
id: messageId,
|
id: messageId,
|
||||||
type: 'ai',
|
type: 'ai',
|
||||||
|
// content 用于展示(可能是裁剪/清洗后的文本)
|
||||||
content: messageContent,
|
content: messageContent,
|
||||||
|
// rawContent 保留完整的 LLM 原始响应,用于上下文与重新生成
|
||||||
|
rawContent: fullContent,
|
||||||
timestamp,
|
timestamp,
|
||||||
artifactId
|
artifactId
|
||||||
};
|
};
|
||||||
@@ -1027,6 +1039,7 @@
|
|||||||
type: 'ai',
|
type: 'ai',
|
||||||
content:
|
content:
|
||||||
content || '生成已被手动终止,您可以点击重新生成继续。',
|
content || '生成已被手动终止,您可以点击重新生成继续。',
|
||||||
|
rawContent: fullContent || content || '',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
artifactId: null,
|
artifactId: null,
|
||||||
interrupted: true
|
interrupted: true
|
||||||
@@ -1084,7 +1097,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = segments.filter(Boolean).join('\n\n').trim();
|
let content = segments.filter(Boolean).join('\n\n').trim();
|
||||||
|
|
||||||
|
// 对于 HTML 模块,额外清理尾部可能残留的空 ```html 代码块
|
||||||
|
// 场景:模型输出两个 ```html 代码块,第二个为空;解析器只提取第一个,
|
||||||
|
// 剩余的空代码块会进入 before/after,最终在气泡中渲染出一个空的 <pre><code>。
|
||||||
|
if (manifest.artifact?.type === 'html' && content) {
|
||||||
|
const withoutEmptyHtmlFence = content.replace(
|
||||||
|
/\n*```(?:html|htm)?\s*```[\s]*$/i,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
if (withoutEmptyHtmlFence.trim()) {
|
||||||
|
content = withoutEmptyHtmlFence.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
@@ -1093,6 +1120,15 @@
|
|||||||
return `已生成 ${manifest.label} 图表,请点击占位卡片查看。`;
|
return `已生成 ${manifest.label} 图表,请点击占位卡片查看。`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTML 模块:避免将完整 HTML 文档渲染到对话气泡中
|
||||||
|
if (manifest.artifact?.type === 'html') {
|
||||||
|
const safeText = (rawContent || '')
|
||||||
|
// 去掉主/副 ```html 代码块,保留其余说明文字
|
||||||
|
.replace(/```(?:html|htm)?[\s\S]*?```/gi, '')
|
||||||
|
.trim();
|
||||||
|
return safeText || `已生成 ${manifest.label} 页面内容,请查看预览区域。`;
|
||||||
|
}
|
||||||
|
|
||||||
return rawContent.trim();
|
return rawContent.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,8 @@
|
|||||||
.filter((msg) => msg.type === 'user' || msg.type === 'ai')
|
.filter((msg) => msg.type === 'user' || msg.type === 'ai')
|
||||||
.map((msg) => ({
|
.map((msg) => ({
|
||||||
role: msg.type === 'user' ? 'user' : 'assistant',
|
role: msg.type === 'user' ? 'user' : 'assistant',
|
||||||
content: msg.content
|
// 优先使用原始内容构建上下文,兼容旧数据回退到 content
|
||||||
|
content: msg.rawContent || msg.content || ''
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
**我的操作流程 (Operational Protocol):**
|
**我的操作流程 (Operational Protocol):**
|
||||||
1. **分析与规划 (Analyze & Plan):** 我首先会分析用户的需求,并制定一个简明的实现计划。我将概述我将采取的具体步骤、关键的设计元素,并简要提及潜在的挑战。这个计划将以自然语言描述,简洁(2-4行)。
|
1. **分析与规划 (Analyze & Plan):** 我首先会分析用户的需求,并制定一个简明的实现计划。我将概述我将采取的具体步骤、关键的设计元素,并简要提及潜在的挑战。这个计划将以自然语言描述,简洁(2-4行)。
|
||||||
2. **生成代码 (Generate Code):** 我将根据规划,编写完整的、统一的HTML文件。这个文件包括HTML结构、用于Tailwind CSS定制的`<style>`标签,以及任何必需的JavaScript代码。
|
2. **生成代码 (Generate Code):** 我将根据规划,编写完整的、统一的HTML文件。这个文件包括HTML结构、用于Tailwind CSS定制的`<style>`标签,以及任何必需的JavaScript代码。
|
||||||
3. **交付与总结 (Deliver & Summarize):** 我将最终的HTML文件呈现在一个markdown代码块中。代码之后,我将提供一份简短的工作总结。
|
3. **交付与总结 (Deliver & Summarize):** 我将最终的HTML文件呈现在一个markdown代码块中。代码之后,我将提供一份简短的工作总结。我要保证每次对话只输出唯一markdown代码块,并保证是完整的HTML
|
||||||
|
|
||||||
**我的技术栈与限制 (Tech Stack & Constraints):**
|
**我的技术栈与限制 (Tech Stack & Constraints):**
|
||||||
* **技术 (Technology):** 我仅使用原生HTML、CSS和JavaScript进行构建。我不会使用任何前端框架,如React、Vue或Angular。
|
* **技术 (Technology):** 我仅使用原生HTML、CSS和JavaScript进行构建。我不会使用任何前端框架,如React、Vue或Angular。
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
* **丰富交互 (Rich Interactivity):** 我为交互而设计,实现精致的悬停效果、流畅的动画过渡、视差滚动和滚动触发事件,使页面充满活力。
|
* **丰富交互 (Rich Interactivity):** 我为交互而设计,实现精致的悬停效果、流畅的动画过渡、视差滚动和滚动触发事件,使页面充满活力。
|
||||||
* **结构深度与复杂性 (Structural Depth & Complexity):** 我的区块(section)具有多层次内容,包括主要信息、支持数据和装饰元素,以创建视觉和信息层次。我确保每个区块包含至少6个精心设计的子元素,构建多层次结构。
|
* **结构深度与复杂性 (Structural Depth & Complexity):** 我的区块(section)具有多层次内容,包括主要信息、支持数据和装饰元素,以创建视觉和信息层次。我确保每个区块包含至少6个精心设计的子元素,构建多层次结构。
|
||||||
* **内容多样性 (Content Diversity):** 我采用多种内容呈现方式,如网格、卡片、时间轴和图文混排布局,以避免单调。
|
* **内容多样性 (Content Diversity):** 我采用多种内容呈现方式,如网格、卡片、时间轴和图文混排布局,以避免单调。
|
||||||
* **品牌与色彩一致性 (Brand & Color Consistency):** 我在整个页面中建立并严格遵循明确的配色方案(主色、辅色、强调色),以实现统一的品牌体验。所有元素,从按钮到边框,都遵循此配色方案。
|
* **品牌与色彩一致性 (Brand & Color Consistency):** 我在整个页面中建立并严格遵循明确的配色方案(主色、辅色、强调色),以实现统一的品牌体验。我会注意前景色和背景色,不会让文字和背景过于重叠导致文字看不清。所有元素,从按钮到边框,都遵循此配色方案。
|
||||||
* **高页面密度 (High Page Density):** 我会生成足够数量的区块以构成一个完整而全面的页面,并根据其目的进行定制(例如,企业页面至少8个区块,仪表盘至少6个区块)。简单的页面(如联系表单)是例外,但其功能将是完整的。
|
* **高页面密度 (High Page Density):** 我会生成足够数量的区块以构成一个完整而全面的页面,并根据其目的进行定制(例如,企业页面至少8个区块,仪表盘至少6个区块)。简单的页面(如联系表单)是例外,但其功能将是完整的。
|
||||||
|
|
||||||
**我的边界条件 (Boundary Conditions):**
|
**我的边界条件 (Boundary Conditions):**
|
||||||
|
|||||||
197
设计/原型.html
197
设计/原型.html
@@ -14,61 +14,63 @@
|
|||||||
font-family: 'Inter', sans-serif;
|
font-family: 'Inter', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 狂野线条效果 */
|
/* Apple 风格边框 */
|
||||||
.wild-border {
|
.apple-card {
|
||||||
border: 3px solid;
|
border: 1px solid rgba(0,0,0,0.08);
|
||||||
box-shadow: 4px 4px 0px rgba(0,0,0,0.3);
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.07), 0 1px 3px rgba(0,0,0,0.06);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 切换按钮激活状态 */
|
/* 切换按钮激活状态 - Apple 风格 */
|
||||||
.mode-btn-active {
|
.mode-btn-active {
|
||||||
transform: translateY(-2px);
|
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||||
box-shadow: 0 4px 0 rgba(0,0,0,0.3);
|
transform: scale(1.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-btn-inactive {
|
.mode-btn-inactive {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 对话气泡样式 */
|
/* 对话气泡样式 - Google 风格 */
|
||||||
.chat-bubble-user {
|
.chat-bubble-user {
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
background: #4C76AB;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px 14px;
|
padding: 12px 16px;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
border: 2px solid #000;
|
border-radius: 18px 18px 4px 18px;
|
||||||
box-shadow: 2px 2px 0 rgba(0,0,0,0.2);
|
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-bubble-ai {
|
.chat-bubble-ai {
|
||||||
background: #fff;
|
background: #f8f9fa;
|
||||||
color: #1f2937;
|
color: #464646;
|
||||||
padding: 10px 14px;
|
padding: 12px 16px;
|
||||||
max-width: 85%;
|
max-width: 85%;
|
||||||
border: 2px solid #10b981;
|
border-radius: 4px 18px 18px 18px;
|
||||||
box-shadow: 2px 2px 0 rgba(16, 185, 129, 0.3);
|
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SVG占位符样式 - 块级换行 + 新配色 */
|
/* SVG占位符样式 - Google 风格 */
|
||||||
.svg-placeholder-block {
|
.svg-placeholder-block {
|
||||||
display: block;
|
display: block;
|
||||||
background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
|
background: #2B4269;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 8px 14px;
|
padding: 10px 16px;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
border: 2px solid #000;
|
border-radius: 8px;
|
||||||
box-shadow: 3px 3px 0 rgba(0,0,0,0.25);
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-placeholder-block:hover {
|
.svg-placeholder-block:hover {
|
||||||
transform: translateX(2px) translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0,0,0,0.16), 0 2px 4px rgba(0,0,0,0.08);
|
||||||
box-shadow: 4px 4px 0 rgba(0,0,0,0.3);
|
transform: translateY(-1px);
|
||||||
background: linear-gradient(135deg, #fb923c 0%, #f87171 100%);
|
background: #5A6270;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 气泡操作按钮 */
|
/* 气泡操作按钮 */
|
||||||
@@ -113,28 +115,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background: white;
|
background: rgba(255,255,255,0.95);
|
||||||
border: 4px solid #000;
|
border-radius: 20px;
|
||||||
box-shadow: 8px 8px 0 rgba(0,0,0,0.4);
|
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1),
|
||||||
|
0 10px 10px -5px rgba(0,0,0,0.04);
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border: 1px solid rgba(255,255,255,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表单输入框样式 */
|
/* 表单输入框样式 - Google 风格 */
|
||||||
.config-input {
|
.config-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 12px 16px;
|
||||||
border: 2px solid #000;
|
border: 1px solid #dadce0;
|
||||||
|
border-radius: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
color: #464646;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-input:focus {
|
.config-input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #667eea;
|
border-color: #4C76AB;
|
||||||
box-shadow: 3px 3px 0 rgba(102, 126, 234, 0.3);
|
box-shadow: 0 0 0 2px rgba(76, 118, 171, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 齿轮旋转动画 */
|
/* 齿轮旋转动画 */
|
||||||
@@ -148,31 +155,31 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100 h-screen flex flex-col">
|
<body class="bg-gray-50 h-screen flex flex-col" style="background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);">
|
||||||
|
|
||||||
<!-- 顶部标题栏 -->
|
<!-- 顶部标题栏 -->
|
||||||
<header class="bg-gradient-to-r from-orange-500 to-pink-500 p-3 flex items-center justify-between border-b-4 border-black">
|
<header class="px-6 py-4 flex items-center justify-between" style="background: rgba(255,255,255,0.8); backdrop-filter: blur(20px); border-bottom: 1px solid rgba(0,0,0,0.06);">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-4">
|
||||||
<iconify-icon icon="ph:lightning-fill" class="text-3xl text-white"></iconify-icon>
|
<iconify-icon icon="ph:lightning-fill" class="text-3xl" style="color: #4C76AB;"></iconify-icon>
|
||||||
<h1 id="page-title" class="text-2xl font-black text-white tracking-tight">产品画布</h1>
|
<h1 id="page-title" class="text-2xl font-semibold tracking-tight" style="color: #464646;">产品画布</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧按钮组 -->
|
<!-- 右侧按钮组 -->
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-4">
|
||||||
<!-- API配置按钮 -->
|
<!-- API配置按钮 -->
|
||||||
<button id="settings-btn" class="settings-btn bg-white/20 text-white p-2 border-2 border-white hover:bg-white/30 transition-all" title="API配置">
|
<button id="settings-btn" class="settings-btn p-3 rounded-full hover:bg-gray-100 transition-all" style="color: #666666;" title="API配置">
|
||||||
<iconify-icon icon="ph:gear-six-fill" class="text-2xl"></iconify-icon>
|
<iconify-icon icon="ph:gear-six-fill" class="text-xl"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<span class="text-white font-bold text-sm">点击切换模式</span>
|
<span class="font-medium text-sm" style="color: #888888;">点击切换模式</span>
|
||||||
<iconify-icon icon="ph:hand-pointing-fill" class="text-2xl text-yellow-300 wave-hand"></iconify-icon>
|
<iconify-icon icon="ph:hand-pointing-fill" class="text-2xl wave-hand" style="color: #5A6270;"></iconify-icon>
|
||||||
|
|
||||||
<button id="canvas-mode-btn" class="mode-btn-active bg-white text-orange-600 px-4 py-2 font-bold border-2 border-black hover:bg-orange-50 transition-all duration-200">
|
<button id="canvas-mode-btn" class="mode-btn-active px-5 py-2.5 font-medium rounded-full hover:bg-gray-100 transition-all duration-300" style="color: #464646; background: rgba(76,118,171,0.1);">
|
||||||
<iconify-icon icon="ph:pen-nib-duotone" class="align-middle mr-1"></iconify-icon>
|
<iconify-icon icon="ph:pen-nib-duotone" class="align-middle mr-2"></iconify-icon>
|
||||||
产品画布
|
产品画布
|
||||||
</button>
|
</button>
|
||||||
<button id="swot-mode-btn" class="mode-btn-inactive bg-white text-purple-600 px-4 py-2 font-bold border-2 border-black hover:bg-purple-50 transition-all duration-200">
|
<button id="swot-mode-btn" class="mode-btn-inactive px-5 py-2.5 font-medium rounded-full hover:bg-gray-100 transition-all duration-300" style="color: #666666;">
|
||||||
<iconify-icon icon="ph:chart-bar-duotone" class="align-middle mr-1"></iconify-icon>
|
<iconify-icon icon="ph:chart-bar-duotone" class="align-middle mr-2"></iconify-icon>
|
||||||
SWOT分析
|
SWOT分析
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -182,7 +189,7 @@
|
|||||||
<main class="flex-1 grid grid-cols-1 md:grid-cols-3 gap-4 p-4 overflow-hidden">
|
<main class="flex-1 grid grid-cols-1 md:grid-cols-3 gap-4 p-4 overflow-hidden">
|
||||||
|
|
||||||
<!-- 左侧对话面板 -->
|
<!-- 左侧对话面板 -->
|
||||||
<div class="md:col-span-1 bg-white wild-border border-cyan-500 flex flex-col">
|
<div class="md:col-span-1 bg-white apple-card flex flex-col">
|
||||||
<!-- 对话历史区 -->
|
<!-- 对话历史区 -->
|
||||||
<div id="chat-history" class="flex-1 p-4 overflow-y-auto space-y-3">
|
<div id="chat-history" class="flex-1 p-4 overflow-y-auto space-y-3">
|
||||||
|
|
||||||
@@ -253,40 +260,43 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 输入区 -->
|
<!-- 输入区 -->
|
||||||
<div class="p-3 border-t-3 border-gray-300 bg-yellow-50">
|
<div class="p-5 border-t bg-white" style="border-color: rgba(0,0,0,0.06);">
|
||||||
<div class="relative flex items-center gap-2">
|
<div class="relative flex items-center gap-3">
|
||||||
<input
|
<input
|
||||||
id="chat-input"
|
id="chat-input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="输入您的想法,按Enter发送..."
|
placeholder="输入您的想法,按Enter发送..."
|
||||||
class="flex-1 p-2 border-2 border-gray-800 focus:border-cyan-500 focus:outline-none transition-colors font-medium"
|
class="flex-1 px-5 py-4 border focus:outline-none transition-all font-normal rounded-2xl"
|
||||||
|
style="border-color: rgba(0,0,0,0.08); color: #464646; background: rgba(248,249,250,0.8);"
|
||||||
|
onfocus="this.style.borderColor='#4C76AB'; this.style.boxShadow='0 0 0 3px rgba(76,118,171,0.15)'; this.style.background='rgba(255,255,255,0.95)'"
|
||||||
|
onblur="this.style.borderColor='rgba(0,0,0,0.08)'; this.style.boxShadow='none'; this.style.background='rgba(248,249,250,0.8)'"
|
||||||
/>
|
/>
|
||||||
<button id="send-button" class="text-cyan-600 hover:text-cyan-700 transition-colors p-2 hover:scale-110 transform duration-200">
|
<button id="send-button" class="p-3 rounded-full transition-all hover:scale-105" style="color: white; background: #4C76AB; box-shadow: 0 2px 8px rgba(76,118,171,0.3);" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
|
||||||
<iconify-icon icon="ph:paper-plane-tilt-fill" class="text-3xl"></iconify-icon>
|
<iconify-icon icon="ph:paper-plane-tilt-fill" class="text-xl"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧显示面板 -->
|
<!-- 右侧显示面板 -->
|
||||||
<div class="md:col-span-2 bg-white wild-border border-purple-600 flex flex-col">
|
<div class="md:col-span-2 bg-white apple-card flex flex-col">
|
||||||
<div id="svg-viewer" class="flex-1 flex items-center justify-center p-4 bg-gradient-to-br from-purple-50 to-pink-50 overflow-auto">
|
<div id="svg-viewer" class="flex-1 flex items-center justify-center p-8 overflow-auto" style="background: linear-gradient(135deg, #fafafa 0%, #f8f9fa 100%);">
|
||||||
<div id="svg-placeholder" class="text-center text-gray-400">
|
<div id="svg-placeholder" class="text-center" style="color: #787878;">
|
||||||
<iconify-icon icon="ph:image-square" class="text-6xl mx-auto text-purple-400"></iconify-icon>
|
<iconify-icon icon="ph:image-square" class="text-6xl mx-auto" style="color: #5586F5;"></iconify-icon>
|
||||||
<p class="mt-2 font-bold" id="placeholder-text">生成的产品画布将在此处显示</p>
|
<p class="mt-2 font-bold" id="placeholder-text">生成的产品画布将在此处显示</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<div class="p-3 border-t-3 border-gray-300 flex justify-end items-center gap-2 bg-gray-800">
|
<div class="p-5 border-t flex justify-end items-center gap-4" style="border-color: rgba(0,0,0,0.06); background: rgba(248,249,250,0.8);">
|
||||||
<button id="download-svg-btn" class="p-2 bg-orange-500 text-white border-2 border-black hover:bg-orange-600 transition-all" title="下载SVG">
|
<button id="download-svg-btn" class="p-3 text-white rounded-xl transition-all" style="background: #5A6270; box-shadow: 0 4px 12px rgba(90,98,112,0.25);" title="下载SVG" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
|
||||||
<iconify-icon icon="mdi:download-outline" class="text-xl"></iconify-icon>
|
<iconify-icon icon="mdi:download-outline" class="text-lg"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
<button id="export-image-btn" class="p-2 bg-green-500 text-white border-2 border-black hover:bg-green-600 transition-all" title="导出为图片">
|
<button id="export-image-btn" class="p-3 text-white rounded-xl transition-all" style="background: #2B4269; box-shadow: 0 4px 12px rgba(43,66,105,0.25);" title="导出为图片" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
|
||||||
<iconify-icon icon="mdi:image-outline" class="text-xl"></iconify-icon>
|
<iconify-icon icon="mdi:image-outline" class="text-lg"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
<button id="view-code-btn" class="p-2 bg-blue-500 text-white border-2 border-black hover:bg-blue-600 transition-all" title="查看代码">
|
<button id="view-code-btn" class="p-3 text-white rounded-xl transition-all" style="background: #4C76AB; box-shadow: 0 4px 12px rgba(76,118,171,0.25);" title="查看代码" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
|
||||||
<iconify-icon icon="mdi:code-tags" class="text-xl"></iconify-icon>
|
<iconify-icon icon="mdi:code-tags" class="text-lg"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -297,13 +307,13 @@
|
|||||||
<div id="config-modal" class="modal-overlay">
|
<div id="config-modal" class="modal-overlay">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<!-- 模态窗头部 -->
|
<!-- 模态窗头部 -->
|
||||||
<div class="bg-gradient-to-r from-blue-600 to-purple-600 p-4 border-b-4 border-black flex items-center justify-between">
|
<div class="p-6 border-b flex items-center justify-between" style="background: rgba(255,255,255,0.95); border-color: rgba(0,0,0,0.06); border-radius: 20px 20px 0 0;">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-4">
|
||||||
<iconify-icon icon="ph:plugs-connected-fill" class="text-3xl text-white"></iconify-icon>
|
<iconify-icon icon="ph:plugs-connected-fill" class="text-2xl" style="color: #4C76AB;"></iconify-icon>
|
||||||
<h2 class="text-xl font-black text-white">API 配置</h2>
|
<h2 class="text-xl font-semibold" style="color: #464646;">API 配置</h2>
|
||||||
</div>
|
</div>
|
||||||
<button id="close-modal-btn" class="text-white hover:bg-white/20 p-2 transition-all">
|
<button id="close-modal-btn" class="hover:bg-gray-100 p-3 rounded-full transition-all" style="color: #666666;" onmouseover="this.style.backgroundColor='#f0f0f0'" onmouseout="this.style.backgroundColor='transparent'">
|
||||||
<iconify-icon icon="ph:x-bold" class="text-2xl"></iconify-icon>
|
<iconify-icon icon="ph:x-bold" class="text-xl"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -311,8 +321,8 @@
|
|||||||
<div class="p-6 space-y-4">
|
<div class="p-6 space-y-4">
|
||||||
<!-- API URL -->
|
<!-- API URL -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block font-bold text-gray-800 mb-2 flex items-center gap-2">
|
<label class="block font-semibold mb-3 flex items-center gap-3" style="color: #464646;">
|
||||||
<iconify-icon icon="ph:link-bold" class="text-lg text-blue-600"></iconify-icon>
|
<iconify-icon icon="ph:link-bold" class="text-lg" style="color: #4C76AB;"></iconify-icon>
|
||||||
API URL
|
API URL
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -326,8 +336,8 @@
|
|||||||
|
|
||||||
<!-- API Key -->
|
<!-- API Key -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block font-bold text-gray-800 mb-2 flex items-center gap-2">
|
<label class="block font-semibold mb-3 flex items-center gap-3" style="color: #464646;">
|
||||||
<iconify-icon icon="ph:key-bold" class="text-lg text-green-600"></iconify-icon>
|
<iconify-icon icon="ph:key-bold" class="text-lg" style="color: #2B4269;"></iconify-icon>
|
||||||
API Key
|
API Key
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -341,8 +351,8 @@
|
|||||||
|
|
||||||
<!-- Model -->
|
<!-- Model -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block font-bold text-gray-800 mb-2 flex items-center gap-2">
|
<label class="block font-semibold mb-3 flex items-center gap-3" style="color: #464646;">
|
||||||
<iconify-icon icon="ph:robot-bold" class="text-lg text-purple-600"></iconify-icon>
|
<iconify-icon icon="ph:robot-bold" class="text-lg" style="color: #5A6270;"></iconify-icon>
|
||||||
模型 (Model)
|
模型 (Model)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -355,19 +365,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 状态显示 -->
|
<!-- 状态显示 -->
|
||||||
<div id="config-status" class="p-3 border-2 border-gray-300 bg-gray-50 text-sm text-gray-600 hidden">
|
<div id="config-status" class="p-4 border rounded-2xl bg-gray-50 text-sm hidden" style="border-color: rgba(0,0,0,0.06); color: #888888;">
|
||||||
<iconify-icon icon="ph:info" class="align-middle"></iconify-icon>
|
<iconify-icon icon="ph:info" class="align-middle"></iconify-icon>
|
||||||
<span id="status-text">等待操作...</span>
|
<span id="status-text">等待操作...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模态窗底部按钮 -->
|
<!-- 模态窗底部按钮 -->
|
||||||
<div class="p-4 border-t-3 border-gray-300 bg-gray-100 flex gap-3 justify-end">
|
<div class="p-6 border-t bg-white flex gap-4 justify-end" style="border-color: rgba(0,0,0,0.06); border-radius: 0 0 20px 20px;">
|
||||||
<button id="test-api-btn" class="px-4 py-2 bg-yellow-500 text-white font-bold border-2 border-black hover:bg-yellow-600 transition-all flex items-center gap-2">
|
<button id="test-api-btn" class="px-6 py-3 text-white font-medium rounded-2xl transition-all flex items-center gap-3" style="background: #5A6270; box-shadow: 0 4px 12px rgba(90,98,112,0.25);" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
|
||||||
<iconify-icon icon="ph:flask-bold"></iconify-icon>
|
<iconify-icon icon="ph:flask-bold"></iconify-icon>
|
||||||
测试连接
|
测试连接
|
||||||
</button>
|
</button>
|
||||||
<button id="save-config-btn" class="px-4 py-2 bg-green-500 text-white font-bold border-2 border-black hover:bg-green-600 transition-all flex items-center gap-2">
|
<button id="save-config-btn" class="px-6 py-3 text-white font-medium rounded-2xl transition-all flex items-center gap-3" style="background: #4C76AB; box-shadow: 0 4px 12px rgba(76,118,171,0.25);" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
|
||||||
<iconify-icon icon="ph:floppy-disk-bold"></iconify-icon>
|
<iconify-icon icon="ph:floppy-disk-bold"></iconify-icon>
|
||||||
保存配置
|
保存配置
|
||||||
</button>
|
</button>
|
||||||
@@ -505,19 +515,22 @@
|
|||||||
configStatus.classList.remove('hidden');
|
configStatus.classList.remove('hidden');
|
||||||
statusText.textContent = message;
|
statusText.textContent = message;
|
||||||
|
|
||||||
configStatus.classList.remove('border-gray-300', 'bg-gray-50', 'text-gray-600');
|
configStatus.style.borderColor = '#787878';
|
||||||
configStatus.classList.remove('border-green-500', 'bg-green-50', 'text-green-700');
|
configStatus.style.backgroundColor = '#f9fafb';
|
||||||
configStatus.classList.remove('border-red-500', 'bg-red-50', 'text-red-700');
|
configStatus.style.color = '#787878';
|
||||||
configStatus.classList.remove('border-blue-500', 'bg-blue-50', 'text-blue-700');
|
|
||||||
|
|
||||||
if (type === 'success') {
|
if (type === 'success') {
|
||||||
configStatus.classList.add('border-green-500', 'bg-green-50', 'text-green-700');
|
configStatus.style.borderColor = '#47A74F';
|
||||||
|
configStatus.style.backgroundColor = '#e8f5e9';
|
||||||
|
configStatus.style.color = '#2e7d32';
|
||||||
} else if (type === 'error') {
|
} else if (type === 'error') {
|
||||||
configStatus.classList.add('border-red-500', 'bg-red-50', 'text-red-700');
|
configStatus.style.borderColor = '#E04639';
|
||||||
|
configStatus.style.backgroundColor = '#ffebee';
|
||||||
|
configStatus.style.color = '#c62828';
|
||||||
} else if (type === 'loading') {
|
} else if (type === 'loading') {
|
||||||
configStatus.classList.add('border-blue-500', 'bg-blue-50', 'text-blue-700');
|
configStatus.style.borderColor = '#5586F5';
|
||||||
} else {
|
configStatus.style.backgroundColor = '#e3f2fd';
|
||||||
configStatus.classList.add('border-gray-300', 'bg-gray-50', 'text-gray-600');
|
configStatus.style.color = '#1565c0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user