Merge pull request #160 from xunchahaha:dev

Dev
This commit is contained in:
xuncha
2026-02-01 15:25:13 +08:00
committed by GitHub
3 changed files with 97 additions and 11 deletions

View File

@@ -16,6 +16,10 @@ export interface GroupMember {
username: string
displayName: string
avatarUrl?: string
nickname?: string
alias?: string
remark?: string
groupNickname?: string
}
export interface GroupMessageRank {
@@ -211,14 +215,55 @@ class GroupAnalyticsService {
}
const members = result.members as { username: string; avatarUrl?: string }[]
const usernames = members.map((m) => m.username)
const displayNames = await wcdbService.getDisplayNames(usernames)
const usernames = members.map((m) => m.username).filter(Boolean)
const data: GroupMember[] = members.map((m) => ({
username: m.username,
displayName: displayNames.success && displayNames.map ? (displayNames.map[m.username] || m.username) : m.username,
avatarUrl: m.avatarUrl
}))
const [displayNames, groupNicknames] = await Promise.all([
wcdbService.getDisplayNames(usernames),
this.getGroupNicknamesForRoom(chatroomId)
])
const contactMap = new Map<string, { remark?: string; nickName?: string; alias?: string }>()
const concurrency = 6
await this.parallelLimit(usernames, concurrency, async (username) => {
const contactResult = await wcdbService.getContact(username)
if (contactResult.success && contactResult.contact) {
const contact = contactResult.contact as any
contactMap.set(username, {
remark: contact.remark || '',
nickName: contact.nickName || contact.nick_name || '',
alias: contact.alias || ''
})
} else {
contactMap.set(username, { remark: '', nickName: '', alias: '' })
}
})
const myWxid = this.cleanAccountDirName(this.configService.get('myWxid') || '')
const data: GroupMember[] = members.map((m) => {
const wxid = m.username || ''
const displayName = displayNames.success && displayNames.map ? (displayNames.map[wxid] || wxid) : wxid
const contact = contactMap.get(wxid)
const nickname = contact?.nickName || ''
const remark = contact?.remark || ''
const alias = contact?.alias || ''
const rawGroupNickname = groupNicknames.get(wxid.toLowerCase()) || ''
const normalizedWxid = this.cleanAccountDirName(wxid)
const groupNickname = this.normalizeGroupNickname(
rawGroupNickname,
normalizedWxid === myWxid ? myWxid : wxid,
''
)
return {
username: wxid,
displayName,
nickname,
alias,
remark,
groupNickname,
avatarUrl: m.avatarUrl
}
})
return { success: true, data }
} catch (e) {

View File

@@ -16,6 +16,10 @@ interface GroupMember {
username: string
displayName: string
avatarUrl?: string
nickname?: string
alias?: string
remark?: string
groupNickname?: string
}
interface GroupMessageRank {
@@ -298,6 +302,10 @@ function GroupAnalyticsPage() {
const renderMemberModal = () => {
if (!selectedMember) return null
const nickname = (selectedMember.nickname || '').trim()
const alias = (selectedMember.alias || '').trim()
const remark = (selectedMember.remark || '').trim()
const groupNickname = (selectedMember.groupNickname || '').trim()
return (
<div className="member-modal-overlay" onClick={() => setSelectedMember(null)}>
@@ -320,11 +328,40 @@ function GroupAnalyticsPage() {
</div>
<div className="detail-row">
<span className="detail-label"></span>
<span className="detail-value">{selectedMember.displayName}</span>
<button className="copy-btn" onClick={() => handleCopy(selectedMember.displayName, 'displayName')}>
{copiedField === 'displayName' ? <Check size={14} /> : <Copy size={14} />}
</button>
<span className="detail-value">{nickname || '未设置'}</span>
{nickname && (
<button className="copy-btn" onClick={() => handleCopy(nickname, 'nickname')}>
{copiedField === 'nickname' ? <Check size={14} /> : <Copy size={14} />}
</button>
)}
</div>
{alias && (
<div className="detail-row">
<span className="detail-label"></span>
<span className="detail-value">{alias}</span>
<button className="copy-btn" onClick={() => handleCopy(alias, 'alias')}>
{copiedField === 'alias' ? <Check size={14} /> : <Copy size={14} />}
</button>
</div>
)}
{groupNickname && (
<div className="detail-row">
<span className="detail-label"></span>
<span className="detail-value">{groupNickname}</span>
<button className="copy-btn" onClick={() => handleCopy(groupNickname, 'groupNickname')}>
{copiedField === 'groupNickname' ? <Check size={14} /> : <Copy size={14} />}
</button>
</div>
)}
{remark && (
<div className="detail-row">
<span className="detail-label"></span>
<span className="detail-value">{remark}</span>
<button className="copy-btn" onClick={() => handleCopy(remark, 'remark')}>
{copiedField === 'remark' ? <Check size={14} /> : <Copy size={14} />}
</button>
</div>
)}
</div>
</div>
</div>

View File

@@ -219,6 +219,10 @@ export interface ElectronAPI {
username: string
displayName: string
avatarUrl?: string
nickname?: string
alias?: string
remark?: string
groupNickname?: string
}>
error?: string
}>