From fd233ae7aa2327c396cc2192b679c17aead3e4ac Mon Sep 17 00:00:00 2001 From: ulleo Date: Thu, 30 Jul 2026 16:51:51 +0800 Subject: [PATCH] feat: optimize chat list sorting --- backend/apps/chat/api/chat.py | 4 +-- backend/apps/chat/curd/chat.py | 34 +++++++++++++++++++++++--- backend/apps/chat/models/chat_model.py | 17 +++++++++++++ frontend/src/api/chat.ts | 9 +++++++ frontend/src/views/chat/ChatList.vue | 6 ++--- 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/backend/apps/chat/api/chat.py b/backend/apps/chat/api/chat.py index 8a2bed721..c063f344b 100644 --- a/backend/apps/chat/api/chat.py +++ b/backend/apps/chat/api/chat.py @@ -16,7 +16,7 @@ format_json_data, format_json_list_data, get_chart_config, list_recent_questions, rename_chat_with_user, \ get_chat_log_history, get_chart_data_with_user_live from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, AxisObj, QuickCommand, \ - ChatInfo, Chat, ChatFinishStep, ChatQuestionBase, SimpleChat + ChatInfo, Chat, ChatFinishStep, ChatQuestionBase, SimpleChat, ChatItem from apps.chat.task.llm import LLMService from apps.swagger.i18n import PLACEHOLDER_PREFIX from apps.system.schemas.permission import SqlbotPermission, require_permissions @@ -29,7 +29,7 @@ router = APIRouter(tags=["Data Q&A"], prefix="/chat") -@router.get("/list", response_model=List[Chat], summary=f"{PLACEHOLDER_PREFIX}get_chat_list") +@router.get("/list", response_model=List[ChatItem], summary=f"{PLACEHOLDER_PREFIX}get_chat_list") async def chats(session: SessionDep, current_user: CurrentUser): return list_chats(session, current_user) diff --git a/backend/apps/chat/curd/chat.py b/backend/apps/chat/curd/chat.py index e261c2b6f..292a3d5cf 100644 --- a/backend/apps/chat/curd/chat.py +++ b/backend/apps/chat/curd/chat.py @@ -9,7 +9,7 @@ from sqlalchemy.orm import aliased from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion, ChatLog, \ - TypeEnum, OperationEnum, ChatRecordResult, ChatLogHistory, ChatLogHistoryItem + TypeEnum, OperationEnum, ChatRecordResult, ChatLogHistory, ChatLogHistoryItem, ChatItem from apps.datasource.crud.datasource import get_ds from apps.datasource.crud.recommended_problem import get_datasource_recommended_chart from apps.datasource.models.datasource import CoreDatasource @@ -41,10 +41,31 @@ def get_chat(session: SessionDep, chat_id: int) -> Chat: return chat -def list_chats(session: SessionDep, current_user: CurrentUser) -> List[Chat]: +def list_chats(session: SessionDep, current_user: CurrentUser) -> List[ChatItem]: oid = current_user.oid if current_user.oid is not None else 1 - chart_list = session.query(Chat).filter(and_(Chat.create_by == current_user.id, Chat.oid == oid)).order_by( - Chat.create_time.desc()).all() + # 子查询:获取每个chat对应的最新chat_record的create_time + latest_record_subq = ( + session.query( + ChatRecord.chat_id, + func.max(ChatRecord.create_time).label('latest_record_time') + ) + .group_by(ChatRecord.chat_id) + .subquery() + ) + # 按最新chat_record的create_time排序,如果没有chat_record则使用chat自身的create_time + sort_time = func.coalesce(latest_record_subq.c.latest_record_time, Chat.create_time) + results = ( + session.query(Chat, sort_time.label('latest_record_time')) + .outerjoin(latest_record_subq, Chat.id == latest_record_subq.c.chat_id) + .filter(and_(Chat.create_by == current_user.id, Chat.oid == oid)) + .order_by(sort_time.desc()) + .all() + ) + chart_list = [] + for chat, latest_record_time in results: + item = ChatItem(**chat.model_dump()) + item.latest_record_time = latest_record_time + chart_list.append(item) return chart_list @@ -476,6 +497,11 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr chat_info.records = result + # 从已查出的records中取最新的create_time + record_times = [r.get('create_time') for r in result if r.get('create_time') is not None] + if record_times: + chat_info.latest_record_time = max(record_times) + return chat_info diff --git a/backend/apps/chat/models/chat_model.py b/backend/apps/chat/models/chat_model.py index 6e550afb5..f169cfb17 100644 --- a/backend/apps/chat/models/chat_model.py +++ b/backend/apps/chat/models/chat_model.py @@ -179,6 +179,22 @@ class SimpleChat(BaseModel): id: int = None brief: str = '' +class ChatItem(BaseModel): + id: Optional[int] = None + oid: Optional[int] = None + create_time: Optional[datetime] = None + create_by: Optional[int] = None + brief: Optional[str] = None + chat_type: Optional[str] = "chat" + datasource: Optional[int] = None + engine_type: Optional[str] = None + origin: Optional[int] = 0 + brief_generate: Optional[bool] = False + recommended_question_answer: Optional[str] = None + recommended_question: Optional[str] = None + recommended_generate: Optional[bool] = False + latest_record_time: Optional[datetime] = None + class ChatInfo(BaseModel): id: Optional[int] = None create_time: datetime = None @@ -192,6 +208,7 @@ class ChatInfo(BaseModel): datasource_exists: bool = True recommended_question: Optional[str] = None recommended_generate: Optional[bool] = False + latest_record_time: Optional[datetime] = None records: List[ChatRecord | dict] = [] diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index 4a52187ee..0b7527444 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -148,6 +148,7 @@ export class ChatRecord { export class Chat { id?: number create_time?: Date | string + latest_record_time?: Date | string create_by?: number brief?: string chat_type?: string @@ -161,6 +162,7 @@ export class Chat { constructor( id: number, create_time: Date | string, + latest_record_time: Date | string, create_by: number, brief: string, chat_type: string, @@ -170,6 +172,7 @@ export class Chat { constructor( id?: number, create_time?: Date | string, + latest_record_time?: Date | string, create_by?: number, brief?: string, chat_type?: string, @@ -178,6 +181,7 @@ export class Chat { ) { this.id = id this.create_time = getDate(create_time) + this.latest_record_time = getDate(latest_record_time ?? create_time) this.create_by = create_by this.brief = brief this.chat_type = chat_type @@ -196,6 +200,7 @@ export class ChatInfo extends Chat { constructor( id: number, create_time: Date | string, + latest_record_time: Date | string, create_by: number, brief: string, chat_type: string, @@ -211,6 +216,7 @@ export class ChatInfo extends Chat { constructor( param1?: number | Chat, create_time?: Date | string, + latest_record_time?: Date | string, create_by?: number, brief?: string, chat_type?: string, @@ -228,6 +234,7 @@ export class ChatInfo extends Chat { if (param1 instanceof Chat) { this.id = param1.id this.create_time = getDate(param1.create_time) + this.latest_record_time = getDate(param1.latest_record_time ?? param1.create_time) this.create_by = param1.create_by this.brief = param1.brief this.chat_type = param1.chat_type @@ -239,6 +246,7 @@ export class ChatInfo extends Chat { } else { this.id = param1 this.create_time = getDate(create_time) + this.latest_record_time = getDate(latest_record_time ?? create_time) this.create_by = create_by this.brief = brief this.chat_type = chat_type @@ -408,6 +416,7 @@ export const chatApi = { return new ChatInfo( data.id, data.create_time, + data.latest_record_time, data.create_by, data.brief, data.chat_type, diff --git a/frontend/src/views/chat/ChatList.vue b/frontend/src/views/chat/ChatList.vue index 33799afc5..f98d7b98a 100644 --- a/frontend/src/views/chat/ChatList.vue +++ b/frontend/src/views/chat/ChatList.vue @@ -3,7 +3,7 @@ import icon_more_outlined from '@/assets/svg/icon_more_outlined.svg' import icon_expand_down_filled from '@/assets/embedded/icon_expand-down_filled.svg' import rename from '@/assets/svg/icon_rename_outlined.svg' import delIcon from '@/assets/svg/icon_delete.svg' -import { type Chat, chatApi } from '@/api/chat.ts' +import { type Chat, chatApi, ChatInfo } from '@/api/chat.ts' import { computed, reactive, ref } from 'vue' import dayjs from 'dayjs' import { getDate } from '@/utils/utils.ts' @@ -13,7 +13,7 @@ import { useI18n } from 'vue-i18n' const props = withDefaults( defineProps<{ currentChatId?: number - chatList: Array + chatList: Array loading?: boolean }>(), { @@ -30,7 +30,7 @@ function groupByDate(chat: Chat) { const todayEnd = dayjs(dayjs().format('YYYY-MM-DD') + ' 23:59:59').toDate() const weekStart = dayjs(dayjs().subtract(7, 'day').format('YYYY-MM-DD') + ' 00:00:00').toDate() - const time = getDate(chat.create_time) + const time = getDate(chat.latest_record_time ?? chat.create_time) if (time) { if (time >= todayStart && time <= todayEnd) {