캐릭터 챗봇 #338

Merged
klaus merged 119 commits from test into main 2025-09-10 06:08:47 +00:00
3 changed files with 36 additions and 6 deletions
Showing only changes of commit f2ca013b96 - Show all commits

View File

@ -2,6 +2,8 @@ package kr.co.vividnext.sodalive.chat.room.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import kr.co.vividnext.sodalive.chat.character.CharacterType
import java.time.LocalDateTime
/** /**
* 채팅방 생성 요청 DTO * 채팅방 생성 요청 DTO
@ -24,7 +26,9 @@ data class ChatRoomListItemDto(
val chatRoomId: Long, val chatRoomId: Long,
val title: String, val title: String,
val imageUrl: String, val imageUrl: String,
val lastMessagePreview: String? val opponentType: String,
val lastMessagePreview: String?,
val lastMessageTimeLabel: String
) )
/** /**
@ -40,10 +44,13 @@ data class ChatMessageItemDto(
/** /**
* 채팅방 목록 쿼리 DTO (레포지토리 투영용) * 채팅방 목록 쿼리 DTO (레포지토리 투영용)
*/ */
data class ChatRoomListQueryDto( data class ChatRoomListQueryDto(
val chatRoomId: Long, val chatRoomId: Long,
val title: String, val title: String,
val imagePath: String? val imagePath: String?,
val characterType: CharacterType,
val lastActivityAt: LocalDateTime?
) )
/** /**

View File

@ -40,7 +40,9 @@ interface ChatRoomRepository : JpaRepository<ChatRoom, Long> {
SELECT new kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListQueryDto( SELECT new kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListQueryDto(
r.id, r.id,
r.title, r.title,
pc.character.imagePath pc.character.imagePath,
pc.character.characterType,
COALESCE(MAX(m.createdAt), r.createdAt)
) )
FROM ChatRoom r FROM ChatRoom r
JOIN r.participants p JOIN r.participants p

View File

@ -199,18 +199,39 @@ class ChatRoomService(
val latest = messageRepository.findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(room) val latest = messageRepository.findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(room)
val preview = latest?.message?.let { msg -> val preview = latest?.message?.let { msg ->
if (msg.length <= 25) msg else msg.take(25) + "..." if (msg.length <= 30) msg else msg.take(30) + "..."
} }
val imageUrl = "$imageHost/${q.imagePath ?: "profile/default-profile.png"}"
val opponentType = q.characterType.name // Clone or Character
val time = latest?.createdAt ?: q.lastActivityAt
val timeLabel = formatRelativeTime(time)
ChatRoomListItemDto( ChatRoomListItemDto(
chatRoomId = q.chatRoomId, chatRoomId = q.chatRoomId,
title = q.title, title = q.title,
imageUrl = "$imageHost/${q.imagePath ?: "profile/default-profile.png"}", imageUrl = imageUrl,
lastMessagePreview = preview opponentType = opponentType,
lastMessagePreview = preview,
lastMessageTimeLabel = timeLabel
) )
} }
} }
private fun formatRelativeTime(time: java.time.LocalDateTime?): String {
if (time == null) return ""
val now = java.time.LocalDateTime.now()
val duration = java.time.Duration.between(time, now)
val seconds = duration.seconds
if (seconds <= 60) return "방금"
val minutes = duration.toMinutes()
if (minutes < 60) return "${'$'}minutes분 전"
val hours = duration.toHours()
if (hours < 24) return "${'$'}hours시간 전"
// 그 외: 날짜 (yyyy-MM-dd)
return time.toLocalDate().toString()
}
@Transactional(readOnly = true) @Transactional(readOnly = true)
fun isMyRoomSessionActive(member: Member, chatRoomId: Long): Boolean { fun isMyRoomSessionActive(member: Member, chatRoomId: Long): Boolean {
val room = chatRoomRepository.findById(chatRoomId).orElseThrow { val room = chatRoomRepository.findById(chatRoomId).orElseThrow {