fix(Content_type): Content type fix to fit Weixin documenation

This commit is contained in:
Symb0x76
2025-09-24 16:04:43 +08:00
parent d66e1eb23c
commit e53e97a82e
7 changed files with 99 additions and 11 deletions
+4 -11
View File
@@ -325,6 +325,7 @@ func (s *Service) handleDashboard(c *gin.Context) {
"撤回消息":0,
}
for k, v := range gstats.ByType { if _, ok := msgTypes[k]; ok { msgTypes[k] += v } }
for k, v := range gstats.ByType { if _, ok := msgTypes[k]; ok { msgTypes[k] += v } }
// 时间轴
durationDays := 0.0
@@ -404,7 +405,7 @@ func (s *Service) handleDashboard(c *gin.Context) {
WeeklyAvg int `json:"weekly_avg"`
MostActiveHour string `json:"most_active_hour"`
}
type ContentAnalysis struct { Text int64 `json:"text_messages"`; Images int64 `json:"images"`; Voice int64 `json:"voice_messages"`; Files int64 `json:"files"`; Links int64 `json:"links"`; FileLinkTotal int64 `json:"file_link_total"`; Others int64 `json:"others"` }
type ContentAnalysis struct { Text int64 `json:"text_messages"`; Images int64 `json:"images"`; Voice int64 `json:"voice_messages"`; Files int64 `json:"files"`; Links int64 `json:"links"`; Others int64 `json:"others"` }
type GroupListItem struct { Name string `json:"name"`; Members int `json:"members"`; Messages int64 `json:"messages"`; Active bool `json:"active"` }
type HourlyActivity struct { Hour string `json:"hour"`; Messages int64 `json:"messages"` }
type GroupAnalysis struct {
@@ -510,16 +511,8 @@ func (s *Service) handleDashboard(c *gin.Context) {
GroupAnalysis: GroupAnalysis{
Title: "群聊分析",
Overview: GroupOverview{ TotalGroups: len(overviewGroups), ActiveGroups: activeGroups, TodayMessages: int(todayMessages), WeeklyAvg: weeklyAvg, MostActiveHour: mostActiveHour },
// 扩展:增加 links 与汇总 file_link_total
ContentAnalysis: ContentAnalysis{
Text: msgTypes["文本消息"],
Images: msgTypes["图片消息"],
Voice: msgTypes["语音消息"],
Files: msgTypes["文件消息"],
Links: msgTypes["链接消息"],
FileLinkTotal: msgTypes["文件消息"] + msgTypes["链接消息"],
Others: totalMsgs - (msgTypes["文本消息"] + msgTypes["图片消息"] + msgTypes["语音消息"] + msgTypes["文件消息"] + msgTypes["链接消息"]),
},
// 扩展:增加 links 字段(结构体需更新)
ContentAnalysis: ContentAnalysis{ Text: msgTypes["文本消息"], Images: msgTypes["图片消息"], Voice: msgTypes["语音消息"], Files: msgTypes["文件消息"], Links: msgTypes["链接消息"], Others: totalMsgs - (msgTypes["文本消息"]+msgTypes["图片消息"]+msgTypes["语音消息"]+msgTypes["文件消息"]+msgTypes["链接消息"]) },
GroupList: glist,
HourlyActivity: hacts,
},
@@ -982,6 +982,39 @@ func (ds *DataSource) MonthlyTrend(ctx context.Context, months int) ([]model.Mon
return trends, nil
}
// GroupMessageTypeStats 统计群聊消息类型分布(Darwin v3)
func (ds *DataSource) GroupMessageTypeStats(ctx context.Context) (map[string]int64, error) {
result := make(map[string]int64)
// 构建群聊 md5 映射
mapping := make(map[string]string)
if cdb, err := ds.dbm.GetDB(ChatRoom); err == nil {
if rows, err2 := cdb.QueryContext(ctx, `SELECT IFNULL(m_nsUsrName,"") FROM GroupContact`); err2 == nil {
for rows.Next() { var uname string; if rows.Scan(&uname)==nil && uname!="" { sum := md5.Sum([]byte(uname)); mapping["Chat_"+hex.EncodeToString(sum[:])] = uname } }
rows.Close()
}
}
dbs, err := ds.dbm.GetDBs(Message)
if err != nil { return result, nil }
for _, db := range dbs {
trows, err := db.QueryContext(ctx, `SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'Chat_%' AND name NOT LIKE '%_dels'`)
if err != nil { continue }
var tables []string
for trows.Next() { var name string; if trows.Scan(&name)==nil { tables = append(tables, name) } }
trows.Close()
for _, tbl := range tables { if _, ok := mapping[tbl]; !ok { continue }
// 非49
q := fmt.Sprintf(`SELECT messageType, COUNT(*) FROM %s WHERE messageType != 49 GROUP BY messageType`, tbl)
rows, err2 := db.QueryContext(ctx, q)
if err2 == nil { for rows.Next(){ var t int64; var cnt int64; if rows.Scan(&t,&cnt)==nil { label := mapV4TypeToLabel(t); if label!="" { result[label]+=cnt } } }; rows.Close() }
// 49
q49 := fmt.Sprintf(`SELECT msgContent FROM %s WHERE messageType = 49`, tbl)
orows, err3 := db.QueryContext(ctx, q49)
if err3 == nil { for orows.Next(){ var mc string; if orows.Scan(&mc)==nil { lc := strings.ToLower(mc); if strings.Contains(lc,"<appmsg"){ if strings.Contains(lc,"<type>") && strings.Contains(lc,"</type>"){ i1:=strings.Index(lc,"<type>"); i2:=strings.Index(lc[i1+6:],"</type>"); if i1>=0 && i2>0 { val := strings.TrimSpace(lc[i1+6:i1+6+i2]); if val=="6" { result["文件消息"]++; continue }; if val=="5" || val=="33" { result["链接消息"]++; continue } } } }; if strings.Contains(lc,"http://") || strings.Contains(lc,"https://") { result["链接消息"]++; continue }; result["XML消息"]++ } }; orows.Close() }
}
}
return result, nil
}
// Heatmap 小时x星期(wday: 0=Sunday..6)
func (ds *DataSource) Heatmap(ctx context.Context) ([24][7]int64, error) {
var grid [24][7]int64
@@ -38,6 +38,8 @@ type DataSource interface {
GlobalMessageStats(ctx context.Context) (*model.GlobalMessageStats, error)
// 群聊消息计数:返回 talker(群名) -> count
GroupMessageCounts(ctx context.Context) (map[string]int64, error)
// 群聊消息类型分布:返回 typeLabel -> count(只统计群消息)
GroupMessageTypeStats(ctx context.Context) (map[string]int64, error)
// 群聊今日消息计数:返回 talker(群名) -> today_count
GroupTodayMessageCounts(ctx context.Context) (map[string]int64, error)
// 本周(从周一00:00起)群聊消息总数(所有群合计)
@@ -1181,4 +1181,33 @@ func (ds *DataSource) GlobalTodayHourly(ctx context.Context) ([24]int64, error)
}
}
return hours, nil
}
// GroupMessageTypeStats 统计群聊消息类型分布(v4)
func (ds *DataSource) GroupMessageTypeStats(ctx context.Context) (map[string]int64, error) {
result := make(map[string]int64)
cdb, err := ds.dbm.GetDB(Contact)
if err != nil { return result, nil }
urows, err := cdb.QueryContext(ctx, `SELECT username FROM chat_room`)
if err != nil { return result, nil }
var rooms []string
for urows.Next() { var u string; if urows.Scan(&u)==nil { rooms = append(rooms, u) } }
urows.Close()
if len(rooms) == 0 { return result, nil }
dbs, err := ds.dbm.GetDBs(Message)
if err != nil { return result, nil }
for _, db := range dbs {
for _, uname := range rooms {
md5sum := md5.Sum([]byte(uname)); tbl := "Msg_" + hex.EncodeToString(md5sum[:])
// 先统计非49
q := fmt.Sprintf(`SELECT local_type, COUNT(*) FROM %s WHERE local_type != 49 GROUP BY local_type`, tbl)
rows, err := db.QueryContext(ctx, q)
if err == nil { for rows.Next(){ var t int64; var cnt int64; if rows.Scan(&t,&cnt)==nil { label := mapV4TypeToLabel(t); if label!="" { result[label]+=cnt } } }; rows.Close() }
// 处理49
q49 := fmt.Sprintf(`SELECT message_content FROM %s WHERE local_type=49`, tbl)
orows, err := db.QueryContext(ctx, q49)
if err == nil { for orows.Next(){ var mc []byte; if err := orows.Scan(&mc); err==nil { lc := strings.ToLower(string(mc)); if strings.Contains(lc,"<appmsg"){ if strings.Contains(lc,"<type>") && strings.Contains(lc,"</type>"){ i1:=strings.Index(lc,"<type>"); i2:=strings.Index(lc[i1+6:],"</type>"); if i1>=0 && i2>0 { val := strings.TrimSpace(lc[i1+6:i1+6+i2]); if val=="6" { result["文件消息"]++; continue }; if val=="5" || val=="33" { result["链接消息"]++; continue } } } }; if strings.Contains(lc,"http://") || strings.Contains(lc,"https://") { result["链接消息"]++; continue }; result["XML消息"]++ } }; orows.Close() }
}
}
return result, nil
}
@@ -902,6 +902,26 @@ func (ds *DataSource) GroupWeekMessageCount(ctx context.Context) (int64, error)
return total, nil
}
// GroupMessageTypeStats 统计群聊消息类型分布(Windows v3)
func (ds *DataSource) GroupMessageTypeStats(ctx context.Context) (map[string]int64, error) {
result := make(map[string]int64)
dbs, err := ds.dbm.GetDBs(Message)
if err != nil { return result, nil }
for _, db := range dbs {
rows, err := db.QueryContext(ctx, `SELECT Type, SubType, COUNT(*) FROM MSG WHERE StrTalker LIKE '%@chatroom' GROUP BY Type, SubType`)
if err != nil { continue }
for rows.Next() {
var t int64; var st int64; var cnt int64
if rows.Scan(&t,&st,&cnt)==nil {
label := mapV3TypeToLabel(t, st)
if label != "" { result[label] += cnt }
}
}
rows.Close()
}
return result, nil
}
// MonthlyTrend 返回每月 sent/received(近 months 月,若 months<=0 则返回全部)
func (ds *DataSource) MonthlyTrend(ctx context.Context, months int) ([]model.MonthlyTrend, error) {
agg := make(map[string][2]int64)
@@ -153,3 +153,10 @@ func (r *Repository) GroupWeekMessageCount(ctx context.Context) (int64, error) {
}
return 0, nil
}
func (r *Repository) GroupMessageTypeStats(ctx context.Context) (map[string]int64, error) {
if ds, ok := r.ds.(interface{ GroupMessageTypeStats(context.Context) (map[string]int64, error) }); ok {
return ds.GroupMessageTypeStats(ctx)
}
return map[string]int64{}, nil
}
+4
View File
@@ -163,3 +163,7 @@ func (w *DB) GroupTodayMessageCounts() (map[string]int64, error) {
func (w *DB) GroupWeekMessageCount() (int64, error) {
return w.repo.GroupWeekMessageCount(context.Background())
}
func (w *DB) GroupMessageTypeStats() (map[string]int64, error) {
return w.repo.GroupMessageTypeStats(context.Background())
}