feat(system): 增加分布式兼容和语音视频通话、移动端部分兼容 (#311)

* fix(config): 🐛 修复ios因Cargo.toml中系统限制条件排序问题导致无法启动

* feat(common):  tauri 登录命令 存储 token

* feat(common):  tauri 存储 room 信息

* feat(common):  sqlite 存储房间信息,群成员信息

* feat(common):  修改我的群的信息

* feat(common):  游标分页查询群组成员

* style(login): 💄 完善登录页面和图标

* feat(common):  查询全部群成员;优化前端显示逻辑

* feat(common):  更新 gitignore

* feat(common):  使用缓存检测是否强制更新本地数据,或采取静默更新

* fix(hook): 🐛 枚举使用错误修复

* fix(Android): 🐛 修改Android中的安全距离和启动页面

* fix(style): 🐛 修改pc登录按钮的样式

修复计时器worker计时问题
修改一些样式
移除修改ip地址的测试功能
修复刷新接口时候判断的群聊问题

* feat(system):  增加获取系统盘的信息和文件磁盘占用情况功能

优化一些重要提示的样式

* feat(common):  sqlite 存储会话

* feat(common):  sqlite 存储聊天信息

* fix(common): 🐛 sqlite需要根据登录的用户 id 进行数据隔离

* fix(mac): 🐛 修复mac上点击系统托盘图标和程序坞图标不展示主窗口的问题

* fix(windows): 🐛 修复win上右键任务栏图标关闭应用后无法再打开主窗口的问题

closed #IBQB1H

* fix(common): 🐛 添加 sqlite数据库迁移代码

* fix(view): 🐛 会话接口新增detailId;sqlite 数据结构变更;登录保存用户 id bug 修复;

* feat(util):  增强录音音频响度

* feat(common):  sqlite 存储消息

* fix(common): 🐛 sqlite 存储消息体异常

* feat(setting):  增加应用占用磁盘空间计算功能和可视化

* fix(hook): 🐛 修复音频文件命名不一致问题

* feat(common):  添加 tauri 日志插件

* feat(common):  rust 层发送消息

* feat(view):  新增自动下载音频功能,优先播放本地音频,修复音频频谱波形异常问题

* fix(component): 🐛 群成员监听显示问题;tauri 事件监听响应多次问题;消息列表显示顺序问题;

* fix(view): 🐛 修复发送语音后无法播放本地音频问题

* fix(common): 🐛 im_message 表关闭 nickname 非空限制

* fix(common): 🐛 设置账号第一次在客户端登录,设置is_init 为 true,进行初始化获取近期所有消息

* fix(common): 🐛 配置 tauri 的环境变量,用于 migration 启动

* fix(common): 🐛 登录之后,聊天页面初始化,未显示聊天记录 bug

* feat(system):  合并master

* style(common): 💄 引入 tauri websocket; 格式化 rust 代码;

* fix(mac): 🐛 修复mac语音播放问题

增加机器人样式和类型

* fix(common): 🐛 ws 接收消息存储本地

* fix(common): 🐛 rust 报错没有在前端提示问题修复

* fix(common): 🐛 修复登录页面请求接口 bug,以及首屏骨架屏问题;

* build(system): 📦 移除一些依赖,更新图标

* fix(view): 🐛 修复系统托盘在自动登录时不显示退出问题

优化在其他不需要显示window.$message提示的窗口可禁用

* perf(voice):  优化录音组件的样式

* fix(store): 🐛 修复安卓无法获取安全区域问题

* fix(common): 🐛 token 更新bug修复

* feat(mobile):  新增和优化消息页面布局

* feat(common):  离线消息同步

* build(system): 📦 修改项目一些样式和图标

修复判断安卓的方法异步问题导致mac release版本页面不加载问题

* build(icon): 📦 更新除了mac系统的图标

* fix(common): 🐛 将数据库迁移 crate 集成到主进程中

* style(common): 💄 修改 tauri 日志配置,输出日志到 logs 目录下;并对日志级别添加颜色;

* feat(mobile):  新增联系人页面

* feat(common):  引入 tauri-devtools

* feat(mobile):  新增点击加号图标的小弹窗页面

* docs(common): 📝 env文件修改

* fix(router): 🐛 补充提交路由文件,前一次提交缺少更新的路由文件

* fix(common): 🐛 rust 依赖调整;配置调整;

* build(config): 📦 修改配置

* fix(common): 🐛 rust .env 文件读取问题修复

* fix(layout): 🐛 修复主页布局漏洞

* build(system): 📦 拉取master的内容

* refactor(view): ♻️ 对接登录参数

* fix(common): 🐛 在线消息保存修复;

* fix(common): 🐛 sqlite 保存消息 mark

* fix(common): 🐛 消息标记同步问题

* feat(mobile):  新增通讯录页面内容

* fix(common): 🐛 项目启动之后,还在登录页面时,还会请求房间消息数据等

* fix(common): 🐛 windows启动造成 panic: 去掉 main 的运行时

* fix(common): 🐛 清除缓存,程序卡死

* fix(config): 🐛 更改sqlite configuration配置

修复windows启动控制台打印报错问题

* fix(common): 🐛 修复清除缓存,系统崩溃问题;

* fix(common): 🐛 群成员角色判定 bug 修复

* fix(common): 🐛 修复群成员搜索 bug

* fix(rust): 🐛 修复字段类型的字节数量

* feat(mobile):  联系人页面中移植客户端的好友组件

* fix(common): 🐛 修复动态窗口,邮件窗口,AI 插件窗口关闭 bug

* fix(common): 🐛 修复会话列表最新消息显示问题

* fix(common): 🐛 左侧功能窗口打开之后,鼠标划上显示问题

* perf(system):  适配cloud

* perf(centext):  优化切换会话时候卡顿问题

修复data.list[0]报错问题

* fix(common): 🐛 重构 Tauri事件的监听器释放逻辑;

* refactor(common): ♻️ 重构 Tauri 的事件监听相关代码;增加日志记录;

* feat(util):  新增DOM计算函数,完善社区页面和功能

* refactor(common): ♻️ 重构 useTauriListener

* fix(common): 🐛 监听 home 窗口关闭的时候,把 home 窗口隐藏

* perf(ws):  移除ws重连次数限制

* fix(common): 🐛 ios 窗口关闭弹窗 bug;修改群屏蔽状态导致消息错乱 bug;

* feat(util):  新增小屏安全区域页面适配,优化多次监听resize导致的性能问题

* fix(common): 🐛 初始化消息发送时的消息状态为发送中

* fix(ios): 🐛 修复rust依赖问题导致ios启动失败

* chore(format): 🔨 使用biome替换eslint

* perf(rust):  添加超时机制和错误处理优化

优化数据库连接池配置,调整连接参数和日志级别
新增全局超时配置模块
改进 IM 客户端锁机制,避免跨 await 持有锁
增强命令函数错误处理,返回 Result 类型
优化托盘图标创建逻辑,添加默认图标检查
重构应用初始化流程,使用异步任务避免阻塞

* fix(scanner): 🐛 修复存储扫描导致程序崩溃(扫描中关闭未解决)

* fix(configuration): 🐛 修复release打包后初始化应用数据失败问题

* perf(rust):  优化未处理的unwrap()

* fix(hide_notify): 🐛 修复hide_notify事件无限循环导致程序崩溃问题

* fix(voice): 🐛 修复输入框切换录音组件后选择表情包导致错位问题

* fix(view): 🐛 windwos notify和tray导致系统卡死

* fix(style): 🐛 修复样式错乱问题

* fix(common): 🐛 windows 接收消息 打开主窗口卡死

* fix(style): 🐛 修改图标样式

* fix(common): 🐛 windows接收群消息卡死

* build(sqlite): 📦 合并sqlite分支代码

* fix(common): 🐛 mac docker 计数

* fix(common): 🐛 添加macos编译;解决rust警告

* fix(common): 🐛 mac badge 计数

* fix(common): 🐛 修复自动登录问题;修复watch 的异步问题导致的数据竞态问题

* fix(common): 🐛 删除会话功能;

* build(ios): 📦 增加移动端所需的配置

* fix(common): 🐛 ios 启动 tauri 插件和命令适配

* fix(common): 🐛 查询消息根据 id 排序时,将 id 转为数值进行排序

* refactor(common): ♻️ 使用 tracing 作为日志框架

* fix(unreadCount): 🐛 修复标记重复问题

* style(lint): 💄 优化了biome的配置

按照新的biome配置格式化代码

* style(biome): 💄 完善biome规则配置

* style(biome): 💄 增加自动移除未使用的导入

* feat(mobile):  新增“我的”页面内容及动画,修复安全边距问题

* fix(common): 🐛 修改AnnouncementBody类型

* fix(common): 🐛 修改 ApiResult 类型

* feat(mobile):  新增聊天室页面

* fix(ios): 🐛 添加log依赖

* fix(common): 🐛 去掉 home 窗口的重复监听

* fix(common): 🐛 发送消息接口,用channel 代替 event,解决系统卡死;

* fix(common): 🐛 android启动问题

* fix(rust): 🐛 修复ios签名问题

修复ios底部栏不显示问题|移除冗余的权限配置

* refactor(common): ♻️ 将 db.sqlite 设置为resource,通过 tauri api 进行读取

* test(common):  新增视频通话局部代码

* fix(rust): 🐛 修复移动端无法启动并且无法创建对应文件的问题

* test(common):  优化通话逻辑

* feat(mobile):  新增客户端对象,修复加载页载入问题

* chore(common): 🔨 修改 tauri 配置文件

* ci(log): 🎡 修改日志打印的级别和语言都为英文

* fix(common): 🐛 notify_cotent事件修改

* feat(common):  初步实现 webrtc

* fix(common): 🐛 发送视频通话请求

* fix(common): 🐛 webrtc实现-待测试

* fix(common): 🐛 webrtc-测试

* style(common): 💄 webrtc 页面 ui调整

* fix(common): 🐛 rtc 页面头像显示

* fix(common): 🐛 rtc 第一次切换摄像头未显示远程

* fix(common): 🐛 webrtc 挂断

* fix(common): 🐛 rtc 通话结束

* fix(common): 🐛 ws监听挂断消息

* fix(common): 🐛 rtc 设备检查

* fix(common): 🐛 检查audiooutput

* fix(common): 🐛 检查音量来判断用户是否开启 audio

* fix(common): 🐛 检查音量判断声音设备

* fix(agreement): 🐛 前端对接cloud的刷新token

* fix(common): 🐛 重构 webrtc

* fix(common): 🐛 webrtc 异常

* fix(common): 🐛 rtc 异常

* fix(common): 🐛 rtc candidate

* fix(common): 🐛 通知窗口

* fix(common): 🐛 rtc 通话时间显示

* fix(common): 🐛 关闭扬声器功能

* fix(common): 🐛 关闭麦克风

* fix(common): 🐛 win 通知窗口显示问题

* fix(common): 🐛 rtc调整设置通知通知栏的高度

* feat(common):  新增处理进群审核接口、音视频处理约定逻辑

* fix(common): 🐛 前端刷新 token 之后调用 command 更新 rust 部分的 token

* fix(common): 🐛 显示视频通话消息

* fix(common): 🐛 webrtc 语音通话调用

* fix(common): 🐛 查询所有会话 bug

* build(build): 📦 升级一些依赖版本

* refactor(common): ♻️ rust 重构ws

* style(avatar): 💄 优化头像加载失败时候展示的图片

* fix(common): 🐛 rust ws

* fix(common): 🐛 修复群聊状态显示、同步后端打电话逻辑

* fix(common): 🐛 查询群成员报错 异步问题

* fix(common): 🐛 群成员 异步问题

* refactor(common): ♻️ rust 异常处理

* fix(common): 🐛 消息 骨架屏 异常

* fix(common): 🐛 删除无用代码

* fix(common): 🐛 win 图标闪烁问题

* fix(common): 🐛 ws 保活

* feat(ChatFooter):  增加输入框和ChatFooter组件的拖拽效果

优化私聊在线状态

* fix(common): 🐛 webrtc 切换视频关闭远程视频流

* fix(common): 🐛 message mark issue resolve

* fix(common): 🐛 message mark issue resolve

* refactor(common): ♻️ delete useless code

* fix(common): 🐛 save_room_member_batch cause database lock

* fix(common): 🐛 show the system messgage of join group

* fix(common): 🐛 message sound

* build(img): 📦 压缩一些图片为webp

修改一下代码的逻辑

* perf(global):  优化群成员排序、输入框发送事件为form表单的提交事件

优化chatfooter输入框高度拖拽和home窗口拖拽时性能问题
优化home窗口拖拽会持续触发当前会话选中后对应房间已读触发问题

* chore(lint): 🔨 优化lint的配置

* perf(rtcCall):  优化通话窗口的样式和关闭窗口会挂断的功能

* fix(common): 🐛 ws reconnect in backend reboot

* fix(common): 🐛 webrtc relate message show

* fix(common): 🐛 ws delete useless code

* fix(common): 🐛 resolve ws multi connection

* docs(config): 📝 更新群二维码和赞助榜

* fix(common): 🐛 ws setAppBackGroundState

* fix(common): 🐛 env config modify

* fix(common): 🐛 webrtc on CANCEL

* fix(common): 🐛 group announcement update

* fix(common): 🐛 announcement issuce

* fix(common): 🐛 webrtc windows dragable

* fix(system): 🐛 fix location of call component and some page styles

* fix(common): 🐛 webrtc issue

* ci(common): 🎡 .env.dev modify

* fix(common): 🐛 gET_ROOM_MEMBERS command issue

* fix(common): 🐛 update my group info

* fix(common): 🐛 webrtc audio call issue

* fix(common): 🐛 webrtc video or audio status switch issue

* fix(group): 🐛 fixed some logic and restrictions on inviting members into groups

Optimize Create Script

* style(style): 💄 remove some styles and comments

* fix(common): 🐛 fix WebRTC audio cannot be heard

* fix(common): 🐛 info import error

* fix(common): 🐛 fix #ICT1BO group info update

* fix(common): 🐛 fix "不是好友关系" issue

* fix(common): 🐛 add group apply list

* fix(common): 🐛 webrtc if can't acquire device then hang up

* fix(common): 🐛 mute local video ele

* fix(common): 🐛 同步最新申请接口

* fix(common): 🐛 change isSpeakerOn and mute the bell

* fix(common): 🐛 group apply invite dom

* style(style): 💄 change the style of language statistics and incoming call notifications

---------

Co-authored-by: ql <254693270@qq.com>
Co-authored-by: 卡仔 <1271013637@qq.com>
Co-authored-by: 乾乾 <1046762075@qq.com>
This commit is contained in:
Dawn
2025-08-15 19:23:55 +08:00
committed by GitHub
parent 2c9e2d0376
commit ac3dac35a3
340 changed files with 12828 additions and 6822 deletions

View File

@@ -8,4 +8,37 @@ registry = "sparse+https://rsproxy.cn/index/"
[registries.rsproxy]
index = "https://rsproxy.cn/crates.io-index"
[net]
git-fetch-with-cli = true
git-fetch-with-cli = true
# Android NDK 链接配置
[target.aarch64-linux-android]
linker = "aarch64-linux-android-clang"
rustflags = [
"-C", "link-arg=-lc++_shared",
"-C", "link-arg=-llog",
"-C", "link-arg=-landroid",
]
[target.armv7-linux-androideabi]
linker = "armv7a-linux-androideabi-clang"
rustflags = [
"-C", "link-arg=-lc++_shared",
"-C", "link-arg=-llog",
"-C", "link-arg=-landroid",
]
[target.i686-linux-android]
linker = "i686-linux-android-clang"
rustflags = [
"-C", "link-arg=-lc++_shared",
"-C", "link-arg=-llog",
"-C", "link-arg=-landroid",
]
[target.x86_64-linux-android]
linker = "x86_64-linux-android-clang"
rustflags = [
"-C", "link-arg=-lc++_shared",
"-C", "link-arg=-llog",
"-C", "link-arg=-landroid",
]

View File

@@ -2,9 +2,9 @@
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 末尾空格修剪
insert_final_newline = true # 始终在文件末尾插入一个新行
[*]
charset = utf-8
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

View File

@@ -1,7 +1,7 @@
# 后端服务地址
VITE_SERVICE_URL="https://hulaspark.com/api"
# # websocket服务地址
VITE_WEBSOCKET_URL="wss://hulaspark.com/websocket"
# websocket服务地址
VITE_WEBSOCKET_URL="wss://hulaspark.com/api/ws/ws"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 项目名称
@@ -9,6 +9,11 @@ VITE_APP_NAME="HuLa"
# gitee token
VITE_GITEE_TOKEN="a9029798336825cea39ac9e4413b8579"
# 启用本地的服务地址,先要注释掉上面的服务地址
# VITE_SERVICE_URL="http://192.168.1.24:9190"
# VITE_WEBSOCKET_URL="ws://192.168.1.24:8090/websocket"
# TURN信令服务器
VITE_TURN_SERVER_URL=
VITE_TURN_SERVER_USER=
VITE_TURN_SERVER_PWD=
VITE_USE_RUST_WEBSOCKET=true
RUST_BACKTRACE=1
APP_ENVIRONMENT=local

View File

@@ -1,10 +1,19 @@
# 后端服务地址
VITE_SERVICE_URL="https://hulaspark.com/api"
# websocket服务地址
VITE_WEBSOCKET_URL="wss://hulaspark.com/websocket"
VITE_WEBSOCKET_URL="wss://hulaspark.com/api/ws/ws"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 项目名称
VITE_APP_NAME="HuLa"
# gitee token
VITE_GITEE_TOKEN="a9029798336825cea39ac9e4413b8579"
# TURN信令服务器
VITE_TURN_SERVER_URL=
VITE_TURN_SERVER_USER=
VITE_TURN_SERVER_PWD=
VITE_USE_RUST_WEBSOCKET=true
RUST_BACKTRACE=1
APP_ENVIRONMENT=production

View File

@@ -1,14 +0,0 @@
node_modules
*.md
*.scss
.vscode
.idea
dist
public
index.html
src/assets
.eslintrc.cjs
**/config
src-tauri/**
commitlint.config.cjs
auto-imports.d.ts

57
.eslintrc.cjs vendored
View File

@@ -1,57 +0,0 @@
module.exports = {
// 运行环境
env: {
browser: true, // 浏览器
es6: true, // es6语法
jest: true
},
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true
}
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-essential',
'plugin:prettier/recommended'
],
overrides: [
{
env: {
node: true
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script'
}
}
],
plugins: ['@typescript-eslint', 'vue'],
rules: {
'@typescript-eslint/no-non-null-assertion': 'off',
/** 允许ts使用命名空间 */
'@typescript-eslint/no-namespace': 'off',
/**
* 使用新vue3.3的defineProps解构语法需要关闭这个校验
* eslint-plugin-vue新版本已废弃 vue/no-setup-props-destructure,如果新版本eslint-plugin-vue
* 需要改成vue/no-setup-props-reactivity-loss规则
* */
'vue/no-setup-props-destructure': 'off',
'no-undef': 'off',
'no-var': 'error', // 不能使用var
'no-multiple-empty-lines': ['warn', { max: 2 }], // 不允许多个空行
quotes: [1, 'single'], //引号类型 `` "" ''
semi: ['error', 'never'], // 不允许在末尾加分号
'vue/multi-word-component-names': 'off', //关闭组件命名规则
'@typescript-eslint/no-explicit-any': 'off', // 关闭any校验
'no-redeclare': 2, //禁止重复声明变量
'eol-last': 'off', // 关闭行尾符linebreak-style的校验
'vue/use-v-on-exact': 'off', // 如果使用了键盘事件,这个规则必须添加 exact,例如 `@keydown.exact`。该事件对 chat-editor 存在影响
}
}

