@@ -37,6 +37,44 @@ export interface ContactInfo {
3737 lastContactTime ?: number
3838}
3939
40+ const SYSTEM_CONTACT_USERNAMES = new Set ( [
41+ 'filehelper' ,
42+ 'fmessage' ,
43+ 'floatbottle' ,
44+ 'medianote' ,
45+ 'newsapp' ,
46+ 'qmessage' ,
47+ 'qqmail' ,
48+ 'weixin' ,
49+ 'brandsessionholder' ,
50+ 'brandservicesessionholder' ,
51+ 'notifymessage' ,
52+ 'opencustomerservicemsg' ,
53+ 'notification_messages' ,
54+ 'userexperience_alarm'
55+ ] )
56+
57+ function isSystemContactUsername ( username : string ) : boolean {
58+ const lower = username . trim ( ) . toLowerCase ( )
59+ if ( ! lower ) return true
60+ if ( SYSTEM_CONTACT_USERNAMES . has ( lower ) ) return true
61+ return lower . startsWith ( 'fake_' ) || lower . includes ( '@kefu.openim' ) || lower . includes ( 'service_' )
62+ }
63+
64+ function detectContactInfoType ( username : string , row : Record < string , any > ) : ContactInfo [ 'type' ] | null {
65+ const lower = username . trim ( ) . toLowerCase ( )
66+ if ( isSystemContactUsername ( lower ) ) return null
67+ if ( lower . includes ( '@chatroom' ) ) return 'group'
68+ if ( lower . startsWith ( 'gh_' ) ) return 'official'
69+
70+ const rawType = row . local_type ?? row . type
71+ const numericType = rawType === null || rawType === undefined || rawType === '' ? Number . NaN : Number ( rawType )
72+ if ( Number . isFinite ( numericType ) && numericType === 3 ) return 'official'
73+
74+ // 不同微信版本的 contact.local_type 含义不稳定;普通个人号在排除系统号后应作为好友保留。
75+ return 'friend'
76+ }
77+
4078export interface Message {
4179 localId : number
4280 serverId : number
@@ -607,11 +645,13 @@ class ChatService extends EventEmitter {
607645 const hasBigHeadUrl = columnNames . includes ( 'big_head_url' )
608646 const hasSmallHeadUrl = columnNames . includes ( 'small_head_url' )
609647 const hasLocalType = columnNames . includes ( 'local_type' )
648+ const hasType = columnNames . includes ( 'type' )
610649
611650 const selectCols = [ 'username' , 'remark' , 'nick_name' , 'alias' , 'quan_pin' , 'flag' ]
612651 if ( hasBigHeadUrl ) selectCols . push ( 'big_head_url' )
613652 if ( hasSmallHeadUrl ) selectCols . push ( 'small_head_url' )
614653 if ( hasLocalType ) selectCols . push ( 'local_type' )
654+ if ( hasType ) selectCols . push ( 'type' )
615655
616656 const rows = await dbAdapter . all < any > (
617657 'contact' ,
@@ -620,27 +660,13 @@ class ChatService extends EventEmitter {
620660 )
621661
622662 const contacts : ContactInfo [ ] = [ ]
623- const excludeNames = [ 'medianote' , 'floatbottle' , 'qmessage' , 'qqmail' , 'fmessage' ]
624663
625664 for ( const row of rows ) {
626665 const username = row . username || ''
627666 if ( ! username ) continue
628667
629- let type : 'friend' | 'group' | 'official' | 'former_friend' | 'other' = 'other'
630- const localType = hasLocalType ? ( row . local_type || 0 ) : 0
631- const quanPin = row . quan_pin || ''
632-
633- if ( username . includes ( '@chatroom' ) ) {
634- type = 'group'
635- } else if ( username . startsWith ( 'gh_' ) ) {
636- type = 'official'
637- } else if ( / ^ (? ! .* ( g h _ | @ c h a t r o o m ) ) .* $ / . test ( username ) && localType === 1 && ! excludeNames . includes ( username ) ) {
638- type = 'friend'
639- } else if ( / ^ (? ! .* ( g h _ | @ c h a t r o o m ) ) .* $ / . test ( username ) && localType === 0 && quanPin ) {
640- type = 'former_friend'
641- } else {
642- continue
643- }
668+ const type = detectContactInfoType ( username , row )
669+ if ( ! type ) continue
644670
645671 const displayName = row . remark || row . nick_name || row . alias || username
646672 let avatarUrl : string | undefined
0 commit comments