mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 19:47:08 +08:00
feat: 完善日报图片与公众号消息展示
修复日报图片读取格式与模型不支持时的友好降级 恢复话题关键词回退,确保词云在缺少顶层关键词时仍可展示 支持公众号多文章消息在聊天、日报、检索和 HTML 导出中完整呈现 迁移账号身份缓存并优化首次连接的账号占位信息 补充图片、词云、账号缓存与多文章消息回归测试
This commit is contained in:
@@ -72,3 +72,34 @@ describe('ImageBubble', () => {
|
||||
expect(await screen.findByAltText('图片')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
describe('RichMessageBubble', () => {
|
||||
it('renders every article in a public-account bundle', async () => {
|
||||
const open = vi.spyOn(window, 'open').mockImplementation(() => null)
|
||||
|
||||
render(
|
||||
<RichMessageBubble
|
||||
contentData={{
|
||||
type: 'share',
|
||||
title: 'Article one',
|
||||
url: 'https://example.test/one',
|
||||
appname: 'Fixture Publisher',
|
||||
articles: [
|
||||
{ title: 'Article one', url: 'https://example.test/one' },
|
||||
{ title: 'Article two', url: 'https://example.test/two' },
|
||||
{ title: 'Article three', url: 'https://example.test/three' }
|
||||
]
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
expect(screen.getByText('Fixture Publisher')).toBeVisible()
|
||||
expect(screen.getByRole('button', { name: 'Article one' })).toBeVisible()
|
||||
expect(screen.getByRole('button', { name: 'Article two' })).toBeVisible()
|
||||
expect(screen.getByRole('button', { name: 'Article three' })).toBeVisible()
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Article three' }))
|
||||
expect(open).toHaveBeenCalledWith('https://example.test/three', '_blank')
|
||||
open.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs'
|
||||
import { mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync, mkdirSync } from 'fs'
|
||||
import { createHash } from 'crypto'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -105,4 +106,39 @@ describe('bootstrap cache', () => {
|
||||
}).nickname
|
||||
).toBe('濑岛田井卫')
|
||||
})
|
||||
|
||||
it('migrates the previous startup cache so account discovery can show identity before unlock', () => {
|
||||
const legacyRoot = '/fixture/legacy-account'
|
||||
const digest = createHash('sha1')
|
||||
.update(`${process.platform}:${legacyRoot}`)
|
||||
.digest('hex')
|
||||
.slice(0, 16)
|
||||
const legacyFile = join(userData, 'cache', 'bootstrap', `${process.platform}-${digest}.json`)
|
||||
mkdirSync(join(userData, 'cache', 'bootstrap'), { recursive: true })
|
||||
writeFileSync(
|
||||
legacyFile,
|
||||
JSON.stringify({
|
||||
version: 1,
|
||||
platform: process.platform,
|
||||
accountRoot: legacyRoot,
|
||||
updatedAt: Date.now(),
|
||||
self: {
|
||||
wxid: 'wxid_legacy',
|
||||
nickname: '缓存昵称',
|
||||
avatar: 'data:image/png;base64,fixture',
|
||||
accountRoot: legacyRoot
|
||||
},
|
||||
contacts: []
|
||||
}),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
clearBootstrapCache()
|
||||
expect(getBootstrapCache(legacyRoot)?.self).toMatchObject({
|
||||
wxid: 'wxid_legacy',
|
||||
nickname: '缓存昵称',
|
||||
avatar: 'data:image/png;base64,fixture'
|
||||
})
|
||||
flushBootstrapCacheWritesSync()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { parseGroupDailyReport } from '../../src/renderer/src/utils/group-report'
|
||||
import type { GroupReportMetadata } from '../../src/shared/group-report'
|
||||
|
||||
const metadata: GroupReportMetadata = {
|
||||
groupName: '测试群',
|
||||
reportDate: '2026-08-06',
|
||||
dateRange: '今日',
|
||||
messageCount: 3,
|
||||
activeUsers: 2,
|
||||
timeSpan: '1 h',
|
||||
generatedAt: '2026/8/6 12:00:00',
|
||||
recordNote: 'fixture',
|
||||
footerNote: '',
|
||||
heroParticipants: [],
|
||||
reportMode: 'full'
|
||||
}
|
||||
|
||||
const media = {
|
||||
gallery: [],
|
||||
voiceHighlights: [],
|
||||
funBadges: []
|
||||
}
|
||||
|
||||
describe('group report parsing', () => {
|
||||
it('falls back to topic keywords when the model omits top-level keywords', () => {
|
||||
const report = parseGroupDailyReport(
|
||||
JSON.stringify({
|
||||
topics: [
|
||||
{
|
||||
title: '健身安排',
|
||||
summary: '讨论训练时间和肌酸。',
|
||||
keywords: ['肌酸', '训练']
|
||||
}
|
||||
]
|
||||
}),
|
||||
[],
|
||||
'',
|
||||
[],
|
||||
metadata,
|
||||
media
|
||||
)
|
||||
|
||||
expect(report.keywords).toEqual(['肌酸', '训练', '健身安排'])
|
||||
})
|
||||
})
|
||||
@@ -69,6 +69,23 @@ describe('message parser', () => {
|
||||
expect(parsed).toMatchObject({ type: 'share', title: '普通分享', typeVal: '5' })
|
||||
})
|
||||
|
||||
it('preserves every article in a public-account multi-article message', () => {
|
||||
const parsed = parseMessageContent(
|
||||
`<appmsg><type>5</type><appname>长江日报</appname><mmreader><category count="3"><item><title><![CDATA[女子吃酒席时意外发现]]></title><url><![CDATA[https://mp.weixin.qq.com/a]]></url><cover><![CDATA[https://img.test/a.jpg]]></cover></item><item><title>霍尔木兹海峡开放临时协议</title><digest>国际油价短期走势</digest><url>https://mp.weixin.qq.com/b</url></item><item><title>东野圭吾新作</title><url>https://mp.weixin.qq.com/c</url></item></category></mmreader></appmsg>`,
|
||||
49
|
||||
)
|
||||
|
||||
expect(parsed).toMatchObject({ type: 'share', appname: '长江日报' })
|
||||
if (parsed.type === 'share') {
|
||||
expect(parsed.articles).toHaveLength(3)
|
||||
expect(parsed.articles?.map((article) => article.title)).toEqual([
|
||||
'女子吃酒席时意外发现',
|
||||
'霍尔木兹海峡开放临时协议',
|
||||
'东野圭吾新作'
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
it('uses the quoted group member id instead of the chatroom id', () => {
|
||||
const parsed = parseMessageContent(
|
||||
'<appmsg><type>57</type><title>回复内容</title><refermsg><type>1</type><fromusr>123456789@chatroom</fromusr><chatusr>wxid_fixture_member</chatusr><content>被引用内容</content></refermsg></appmsg>',
|
||||
|
||||
Reference in New Issue
Block a user