34
.gitattributes vendored
View File

@@ -1,5 +1,7 @@
# Auto detect text files and perform LF normalization
* text=auto eol=lf
# 行尾符设置
"*.rs" eol=lf
"Cargo.toml" eol=lf
"Cargo.lock" eol=lf
@@ -20,3 +22,35 @@
"*.sass" eol=lf
"*.styl" eol=lf
"*.md" eol=lf
# 代码统计设置 - 只统计 Vue、TypeScript 和 Rust 文件
# 排除 JavaScript 文件
"*.js" linguist-vendored
"*.jsx" linguist-vendored
"*.cjs" linguist-vendored
"*.mjs" linguist-vendored
# 排除样式文件
"*.css" linguist-vendored
"*.scss" linguist-vendored
"*.sass" linguist-vendored
"*.less" linguist-vendored
"*.styl" linguist-vendored
# 排除配置和文档文件
"*.json" linguist-vendored
"*.html" linguist-vendored
"*.md" linguist-documentation
"*.yml" linguist-vendored
"*.yaml" linguist-vendored
# 排除其他语言文件
"*.kt" linguist-vendored
"*.java" linguist-vendored
"*.py" linguist-vendored
# 确保构建目录和依赖目录不被统计
"**/target/**" linguist-vendored
"/node_modules/**" linguist-vendored
"/scripts/**" linguist-vendored
"/build/**" linguist-vendored

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ target
.claude/
*.sqlite
db.sqlite
.idea

