fix: 修复前端TypeScript类型错误
This commit is contained in:
parent
b0a8c6edb9
commit
20d4048543
|
|
@ -107,7 +107,7 @@ const extractMetadata = (content: string) => {
|
||||||
|
|
||||||
// 1. Extract Title (First H1 or first non-empty line)
|
// 1. Extract Title (First H1 or first non-empty line)
|
||||||
const titleMatch = content.match(/^#\s+(.*)/m)
|
const titleMatch = content.match(/^#\s+(.*)/m)
|
||||||
if (titleMatch) {
|
if (titleMatch && titleMatch[1]) {
|
||||||
title = titleMatch[1].trim()
|
title = titleMatch[1].trim()
|
||||||
} else {
|
} else {
|
||||||
const firstLine = lines.find(l => l.trim().length > 0)
|
const firstLine = lines.find(l => l.trim().length > 0)
|
||||||
|
|
@ -136,12 +136,12 @@ const extractMetadata = (content: string) => {
|
||||||
// Look for "Core Logic", "Architecture", "Introduction" headers
|
// Look for "Core Logic", "Architecture", "Introduction" headers
|
||||||
const logicRegex = /##\s*(Core Logic|Architecture|Introduction|About|Features)([\s\S]*?)(##|$)/i
|
const logicRegex = /##\s*(Core Logic|Architecture|Introduction|About|Features)([\s\S]*?)(##|$)/i
|
||||||
const logicMatch = content.match(logicRegex)
|
const logicMatch = content.match(logicRegex)
|
||||||
if (logicMatch) {
|
if (logicMatch && logicMatch[2]) {
|
||||||
coreLogic = logicMatch[2].trim().substring(0, 300) + (logicMatch[2].length > 300 ? '...' : '')
|
coreLogic = logicMatch[2].trim().substring(0, 300) + (logicMatch[2].length > 300 ? '...' : '')
|
||||||
} else {
|
} else {
|
||||||
// Fallback: First paragraph after title
|
// Fallback: First paragraph after title
|
||||||
const paragraphs = content.split(/\n\s*\n/)
|
const paragraphs = content.split(/\n\s*\n/)
|
||||||
if (paragraphs.length > 1) {
|
if (paragraphs.length > 1 && paragraphs[1]) {
|
||||||
coreLogic = paragraphs[1].trim().substring(0, 200) + '...'
|
coreLogic = paragraphs[1].trim().substring(0, 200) + '...'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 选中提供商说明 -->
|
<!-- 选中提供商说明 -->
|
||||||
<div class="provider-info">
|
<div class="provider-info" v-if="selectedProvider">
|
||||||
<span class="provider-desc">{{ selectedProvider.desc }}</span>
|
<span class="provider-desc">{{ selectedProvider.desc }}</span>
|
||||||
<span class="provider-pricing">{{ selectedProvider.pricing }}</span>
|
<span class="provider-pricing">{{ selectedProvider.pricing }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
<h2 class="section-title">连接配置</h2>
|
<h2 class="section-title">连接配置</h2>
|
||||||
|
|
||||||
<!-- API 密钥配置 -->
|
<!-- API 密钥配置 -->
|
||||||
<div v-if="showApiKey" class="form-group">
|
<div v-if="showApiKey && selectedProvider" class="form-group">
|
||||||
<label class="form-label">API 密钥</label>
|
<label class="form-label">API 密钥</label>
|
||||||
<input
|
<input
|
||||||
v-model="apiKey"
|
v-model="apiKey"
|
||||||
|
|
@ -161,13 +161,6 @@ const KeyIcon = () => h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'cu
|
||||||
h('path', { d: 'M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4' })
|
h('path', { d: 'M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4' })
|
||||||
])
|
])
|
||||||
|
|
||||||
const ServerIcon = () => h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.5 }, [
|
|
||||||
h('rect', { x: '2', y: '2', width: '20', height: '8', rx: '2', ry: '2' }),
|
|
||||||
h('rect', { x: '2', y: '14', width: '20', height: '8', rx: '2', ry: '2' }),
|
|
||||||
h('line', { x1: '6', y1: '6', x2: '6.01', y2: '6' }),
|
|
||||||
h('line', { x1: '6', y1: '18', x2: '6.01', y2: '18' })
|
|
||||||
])
|
|
||||||
|
|
||||||
// 侧边栏导航
|
// 侧边栏导航
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ key: 'provider', label: '模型服务', icon: CloudIcon },
|
{ key: 'provider', label: '模型服务', icon: CloudIcon },
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@
|
||||||
<div class="progress-comparison">
|
<div class="progress-comparison">
|
||||||
<div class="progress-row">
|
<div class="progress-row">
|
||||||
<span class="label">我方</span>
|
<span class="label">我方</span>
|
||||||
<n-progress type="line" :percentage="getOurProgress(selectedSignal)" color="#63e2b7" rail-color="rgba(255,255,255,0.1)" height="6" processing />
|
<n-progress type="line" :percentage="Number(getOurProgress(selectedSignal))" color="#63e2b7" rail-color="rgba(255,255,255,0.1)" :height="6" processing />
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-row">
|
<div class="progress-row">
|
||||||
<span class="label">竞品</span>
|
<span class="label">竞品</span>
|
||||||
<n-progress type="line" :percentage="getCompetitorProgress(selectedSignal)" color="#f5222d" rail-color="rgba(255,255,255,0.1)" height="6" />
|
<n-progress type="line" :percentage="Number(getCompetitorProgress(selectedSignal))" color="#f5222d" rail-color="rgba(255,255,255,0.1)" :height="6" />
|
||||||
</div>
|
</div>
|
||||||
<div class="lead-time-text" v-if="selectedSignal">
|
<div class="lead-time-text" v-if="selectedSignal">
|
||||||
{{ getLeadTimeText(selectedSignal) }}
|
{{ getLeadTimeText(selectedSignal) }}
|
||||||
|
|
@ -134,18 +134,18 @@
|
||||||
'new-signal-flash': isNewSignal(signal.latestSignal)
|
'new-signal-flash': isNewSignal(signal.latestSignal)
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #header>
|
<n-card-header>
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
<div style="display: flex; align-items: center; gap: 6px;">
|
<div style="display: flex; align-items: center; gap: 6px;">
|
||||||
<n-tag :type="getPriorityType(signal.latestSignal.priority)" size="small" round>
|
<n-tag :type="getPriorityType(signal.latestSignal?.priority || 'medium')" size="small" round>
|
||||||
{{ getPriorityLabel(signal.latestSignal.priority) }}
|
{{ getPriorityLabel(signal.latestSignal?.priority || 'medium') }}
|
||||||
</n-tag>
|
</n-tag>
|
||||||
<n-tag :type="getImpactColor(signal.impact_score)" size="small" round>{{ signal.source }}</n-tag>
|
<n-tag :type="getImpactColor(signal.impact_score)" size="small" round>{{ signal.source }}</n-tag>
|
||||||
<n-tag v-if="signal.count > 1" type="info" size="tiny" round>{{ signal.count }}条</n-tag>
|
<n-tag v-if="signal.count > 1" type="info" size="tiny" round>{{ signal.count }}条</n-tag>
|
||||||
</div>
|
</div>
|
||||||
<n-text depth="3" style="font-size: 12px;">{{ formatDate(signal.created_at) }}</n-text>
|
<n-text depth="3" style="font-size: 12px;">{{ formatDate(signal.created_at) }}</n-text>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</n-card-header>
|
||||||
<n-text class="signal-content" :depth="1">{{ signal.content }}</n-text>
|
<n-text class="signal-content" :depth="1">{{ signal.content }}</n-text>
|
||||||
</n-list-item>
|
</n-list-item>
|
||||||
</n-list>
|
</n-list>
|
||||||
|
|
@ -493,7 +493,7 @@
|
||||||
:percentage="getTaskProgress(task)"
|
:percentage="getTaskProgress(task)"
|
||||||
:color="getTaskTypeColor(task.type, true)"
|
:color="getTaskTypeColor(task.type, true)"
|
||||||
rail-color="rgba(255,255,255,0.1)"
|
rail-color="rgba(255,255,255,0.1)"
|
||||||
height="4"
|
:height="4"
|
||||||
:show-indicator="false"
|
:show-indicator="false"
|
||||||
style="margin-top: 8px;"
|
style="margin-top: 8px;"
|
||||||
:class="{ 'progress-pulse': taskExecuting }"
|
:class="{ 'progress-pulse': taskExecuting }"
|
||||||
|
|
@ -543,7 +543,7 @@
|
||||||
<n-modal v-model:show="showCompetitorModal">
|
<n-modal v-model:show="showCompetitorModal">
|
||||||
<n-card style="width: 400px" title="⚔️ 设定主要竞品(某漫、某画等)" :bordered="false" size="large" role="dialog" aria-modal="true" class="glass-modal">
|
<n-card style="width: 400px" title="⚔️ 设定主要竞品(某漫、某画等)" :bordered="false" size="large" role="dialog" aria-modal="true" class="glass-modal">
|
||||||
<n-space vertical>
|
<n-space vertical>
|
||||||
<n-input v-for="(comp, index) in competitors" :key="index" v-model:value="competitors[index]" placeholder="输入竞品名称..." />
|
<n-input v-for="(_comp, index) in competitors" :key="index" v-model:value="competitors[index]" placeholder="输入竞品名称..." />
|
||||||
</n-space>
|
</n-space>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<n-button type="primary" block @click="saveCompetitors">
|
<n-button type="primary" block @click="saveCompetitors">
|
||||||
|
|
@ -573,11 +573,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, watch, nextTick, computed } from 'vue'
|
import { ref, onMounted, onUnmounted, reactive, watch, computed } from 'vue'
|
||||||
import {
|
import {
|
||||||
NLayout, NLayoutSider, NLayoutContent, NSpace, NCard, NButton, NList, NListItem, NTag, NText,
|
NLayout, NLayoutSider, NLayoutContent, NSpace, NCard, NButton, NList, NListItem, NTag, NText,
|
||||||
NGrid, NGridItem, NDivider, NResult, NCheckbox, NThing, NScrollbar, NSpin, NModal, NForm, NFormItem,
|
NGrid, NGridItem, NScrollbar, NSpin, NModal, NForm, NFormItem,
|
||||||
NInput, useMessage, NEmpty, NProgress, NIcon, NSteps, NStep, NStatistic
|
NInput, useMessage, NProgress, NIcon, NSteps, NStep, NStatistic, NCardHeader
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import VChart from 'vue-echarts'
|
import VChart from 'vue-echarts'
|
||||||
|
|
@ -859,12 +859,14 @@ const factSnippets: Record<string, { title: string; source: string; content: str
|
||||||
|
|
||||||
const showFactSnippetModal = (type: string) => {
|
const showFactSnippetModal = (type: string) => {
|
||||||
const snippet = factSnippets[type] || factSnippets['Whitepaper']
|
const snippet = factSnippets[type] || factSnippets['Whitepaper']
|
||||||
|
if (snippet) {
|
||||||
currentFactSnippet.value = {
|
currentFactSnippet.value = {
|
||||||
title: snippet.title,
|
title: snippet.title,
|
||||||
source: snippet.source,
|
source: snippet.source,
|
||||||
content: snippet.content
|
content: snippet.content
|
||||||
}
|
}
|
||||||
showFactSnippet.value = true
|
showFactSnippet.value = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Logic ---
|
// --- Logic ---
|
||||||
|
|
@ -947,8 +949,8 @@ const getRelatedKnowledgeNodes = () => {
|
||||||
return Array.isArray(knowledgeNodes) ? knowledgeNodes : []
|
return Array.isArray(knowledgeNodes) ? knowledgeNodes : []
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTechStackType = (category: string) => {
|
const getTechStackType = (category: string): 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary' => {
|
||||||
const typeMap: Record<string, string> = {
|
const typeMap: Record<string, 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary'> = {
|
||||||
framework: 'success',
|
framework: 'success',
|
||||||
model: 'error',
|
model: 'error',
|
||||||
tool: 'info',
|
tool: 'info',
|
||||||
|
|
@ -994,8 +996,8 @@ const getKnowledgeNodeIcon = (category: string) => {
|
||||||
return iconMap[category] || '🧠'
|
return iconMap[category] || '🧠'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getKnowledgeNodeType = (category: string) => {
|
const getKnowledgeNodeType = (category: string): 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary' => {
|
||||||
const typeMap: Record<string, string> = {
|
const typeMap: Record<string, 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary'> = {
|
||||||
tech_stack: 'success',
|
tech_stack: 'success',
|
||||||
competitor: 'error',
|
competitor: 'error',
|
||||||
market: 'info'
|
market: 'info'
|
||||||
|
|
@ -1163,13 +1165,13 @@ const getPriorityLabel = (priority: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Voting helpers
|
// Voting helpers
|
||||||
const getModelVoteType = (modelName: string, strategicInfo: any) => {
|
const getModelVoteType = (_modelName: string, strategicInfo: any) => {
|
||||||
// For now, since we don't have individual model results in the response,
|
// For now, since we don't have individual model results in the response,
|
||||||
// we'll return a default type. This could be enhanced if we send individual results.
|
// we'll return a default type. This could be enhanced if we send individual results.
|
||||||
return strategicInfo.is_strategic ? 'success' : 'default'
|
return strategicInfo.is_strategic ? 'success' : 'default'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getModelVoteLabel = (modelName: string, strategicInfo: any) => {
|
const getModelVoteLabel = (_modelName: string, strategicInfo: any) => {
|
||||||
// Similar to above, placeholder logic
|
// Similar to above, placeholder logic
|
||||||
return strategicInfo.is_strategic ? '战略级' : '非战略'
|
return strategicInfo.is_strategic ? '战略级' : '非战略'
|
||||||
}
|
}
|
||||||
|
|
@ -1617,7 +1619,6 @@ const checkOllamaStatus = async () => {
|
||||||
// 本地 Ollama
|
// 本地 Ollama
|
||||||
ollamaReady.value = data.status === 'ready'
|
ollamaReady.value = data.status === 'ready'
|
||||||
const modelCount = data.model_count || 0
|
const modelCount = data.model_count || 0
|
||||||
const models = data.available_models || []
|
|
||||||
|
|
||||||
if (ollamaReady.value) {
|
if (ollamaReady.value) {
|
||||||
message.success(`✅ Ollama 已就绪 (${modelCount} 个模型)`)
|
message.success(`✅ Ollama 已就绪 (${modelCount} 个模型)`)
|
||||||
|
|
@ -1651,7 +1652,7 @@ const startOllama = async () => {
|
||||||
} else {
|
} else {
|
||||||
message.error(response.data.message)
|
message.error(response.data.message)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
message.error('启动失败: ' + (error.response?.data?.detail || error.message))
|
message.error('启动失败: ' + (error.response?.data?.detail || error.message))
|
||||||
} finally {
|
} finally {
|
||||||
startingOllama.value = false
|
startingOllama.value = false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue