Skip to content

Commit a7a8fa2

Browse files
authored
Merge pull request #11 from wsrh8888/feature-rh
Feature rh
2 parents f1124b6 + 95d9f5c commit a7a8fa2

File tree

23 files changed

+241
-208
lines changed

23 files changed

+241
-208
lines changed

.cursor/rules/rule.mdc

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,21 @@ alwaysApply: true
33
---
44
# 项目概述
55

6-
这是一个开源的IM(即时通讯)项目,对标大厂和开源IM产品。本项目使用分为3层
6+
这是一个开源的IM(即时通讯)项目,对标大厂和开源IM产品。
77

88
### 技术架构
9-
vite+ electron+vue3
9+
vite+ eluniappectron+vue3
1010

1111
### ts别名
12-
commonModule: path.resolve(__dirname, 'src/common'),
13-
mainModule: path.resolve(__dirname, 'src/main'),
14-
renderModule: path.resolve(__dirname, 'src/render'),
15-
preloadModule: path.resolve(__dirname, 'src/preload'),
16-
1712

1813
### 文件命名
1914
- 所有的文件不能以大写字母开头, 如果是多个单词采用驼峰命名
2015
- 文件名字如果我文件夹已经携带了xx, 这个子文件就不要在携带xxx开头的了
2116

2217
### css的编写
23-
- 我使用less, 你的css开发的时候采用嵌套结构
24-
25-
### axios规范
26-
- 我的axios底层是renderModule/utils/request/ajax, 这里返回的数据是.data已经包好的, 同时没有异常
27-
- renderModule/utils/request/ajax 底层封装了header相关的,各个模块不要在加了。
28-
- 主进程的api在 mainModule/api 渲染进程的在 renderModule/api
29-
- axios的接口的定义在 commonModule/type/ajax
30-
31-
### vue文件编写规范
32-
- 不要 script lang="ts" setup 这种组件, 采用export default defineComponent这样的代码
33-
# 注意事项
18+
- 我使用scss, 你的css开发的时候采用嵌套结构
3419

3520
### 切记
3621
- 不要过度开发
3722
- 不要写md文件
38-
- 尽可能使用别名不要使用../之类的相对路径
39-
- 不要运行任何的npm run 命令
40-
- 不要运行任何的npm run build-electron 命令
23+
- 尽可能使用别名不要使用../之类的相对路径

build/shell/beaver.nsi

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
; 定义安装程序的常量
21
!define PRODUCT_NAME "º£ÀêIM"
32
!define PRODUCT_VERSION ${VERSION}
43
!define RESOURCE_DIR ${RESOURCEDIR}
@@ -11,7 +10,7 @@
1110
!define PRODUCT_USER_KEY "HKCU"
1211
!define PRODUCT_CLIENT_TYPE 0
1312

14-
!define DAEMON_DIR_REGKEY "Software\HLW\beaver"
13+
!define DAEMON_DIR_REGKEY "Software\beaver"
1514

1615
!define AUTORUN_REGKEY "Software\Microsoft\Windows\CurrentVersion\Run"
1716
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
@@ -20,73 +19,59 @@
2019
SetCompressor lzma
2120
!addincludedir .\include
2221

23-
; 包含必要的NSIS库和模块
24-
!include "MUI2.nsh" ; 使用现代用户界面2 (MUI2) 模块
25-
!include "FileFunc.nsh" ; 文件操作模块
26-
!include "LogicLib.nsh" ; 逻辑操作模块
22+
!include "MUI2.nsh" ;
23+
!include "FileFunc.nsh" ;
24+
!include "LogicLib.nsh" ;
2725
!include "WordFunc.nsh" ;
2826
!include "beaver.nsh" ;
2927

30-
; 定义MUI界面设置
3128
!define MUI_ABORTWARNING
3229
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
3330

34-
; 安装过程页面定义
3531
!insertmacro MUI_PAGE_WELCOME
36-
!insertmacro MUI_PAGE_DIRECTORY ; 添加目录选择页面
32+
!insertmacro MUI_PAGE_DIRECTORY
3733
!insertmacro MUI_PAGE_INSTFILES
3834
!insertmacro MUI_PAGE_FINISH
3935

40-
; 卸载过程页面定义
4136
!insertmacro MUI_UNPAGE_WELCOME
4237
!insertmacro MUI_UNPAGE_CONFIRM
4338
!insertmacro MUI_UNPAGE_INSTFILES
4439
!insertmacro MUI_UNPAGE_FINISH
4540

46-
; 定义语言设置
4741
!insertmacro MUI_LANGUAGE "SimpChinese"
4842

49-
; 保留InstallOptions插件
5043
ReserveFile /plugin "InstallOptions.dll"
5144

52-
; 定义安装程序的基本信息
5345
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
5446
OutFile "${OUTPUT_DIR}"
55-
InstallDir "$APPDATA\beaver" ; 设置默认安装路径
47+
InstallDir "$APPDATA\beaver"
5648
ShowInstDetails show
5749
ShowUnInstDetails show
5850

59-
; 定义版本信息
6051
VIProductVersion ${PRODUCT_VERSION}
6152
VIAddVersionKey FileDescription "${PRODUCT_PROCESS_NAME}"
6253
VIAddVersionKey FileVersion "${PRODUCT_VERSION}"
6354
VIAddVersionKey ProductName "${PRODUCT_NAME}"
6455
VIAddVersionKey OriginalFilename "${PRODUCT_PROCESS_NAME}"
6556

66-
; 请求管理员权限
6757
RequestExecutionLevel admin
6858

69-
; 主安装部分
7059
Section "MainSection" SEC01
7160
SetOutPath "$INSTDIR"
7261
SetOverwrite on
7362
!insertmacro INSTALL_BEAVER $INSTDIR ${RESOURCE_DIR} ${PRODUCT_VERSION}
7463

75-
; 创建卸载程序
7664
WriteUninstaller "$INSTDIR\uninstall.exe"
7765

78-
; 创建桌面快捷方式
79-
CreateShortcut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\海狸.exe" "$INSTDIR\app.ico"
66+
CreateShortcut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\beaver.exe" "$INSTDIR\app.ico"
8067

81-
; 注册卸载信息到注册表
8268
WriteRegStr ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME} ${PRODUCT_VERSION}"
8369
WriteRegStr ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstall.exe"
8470
WriteRegStr ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
8571
WriteRegStr ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
8672
WriteRegStr ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
8773
SectionEnd
8874

89-
; 注册部分
9075
Section -Post
9176
SetRegView 64
9277
System::Alloc 16
@@ -96,33 +81,24 @@ Section -Post
9681
!insertmacro REGISTER_BEAVER $INSTDIR ${PRODUCT_VERSION}
9782
SectionEnd
9883

99-
/******************************
100-
* 以下是安装程序的卸载部分 *
101-
******************************/
10284