19
.lintstagedrc.mjs vendored
View File

@@ -5,11 +5,18 @@ function createCommand(prefix, join) {
}
export default {
'*.{js,jsx,ts,tsx,vue}': [
'oxlint src',
createCommand('pnpm eslint --fix', ''),
createCommand('prettier --write', '--write'),
// () => 'pnpm test:run',
() => 'vue-tsc --noEmit'
// JavaScript/TypeScript 文件使用 Biome (排除 .d.ts 文件)
'*.{js,jsx,ts,tsx,json}': [
(filenames) => {
const filteredFiles = filenames.filter((f) => !f.includes('src-tauri/') && !f.endsWith('.d.ts'))
return filteredFiles.length > 0
? `biome check --write --unsafe ${filteredFiles.map((f) => path.relative(process.cwd(), f)).join(' ')}`
: 'echo "No files to check"'
}
],
// Vue 文件:使用 Biome 检查和修复,然后用 Prettier 格式化
'*.vue': [
createCommand('biome check --write --unsafe', ''),
createCommand('prettier --write', '')
]
}

View File

@@ -4,11 +4,11 @@
"printWidth": 120,
"useTabs": false,
"tabWidth": 2,
"jsxSingleQuote": false,
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "always",
"bracketSameLine": true,
"jsxBracketSameLine": true,
"endOfLine": "lf"
}
"endOfLine": "lf",
"vueIndentScriptAndStyle": false,
"htmlWhitespaceSensitivity": "ignore"
}

