From 1cfd4f36ae58f2d67978930998b06a87ce3c6fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Sun, 21 Dec 2025 13:47:52 +0800 Subject: [PATCH] Add files via upload --- internal/knowledge/manager.go | 84 +++++++++++++++++++++++++++++------ internal/knowledge/types.go | 45 +++++++++++++++---- web/static/js/knowledge.js | 31 ++++++++++--- 3 files changed, 131 insertions(+), 29 deletions(-) diff --git a/internal/knowledge/manager.go b/internal/knowledge/manager.go index e62c9143..bebfc4eb 100644 --- a/internal/knowledge/manager.go +++ b/internal/knowledge/manager.go @@ -160,14 +160,42 @@ func (m *Manager) GetItems(category string) ([]*KnowledgeItem, error) { return nil, fmt.Errorf("扫描知识项失败: %w", err) } - // 解析时间 - item.CreatedAt, _ = time.Parse("2006-01-02 15:04:05.999999999-07:00", createdAt) - if item.CreatedAt.IsZero() { - item.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) + // 解析时间 - 支持多种格式 + timeFormats := []string{ + "2006-01-02 15:04:05.999999999-07:00", + "2006-01-02 15:04:05.999999999", + "2006-01-02T15:04:05.999999999Z07:00", + "2006-01-02T15:04:05Z", + "2006-01-02 15:04:05", + time.RFC3339, + time.RFC3339Nano, } - item.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05.999999999-07:00", updatedAt) - if item.UpdatedAt.IsZero() { - item.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) + + // 解析创建时间 + if createdAt != "" { + for _, format := range timeFormats { + parsed, err := time.Parse(format, createdAt) + if err == nil && !parsed.IsZero() { + item.CreatedAt = parsed + break + } + } + } + + // 解析更新时间 + if updatedAt != "" { + for _, format := range timeFormats { + parsed, err := time.Parse(format, updatedAt) + if err == nil && !parsed.IsZero() { + item.UpdatedAt = parsed + break + } + } + } + + // 如果更新时间为空,使用创建时间 + if item.UpdatedAt.IsZero() && !item.CreatedAt.IsZero() { + item.UpdatedAt = item.CreatedAt } items = append(items, item) @@ -192,14 +220,42 @@ func (m *Manager) GetItem(id string) (*KnowledgeItem, error) { return nil, fmt.Errorf("查询知识项失败: %w", err) } - // 解析时间 - item.CreatedAt, _ = time.Parse("2006-01-02 15:04:05.999999999-07:00", createdAt) - if item.CreatedAt.IsZero() { - item.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) + // 解析时间 - 支持多种格式 + timeFormats := []string{ + "2006-01-02 15:04:05.999999999-07:00", + "2006-01-02 15:04:05.999999999", + "2006-01-02T15:04:05.999999999Z07:00", + "2006-01-02T15:04:05Z", + "2006-01-02 15:04:05", + time.RFC3339, + time.RFC3339Nano, } - item.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05.999999999-07:00", updatedAt) - if item.UpdatedAt.IsZero() { - item.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) + + // 解析创建时间 + if createdAt != "" { + for _, format := range timeFormats { + parsed, err := time.Parse(format, createdAt) + if err == nil && !parsed.IsZero() { + item.CreatedAt = parsed + break + } + } + } + + // 解析更新时间 + if updatedAt != "" { + for _, format := range timeFormats { + parsed, err := time.Parse(format, updatedAt) + if err == nil && !parsed.IsZero() { + item.UpdatedAt = parsed + break + } + } + } + + // 如果更新时间为空,使用创建时间 + if item.UpdatedAt.IsZero() && !item.CreatedAt.IsZero() { + item.UpdatedAt = item.CreatedAt } return item, nil diff --git a/internal/knowledge/types.go b/internal/knowledge/types.go index 6608f1e7..53b54444 100644 --- a/internal/knowledge/types.go +++ b/internal/knowledge/types.go @@ -8,14 +8,42 @@ import ( // KnowledgeItem 知识库项 type KnowledgeItem struct { ID string `json:"id"` - Category string `json:"category"` // 风险类型(文件夹名) - Title string `json:"title"` // 标题(文件名) - FilePath string `json:"filePath"` // 文件路径 - Content string `json:"content"` // 文件内容 + Category string `json:"category"` // 风险类型(文件夹名) + Title string `json:"title"` // 标题(文件名) + FilePath string `json:"filePath"` // 文件路径 + Content string `json:"content"` // 文件内容 CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } +// MarshalJSON 自定义JSON序列化,确保时间格式正确 +func (k *KnowledgeItem) MarshalJSON() ([]byte, error) { + type Alias KnowledgeItem + aux := &struct { + *Alias + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` + }{ + Alias: (*Alias)(k), + } + + // 格式化创建时间 + if k.CreatedAt.IsZero() { + aux.CreatedAt = "" + } else { + aux.CreatedAt = k.CreatedAt.Format(time.RFC3339) + } + + // 格式化更新时间 + if k.UpdatedAt.IsZero() { + aux.UpdatedAt = "" + } else { + aux.UpdatedAt = k.UpdatedAt.Format(time.RFC3339) + } + + return json.Marshal(aux) +} + // KnowledgeChunk 知识块(用于向量化) type KnowledgeChunk struct { ID string `json:"id"` @@ -23,7 +51,7 @@ type KnowledgeChunk struct { ChunkIndex int `json:"chunkIndex"` ChunkText string `json:"chunkText"` Embedding []float32 `json:"-"` // 向量嵌入,不序列化到JSON - CreatedAt time.Time `json:"createdAt"` + CreatedAt time.Time `json:"createdAt"` } // RetrievalResult 检索结果 @@ -59,9 +87,8 @@ func (r *RetrievalLog) MarshalJSON() ([]byte, error) { // SearchRequest 搜索请求 type SearchRequest struct { - Query string `json:"query"` - RiskType string `json:"riskType,omitempty"` // 可选:指定风险类型 - TopK int `json:"topK,omitempty"` // 返回Top-K结果,默认5 + Query string `json:"query"` + RiskType string `json:"riskType,omitempty"` // 可选:指定风险类型 + TopK int `json:"topK,omitempty"` // 返回Top-K结果,默认5 Threshold float64 `json:"threshold,omitempty"` // 相似度阈值,默认0.7 } - diff --git a/web/static/js/knowledge.js b/web/static/js/knowledge.js index 6926ebca..f01be7ee 100644 --- a/web/static/js/knowledge.js +++ b/web/static/js/knowledge.js @@ -154,7 +154,19 @@ function renderKnowledgeItemCard(item) { // 格式化时间 const createdTime = formatTime(item.createdAt); const updatedTime = formatTime(item.updatedAt); - const isRecent = item.updatedAt && (Date.now() - new Date(item.updatedAt).getTime()) < 7 * 24 * 60 * 60 * 1000; + + // 优先显示更新时间,如果没有更新时间则显示创建时间 + const displayTime = updatedTime || createdTime; + const timeLabel = updatedTime ? '更新时间' : '创建时间'; + + // 判断是否为最近更新(7天内) + let isRecent = false; + if (item.updatedAt && updatedTime) { + const updateDate = new Date(item.updatedAt); + if (!isNaN(updateDate.getTime())) { + isRecent = (Date.now() - updateDate.getTime()) < 7 * 24 * 60 * 60 * 1000; + } + } return `
@@ -182,10 +194,9 @@ function renderKnowledgeItemCard(item) {
`; @@ -1483,17 +1494,25 @@ function formatTime(timeStr) { date = new Date(timeStr); } - // 如果日期无效,返回原始字符串 + // 如果日期无效,检查是否是零值时间 if (isNaN(date.getTime())) { + // 检查是否是零值时间的字符串形式 + if (typeof timeStr === 'string' && (timeStr.includes('0001-01-01') || timeStr.startsWith('0001'))) { + return ''; + } console.warn('无法解析时间:', timeStr); - return timeStr; + return ''; } // 检查日期是否合理(不在1970年之前,不在未来太远) const year = date.getFullYear(); if (year < 1970 || year > 2100) { + // 如果是零值时间(0001-01-01),返回空字符串,不显示 + if (year === 1) { + return ''; + } console.warn('时间值不合理:', timeStr, '解析为:', date); - return timeStr; + return ''; } return date.toLocaleString('zh-CN', {