10385
Section Uninstall
10486
SetRegView 64
10587
!insertmacro UNINSTALL_BEAVER $INSTDIR
106-
; 删除注册表中与卸载程序相关的键
10788
DeleteRegKey ${PRODUCT_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
10889

109-
; 删除桌面快捷方式
11090
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
11191
SetAutoClose true
11292
SectionEnd
11393

114-
; 初始化函数(卸载过程)
11594
Function un.onInit
11695
FunctionEnd
11796

118-
; 安装成功后的函数
11997
Function .onInstSuccess
12098
FunctionEnd
12199

122-
; 卸载成功后的函数
123100
Function un.onUninstSuccess
124101
FunctionEnd
125102

126-
; 初始化函数
127103
Function .onInit
128104
FunctionEnd

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "beaver",
33
"type": "module",
4-
"version": "1.0.0",
4+
"version": "1.1.0",
55
"private": true,
66
"description": "beaverIM",
77
"author": "Robert",

src/common/type/preload/notification.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ export enum NotificationMediaViewerCommand {
162162
* data: { url: string, title?: string }
163163
*/
164164
UPDATE_AUDIO = 'updateAudio',
165+
/**
166+
* 更新朋友圈数据
167+
* data: any
168+
*/
169+
UPDATE_MOMENT = 'updateMoment',
170+
/**
171+
* 更新升级信息
172+
*/
173+
UPDATE_UPDATER = 'updateUpdater',
165174
}
166175

167176
/**

src/main/api/emoji.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,13 @@ export const getEmojiPackageContentsByPackageIdsApi = (data: { packageIds: strin
9292
data,
9393
url: `${getBaseUrl()}/api/emoji/package-contents-by-package-ids`,
9494
})
95+
}
96+
97+
// 获取表情包内容列表(通过关联ID列表)
98+
export const getEmojiPackageContentsByRelationIdsApi = (data: { relationIds: string[] }) => {
99+
return ajax<EmojiPackageContentsResponse>({
100+
method: 'POST',
101+
data,
102+
url: `${getBaseUrl()}/api/emoji/package-contents-by-relation-ids`,
103+
})
95104
}

src/main/business/emoji/package-emoji.ts

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { QueueItem } from '../base/base'
22
import { NotificationEmojiCommand, NotificationModule } from 'commonModule/type/preload/notification'
3-
import { getEmojiPackageContentsByPackageIdsApi } from 'mainModule/api/emoji'
3+
import { getEmojiPackageContentsByRelationIdsApi } from 'mainModule/api/emoji'
44
import dBServiceEmojiPackageEmoji from 'mainModule/database/services/emoji/package-emoji'
55
import { sendMainNotification } from 'mainModule/ipc/main-to-render'
66
import { BaseBusiness } from '../base/base'
@@ -46,55 +46,41 @@ class EmojiPackageEmojiBusiness extends BaseBusiness<PackageEmojiSyncItem> {
4646
protected async processBatchRequests(items: PackageEmojiSyncItem[]): Promise<void> {
4747
// 聚合所有需要同步的relationIds
4848
const relationIds = [...new Set(items.flatMap(item => item.relationIds))]
49+
console.log('package-emoji 开始数据同步', items)
4950

5051
if (relationIds.length === 0) {
5152
return
5253
}
5354

5455
try {
55-
// 首先尝试从本地数据库获取这些relationId对应的packageId
56-
const existingRelations = await dBServiceEmojiPackageEmoji.getEmojisByRelationIds({ relationIds })
56+
// 直接用relationIds获取表情包内容详情
57+
const response = await getEmojiPackageContentsByRelationIdsApi({
58+
relationIds: relationIds,
59+
})
5760

58-
// 提取packageIds
59-
const packageIds = [...new Set(existingRelations.map(relation => relation.packageId))]
61+
if (response.result?.contents && response.result.contents.length > 0) {
62+
// 更新本地数据库
63+
const contentRows = response.result.contents.map((contentData: any) => ({
64+
relationId: contentData.relationId,
65+
packageId: contentData.packageId,
66+
emojiId: contentData.emojiId,
67+
sortOrder: contentData.sortOrder,
68+
version: contentData.version,
69+
createdAt: contentData.createdAt,
70+
updatedAt: contentData.updatedAt,
71+
}))
6072

61-
if (packageIds.length > 0) {
62-
// 根据packageIds获取表情包内容详情
63-
const response = await getEmojiPackageContentsByPackageIdsApi({
64-
packageIds: packageIds,
65-
})
66-
67-
if (response.result?.contents && response.result.contents.length > 0) {
68-
// 过滤出需要的表情关联数据
69-
const contents = response.result.contents.filter(content =>
70-
relationIds.includes(content.relationId)
71-
)
72-
73-
if (contents.length > 0) {
74-
// 更新本地数据库
75-
const contentRows = contents.map((contentData: any) => ({
76-
relationId: contentData.relationId,
77-
packageId: contentData.packageId,
78-
emojiId: contentData.emojiId,
79-
sortOrder: contentData.sortOrder,
80-
version: contentData.version,
81-
createdAt: contentData.createdAt,
82-
updatedAt: contentData.updatedAt,
83-
}))
73+
await dBServiceEmojiPackageEmoji.batchCreate({ relations: contentRows })
8474

85-
await dBServiceEmojiPackageEmoji.batchCreate({ relations: contentRows })
86-
87-
// 发送通知到render进程,告知表情包内容数据已同步
88-
sendMainNotification('*', NotificationModule.EMOJI, NotificationEmojiCommand.EMOJI_PACKAGE_CONTENT_UPDATE, {
89-
updatedPackageContents: contentRows.map((content: any) => ({
90-
relationId: content.relationId,
91-
packageId: content.packageId,
92-
emojiId: content.emojiId,
93-
version: content.version,
94-
})),
95-
})
96-
}
97-
}
75+
// 发送通知到render进程,告知表情包内容数据已同步
76+
sendMainNotification('*', NotificationModule.EMOJI, NotificationEmojiCommand.EMOJI_PACKAGE_CONTENT_UPDATE, {
77+
updatedPackageContents: contentRows.map((content: any) => ({
78+
relationId: content.relationId,
79+
packageId: content.packageId,
80+
emojiId: content.emojiId,
81+
version: content.version,
82+
})),
83+
})
9884
}
9985
} catch (error) {
10086
console.error('批量同步表情包表情关联失败:', error)

src/main/database/services/emoji/package-collect.ts

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import type {
1212
DBGetPackageCollectByIdRes,
1313
DBDeletePackageCollectReq,
1414
} from 'commonModule/type/database/server/emoji/package-collect'
15+
import type { IDBEmojiPackageCollect } from 'commonModule/type/database/db/emoji'
16+
import Logger from 'mainModule/utils/logger'
17+
18+
const logger = new Logger('database-emoji-package-collect')
1519

1620
// 表情包收藏服务
1721
class EmojiPackageCollect extends BaseService {
@@ -24,25 +28,54 @@ class EmojiPackageCollect extends BaseService {
2428

2529
/**
2630
* @description 批量创建表情包收藏(upsert操作)
31+
* 注意:使用先查询再插入/更新的方式,避免 onConflictDoUpdate 消耗 AUTOINCREMENT 序列值
2732
*/
2833
async batchCreate(req: DBBatchCreatePackageCollectsReq): Promise<void> {
2934
if (req.collects.length === 0) {
3035
return
3136
}
3237

38+
// 批量查询所有已存在的记录
39+
const packageCollectIds = req.collects.map(c => c.packageCollectId)
40+
const existingMap = await this.getPackageCollectsByIds({ ids: packageCollectIds })
41+
42+
// 分离需要插入和更新的记录
43+
const toInsert: typeof req.collects = []
44+
const toUpdate: typeof req.collects = []
45+
3346
for (const collectData of req.collects) {
34-
await this.db.insert(emojiPackageCollect)
35-
.values(collectData)
36-
.onConflictDoUpdate({
37-
target: emojiPackageCollect.packageCollectId,
38-
set: {
39-
userId: collectData.userId,
40-
packageId: collectData.packageId,
41-
version: collectData.version,
42-
updatedAt: collectData.updatedAt,
43-
},
44-
})
45-
.run()
47+
if (existingMap.has(collectData.packageCollectId)) {
48+
toUpdate.push(collectData)
49+
} else {
50+
toInsert.push(collectData)
51+
}
52+
}
53+
54+
// 批量插入新记录
55+
if (toInsert.length > 0) {
56+
for (const collectData of toInsert) {
57+
await this.db.insert(emojiPackageCollect).values(collectData).run()
58+
}
59+
}
60+
61+
// 批量更新已存在的记录
62+
if (toUpdate.length > 0) {
63+
for (const collectData of toUpdate) {
64+
const updateData: any = {
65+
userId: collectData.userId,
66+
packageId: collectData.packageId,
67+
version: collectData.version,
68+
}
69+
// updatedAt 是可选的,如果存在则更新
70+
if ('updatedAt' in collectData && collectData.updatedAt !== undefined) {
71+
updateData.updatedAt = collectData.updatedAt
72+
}
73+
await this.db
74+
.update(emojiPackageCollect)
75+
.set(updateData)
76+
.where(eq(emojiPackageCollect.packageCollectId, collectData.packageCollectId))
77+
.run()
78+
}
4679
}
4780
}
4881

@@ -61,14 +94,15 @@ class EmojiPackageCollect extends BaseService {
6194
.where(inArray(emojiPackageCollect.packageCollectId, req.ids as any))
6295

6396
const collectMap = new Map<string, IDBEmojiPackageCollect>()
64-
collectList.forEach((item) => {
97+
collectList.forEach((item: IDBEmojiPackageCollect) => {
6598
collectMap.set(item.packageCollectId, item)
6699
})
67100

68101
return collectMap
69102
}
70103
catch (error) {
71104
logger.error({ text: '表情包收藏数据获取失败2', data: { error: (error as any)?.message } })
105+
return new Map()
72106
}
73107
}
74108

0 commit comments

Comments
 (0)