View File

@@ -1,7 +1,5 @@
{
"css.customData": [
".vscode/tailwindcss.json"
],
"java.configuration.updateBuildConfiguration": "disabled",
"typescript.tsdk": "node_modules/typescript/lib",
"css.customData": [".vscode/tailwindcss.json"],
"java.configuration.updateBuildConfiguration": "disabled",
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@@ -348,7 +348,7 @@ Execute **pnpm run commit** to invoke _git commit_ interaction, complete informa
| 2025-05-27 | **临安居士** | `¥188` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-04-20 | **姜兴(Simon)** | `¥188` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-02-17 | **禾硕** | `¥168` | ![Alipay](https://img.shields.io/badge/Alipay-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-07-15 | **zhongjing** | `¥100` | ![WeChat](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-08-13 | **zhongjing** | `¥100` | ![WeChat](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-07-15 | **粉兔** | `¥100` | ![WeChat](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-02-8 | **Boom....** | `¥100` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |
@@ -366,7 +366,7 @@ Execute **pnpm run commit** to invoke _git commit_ interaction, complete informa
### 🥉 Bronze Sponsors ($3-7)
| 💝 Date | 👤 Sponsor | 💰 Amount | 🏷️ Platform |
|---------|----------|--------|---------|
| 2025-06-03 | ***持** | `¥20` | ![Alipay](https://img.shields.io/badge/支付宝赞赏-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-08-12 | ***持** | `¥20` | ![Alipay](https://img.shields.io/badge/支付宝赞赏-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-06-03 | **洪流** | `¥20` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-05-27 | **刘启成** | `¥20` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-05-20 | **匿名赞助者** | `¥20` | ![WeChat](https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white) |

View File

@@ -349,7 +349,7 @@ sudo xattr -r -d com.apple.quarantine /Applications/应用名称.app
| 2025-05-27 | **临安居士** | `¥188` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-04-20 | **姜兴(Simon)** | `¥188` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-02-17 | **禾硕** | `¥168` | ![支付宝赞赏](https://img.shields.io/badge/支付宝赞赏-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-07-15 | **zhongjing** | `¥100` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-08-13 | **zhongjing** | `¥100` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-07-15 | **粉兔** | `¥100` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-02-8 | **Boom....** | `¥100` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
@@ -367,7 +367,7 @@ sudo xattr -r -d com.apple.quarantine /Applications/应用名称.app
### 🥉 铜牌赞助者 (¥20-49)
| 💝 日期 | 👤 赞助者 | 💰 金额 | 🏷️ 平台 |
|---------|----------|--------|---------|
| 2025-06-03 | ***持** | `¥20` | ![支付宝赞赏](https://img.shields.io/badge/支付宝赞赏-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-08-12 | ***持** | `¥20` | ![支付宝赞赏](https://img.shields.io/badge/支付宝赞赏-1677FF?style=flat&logo=alipay&logoColor=white) |
| 2025-06-03 | **洪流** | `¥20` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-05-27 | **刘启成** | `¥20` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |
| 2025-05-20 | **匿名赞助者** | `¥20` | ![微信赞赏](https://img.shields.io/badge/微信赞赏-07C160?style=flat&logo=wechat&logoColor=white) |

112
biome.json vendored Normal file
View File

@@ -0,0 +1,112 @@
{
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
"files": {
"ignoreUnknown": false,
"includes": [
"**/*.{js,jsx,ts,tsx,vue,json}",
"!.*/**",
"!public/**",
"!src/typings/*.d.ts",
"!src-tauri/**",
"!node_modules/**",
"!dist/**"
]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 120,
"attributePosition": "auto",
"bracketSameLine": true,
"bracketSpacing": true,
"expand": "auto",
"useEditorconfig": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"a11y": {
"noStaticElementInteractions": "off",
"useKeyWithClickEvents": "off",
"noSvgWithoutTitle": "off",
"useAltText": "off"
},
"complexity": {
"useOptionalChain": "off",
"useLiteralKeys": "off",
"useDateNow": "off",
"noStaticOnlyClass": "off"
},
"correctness": {
"noUnusedVariables": "warn",
"noUnusedImports": "warn"
},
"style": {
"useNodejsImportProtocol": "off",
"noNonNullAssertion": "off",
"useNamingConvention": "off",
"useTemplate": "off"
},
"suspicious": {
"noGlobalIsNan": "off",
"noExplicitAny": "off",
"noAssignInExpressions": "off",
"noImplicitAnyLet": "off",
"noConfusingVoidType": "off",
"noArrayIndexKey": "off"
}
}
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "none",
"semicolons": "asNeeded",
"arrowParentheses": "always",
"bracketSameLine": true,
"quoteStyle": "single",
"attributePosition": "auto",
"bracketSpacing": true
}
},
"json": {
"formatter": {
"trailingCommas": "none"
}
},
"assist": {
"enabled": true,
"actions": { "source": { "organizeImports": "on" } }
},
"overrides": [
{
"includes": ["**/*.vue"],
"linter": {
"rules": {
"correctness": {
"noUnusedVariables": "off",
"noUnusedImports": "off"
},
"style": {
"useNamingConvention": "off",
"useTemplate": "off"
},
"suspicious": {
"noExplicitAny": "off",
"noAssignInExpressions": "off",
"noImplicitAnyLet": "off"
}
}
},
"formatter": {
"enabled": true
}
}
]
}

View File

@@ -1,5 +1,5 @@
//使用path需要按照@types/node依赖
import path from 'path'
import path from 'node:path'
/**
* 获取项目根路径

123
index.html vendored
View File

@@ -2,16 +2,131 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no viewport-fit=cover" />
<title>HuLa</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no viewport-fit=cover" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<!--引入iconpark图标库-->
<script defer src="/icon.js"></script>
<!-- 🎯 预加载图片资源(仅移动端) -->
<script>
if (/Mobi|Android|iPhone/i.test(navigator.userAgent)) {
const preloadImages = ['/Mobile/1.png', '/Mobile/2.png', '/Mobile/3.png', '/Mobile/4.png']
preloadImages.forEach(src => {
const link = document.createElement('link')
link.rel = 'preload'
link.as = 'image'
link.href = src
document.head.appendChild(link)
})
}
</script>
<!-- iconpark图标库 -->
<script async src="/icon.js"></script>
<!-- 🧩 加载页样式 -->
<style id="loading-css">
#loading-page {
position: fixed;
inset: 0;
z-index: 9999;
background-image: url('/Mobile/2.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
transition: opacity 0.4s ease-out;
opacity: 1;
}
.bottom-bar {
position: absolute;
bottom: 40px;
display: flex;
gap: 16px;
align-items: center;
}
.rounded-14px {
border-radius: 14px;
}
.size-50px {
width: 50px;
height: 50px;
}
.w-300px {
width: 300px;
}
.h-200px {
height: 200px;
}
.w-78px {
width: 78px;
}
.h-40px {
height: 40px;
}
.mb-140px {
margin-bottom: 140px;
}
</style>
</head>
<body>
<!-- 🚀 加载页 DOM -->
<div id="loading-page">
<img src="/Mobile/4.png" alt="hula" class="w-300px h-200px mb-140px" />
<div class="bottom-bar">
<img src="/Mobile/3.png" alt="hula" class="size-50px rounded-14px" />
<img src="/Mobile/1.png" alt="hula" class="w-78px h-40px" />
</div>
</div>
<!-- Vue 应用挂载点 -->
<div id="app"></div>
<!-- 🎯 加载页逻辑控制(淡出 + 清理) -->
<script>
function isMobileDevice() {
return /Mobi|Android|iPhone/i.test(navigator.userAgent)
}
if (!isMobileDevice()) {
document.getElementById('loading-page')?.remove()
document.getElementById('loading-css')?.remove()
}
window.addEventListener('DOMContentLoaded', () => {
const interval = setInterval(() => {
const isMounted = document.getElementById('app')?.children.length > 0
if (isMounted) {
const loader = document.getElementById('loading-page')
if (loader) {
loader.style.opacity = '0'
setTimeout(() => {
loader.remove()
document.getElementById('loading-css')?.remove()
}, 450) // 等待 transition 完成后再移除
}
clearInterval(interval)
}
}, 100)
})
</script>
<!-- 🚀 Vue 应用入口 -->
<script type="module" src="/src/main.ts"></script>
</body>
</html>

72
package.json vendored
View File

@@ -22,6 +22,7 @@
"build": "vue-tsc --noEmit && vite build",
"========= 启动HuLa桌面应用程序 =========": "",
"tauri:dev": "tauri dev",
"td": "tauri dev",
"========= 打包桌面应用程序 =========": "",
"tauri:build": "tauri build",
"========= 打包后可调试并且可以弹出控制台 =========": "",
@@ -42,7 +43,15 @@
"preinstall": "npx only-allow pnpm && node scripts/check-all.js",
"========= 使用commit来进行代码提交 =========": "",
"commit": "git add . && git-cz",
"========= 校验代码规范 =========": "",
"========= 只检查代码问题和格式(不修复) =========": "",
"check": "biome check",
"========= 修复代码问题和格式并且检查 =========": "",
"check:write": "biome check --write --unsafe",
"========= 格式化Vue文件模板 =========": "",
"format:vue": "npx prettier --write \"src/**/*.vue\"",
"========= 完整格式化(JS+Vue) =========": "",
"format:all": "pnpm check:write && pnpm format:vue",
"========= Git提交前的代码检查 =========": "",
"lint:staged": "lint-staged && vue-tsc --noEmit",
"========= 安装husky =========": "",
"prepare": "husky",
@@ -63,12 +72,12 @@
"@actions/github": "^6.0.0",
"@breezystack/lamejs": "^1.2.7",
"@fingerprintjs/fingerprintjs": "^4.6.2",
"@tauri-apps/api": "2.6.0",
"@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-autostart": "2.5.0",
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
"@tauri-apps/plugin-dialog": "^2.3.0",
"@tauri-apps/plugin-fs": "^2.4.0",
"@tauri-apps/plugin-http": "2.5.0",
"@tauri-apps/plugin-dialog": "^2.3.2",
"@tauri-apps/plugin-fs": "^2.4.1",
"@tauri-apps/plugin-http": "2.5.1",
"@tauri-apps/plugin-log": "^2.6.0",
"@tauri-apps/plugin-notification": "^2.3.0",
"@tauri-apps/plugin-opener": "^2.4.0",
@@ -81,7 +90,6 @@
"@vue-office/excel": "^1.7.14",
"@vue-office/pdf": "^2.0.10",
"@vue-office/pptx": "^1.0.1",
"base64url": "^3.0.1",
"colorthief": "^2.6.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.11",
@@ -99,57 +107,50 @@
"seemly": "^0.3.10",
"tauri-plugin-mic-recorder-api": "^2.0.0",
"tauri-plugin-safe-area-insets": "^0.1.0",
"vue": "^3.5.17",
"vue": "^3.5.18",
"vue-cropper": "1.1.4",
"vue-demi": "0.14.6",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@babel/eslint-parser": "^7.25.9",
"@biomejs/biome": "^2.1.4",
"@commitlint/cli": "^19.6.0",
"@commitlint/config-conventional": "^19.6.0",
"@iconify/vue": "^5.0.0",
"@release-it/bumper": "^6.0.1",
"@release-it/conventional-changelog": "8.0.2",
"@rollup/plugin-terser": "^0.4.4",
"@tauri-apps/cli": "2.6.2",
"@tauri-apps/cli": "2.7.1",
"@types/crypto-js": "^4.2.2",
"@types/lodash-es": "^4.17.12",
"@types/node": "^24.0.10",
"@typescript-eslint/eslint-plugin": "7.1.0",
"@typescript-eslint/parser": "^7.15.0",
"@unocss/preset-wind3": "^66.3.3",
"@unocss/reset": "^66.3.3",
"@unocss/transformer-directives": "^66.3.3",
"@unocss/transformer-variant-group": "^66.3.3",
"@unocss/vite": "^66.3.3",
"@vitejs/plugin-vue": "^6.0.0",
"@unocss/preset-wind3": "^66.4.2",
"@unocss/reset": "^66.4.2",
"@unocss/transformer-directives": "^66.4.2",
"@unocss/transformer-variant-group": "^66.4.2",
"@unocss/vite": "^66.4.2",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.0.1",
"@vitest/coverage-v8": "^3.0.5",
"@vitest/ui": "^3.0.5",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.2.4",
"@vue/test-utils": "^2.4.6",
"@vueuse/core": "^13.5.0",
"chalk": "^5.3.0",
"commitizen": "^4.3.1",
"cz-git": "^1.11.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.27.0",
"happy-dom": "^15.11.7",
"husky": "^9.0.11",
"husky": "^9.1.7",
"lint-staged": "^15.2.7",
"oxlint": "^0.2.18",
"prettier": "^3.3.2",
"prettier": "^3.6.2",
"release-it": "^17.11.0",
"sass": "1.89.2",
"typescript": "^5.8.3",
"sass": "1.90.0",
"typescript": "^5.9.2",
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0",
"vite": "7.0.5",
"vite": "7.1.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vitest": "^3.0.5",
"vue-tsc": "^3.0.1"
"vitest": "^3.2.4",
"vue-tsc": "^3.0.5"
},
"config": {
"commitizen": {
@@ -157,11 +158,6 @@
}
},
"pnpm": {
"ignoredBuiltDependencies": [
"esbuild",
"vue-demi",
"@parcel/watcher",
"sharp"
]
"ignoredBuiltDependencies": ["esbuild", "vue-demi", "@parcel/watcher", "sharp"]
}
}

3609
pnpm-lock.yaml generated vendored

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

BIN
public/Mobile/1.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 KiB

BIN
public/Mobile/2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

BIN
public/Mobile/3.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

BIN
public/Mobile/4.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

BIN
public/avatar/001.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

BIN
public/avatar/002.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

BIN
public/avatar/003.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

BIN
public/avatar/004.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

BIN
public/avatar/005.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

BIN
public/avatar/006.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

BIN
public/avatar/007.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

BIN
public/avatar/008.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

BIN
public/avatar/009.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

BIN
public/avatar/010.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

BIN
public/avatar/011.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

BIN
public/avatar/012.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

BIN
public/avatar/013.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

BIN
public/avatar/014.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

BIN
public/avatar/015.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

BIN
public/avatar/016.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

BIN
public/avatar/017.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

BIN
public/avatar/018.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

BIN
public/avatar/019.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

BIN
public/avatar/020.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

BIN
public/avatar/021.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
public/avatar/022.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

2
public/icon.js vendored

File diff suppressed because one or more lines are too long

BIN
public/logoD.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
public/logoL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
public/sound/hula_bell.mp3 Normal file

Binary file not shown.

BIN
public/sound/message.mp3 Normal file

Binary file not shown.

View File

@@ -1,7 +1,7 @@
import { execSync } from 'child_process'
import chalk from 'chalk'
import { fileURLToPath } from 'url'
import { execSync } from 'child_process'
import { dirname, join } from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
@@ -20,7 +20,7 @@ async function runScript(scriptPath, description) {
const duration = ((performance.now() - startTime) / 1000).toFixed(2)
console.log(chalk.green(`\n${description}完成 (${duration}s)\n`))
return true
} catch (error) {
} catch (_error) {
console.error(chalk.red(`\n${description}失败`))
return false
}

View File

@@ -1,7 +1,7 @@
import { execSync } from 'child_process'
import chalk from 'chalk'
import { platform } from 'os'
import { execSync } from 'child_process'
import { existsSync } from 'fs'
import { platform } from 'os'
// 环境安装指南
const INSTALL_GUIDES = {

40
scripts/check-env.js vendored
View File

@@ -1,12 +1,12 @@
import { existsSync, writeFileSync } from 'fs'
import { join } from 'path'
import chalk from 'chalk'
import { existsSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
// 用于写入.env.local配置文件该文件默认不会被git管理所以不必担心会提交到远程仓库
const envPath = join(process.cwd(), '.env.local')
// 用于写入 .env.development.local 配置文件
const devEnvPath = join(process.cwd(), '.env.development')
const devLocalEnvPath = join(process.cwd(), '.env.development.local')
if (!existsSync(envPath)) {
const defaultEnvContent = `# 有道云翻译key
const defaultEnvContent = `# 有道云翻译key
VITE_YOUDAO_APP_KEY=
VITE_YOUDAO_APP_SECRET=
# 腾讯云翻译key
@@ -14,13 +14,25 @@ VITE_TENCENT_API_KEY=
VITE_TENCENT_SECRET_ID=
`
try {
writeFileSync(envPath, defaultEnvContent, 'utf8')
console.log(chalk.green('✨ 成功创建.env.local文件'))
} catch (error) {
console.log(chalk.red('\n❌ 创建.env.local文件失败。'))
process.exit(1)
try {
if (existsSync(devLocalEnvPath)) {
console.log(chalk.green('✅ 检测到 .env.development.local 已存在,跳过创建'))
process.exit(0)
}
} else {
console.log(chalk.green('✅ .env.local文件已创建'))
let content = defaultEnvContent
if (existsSync(devEnvPath)) {
const devContent = readFileSync(devEnvPath, 'utf8')
content += (content.endsWith('\n') ? '' : '\n') + devContent
}
writeFileSync(devLocalEnvPath, content, 'utf8')
if (existsSync(devEnvPath)) {
console.log(chalk.green('✨ 已创建 .env.development.local'))
} else {
console.log(chalk.yellow('⚠️ 未找到 .env.development仅创建默认模板的 .env.development.local'))
}
} catch (_error) {
console.log(chalk.red('\n❌ 处理 .env.development.local 文件失败。'))
process.exit(1)
}

View File

@@ -1,2 +0,0 @@
RUST_BACKTRACE=1
DATABASE_URL=sqlite:../db.sqlite?mode=rwc

703
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,11 +31,11 @@ name = "hula_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.3.0", features = [] }
tauri-build = { version = "2.3.1", features = [] }
[dependencies]
# Tauri 官方依赖
tauri = { version = "2.6.2", features = [
tauri = { version = "2.7.0", features = [
"protocol-asset",
"macos-private-api",
"tray-icon",
@@ -57,6 +57,10 @@ tauri-plugin-clipboard-manager = "2"
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
tauri-plugin-notification = "2"
tauri-plugin-opener = "2"
# tauri-plugin-devtools = "2"
tauri-plugin-log = { version = "2", features = ["colored"] }
tracing = "0.1"
tracing-subscriber = "0.3.0"
# Tauri 非官方依赖
tauri-plugin-mic-recorder = "2"
@@ -66,9 +70,8 @@ async-walkdir = "2.0.0"
moka = { version = "0.12.10", features = ["future"] }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] }
tauri-plugin-devtools = "2.0.0"
sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "runtime-tokio-rustls", "macros" ] }
sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "runtime-tokio-rustls", "macros", "debug-print" ] }
chrono = "0.4.41"
entity = { path = "entity" }
@@ -77,23 +80,28 @@ anyhow = "1.0.98"
thiserror = "2.0.12"
config = { version = "0.15.11", default-features = false, features = ["yaml"] }
http = "0.2"
tauri-plugin-log = { version = "2.6.0", features = ["colored"] }
log = "0.4" # 基础日志接口
lazy_static = "1.4"
mime_guess = "2.0.5"
base64 = "0.22.1"
rodio = "0.17.3"
image = { version = "0.25", features = ["jpeg", "png"] }
reqwest = { version = "0.11", features = [
reqwest = { version = "0.11", default-features = false, features = [
"json",
"socks",
"rustls-tls",
"blocking",
] }
futures = "0.3"
dotenv = "0.15.0"
# 安卓的依赖
[target."cfg(target_os = \"android\")".dependencies]
# WebSocket 相关依赖
tokio-tungstenite = { version = "0.23", features = ["rustls-tls-webpki-roots"] }
futures-util = "0.3"
url = "2.5"
uuid = { version = "1.10", features = ["v4"] }
# 移动端的依赖 (iOS 和 Android)
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
tauri-plugin-safe-area-insets = "0.1.0"
# 不兼容移动端的依赖

10
src-tauri/Info.plist Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>Request camera access for WebRTC</string>
<key>NSMicrophoneUsageDescription</key>
<string>Request microphone access for WebRTC</string>
</dict>
</plist>

View File

@@ -96,6 +96,7 @@
"opener:allow-open-path",
"mic-recorder:default",
"log:default",
"log:allow-log",
{
"identifier": "shell:allow-execute",
"allow": [
@@ -180,54 +181,6 @@
"url": "https://*:*"
}
]
},
{
"identifier": "fs:write-files",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-mkdir",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:read-dirs",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:read-files",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-copy-file",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-read-text-file",
"allow": [
{
"path": "**"
}
]
}
]
}

View File

@@ -6,6 +6,7 @@
"windows": ["*"],
"permissions": [
"core:default",
"core:webview:allow-internal-toggle-devtools",
"http:allow-fetch",
"http:allow-fetch-cancel",
"http:allow-fetch-read-body",
@@ -36,6 +37,8 @@
"notification:allow-create-channel",
"notification:allow-permission-state",
"safe-area-insets:default",
"log:default",
"log:allow-log",
{
"identifier": "shell:allow-execute",
"allow": [
@@ -120,54 +123,6 @@
"url": "https://*:*"
}
]
},
{
"identifier": "fs:write-files",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-mkdir",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:read-dirs",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:read-files",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-copy-file",
"allow": [
{
"path": "**"
}
]
},
{
"identifier": "fs:allow-read-text-file",
"allow": [
{
"path": "**"
}
]
}
]
}

View File

@@ -1,7 +1,4 @@
# application:
# host: 127.0.0.1
# base_url: "http://127.0.0.1"
# database:
# require_ssl: false
# backend:
# base_url: http://localhost:9190
database:
sqlite_file: db.sqlite
backend:
base_url: https://hulaspark.com/api

View File

@@ -1,4 +1,4 @@
# application:
# host: 127.0.0.1
# backend:
# base_url: http://localhost:9190
database:
sqlite_file: db.sqlite
backend:
base_url: https://hulaspark.com/api

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"
[dependencies]
sea-orm = { version = "1.1.0" }
sea-orm = { version = "1.1.14" }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
serde_json = "1.0.141"

View File

@@ -10,15 +10,15 @@ pub struct Model {
pub detail_id: String,
pub room_id: String,
#[serde(rename = "type")]
pub contact_type: Option<u8>,
pub hot_flag: Option<u8>,
pub contact_type: Option<u32>,
pub hot_flag: Option<u32>,
pub top: Option<bool>,
pub account: Option<String>,
pub operate: Option<u8>,
pub operate: Option<u32>,
pub remark: Option<String>,
pub my_name: Option<String>,
// "通知类型 0 -> 允许接受消息 1 -> 接收但不提醒[免打扰] 4 -> 已退出群聊"
pub mute_notification: Option<u8>,
pub mute_notification: Option<u32>,
// 删除会话
pub hide: Option<bool>,
pub active_time: Option<i64>,
@@ -28,7 +28,7 @@ pub struct Model {
#[serde(rename = "name")]
pub contact_name: Option<String>,
pub text: Option<String>,
pub unread_count: Option<u8>,
pub unread_count: Option<u32>,
pub create_time: Option<i64>,
pub update_time: Option<i64>,
#[serde(skip)]

View File

@@ -24,7 +24,8 @@ pub struct Model {
pub send_status: String,
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -13,6 +13,7 @@ pub struct Model {
pub account: Option<String>,
pub my_name: Option<String>,
pub active_status: Option<u8>,
#[serde(rename = "roleId")]
pub group_role: Option<i64>,
pub loc_place: Option<String>,
pub last_opt_time: i64,

View File

@@ -1,4 +1,4 @@
/src/main/java/com/hula_app/app/generated
/src/main/java/com/hula_ios/app/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts

View File

@@ -15,14 +15,21 @@ val tauriProperties = Properties().apply {
android {
compileSdk = 34
namespace = "com.hula_app.app"
namespace = "com.hula_ios.app"
ndkVersion = "25.1.8937393"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.hula_app.app"
applicationId = "com.hula_ios.app"
minSdk = 24
targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
}
}
buildTypes {
getByName("debug") {

View File

@@ -0,0 +1,4 @@
database:
sqlite_file: db.sqlite
backend:
base_url: http://192.168.1.37:18760

View File

@@ -0,0 +1,4 @@
database:
sqlite_file: db.sqlite
backend:
base_url: http://192.168.1.37:18760

View File

@@ -0,0 +1,4 @@
database:
sqlite_file: db.sqlite
backend:
base_url: http://192.168.1.37:18760

View File

@@ -1,4 +1,4 @@
package com.hula_app.app
package com.hula_ios.app
import android.os.Bundle
import android.webkit.WebView

0
src-tauri/gen/android/gradlew vendored Normal file → Executable file
View File

View File

@@ -0,0 +1,4 @@
database:
sqlite_file: db.sqlite
backend:
base_url: http://192.168.1.37:18760

Some files were not shown because too many files have changed in this diff Show More