♻️ refactor(im): 业务策略数值从 ImCommonConstants 上移到 ImProperties(按 group / message 子模块分组),常量类仅保留 AT_USER_ID_ALL 协议契约值

♻️ refactor(im): 抽出 utils/config.ts 集中数值常量,按业务域统一前缀(GROUP_ / MESSAGE_ / FRIEND_ / CONVERSATION_ / FORWARD_),constants.ts 只留协议枚举与契约值
im
YunaiV 2026-05-08 17:42:13 +08:00
parent dfd5b39a17
commit c5b082ca80
10 changed files with 83 additions and 59 deletions

View File

@ -34,7 +34,7 @@ import { ref } from 'vue'
import { useMessage } from '@/hooks/web/useMessage'
import { addGroupAdmin, removeGroupAdmin } from '@/api/im/group'
import { GROUP_ADMIN_MAX_COUNT } from '@/views/im/utils/constants'
import { GROUP_ADMIN_MAX_COUNT } from '@/views/im/utils/config'
import GroupMemberPickerPanel from '../picker/GroupMemberPickerPanel.vue'
import type { GroupMemberLite } from './GroupMember.vue'

View File

@ -16,11 +16,10 @@ import {
import {
ImConversationType,
ImMessageType,
PRIVATE_MESSAGE_PULL_SIZE,
GROUP_MESSAGE_PULL_SIZE,
isFriendChatTip,
isFriendNotification
} from '../../utils/constants'
import { MESSAGE_PRIVATE_PULL_SIZE, MESSAGE_GROUP_PULL_SIZE } from '../../utils/config'
import { useUserStore } from '@/store/modules/user'
import type { Message } from '../types'
@ -109,7 +108,7 @@ export const useMessagePuller = () => {
// 私聊 / 群聊各自一套接口和分页大小,按 isPrivate 在循环内分支调度
let minId = startMinId || 0
const isPrivate = conversationType === ImConversationType.PRIVATE
const size = isPrivate ? PRIVATE_MESSAGE_PULL_SIZE : GROUP_MESSAGE_PULL_SIZE
const size = isPrivate ? MESSAGE_PRIVATE_PULL_SIZE : MESSAGE_GROUP_PULL_SIZE
while (true) {
const list = isPrivate
? await apiPullPrivateMessages({ minId, size })

View File

@ -164,7 +164,8 @@ import Icon from '@/components/Icon/src/Icon.vue'
import { formatFileSize } from '@/utils/file'
import { formatSeconds } from '@/utils/formatTime'
import { ImMessageType, MERGE_FORWARD_PREVIEW_LINES } from '@/views/im/utils/constants'
import { ImMessageType } from '@/views/im/utils/constants'
import { MESSAGE_MERGE_PREVIEW_LINES } from '@/views/im/utils/config'
import {
parseMessage,
parseTextSegments,
@ -259,7 +260,7 @@ const mergePreviewLines = computed(() => {
return []
}
return mergePayload.value.messages
.slice(0, MERGE_FORWARD_PREVIEW_LINES)
.slice(0, MESSAGE_MERGE_PREVIEW_LINES)
.map((item) => `${item.senderNickname}${summarizeMessageContent(item)}`)
})

View File

@ -163,12 +163,12 @@ import {
ImConversationType,
ImFriendAddSource,
ImGroupMemberRole,
TIME_TIP_GAP_MS,
isFriendChatTip,
isGroupNotification,
isMediaMessageType,
isNormalMessage
} from '@/views/im/utils/constants'
import { MESSAGE_TIME_TIP_GAP_MS, MESSAGE_RECALL_WINDOW_MS } from '@/views/im/utils/config'
import { pinGroupMessage as apiPinGroupMessage, cancelMuteMember } from '@/api/im/group'
import { removeGroupMember } from '@/api/im/group/member'
import {
@ -254,7 +254,7 @@ const shouldShowTimeTip = computed(() => {
if (!props.prevMessage?.sendTime) {
return true
}
return props.message.sendTime - props.prevMessage.sendTime > TIME_TIP_GAP_MS
return props.message.sendTime - props.prevMessage.sendTime > MESSAGE_TIME_TIP_GAP_MS
})
/** 仅 MessageItem 自身仍要用到的 type 判定(其它分支已下沉到 MessageBubble */
@ -477,9 +477,6 @@ const MENU_KEYS = {
} as const
type MenuKey = (typeof MENU_KEYS)[keyof typeof MENU_KEYS]
/** 撤回时间窗:自己发送的消息超过这个时长就不能再撤回,菜单回退为「删除」(对齐微信 2 分钟) */
const RECALL_WINDOW_MS = 2 * 60 * 1000
/**
* 右键菜单项
* - 引用已落库id0+ 未撤回的消息可引用引用块写入 draftStore.reply
@ -589,7 +586,7 @@ async function handleContextMenu(e: MouseEvent) {
props.message.selfSend &&
!!props.message.id &&
!isRecall.value &&
Date.now() - props.message.sendTime <= RECALL_WINDOW_MS
Date.now() - props.message.sendTime <= MESSAGE_RECALL_WINDOW_MS
if (canRecall) {
items.push({
key: MENU_KEYS.RECALL,

View File

@ -162,9 +162,9 @@ import {
ImConversationType,
ImForwardMode,
ImMessageType,
MERGE_FORWARD_PREVIEW_LINES,
type ImForwardModeValue
} from '@/views/im/utils/constants'
import { MESSAGE_MERGE_PREVIEW_LINES } from '@/views/im/utils/config'
import { getConversationKey, summarizeMessageContent } from '@/views/im/utils/conversation'
import { buildDefaultGroupName } from '@/views/im/utils/group'
import {
@ -271,14 +271,14 @@ const mergePreview = computed(() => {
return null
}
const lines = payload.messages
.slice(0, MERGE_FORWARD_PREVIEW_LINES)
.slice(0, MESSAGE_MERGE_PREVIEW_LINES)
.map((item) => `${item.senderNickname}${summarizeMessageContent(item)}`)
return { title: payload.title, lines }
})
/** 逐条模式预览:取前 N 条摘要 */
const singlePreviewLines = computed(() =>
state.messages.slice(0, MERGE_FORWARD_PREVIEW_LINES).map((m) => summarizeMessageContent(m))
state.messages.slice(0, MESSAGE_MERGE_PREVIEW_LINES).map((m) => summarizeMessageContent(m))
)
/** 待发送的逐条消息:剥离 quote 一次,发送多目标时复用 */

View File

@ -7,11 +7,11 @@ import {
ImMessageType,
ImMessageStatus,
IM_AT_ALL_USER_ID,
RECENT_FORWARD_MAX,
isGroupNotification,
isMediaMessageType,
isNormalMessage
} from '../../utils/constants'
import { CONVERSATION_RECENT_FORWARD_MAX } from '../../utils/config'
import { getCurrentUserId, imStorage, removeQuietly, StorageKeys } from '../../utils/storage'
import { parseRecallMessageId, revokeBlobUrlsInContent } from '../../utils/message'
import { resolveConversationLastContent } from '../../utils/conversation'
@ -126,7 +126,7 @@ export const useConversationStore = defineStore('imConversationStore', {
privateMessageMaxId: 0, // 私聊最大消息 id作为 pull 的游标
groupMessageMaxId: 0, // 群聊最大消息 id作为 pull 的游标
loading: false, // 是否正在批量加载(例如离线消息拉取期间),避免频繁写存储
recentForwardConversationKeys: [] as string[] // 最近转发会话 key 列表(按推送顺序倒序,最大 RECENT_FORWARD_MAX 个)
recentForwardConversationKeys: [] as string[] // 最近转发会话 key 列表(按推送顺序倒序,最大 CONVERSATION_RECENT_FORWARD_MAX 个)
}),
getters: {
@ -188,7 +188,7 @@ export const useConversationStore = defineStore('imConversationStore', {
])
// 缺数据时显式赋空,避免切账号后沿用上一个用户的内存列表
this.recentForwardConversationKeys = Array.isArray(recent)
? recent.slice(0, RECENT_FORWARD_MAX)
? recent.slice(0, CONVERSATION_RECENT_FORWARD_MAX)
: []
if (!meta) {
return
@ -812,7 +812,7 @@ export const useConversationStore = defineStore('imConversationStore', {
// ==================== 最近转发 ====================
/**
* key + + RECENT_FORWARD_MAX
* key + + CONVERSATION_RECENT_FORWARD_MAX
*
* RecommendCardDialog / MessageForwardDialog keys
*/
@ -823,7 +823,7 @@ export const useConversationStore = defineStore('imConversationStore', {
const merged = [...keys, ...this.recentForwardConversationKeys]
this.recentForwardConversationKeys = Array.from(new Set(merged)).slice(
0,
RECENT_FORWARD_MAX
CONVERSATION_RECENT_FORWARD_MAX
)
this.persistRecentForwardConversationKeys()
},

View File

@ -21,11 +21,8 @@ import {
type ImFriendRequestRespVO
} from '@/api/im/friend/request'
import { useConversationStore } from './conversationStore'
import {
FRIEND_REQUEST_PAGE_SIZE,
ImConversationType,
ImFriendRequestHandleResult
} from '../../utils/constants'
import { ImConversationType, ImFriendRequestHandleResult } from '../../utils/constants'
import { FRIEND_REQUEST_PAGE_SIZE } from '../../utils/config'
import { getCurrentUserId, imStorage, setQuietly, StorageKeys } from '../../utils/storage'
import { getFriendDisplayName } from '../../utils/user'
import type { Friend, FriendLite, FriendRequest } from '../types'

View File

@ -128,12 +128,8 @@ import { computed } from 'vue'
import Icon from '@/components/Icon/src/Icon.vue'
import { formatFileSize } from '@/utils/file'
import { formatSeconds } from '@/utils/formatTime'
import {
ImMessageType,
MERGE_FORWARD_PREVIEW_LINES,
isFriendChatTip,
isGroupNotification
} from '@/views/im/utils/constants'
import { ImMessageType, isFriendChatTip, isGroupNotification } from '@/views/im/utils/constants'
import { MESSAGE_MERGE_PREVIEW_LINES } from '@/views/im/utils/config'
import CardLineLabel from '@/views/im/home/components/card/CardLineLabel.vue'
import {
parseMessage,
@ -207,7 +203,7 @@ const mergePreviewLines = computed(() => {
return []
}
return mergePayload.value.messages
.slice(0, MERGE_FORWARD_PREVIEW_LINES)
.slice(0, MESSAGE_MERGE_PREVIEW_LINES)
.map((item) => `${item.senderNickname}${summarizeMessageContent(item)}`)
})

View File

@ -0,0 +1,61 @@
/**
* IM / UI
*
* constants.ts
* - constants.ts enum + IM_AT_ALL_USER_ID
* - config.ts ImProperties UI
*
* yudao.im.*
*/
// ==================== 后端镜像(与 ImProperties 默认值对齐) ====================
/** 群最大成员人数(对齐 yudao.im.group.max-member */
export const GROUP_MAX_MEMBER = 500
/** 单群管理员人数上限(对齐 yudao.im.group.admin-max-count */
export const GROUP_ADMIN_MAX_COUNT = 3
/** 单群置顶消息条数上限(对齐 yudao.im.group.pin-max-count */
export const GROUP_PIN_MAX_COUNT = 5
/** 消息撤回时间限制(分钟,对齐 yudao.im.message.recall-timeout-minutes */
export const MESSAGE_RECALL_TIMEOUT_MINUTES = 5
/** 私聊离线消息最大拉取天数(对齐 yudao.im.message.private-pull-max-days */
export const MESSAGE_PRIVATE_PULL_MAX_DAYS = 30
/** 群聊离线消息最大拉取天数(对齐 yudao.im.message.group-pull-max-days */
export const MESSAGE_GROUP_PULL_MAX_DAYS = 30
// ==================== 前端独有:拉取 / 分页 ====================
/** 每次拉取私聊消息的最大条数(后端上限 1000前端取保守值 100 */
export const MESSAGE_PRIVATE_PULL_SIZE = 100
/** 每次拉取群聊消息的最大条数(后端上限 1000前端取保守值 100 */
export const MESSAGE_GROUP_PULL_SIZE = 100
/** 「我相关」好友申请列表的单次拉取条数(游标分页 page size */
export const FRIEND_REQUEST_PAGE_SIZE = 100
/** 「我相关」加群申请列表的单次拉取条数 */
export const GROUP_REQUEST_PAGE_SIZE = 100
// ==================== 前端独有UI 阈值 ====================
/** 消息之间渲染「时间分隔条」的阈值10 分钟 */
export const MESSAGE_TIME_TIP_GAP_MS = 10 * 60 * 1000
/**
* 退
*
* MESSAGE_RECALL_TIMEOUT_MINUTES5 PC 2
*/
export const MESSAGE_RECALL_WINDOW_MS = 2 * 60 * 1000
/** 合并转发消息MERGE 类型)气泡内预览的最大行数(对齐微信「聊天记录」气泡) */
export const MESSAGE_MERGE_PREVIEW_LINES = 3
/** 最近转发会话 key 列表的最大保留数量(对齐微信 PC 横向头像区可见容量) */
export const CONVERSATION_RECENT_FORWARD_MAX = 12

View File

@ -202,27 +202,6 @@ export const ImFriendRequestHandleResult = {
REFUSED: 2 // 拒绝
} as const
/** 群管理员人数上限(对齐后端 GROUP_ADMIN_MAX_COUNT */
export const GROUP_ADMIN_MAX_COUNT = 3
/** 群置顶消息条数上限(对齐后端 GROUP_PIN_MAX_COUNT */
export const GROUP_PIN_MAX_COUNT = 5
/** 每次拉取私聊消息的最大条数(后端上限 1000前端取保守值 100 */
export const PRIVATE_MESSAGE_PULL_SIZE = 100
/** 每次拉取群聊消息的最大条数(后端上限 1000前端取保守值 100 */
export const GROUP_MESSAGE_PULL_SIZE = 100
/** 「我相关」好友申请列表的单次拉取条数(游标分页 page size前端控制 */
export const FRIEND_REQUEST_PAGE_SIZE = 100
/** 「我相关」加群申请列表的单次拉取条数 */
export const GROUP_REQUEST_PAGE_SIZE = 100
/** 消息之间渲染「时间分隔条」的阈值10 分钟 */
export const TIME_TIP_GAP_MS = 10 * 60 * 1000
/**
* @ userId atUserIds -1 @
*
@ -234,12 +213,6 @@ export const IM_AT_ALL_USER_ID = -1
/** @全体成员 的展示名(对齐微信 PC */
export const IM_AT_ALL_NICKNAME = '所有人'
/** 合并转发气泡内预览的最大行数(对齐微信「聊天记录」气泡) */
export const MERGE_FORWARD_PREVIEW_LINES = 3
/** 最近转发会话 key 列表的最大保留数量(对齐微信 PC 横向头像区可见容量) */
export const RECENT_FORWARD_MAX = 12
/** 转发模式SINGLE 逐条原样转 / MERGE 打包成 MergeMessage */
export const ImForwardMode = {
SINGLE: 'single',