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)
|
||||
const titleMatch = content.match(/^#\s+(.*)/m)
|
||||
if (titleMatch) {
|
||||
if (titleMatch && titleMatch[1]) {
|
||||
title = titleMatch[1].trim()
|
||||
} else {
|
||||
const firstLine = lines.find(l => l.trim().length > 0)
|
||||
|
|
@ -136,12 +136,12 @@ const extractMetadata = (content: string) => {
|
|||
// Look for "Core Logic", "Architecture", "Introduction" headers
|
||||
const logicRegex = /##\s*(Core Logic|Architecture|Introduction|About|Features)([\s\S]*?)(##|$)/i
|
||||
const logicMatch = content.match(logicRegex)
|
||||
if (logicMatch) {
|
||||
if (logicMatch && logicMatch[2]) {
|
||||
coreLogic = logicMatch[2].trim().substring(0, 300) + (logicMatch[2].length > 300 ? '...' : '')
|
||||
} else {
|
||||
// Fallback: First paragraph after title
|
||||
const paragraphs = content.split(/\n\s*\n/)
|
||||
if (paragraphs.length > 1) {
|
||||
if (paragraphs.length > 1 && paragraphs[1]) {
|
||||
coreLogic = paragraphs[1].trim().substring(0, 200) + '...'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
</div>
|
||||
|
||||
<!-- 选中提供商说明 -->
|
||||
<div class="provider-info">
|
||||
<div class="provider-info" v-if="selectedProvider">
|
||||
<span class="provider-desc">{{ selectedProvider.desc }}</span>
|
||||
<span class="provider-pricing">{{ selectedProvider.pricing }}</span>
|
||||
</div>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<h2 class="section-title">连接配置</h2>
|
||||
|
||||
<!-- API 密钥配置 -->
|
||||
<div v-if="showApiKey" class="form-group">
|
||||
<div v-if="showApiKey && selectedProvider" class="form-group">
|
||||
<label class="form-label">API 密钥</label>
|
||||
<input
|
||||
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' })
|
||||
])
|
||||
|
||||
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 = [
|
||||
{ key: 'provider', label: '模型服务', icon: CloudIcon },
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
<div class="progress-comparison">
|
||||
<div class="progress-row">
|
||||
<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 class="progress-row">
|
||||
<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 class="lead-time-text" v-if="selectedSignal">
|
||||
{{ getLeadTimeText(selectedSignal) }}
|
||||
|
|
@ -134,18 +134,18 @@
|
|||
'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; align-items: center; gap: 6px;">
|
||||
<n-tag :type="getPriorityType(signal.latestSignal.priority)" size="small" round>
|
||||
{{ getPriorityLabel(signal.latestSignal.priority) }}
|
||||
<n-tag :type="getPriorityType(signal.latestSignal?.priority || 'medium')" size="small" round>
|
||||
{{ getPriorityLabel(signal.latestSignal?.priority || 'medium') }}
|
||||
</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>
|
||||
</div>
|
||||
<n-text depth="3" style="font-size: 12px;">{{ formatDate(signal.created_at) }}</n-text>
|
||||
</div>
|
||||
</template>
|
||||
</n-card-header>
|
||||
<n-text class="signal-content" :depth="1">{{ signal.content }}</n-text>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
|
|
@ -493,7 +493,7 @@
|
|||
:percentage="getTaskProgress(task)"
|
||||
:color="getTaskTypeColor(task.type, true)"
|
||||
rail-color="rgba(255,255,255,0.1)"
|
||||
height="4"
|
||||
:height="4"
|
||||
:show-indicator="false"
|
||||
style="margin-top: 8px;"
|
||||
:class="{ 'progress-pulse': taskExecuting }"
|
||||
|
|
@ -543,7 +543,7 @@
|
|||
<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-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>
|
||||
<template #footer>
|
||||
<n-button type="primary" block @click="saveCompetitors">
|
||||
|
|
@ -573,11 +573,11 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, reactive, watch, nextTick, computed } from 'vue'
|
||||
import { ref, onMounted, onUnmounted, reactive, watch, computed } from 'vue'
|
||||
import {
|
||||
NLayout, NLayoutSider, NLayoutContent, NSpace, NCard, NButton, NList, NListItem, NTag, NText,
|
||||
NGrid, NGridItem, NDivider, NResult, NCheckbox, NThing, NScrollbar, NSpin, NModal, NForm, NFormItem,
|
||||
NInput, useMessage, NEmpty, NProgress, NIcon, NSteps, NStep, NStatistic
|
||||
NGrid, NGridItem, NScrollbar, NSpin, NModal, NForm, NFormItem,
|
||||
NInput, useMessage, NProgress, NIcon, NSteps, NStep, NStatistic, NCardHeader
|
||||
} from 'naive-ui'
|
||||
import axios from 'axios'
|
||||
import VChart from 'vue-echarts'
|
||||
|
|
@ -859,12 +859,14 @@ const factSnippets: Record<string, { title: string; source: string; content: str
|
|||
|
||||
const showFactSnippetModal = (type: string) => {
|
||||
const snippet = factSnippets[type] || factSnippets['Whitepaper']
|
||||
if (snippet) {
|
||||
currentFactSnippet.value = {
|
||||
title: snippet.title,
|
||||
source: snippet.source,
|
||||
content: snippet.content
|
||||
}
|
||||
showFactSnippet.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// --- Logic ---
|
||||
|
|
@ -947,8 +949,8 @@ const getRelatedKnowledgeNodes = () => {
|
|||
return Array.isArray(knowledgeNodes) ? knowledgeNodes : []
|
||||
}
|
||||
|
||||
const getTechStackType = (category: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
const getTechStackType = (category: string): 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary' => {
|
||||
const typeMap: Record<string, 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary'> = {
|
||||
framework: 'success',
|
||||
model: 'error',
|
||||
tool: 'info',
|
||||
|
|
@ -994,8 +996,8 @@ const getKnowledgeNodeIcon = (category: string) => {
|
|||
return iconMap[category] || '🧠'
|
||||
}
|
||||
|
||||
const getKnowledgeNodeType = (category: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
const getKnowledgeNodeType = (category: string): 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary' => {
|
||||
const typeMap: Record<string, 'default' | 'error' | 'success' | 'warning' | 'info' | 'primary'> = {
|
||||
tech_stack: 'success',
|
||||
competitor: 'error',
|
||||
market: 'info'
|
||||
|
|
@ -1163,13 +1165,13 @@ const getPriorityLabel = (priority: string) => {
|
|||
}
|
||||
|
||||
// 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,
|
||||
// we'll return a default type. This could be enhanced if we send individual results.
|
||||
return strategicInfo.is_strategic ? 'success' : 'default'
|
||||
}
|
||||
|
||||
const getModelVoteLabel = (modelName: string, strategicInfo: any) => {
|
||||
const getModelVoteLabel = (_modelName: string, strategicInfo: any) => {
|
||||
// Similar to above, placeholder logic
|
||||
return strategicInfo.is_strategic ? '战略级' : '非战略'
|
||||
}
|
||||
|
|
@ -1617,7 +1619,6 @@ const checkOllamaStatus = async () => {
|
|||
// 本地 Ollama
|
||||
ollamaReady.value = data.status === 'ready'
|
||||
const modelCount = data.model_count || 0
|
||||
const models = data.available_models || []
|
||||
|
||||
if (ollamaReady.value) {
|
||||
message.success(`✅ Ollama 已就绪 (${modelCount} 个模型)`)
|
||||
|
|
@ -1651,7 +1652,7 @@ const startOllama = async () => {
|
|||
} else {
|
||||
message.error(response.data.message)
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
message.error('启动失败: ' + (error.response?.data?.detail || error.message))
|
||||
} finally {
|
||||
startingOllama.value = false
|
||||
|
|
|
|||
Loading…
Reference in New Issue