feat: 优化聊天档案浏览与增量导出

1. 增加档案加载状态、错误提示和延迟数据加载。
2. 优化移动端工具栏、消息布局及横向滚动控制。
3. 支持按年份折叠时间轴,并同步可见月份定位。
4. 使用自定义文件名作为档案标题。
5. 增量导出时保留历史头像,仅在视觉变化后新增头像版本。
6. 修复附件消息被误判为合并转发的问题。
7. 补充单元、集成及端到端测试覆盖。
This commit is contained in:
majun.jason
2026-08-05 15:00:31 +08:00
parent 4e84b52cc4
commit 933a87ebbb
7 changed files with 842 additions and 84 deletions
+11 -2
View File
@@ -25,8 +25,13 @@ describe('export media', () => {
const html = renderExportPage('脱敏导出')
expect(EXPORT_PAGE_SIZE).toBe(240)
expect(html).toContain('<script src="data/messages.js"></script>')
expect(html).toContain("dataScript.src = 'data/messages.js'")
expect(html).toContain('id="archive-loading"')
expect(html).toContain('正在加载聊天档案')
expect(html).toContain('requestAnimationFrame(() => window.setTimeout(loadArchiveData, 0))')
expect(html).toContain('aria-label="聊天时间轴"')
expect(html).toContain('aria-expanded="')
expect(html).toContain('setExpandedTimelineYear')
expect(html).toContain('data-kind="media"')
expect(html).toContain('placeholder="搜索发送者或消息内容…"')
expect(html).toContain('filtered.slice(windowStart, windowEnd)')
@@ -91,6 +96,10 @@ describe('export media', () => {
search.dispatchEvent(new dom.window.Event('input'))
expect(dom.window.document.querySelectorAll('.message')).toHaveLength(5)
expect(dom.window.document.querySelectorAll('.timeline-month').length).toBeGreaterThan(1)
expect(
dom.window.document.querySelectorAll('.timeline-year[aria-expanded="true"]')
).toHaveLength(1)
expect(dom.window.document.querySelectorAll('.timeline-months:not([hidden])')).toHaveLength(1)
dom.window.close()
})
@@ -124,7 +133,7 @@ describe('export media', () => {
expect(dom.window.document.querySelector('#archive-meta')?.textContent).toMatch(/^更新于 /)
expect(select.options).toHaveLength(3)
expect(select.value).toBe('all')
expect(select.options[0].textContent).toBe('全部聊天3')
expect(select.options[0].textContent).toBe('全部聊天')
expect(dom.window.document.querySelectorAll('.conversation-source')).toHaveLength(3)
expect(dom.window.document.querySelector('#count')?.textContent).toBe(
'已显示 3 / 筛选 3 / 全部 3'
+28
View File
@@ -28,6 +28,34 @@ describe('message parser', () => {
}
})
it.each([
['6', '测试附件.pdf'],
['74', '发送中的附件.zip']
])(
'keeps file app message type %s when attachment metadata contains record tags',
(typeVal, title) => {
const parsed = parseMessageContent(
`<appmsg><type>${typeVal}</type><title>${title}</title><des>1 MB</des><appattach><recorditem>legacy metadata</recorditem><dataitem datatype="8"><datatitle>${title}</datatitle></dataitem></appattach></appmsg>`,
49
)
expect(parsed).toMatchObject({
type: 'share',
title,
typeVal
})
}
)
it('does not classify empty incidental record metadata as a merged forward', () => {
const parsed = parseMessageContent(
'<appmsg><type>5</type><title>普通分享</title><recorditem>legacy metadata</recorditem></appmsg>',
49
)
expect(parsed).toMatchObject({ type: 'share', title: '普通分享', typeVal: '5' })
})
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>',