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 `