feat: 技能市场Hub导入MCP/Skills添加名称说明输入;MCP传输代码验证后独立导入按钮

This commit is contained in:
QihuAI Design committed 2026-07-14 22:33:43 +08:00
1 parent c0ec9e0e88
commit 62631a3b95
1 file changed
+57 -5
+57 -5
View File
@@ -870,7 +870,7 @@ interface HubImportModalProps {
appType: 'skill' | 'mcp';
platforms: typeof skillsHubPlatforms;
onClose: () => void;
onImport: (platformName: string, url: string, skillName: string, price?: number) => void;
onImport: (platformName: string, url: string, skillName: string, price?: number, description?: string) => void;
}
const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onClose, onImport }) => {
@@ -884,6 +884,8 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
const [hubCode, setHubCode] = useState('');
const [hubCodeVerifyResult, setHubCodeVerifyResult] = useState<'idle' | 'checking' | 'pass' | 'fail'>('idle');
const [hubCodeVerifyMsg, setHubCodeVerifyMsg] = useState('');
const [hubName, setHubName] = useState('');
const [hubDescription, setHubDescription] = useState('');
const handleVisit = (url: string) => {
window.open(url, '_blank');
@@ -908,9 +910,10 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
const handleImport = (platformId: string) => {
const url = importUrl[platformId];
// For Skills: require URL; for MCP: require code verification pass
// For Skills: require URL; for MCP: require code verification pass + name
if (appType === 'skill' && !url?.trim()) return;
if (appType === 'mcp' && hubCodeVerifyResult !== 'pass') return;
if (appType === 'mcp' && !hubName.trim()) return;
setImportingId(platformId);
setImportStatus('verifying');
setStatusMsg(appType === 'mcp' ? '正在验证代码...' : '正在验证URL链接...');
@@ -930,13 +933,16 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
setStatusMsg(step.msg);
if (step.status === 'published') {
setTimeout(() => {
onImport(platformId, appType === 'mcp' ? hubCode : url, extractSkillName(url, platformId), importPrice);
const name = appType === 'skill' ? (hubName || extractSkillName(url || '', platformId)) : hubName;
onImport(platformId, appType === 'mcp' ? hubCode : (url || ''), name, importPrice, hubDescription);
setImportingId(null);
setImportStatus('idle');
setImportUrl(prev => ({ ...prev, [platformId]: '' }));
setHubCode('');
setHubCodeVerifyResult('idle');
setHubCodeVerifyMsg('');
setHubName('');
setHubDescription('');
}, 1000);
}
}, delay);
@@ -974,6 +980,28 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
</span>
</div>
{/* Name & Description */}
<div className="form-section">
<label className="form-label">名称 <span className="required">*</span></label>
<input
type="text"
className="form-input"
placeholder={appType === 'skill' ? '请输入Skills工具名称' : '请输入MCP应用名称'}
value={hubName}
onChange={e => setHubName(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">说明</label>
<textarea
className="form-textarea"
placeholder="请描述功能、使用场景等..."
value={hubDescription}
onChange={e => setHubDescription(e.target.value)}
rows={3}
/>
</div>
{/* MCP Hub Import: Code Editor + AI验证 */}
{appType === 'mcp' && (
<div className="hub-code-section">
@@ -1013,6 +1041,29 @@ const mcpClient = new MCPClient({
</div>
)}
{/* MCP 独立导入按钮:直接导入(不依赖选择平台卡片) */}
{appType === 'mcp' && hubCodeVerifyResult === 'pass' && (
<div className="hub-standalone-import" style={{ textAlign: 'center', marginBottom: 20, padding: '16px', background: 'var(--color-bg-secondary)', borderRadius: 8 }}>
<button
className="hub-import-btn"
style={{ padding: '10px 40px', fontSize: 15, fontWeight: 600 }}
onClick={() => handleImport('custom-import')}
disabled={!hubName.trim()}
>
{importingId === 'custom-import' ? (
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<div className="audit-spinner tiny" />
导入中...
</span>
) : '导入'}
</button>
{!hubName.trim() && <div style={{ color: '#f85149', fontSize: 12, marginTop: 6 }}>请先输入名称</div>}
<div style={{ fontSize: 12, color: 'var(--color-text-tertiary)', marginTop: 6 }}>
直接从传输代码导入,无需选择平台
</div>
</div>
)}
<div className="hub-platforms">
{platforms.map(p => (
<div key={p.id} className="hub-platform-card">
@@ -1317,12 +1368,13 @@ const MarketPage: React.FC = () => {
};
// Handle hub import - 调用后端 API 创建应用
const handleHubImport = async (platformName: string, url: string, skillName: string, price?: number) => {
const handleHubImport = async (platformName: string, url: string, skillName: string, price?: number, description?: string) => {
try {
const desc = description || `从 ${platformName} 导入的${showHubImport === 'skill' ? 'Skills工具' : 'MCP应用'} (来源: ${url})`;
await marketAPI.createApp({
name: skillName,
type: showHubImport || 'skill',
description: `从 ${platformName} 导入的${showHubImport === 'skill' ? 'Skills工具' : 'MCP应用'} (来源: ${url})`,
description: desc,
price: price || 0,
is_member_free: (price || 0) === 0,
join_promotion: false,