## 功能概述 - 用户首次使用需验证邀请码才能发起对话 - 在输入框聚焦和点击示例时触发验证检查 - 使用弹窗形式展示邀请码输入界面,包含企业端用户提示和微信二维码 ## 主要变更 ### 新增文件 - `services/invitationService.ts`: 邀请码验证服务,处理验证逻辑和状态管理 - `views/invitationModal.ts`: 邀请码验证弹窗组件(HTML/CSS/JS) - `docs/invitation-code-design.md`: 邀请码功能设计文档 ### 修改文件 - `extension.ts`: 添加更换邀请码命令,退出登录时清除验证状态 - `panels/ICHelperPanel.ts`: 添加邀请码验证状态检查和验证消息处理 - `services/apiClient.ts`: 添加邀请码验证接口调用 - `types/api.ts`: 添加邀请码相关类型定义 - `views/inputArea.ts`: 输入框聚焦时触发邀请码验证检查 - `views/exampleShowcase.ts`: 点击示例时先检查邀请码验证状态 - `views/webviewContent.ts`: 集成邀请码弹窗到主界面 ## 技术实现 - 验证状态保存在 ExtensionContext.globalState 中 - 使用后端接口 POST /api/invitation/verify 进行验证 - 弹窗样式适配 VS Code 主题 - 支持回车键提交验证
285 lines
7.9 KiB
TypeScript
285 lines
7.9 KiB
TypeScript
/**
|
|
* 获取展示区域的 HTML 内容
|
|
*/
|
|
export function getExampleShowcaseContent(): string {
|
|
return `
|
|
<div class="example-showcase" id="exampleShowcase">
|
|
<div class="showcase-title">示例</div>
|
|
<div class="example-cards">
|
|
<div class="example-card" onclick="sendExample(0)">
|
|
<div class="example-icon">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M10 9H9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
</div>
|
|
<div class="example-content">
|
|
<div class="example-title">生成一个SPI控制器</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="example-card" onclick="sendExample(1)">
|
|
<div class="example-icon">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
</div>
|
|
<div class="example-content">
|
|
<div class="example-title">生成一个GMII接口的以太网UDP通信模块</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="web-link">
|
|
<a href="https://iccoder.com" target="_blank" class="web-link-button">
|
|
<span class="link-icon">🌐</span>
|
|
<span>IC Coder Web端</span>
|
|
<span class="link-arrow">→</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取展示区域的样式
|
|
*/
|
|
export function getExampleShowcaseStyles(): string {
|
|
return `
|
|
.example-showcase {
|
|
margin-top: 24px;
|
|
padding: 0;
|
|
opacity: 1;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.example-showcase.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.showcase-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--vscode-foreground);
|
|
margin-bottom: 12px;
|
|
text-align: left;
|
|
}
|
|
|
|
.example-cards {
|
|
display: flex;
|
|
flex-direction: row;
|
|
gap: 12px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.example-card {
|
|
flex: 1;
|
|
min-width: 0;
|
|
background: var(--vscode-input-background);
|
|
border: 1px solid var(--vscode-input-border);
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 10px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.example-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.1) 50%, rgba(168, 85, 247, 0.1) 100%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.example-card:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
.example-card:hover {
|
|
border-color: var(--vscode-focusBorder);
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.example-icon {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--vscode-foreground);
|
|
}
|
|
|
|
.example-icon svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.example-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
flex: 1;
|
|
min-width: 0;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.example-title {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--vscode-foreground);
|
|
line-height: 1.4;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.example-card:hover .example-title {
|
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 50%, #a855f7 100%);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
.example-desc {
|
|
font-size: 11px;
|
|
color: var(--vscode-descriptionForeground);
|
|
line-height: 1.4;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
}
|
|
|
|
.web-link {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding-top: 20px;
|
|
border-top: 1px solid var(--vscode-panel-border);
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.web-link-button {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 10px 20px;
|
|
background: transparent;
|
|
border: none;
|
|
text-decoration: none;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
transition: all 0.2s ease;
|
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 50%, #a855f7 100%);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
outline: none;
|
|
}
|
|
|
|
.web-link-button:focus {
|
|
outline: none;
|
|
}
|
|
|
|
.web-link-button:hover {
|
|
transform: translateY(-1px);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.link-icon {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.link-arrow {
|
|
font-size: 16px;
|
|
transition: transform 0.2s ease;
|
|
}
|
|
|
|
.web-link-button:hover .link-arrow {
|
|
transform: translateX(3px);
|
|
}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取展示区域的脚本
|
|
*/
|
|
export function getExampleShowcaseScript(): string {
|
|
return `
|
|
// 示例文本数组
|
|
const exampleTexts = [
|
|
'生成一个SPI控制器',
|
|
'生成一个GMII接口的以太网UDP通信模块'
|
|
];
|
|
|
|
// 存储待发送的示例索引
|
|
let pendingExampleIndex = -1;
|
|
|
|
// 直接发送示例消息
|
|
function sendExample(index) {
|
|
// 先检查邀请码验证状态
|
|
pendingExampleIndex = index;
|
|
vscode.postMessage({
|
|
command: 'checkInvitationCode'
|
|
});
|
|
}
|
|
|
|
// 实际发送示例消息
|
|
function doSendExample(index) {
|
|
const messageInput = document.getElementById('messageInput');
|
|
const sendButton = document.getElementById('sendButton');
|
|
|
|
if (messageInput && exampleTexts[index]) {
|
|
messageInput.value = exampleTexts[index];
|
|
|
|
// 触发自动调整高度
|
|
if (typeof autoResizeTextarea === 'function') {
|
|
autoResizeTextarea();
|
|
}
|
|
|
|
// 直接触发发送
|
|
if (sendButton && typeof sendButton.click === 'function') {
|
|
sendButton.click();
|
|
} else if (typeof sendMessage === 'function') {
|
|
sendMessage();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 监听消息变化,自动隐藏/显示展示区域
|
|
function updateShowcaseVisibility() {
|
|
const showcase = document.getElementById('exampleShowcase');
|
|
if (showcase) {
|
|
if (hasMessages) {
|
|
showcase.classList.add('hidden');
|
|
} else {
|
|
showcase.classList.remove('hidden');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 扩展原有的布局更新函数
|
|
const originalUpdateInputAreaLayout = updateInputAreaLayout;
|
|
updateInputAreaLayout = function() {
|
|
if (originalUpdateInputAreaLayout) {
|
|
originalUpdateInputAreaLayout();
|
|
}
|
|
updateShowcaseVisibility();
|
|
};
|
|
`;
|
|
}
|