mirror of
https://gitee.com/HuLaSpark/HuLa.git
synced 2024-11-29 10:18:35 +08:00
commit
6e81821b46
@ -9,5 +9,6 @@ index.html
|
||||
src/assets
|
||||
.eslintrc.cjs
|
||||
**/config
|
||||
src-tauri/**
|
||||
commitlint.config.cjs
|
||||
auto-imports.d.ts
|
20
CHANGELOG.md
20
CHANGELOG.md
@ -1,12 +1,26 @@
|
||||
|
||||
|
||||
## [2.5.2](https://github.com/HuLaSpark/HuLa/compare/v2.5.1...v2.5.2) (2024-10-31)
|
||||
## [2.5.3](https://github.com/HuLaSpark/HuLa/compare/v2.5.2...v2.5.3) (2024-11-06)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes | Bug 修复
|
||||
|
||||
* **build:** :bug: 升级wry版本修复mac安装报错问题 ([fefa2f9](https://github.com/HuLaSpark/HuLa/commit/fefa2f970305839064764cd1d82a0d8e557f3148))
|
||||
* **component:** :bug: 修复聊天框内右键菜单问题 ([e59630b](https://github.com/HuLaSpark/HuLa/commit/e59630b70ed0d245174c97136d502bb63cac03ec))
|
||||
* **component:** :bug: 修复输入框换行不兼容webkit的问题 ([345d830](https://github.com/HuLaSpark/HuLa/commit/345d83068711df087dd0ba403446c739151a11dd))
|
||||
* **layout:** :bug: 修复聊天框改变宽度的时候可以选中文本的问题 ([56d79cc](https://github.com/HuLaSpark/HuLa/commit/56d79ccc8ba015a313eabcd938757f35d1d840a4))
|
||||
* **layout:** :bug: 修复选择了图片不显示在输入框中的bug ([c7cdac6](https://github.com/HuLaSpark/HuLa/commit/c7cdac69ce6fa185489dcb480991e3a268fec99d))
|
||||
* **service:** :bug: 修复请求接口bug ([f3723d4](https://github.com/HuLaSpark/HuLa/commit/f3723d4e5a2342314ce6e85931a49f1ddfecab0b))
|
||||
|
||||
|
||||
### ⚡️ Performance Improvements | 性能优化
|
||||
|
||||
* **component:** :zap: 优化右键菜单功能 ([7b53029](https://github.com/HuLaSpark/HuLa/commit/7b530297ac37122ead00a15864e16a73a5547d04))
|
||||
|
||||
## [2.5.2](https://github.com/HuLaSpark/HuLa/compare/v2.5.1...v2.5.2) (2024-10-31)
|
||||
|
||||
### 🐛 Bug Fixes | Bug 修复
|
||||
|
||||
- **build:** :bug: 升级wry版本修复mac安装报错问题 ([fefa2f9](https://github.com/HuLaSpark/HuLa/commit/fefa2f970305839064764cd1d82a0d8e557f3148))
|
||||
- **component:** :bug: 修复聊天框内右键菜单问题 ([e59630b](https://github.com/HuLaSpark/HuLa/commit/e59630b70ed0d245174c97136d502bb63cac03ec))
|
||||
|
||||
## [2.5.1](https://github.com/HuLaSpark/HuLa/compare/v2.5.0...v2.5.1) (2024-10-29)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hula",
|
||||
"type": "module",
|
||||
"version": "2.5.2",
|
||||
"version": "2.5.3",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.12.0",
|
||||
@ -44,7 +44,6 @@
|
||||
"@tauri-apps/plugin-os": "2.0.0",
|
||||
"@tauri-apps/plugin-process": "2.0.0",
|
||||
"@tauri-apps/plugin-updater": "~2",
|
||||
"axios": "^1.7.4",
|
||||
"colorthief": "^2.4.0",
|
||||
"dayjs": "^1.11.11",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
@ -52,7 +51,7 @@
|
||||
"mitt": "^3.0.1",
|
||||
"naive-ui": "^2.40.1",
|
||||
"pinia": "^2.2.1",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"pinia-plugin-persistedstate": "^4.1.2",
|
||||
"pinia-shared-state": "^0.5.1",
|
||||
"vue": "^3.5.11",
|
||||
"vue-draggable-plus": "^0.5.3",
|
||||
|
280
pnpm-lock.yaml
280
pnpm-lock.yaml
@ -32,9 +32,6 @@ importers:
|
||||
'@tauri-apps/plugin-updater':
|
||||
specifier: ~2
|
||||
version: 2.0.0
|
||||
axios:
|
||||
specifier: ^1.7.4
|
||||
version: 1.7.4
|
||||
colorthief:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0
|
||||
@ -57,8 +54,8 @@ importers:
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2))
|
||||
pinia-plugin-persistedstate:
|
||||
specifier: ^3.2.1
|
||||
version: 3.2.1(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2)))
|
||||
specifier: ^4.1.2
|
||||
version: 4.1.2(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
pinia-shared-state:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2))
|
||||
@ -74,7 +71,7 @@ importers:
|
||||
devDependencies:
|
||||
'@babel/eslint-parser':
|
||||
specifier: ^7.24.7
|
||||
version: 7.25.1(@babel/core@7.25.2)(eslint@8.57.0)
|
||||
version: 7.25.1(@babel/core@7.26.0)(eslint@8.57.0)
|
||||
'@commitlint/cli':
|
||||
specifier: ^19.3.0
|
||||
version: 19.4.0(@types/node@20.14.15)(typescript@5.6.2)
|
||||
@ -173,10 +170,10 @@ importers:
|
||||
version: 5.6.2
|
||||
unplugin-auto-import:
|
||||
specifier: ^0.18.2
|
||||
version: 0.18.2(@nuxt/kit@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3))(@vueuse/core@10.11.1(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
version: 0.18.2(@nuxt/kit@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3))(@vueuse/core@10.11.1(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.27.4
|
||||
version: 0.27.4(@babel/parser@7.26.2)(@nuxt/kit@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3))(rollup@4.24.3)(vue@3.5.11(typescript@5.6.2))(webpack-sources@3.2.3)
|
||||
version: 0.27.4(@babel/parser@7.26.2)(@nuxt/kit@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3))(rollup@4.24.3)(vue@3.5.11(typescript@5.6.2))(webpack-sources@3.2.3)
|
||||
vite:
|
||||
specifier: 5.4.10
|
||||
version: 5.4.10(@types/node@20.14.15)(sass@1.77.6)(terser@5.31.5)
|
||||
@ -891,12 +888,12 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nuxt/kit@3.13.1':
|
||||
resolution: {integrity: sha512-FkUL349lp/3nVfTIyws4UDJ3d2jyv5Pk1DC1HQUCOkSloYYMdbRcQAUcb4fe2TCLNWvHM+FhU8jnzGTzjALZYA==}
|
||||
'@nuxt/kit@3.14.0':
|
||||
resolution: {integrity: sha512-Gl30WrzX7YSJqkTyOJlG4LkErShkGoHigWF/htFt9Q27Lx9JNCkOpXlEf+rA/vsDlXJeo8mVNRoMhS4Q+0d1Kg==}
|
||||
engines: {node: ^14.18.0 || >=16.10.0}
|
||||
|
||||
'@nuxt/schema@3.13.1':
|
||||
resolution: {integrity: sha512-ishbhzVGspjshG9AG0hYnKYY6LWXzCtua7OXV7C/DQ2yA7rRcy1xHpzKZUDbIRyxCHHCAcBd8jfHEUmEuhEPrA==}
|
||||
'@nuxt/schema@3.14.0':
|
||||
resolution: {integrity: sha512-uLAAS7Za7+JXJg6phAjUecqBUfON/WZN/NbYic7uCM+4LUT8B4M/5WM9zFCZJi1g9Krns5Wr5GmJJPIfaYt0eQ==}
|
||||
engines: {node: ^14.18.0 || >=16.10.0}
|
||||
|
||||
'@octokit/auth-token@4.0.0':
|
||||
@ -1660,9 +1657,6 @@ packages:
|
||||
aws4@1.13.1:
|
||||
resolution: {integrity: sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==}
|
||||
|
||||
axios@1.7.4:
|
||||
resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
@ -1732,10 +1726,10 @@ packages:
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
|
||||
c12@1.11.2:
|
||||
resolution: {integrity: sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew==}
|
||||
c12@2.0.1:
|
||||
resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==}
|
||||
peerDependencies:
|
||||
magicast: ^0.3.4
|
||||
magicast: ^0.3.5
|
||||
peerDependenciesMeta:
|
||||
magicast:
|
||||
optional: true
|
||||
@ -1763,8 +1757,8 @@ packages:
|
||||
caniuse-lite@1.0.30001651:
|
||||
resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==}
|
||||
|
||||
caniuse-lite@1.0.30001676:
|
||||
resolution: {integrity: sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==}
|
||||
caniuse-lite@1.0.30001677:
|
||||
resolution: {integrity: sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==}
|
||||
|
||||
caseless@0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
@ -1788,6 +1782,10 @@ packages:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
||||
chokidar@4.0.1:
|
||||
resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
chownr@2.0.0:
|
||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2115,6 +2113,9 @@ packages:
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
deep-pick-omit@1.2.1:
|
||||
resolution: {integrity: sha512-2J6Kc/m3irCeqVG42T+SaUMesaK7oGWaedGnQQK/+O0gYc+2SP5bKh/KKTE7d7SJ+GCA9UUE1GRzh6oDe0EnGw==}
|
||||
|
||||
default-browser-id@5.0.0:
|
||||
resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
|
||||
engines: {node: '>=18'}
|
||||
@ -2197,8 +2198,8 @@ packages:
|
||||
ecc-jsbn@0.1.2:
|
||||
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
|
||||
|
||||
electron-to-chromium@1.5.49:
|
||||
resolution: {integrity: sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==}
|
||||
electron-to-chromium@1.5.52:
|
||||
resolution: {integrity: sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==}
|
||||
|
||||
electron-to-chromium@1.5.6:
|
||||
resolution: {integrity: sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==}
|
||||
@ -2514,15 +2515,6 @@ packages:
|
||||
flatted@3.3.1:
|
||||
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
|
||||
|
||||
follow-redirects@1.15.6:
|
||||
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
|
||||
for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
|
||||
@ -2533,10 +2525,6 @@ packages:
|
||||
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
|
||||
engines: {node: '>= 0.12'}
|
||||
|
||||
form-data@4.0.0:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
fs-extra@11.2.0:
|
||||
resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
|
||||
engines: {node: '>=14.14'}
|
||||
@ -2806,6 +2794,10 @@ packages:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
ignore@6.0.2:
|
||||
resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
immutable@4.3.7:
|
||||
resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
|
||||
|
||||
@ -3057,8 +3049,8 @@ packages:
|
||||
resolution: {integrity: sha512-pmfRbVRs/7khFrSAYnSiJ8C0D5GvzkE4Ey2pAvUcJsw1ly/p+7ut27jbJrjY79BpAJQJ4gXYFtK6d1Aub+9baQ==}
|
||||
hasBin: true
|
||||
|
||||
jiti@2.3.3:
|
||||
resolution: {integrity: sha512-EX4oNDwcXSivPrw2qKH2LB5PoFxEvgtv2JgwW0bU858HoLQ+kutSvjLMUqBd0PeJYEinLWhoI9Ol0eYMqj/wNQ==}
|
||||
jiti@2.4.0:
|
||||
resolution: {integrity: sha512-H5UpaUI+aHOqZXlYOaFP/8AzKsg+guWu+Pr3Y8i7+Y3zr1aXAvCvTAQ1RxSc6oVD8R8c7brgNtTVP91E7upH/g==}
|
||||
hasBin: true
|
||||
|
||||
jpeg-js@0.4.4:
|
||||
@ -3661,10 +3653,16 @@ packages:
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
|
||||
pinia-plugin-persistedstate@3.2.1:
|
||||
resolution: {integrity: sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ==}
|
||||
pinia-plugin-persistedstate@4.1.2:
|
||||
resolution: {integrity: sha512-oh4y4lmtXcgbE3BDWTDBUl9F4G1lhtgDI+GnF+cDDZ/fF6wnGYp4TKQ6FCuv9hMLAkNjs6IzADZHwPBYq10ksQ==}
|
||||
peerDependencies:
|
||||
pinia: ^2.0.0
|
||||
'@pinia/nuxt': '>=0.5.0'
|
||||
pinia: '>=2.0.0'
|
||||
peerDependenciesMeta:
|
||||
'@pinia/nuxt':
|
||||
optional: true
|
||||
pinia:
|
||||
optional: true
|
||||
|
||||
pinia-shared-state@0.5.1:
|
||||
resolution: {integrity: sha512-vPgKLrMSVhubQ1TPC+t9Vg2j2cabbJZDybxeG9BxVHrAFw35jb4IBvfFg9JGv+ULKxIdRvvg4u4I0zan2Juqqg==}
|
||||
@ -3776,6 +3774,10 @@ packages:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
|
||||
readdirp@4.0.2:
|
||||
resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
rechoir@0.6.2:
|
||||
resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@ -4603,12 +4605,10 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
optional: true
|
||||
|
||||
'@babel/compat-data@7.25.2': {}
|
||||
|
||||
'@babel/compat-data@7.26.2':
|
||||
optional: true
|
||||
'@babel/compat-data@7.26.2': {}
|
||||
|
||||
'@babel/core@7.25.2':
|
||||
dependencies:
|
||||
@ -4649,11 +4649,10 @@ snapshots:
|
||||
semver: 6.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@babel/eslint-parser@7.25.1(@babel/core@7.25.2)(eslint@8.57.0)':
|
||||
'@babel/eslint-parser@7.25.1(@babel/core@7.26.0)(eslint@8.57.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.2
|
||||
'@babel/core': 7.26.0
|
||||
'@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1
|
||||
eslint: 8.57.0
|
||||
eslint-visitor-keys: 2.1.0
|
||||
@ -4673,7 +4672,6 @@ snapshots:
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 3.0.2
|
||||
optional: true
|
||||
|
||||
'@babel/helper-annotate-as-pure@7.24.7':
|
||||
dependencies:
|
||||
@ -4694,7 +4692,6 @@ snapshots:
|
||||
browserslist: 4.24.2
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
optional: true
|
||||
|
||||
'@babel/helper-create-class-features-plugin@7.25.0(@babel/core@7.25.2)':
|
||||
dependencies:
|
||||
@ -4733,7 +4730,6 @@ snapshots:
|
||||
'@babel/types': 7.26.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)':
|
||||
dependencies:
|
||||
@ -4753,7 +4749,6 @@ snapshots:
|
||||
'@babel/traverse': 7.25.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@babel/helper-optimise-call-expression@7.24.7':
|
||||
dependencies:
|
||||
@ -4788,20 +4783,17 @@ snapshots:
|
||||
|
||||
'@babel/helper-string-parser@7.25.7': {}
|
||||
|
||||
'@babel/helper-string-parser@7.25.9':
|
||||
optional: true
|
||||
'@babel/helper-string-parser@7.25.9': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.24.7': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.7': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.9':
|
||||
optional: true
|
||||
'@babel/helper-validator-identifier@7.25.9': {}
|
||||
|
||||
'@babel/helper-validator-option@7.24.8': {}
|
||||
|
||||
'@babel/helper-validator-option@7.25.9':
|
||||
optional: true
|
||||
'@babel/helper-validator-option@7.25.9': {}
|
||||
|
||||
'@babel/helpers@7.25.0':
|
||||
dependencies:
|
||||
@ -4812,7 +4804,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/template': 7.25.9
|
||||
'@babel/types': 7.26.0
|
||||
optional: true
|
||||
|
||||
'@babel/highlight@7.24.7':
|
||||
dependencies:
|
||||
@ -4839,7 +4830,6 @@ snapshots:
|
||||
'@babel/parser@7.26.2':
|
||||
dependencies:
|
||||
'@babel/types': 7.26.0
|
||||
optional: true
|
||||
|
||||
'@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)':
|
||||
dependencies:
|
||||
@ -4866,8 +4856,7 @@ snapshots:
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.1
|
||||
|
||||
'@babel/standalone@7.26.2':
|
||||
optional: true
|
||||
'@babel/standalone@7.26.2': {}
|
||||
|
||||
'@babel/template@7.25.0':
|
||||
dependencies:
|
||||
@ -4880,7 +4869,6 @@ snapshots:
|
||||
'@babel/code-frame': 7.26.2
|
||||
'@babel/parser': 7.26.2
|
||||
'@babel/types': 7.26.0
|
||||
optional: true
|
||||
|
||||
'@babel/traverse@7.25.3':
|
||||
dependencies:
|
||||
@ -4905,7 +4893,6 @@ snapshots:
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@babel/types@7.25.2':
|
||||
dependencies:
|
||||
@ -4923,7 +4910,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.25.9
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
optional: true
|
||||
|
||||
'@commitlint/cli@19.4.0(@types/node@20.14.15)(typescript@5.6.2)':
|
||||
dependencies:
|
||||
@ -5280,17 +5266,17 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.17.1
|
||||
|
||||
'@nuxt/kit@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)':
|
||||
'@nuxt/kit@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)':
|
||||
dependencies:
|
||||
'@nuxt/schema': 3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
c12: 1.11.2
|
||||
'@nuxt/schema': 3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
c12: 2.0.1
|
||||
consola: 3.2.3
|
||||
defu: 6.1.4
|
||||
destr: 2.0.3
|
||||
globby: 14.0.2
|
||||
hash-sum: 2.0.0
|
||||
ignore: 5.3.2
|
||||
jiti: 1.21.6
|
||||
ignore: 6.0.2
|
||||
jiti: 2.4.0
|
||||
klona: 2.0.6
|
||||
knitwork: 1.1.0
|
||||
mlly: 1.7.2
|
||||
@ -5307,10 +5293,10 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
- webpack-sources
|
||||
optional: true
|
||||
|
||||
'@nuxt/schema@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)':
|
||||
'@nuxt/schema@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)':
|
||||
dependencies:
|
||||
c12: 2.0.1
|
||||
compatx: 0.1.8
|
||||
consola: 3.2.3
|
||||
defu: 6.1.4
|
||||
@ -5324,10 +5310,10 @@ snapshots:
|
||||
unimport: 3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
untyped: 1.5.1
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
- rollup
|
||||
- supports-color
|
||||
- webpack-sources
|
||||
optional: true
|
||||
|
||||
'@octokit/auth-token@4.0.0': {}
|
||||
|
||||
@ -5494,7 +5480,6 @@ snapshots:
|
||||
picomatch: 4.0.2
|
||||
optionalDependencies:
|
||||
rollup: 4.24.3
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.24.3':
|
||||
optional: true
|
||||
@ -6005,8 +5990,7 @@ snapshots:
|
||||
|
||||
acorn@8.12.1: {}
|
||||
|
||||
acorn@8.14.0:
|
||||
optional: true
|
||||
acorn@8.14.0: {}
|
||||
|
||||
add-stream@1.0.0: {}
|
||||
|
||||
@ -6148,14 +6132,6 @@ snapshots:
|
||||
|
||||
aws4@1.13.1: {}
|
||||
|
||||
axios@1.7.4:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
@ -6218,11 +6194,10 @@ snapshots:
|
||||
|
||||
browserslist@4.24.2:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001676
|
||||
electron-to-chromium: 1.5.49
|
||||
caniuse-lite: 1.0.30001677
|
||||
electron-to-chromium: 1.5.52
|
||||
node-releases: 2.0.18
|
||||
update-browserslist-db: 1.1.1(browserslist@4.24.2)
|
||||
optional: true
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
@ -6240,21 +6215,20 @@ snapshots:
|
||||
esbuild: 0.23.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
c12@1.11.2:
|
||||
c12@2.0.1:
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
chokidar: 4.0.1
|
||||
confbox: 0.1.8
|
||||
defu: 6.1.4
|
||||
dotenv: 16.4.5
|
||||
giget: 1.2.3
|
||||
jiti: 1.21.6
|
||||
jiti: 2.4.0
|
||||
mlly: 1.7.2
|
||||
ohash: 1.1.4
|
||||
pathe: 1.1.2
|
||||
perfect-debounce: 1.0.0
|
||||
pkg-types: 1.2.1
|
||||
rc9: 2.1.2
|
||||
optional: true
|
||||
|
||||
cachedir@2.3.0: {}
|
||||
|
||||
@ -6274,8 +6248,7 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001651: {}
|
||||
|
||||
caniuse-lite@1.0.30001676:
|
||||
optional: true
|
||||
caniuse-lite@1.0.30001677: {}
|
||||
|
||||
caseless@0.12.0: {}
|
||||
|
||||
@ -6306,15 +6279,17 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
chownr@2.0.0:
|
||||
optional: true
|
||||
chokidar@4.0.1:
|
||||
dependencies:
|
||||
readdirp: 4.0.2
|
||||
|
||||
chownr@2.0.0: {}
|
||||
|
||||
ci-info@4.0.0: {}
|
||||
|
||||
citty@0.1.6:
|
||||
dependencies:
|
||||
consola: 3.2.3
|
||||
optional: true
|
||||
|
||||
cli-boxes@3.0.0: {}
|
||||
|
||||
@ -6397,8 +6372,7 @@ snapshots:
|
||||
array-ify: 1.0.0
|
||||
dot-prop: 5.3.0
|
||||
|
||||
compatx@0.1.8:
|
||||
optional: true
|
||||
compatx@0.1.8: {}
|
||||
|
||||
computeds@0.0.1: {}
|
||||
|
||||
@ -6413,8 +6387,7 @@ snapshots:
|
||||
|
||||
confbox@0.1.7: {}
|
||||
|
||||
confbox@0.1.8:
|
||||
optional: true
|
||||
confbox@0.1.8: {}
|
||||
|
||||
config-chain@1.1.13:
|
||||
dependencies:
|
||||
@ -6428,8 +6401,7 @@ snapshots:
|
||||
graceful-fs: 4.2.11
|
||||
xdg-basedir: 5.1.0
|
||||
|
||||
consola@3.2.3:
|
||||
optional: true
|
||||
consola@3.2.3: {}
|
||||
|
||||
conventional-changelog-angular@7.0.0:
|
||||
dependencies:
|
||||
@ -6639,6 +6611,8 @@ snapshots:
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
deep-pick-omit@1.2.1: {}
|
||||
|
||||
default-browser-id@5.0.0: {}
|
||||
|
||||
default-browser@5.2.1:
|
||||
@ -6676,8 +6650,7 @@ snapshots:
|
||||
|
||||
deprecation@2.3.1: {}
|
||||
|
||||
destr@2.0.3:
|
||||
optional: true
|
||||
destr@2.0.3: {}
|
||||
|
||||
detect-file@1.0.0: {}
|
||||
|
||||
@ -6705,8 +6678,7 @@ snapshots:
|
||||
dependencies:
|
||||
type-fest: 4.24.0
|
||||
|
||||
dotenv@16.4.5:
|
||||
optional: true
|
||||
dotenv@16.4.5: {}
|
||||
|
||||
duplexer@0.1.2: {}
|
||||
|
||||
@ -6715,8 +6687,7 @@ snapshots:
|
||||
jsbn: 0.1.1
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
electron-to-chromium@1.5.49:
|
||||
optional: true
|
||||
electron-to-chromium@1.5.52: {}
|
||||
|
||||
electron-to-chromium@1.5.6: {}
|
||||
|
||||
@ -6864,8 +6835,7 @@ snapshots:
|
||||
|
||||
escalade@3.1.2: {}
|
||||
|
||||
escalade@3.2.0:
|
||||
optional: true
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-goat@4.0.0: {}
|
||||
|
||||
@ -7172,8 +7142,6 @@ snapshots:
|
||||
|
||||
flatted@3.3.1: {}
|
||||
|
||||
follow-redirects@1.15.6: {}
|
||||
|
||||
for-each@0.3.3:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
@ -7186,12 +7154,6 @@ snapshots:
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
|
||||
form-data@4.0.0:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
|
||||
fs-extra@11.2.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@ -7208,7 +7170,6 @@ snapshots:
|
||||
fs-minipass@2.1.0:
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
optional: true
|
||||
|
||||
fs.realpath@1.0.0: {}
|
||||
|
||||
@ -7291,7 +7252,6 @@ snapshots:
|
||||
ohash: 1.1.4
|
||||
pathe: 1.1.2
|
||||
tar: 6.2.1
|
||||
optional: true
|
||||
|
||||
git-raw-commits@4.0.0:
|
||||
dependencies:
|
||||
@ -7435,8 +7395,7 @@ snapshots:
|
||||
dependencies:
|
||||
has-symbols: 1.0.3
|
||||
|
||||
hash-sum@2.0.0:
|
||||
optional: true
|
||||
hash-sum@2.0.0: {}
|
||||
|
||||
hasown@2.0.2:
|
||||
dependencies:
|
||||
@ -7450,8 +7409,7 @@ snapshots:
|
||||
dependencies:
|
||||
parse-passwd: 1.0.0
|
||||
|
||||
hookable@5.5.3:
|
||||
optional: true
|
||||
hookable@5.5.3: {}
|
||||
|
||||
hosted-git-info@7.0.2:
|
||||
dependencies:
|
||||
@ -7495,6 +7453,8 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
ignore@6.0.2: {}
|
||||
|
||||
immutable@4.3.7: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
@ -7731,8 +7691,7 @@ snapshots:
|
||||
|
||||
jiti@2.0.0-beta.3: {}
|
||||
|
||||
jiti@2.3.3:
|
||||
optional: true
|
||||
jiti@2.4.0: {}
|
||||
|
||||
jpeg-js@0.4.4: {}
|
||||
|
||||
@ -7750,8 +7709,7 @@ snapshots:
|
||||
|
||||
jsesc@2.5.2: {}
|
||||
|
||||
jsesc@3.0.2:
|
||||
optional: true
|
||||
jsesc@3.0.2: {}
|
||||
|
||||
json-buffer@3.0.1: {}
|
||||
|
||||
@ -7794,11 +7752,9 @@ snapshots:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
klona@2.0.6:
|
||||
optional: true
|
||||
klona@2.0.6: {}
|
||||
|
||||
knitwork@1.1.0:
|
||||
optional: true
|
||||
knitwork@1.1.0: {}
|
||||
|
||||
ky@1.7.2: {}
|
||||
|
||||
@ -7925,7 +7881,6 @@ snapshots:
|
||||
magic-string@0.30.12:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
optional: true
|
||||
|
||||
mdn-data@2.0.30: {}
|
||||
|
||||
@ -7975,21 +7930,17 @@ snapshots:
|
||||
minipass@3.3.6:
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
optional: true
|
||||
|
||||
minipass@5.0.0:
|
||||
optional: true
|
||||
minipass@5.0.0: {}
|
||||
|
||||
minizlib@2.1.2:
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
yallist: 4.0.0
|
||||
optional: true
|
||||
|
||||
mitt@3.0.1: {}
|
||||
|
||||
mkdirp@1.0.4:
|
||||
optional: true
|
||||
mkdirp@1.0.4: {}
|
||||
|
||||
mlly@1.7.1:
|
||||
dependencies:
|
||||
@ -8004,10 +7955,8 @@ snapshots:
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.2.1
|
||||
ufo: 1.5.4
|
||||
optional: true
|
||||
|
||||
mri@1.2.0:
|
||||
optional: true
|
||||
mri@1.2.0: {}
|
||||
|
||||
mrmime@2.0.0: {}
|
||||
|
||||
@ -8068,8 +8017,7 @@ snapshots:
|
||||
|
||||
node-bitmap@0.0.1: {}
|
||||
|
||||
node-fetch-native@1.6.4:
|
||||
optional: true
|
||||
node-fetch-native@1.6.4: {}
|
||||
|
||||
node-releases@2.0.18: {}
|
||||
|
||||
@ -8101,7 +8049,6 @@ snapshots:
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.2.1
|
||||
ufo: 1.5.4
|
||||
optional: true
|
||||
|
||||
oauth-sign@0.9.0: {}
|
||||
|
||||
@ -8137,8 +8084,7 @@ snapshots:
|
||||
|
||||
oblivious-set@1.4.0: {}
|
||||
|
||||
ohash@1.1.4:
|
||||
optional: true
|
||||
ohash@1.1.4: {}
|
||||
|
||||
omggif@1.0.10: {}
|
||||
|
||||
@ -8321,8 +8267,7 @@ snapshots:
|
||||
|
||||
pathe@1.1.2: {}
|
||||
|
||||
perfect-debounce@1.0.0:
|
||||
optional: true
|
||||
perfect-debounce@1.0.0: {}
|
||||
|
||||
performance-now@2.1.0: {}
|
||||
|
||||
@ -8336,9 +8281,19 @@ snapshots:
|
||||
|
||||
pidtree@0.6.0: {}
|
||||
|
||||
pinia-plugin-persistedstate@3.2.1(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2))):
|
||||
pinia-plugin-persistedstate@4.1.2(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3):
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
deep-pick-omit: 1.2.1
|
||||
defu: 6.1.4
|
||||
destr: 2.0.3
|
||||
optionalDependencies:
|
||||
pinia: 2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2))
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
- rollup
|
||||
- supports-color
|
||||
- webpack-sources
|
||||
|
||||
pinia-shared-state@0.5.1(pinia@2.2.1(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2)):
|
||||
dependencies:
|
||||
@ -8368,7 +8323,6 @@ snapshots:
|
||||
confbox: 0.1.8
|
||||
mlly: 1.7.2
|
||||
pathe: 1.1.2
|
||||
optional: true
|
||||
|
||||
pngjs@3.4.0: {}
|
||||
|
||||
@ -8432,7 +8386,6 @@ snapshots:
|
||||
dependencies:
|
||||
defu: 6.1.4
|
||||
destr: 2.0.3
|
||||
optional: true
|
||||
|
||||
rc@1.2.8:
|
||||
dependencies:
|
||||
@ -8464,6 +8417,8 @@ snapshots:
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
|
||||
readdirp@4.0.2: {}
|
||||
|
||||
rechoir@0.6.2:
|
||||
dependencies:
|
||||
resolve: 1.22.8
|
||||
@ -8769,8 +8724,7 @@ snapshots:
|
||||
safer-buffer: 2.1.2
|
||||
tweetnacl: 0.14.5
|
||||
|
||||
std-env@3.7.0:
|
||||
optional: true
|
||||
std-env@3.7.0: {}
|
||||
|
||||
stdin-discarder@0.2.2: {}
|
||||
|
||||
@ -8862,7 +8816,6 @@ snapshots:
|
||||
minizlib: 2.1.2
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
optional: true
|
||||
|
||||
terser@5.31.5:
|
||||
dependencies:
|
||||
@ -8999,8 +8952,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
uncrypto@0.1.3:
|
||||
optional: true
|
||||
uncrypto@0.1.3: {}
|
||||
|
||||
unctx@2.3.1(webpack-sources@3.2.3):
|
||||
dependencies:
|
||||
@ -9010,7 +8962,6 @@ snapshots:
|
||||
unplugin: 1.15.0(webpack-sources@3.2.3)
|
||||
transitivePeerDependencies:
|
||||
- webpack-sources
|
||||
optional: true
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
|
||||
@ -9057,7 +9008,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- webpack-sources
|
||||
optional: true
|
||||
|
||||
uniq@1.0.1: {}
|
||||
|
||||
@ -9067,7 +9017,7 @@ snapshots:
|
||||
|
||||
unload@2.4.1: {}
|
||||
|
||||
unplugin-auto-import@0.18.2(@nuxt/kit@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3))(@vueuse/core@10.11.1(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3):
|
||||
unplugin-auto-import@0.18.2(@nuxt/kit@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3))(@vueuse/core@10.11.1(vue@3.5.11(typescript@5.6.2)))(rollup@4.24.3)(webpack-sources@3.2.3):
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.10
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.24.3)
|
||||
@ -9078,13 +9028,13 @@ snapshots:
|
||||
unimport: 3.11.1(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
unplugin: 1.14.1(webpack-sources@3.2.3)
|
||||
optionalDependencies:
|
||||
'@nuxt/kit': 3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
'@nuxt/kit': 3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
'@vueuse/core': 10.11.1(vue@3.5.11(typescript@5.6.2))
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- webpack-sources
|
||||
|
||||
unplugin-vue-components@0.27.4(@babel/parser@7.26.2)(@nuxt/kit@3.13.1(rollup@4.24.3)(webpack-sources@3.2.3))(rollup@4.24.3)(vue@3.5.11(typescript@5.6.2))(webpack-sources@3.2.3):
|
||||
unplugin-vue-components@0.27.4(@babel/parser@7.26.2)(@nuxt/kit@3.14.0(rollup@4.24.3)(webpack-sources@3.2.3))(rollup@4.24.3)(vue@3.5.11(typescript@5.6.2))(webpack-sources@3.2.3):
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.10
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.24.3)
|
||||
@ -9099,7 +9049,7 @@ snapshots:
|
||||
vue: 3.5.11(typescript@5.6.2)
|
||||
optionalDependencies:
|
||||
'@babel/parser': 7.26.2
|
||||
'@nuxt/kit': 3.13.1(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
'@nuxt/kit': 3.14.0(rollup@4.24.3)(webpack-sources@3.2.3)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
@ -9118,7 +9068,6 @@ snapshots:
|
||||
webpack-virtual-modules: 0.6.2
|
||||
optionalDependencies:
|
||||
webpack-sources: 3.2.3
|
||||
optional: true
|
||||
|
||||
untyped@1.5.1:
|
||||
dependencies:
|
||||
@ -9126,12 +9075,11 @@ snapshots:
|
||||
'@babel/standalone': 7.26.2
|
||||
'@babel/types': 7.26.0
|
||||
defu: 6.1.4
|
||||
jiti: 2.3.3
|
||||
jiti: 2.4.0
|
||||
mri: 1.2.0
|
||||
scule: 1.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
update-browserslist-db@1.1.0(browserslist@4.23.3):
|
||||
dependencies:
|
||||
@ -9144,7 +9092,6 @@ snapshots:
|
||||
browserslist: 4.24.2
|
||||
escalade: 3.2.0
|
||||
picocolors: 1.1.1
|
||||
optional: true
|
||||
|
||||
update-notifier@7.3.1:
|
||||
dependencies:
|
||||
@ -9334,8 +9281,7 @@ snapshots:
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yallist@4.0.0:
|
||||
optional: true
|
||||
yallist@4.0.0: {}
|
||||
|
||||
yaml@2.5.0: {}
|
||||
|
||||
|
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@ -2107,7 +2107,7 @@ checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
|
||||
[[package]]
|
||||
name = "hula"
|
||||
version = "2.5.1"
|
||||
version = "2.5.3"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"lazy_static",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "hula"
|
||||
version = "2.5.1"
|
||||
version = "2.5.3"
|
||||
description = "hula"
|
||||
authors = ["nongyehong"]
|
||||
license = ""
|
||||
|
@ -35,7 +35,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": ["identifier", "permissions"],
|
||||
"properties": {
|
||||
|
@ -35,7 +35,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": ["identifier", "permissions"],
|
||||
"properties": {
|
||||
|
@ -35,7 +35,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": ["identifier", "permissions"],
|
||||
"properties": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"productName": "HuLa",
|
||||
"version": "2.5.2",
|
||||
"version": "2.5.3",
|
||||
"identifier": "com.hula.pc",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"productName": "HuLa",
|
||||
"version": "2.5.2",
|
||||
"version": "2.5.3",
|
||||
"identifier": "com.hula.pc",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"productName": "HuLa",
|
||||
"version": "2.5.2",
|
||||
"version": "2.5.3",
|
||||
"identifier": "com.hula.pc",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
89
src/components/common/AddFriendsModal.vue
Normal file
89
src/components/common/AddFriendsModal.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="globalStore.addFriendModalInfo.show"
|
||||
:mask-closable="false"
|
||||
class="rounded-8px"
|
||||
transform-origin="center">
|
||||
<div class="bg-[--bg-edit] w-380px h-fit box-border flex flex-col">
|
||||
<n-flex :size="6" vertical>
|
||||
<div
|
||||
v-if="type() === 'macos'"
|
||||
@click="close"
|
||||
class="mac-close size-13px shadow-inner bg-#ed6a5eff rounded-50% mt-6px select-none absolute left-6px">
|
||||
<svg class="hidden size-7px color-#000 font-bold select-none absolute top-3px left-3px">
|
||||
<use href="#close"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<n-flex class="text-(14px --text-color) select-none pt-6px" justify="center">申请加好友</n-flex>
|
||||
|
||||
<svg
|
||||
v-if="type() === 'windows'"
|
||||
class="size-14px cursor-pointer pt-6px select-none absolute right-6px"
|
||||
@click="close">
|
||||
<use href="#close"></use>
|
||||
</svg>
|
||||
<span class="h-1px w-full bg-[--line-color]"></span>
|
||||
</n-flex>
|
||||
|
||||
<n-flex vertical justify="center" :size="20" class="p-20px">
|
||||
<n-flex align="center" justify="center" :size="20">
|
||||
<n-avatar round size="large" :src="userInfo.avatar" />
|
||||
<n-flex vertical :size="10">
|
||||
<p class="text-[--text-color]">{{ userInfo.name }}</p>
|
||||
<p class="text-(12px [--text-color])">uid: {{ userInfo.uid }}</p>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
<n-input
|
||||
v-model:value="requestMsg"
|
||||
:allow-input="(value: string) => !value.startsWith(' ') && !value.endsWith(' ')"
|
||||
:autosize="{
|
||||
minRows: 3,
|
||||
maxRows: 3
|
||||
}"
|
||||
:maxlength="60"
|
||||
:count-graphemes="countGraphemes"
|
||||
show-count
|
||||
type="textarea"
|
||||
placeholder="输入几句话,对TA说些什么吧" />
|
||||
|
||||
<n-button color="#13987f" @click="addFriend">添加好友</n-button>
|
||||
</n-flex>
|
||||
</div>
|
||||
</n-modal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { leftHook } from '@/layout/left/hook.ts'
|
||||
import apis from '@/services/apis.ts'
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const { countGraphemes } = leftHook()
|
||||
const userInfo = ref(useUserInfo(globalStore.addFriendModalInfo.uid).value)
|
||||
const requestMsg = ref()
|
||||
|
||||
const close = () => {
|
||||
globalStore.addFriendModalInfo.show = false
|
||||
globalStore.addFriendModalInfo.uid = undefined
|
||||
}
|
||||
|
||||
const addFriend = async () => {
|
||||
await apis.sendAddFriendRequest({
|
||||
msg: requestMsg.value,
|
||||
targetUid: globalStore.addFriendModalInfo.uid as number
|
||||
})
|
||||
window.$message.success('已发送好友申请')
|
||||
close()
|
||||
}
|
||||
|
||||
watch(globalStore.addFriendModalInfo, (val) => {
|
||||
if (val.show) {
|
||||
userInfo.value = useUserInfo(val.uid).value
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
@ -36,8 +36,8 @@
|
||||
left: `${pos.posX}px`,
|
||||
top: `${pos.posY}px`
|
||||
}">
|
||||
<div v-resize="handleSize" v-if="menu && menu.length > 0" class="menu-list">
|
||||
<div v-for="(item, index) in menu as any[]" :key="index">
|
||||
<div v-resize="handleSize" v-if="visibleMenu && visibleMenu.length > 0" class="menu-list">
|
||||
<div v-for="(item, index) in visibleMenu as any[]" :key="index">
|
||||
<!-- 禁止的菜单选项需要禁止点击事件 -->
|
||||
<div class="menu-item-disabled" v-if="item.disabled" @click.prevent="$event.preventDefault()">
|
||||
<svg><use :href="`#${item.icon}`"></use></svg>
|
||||
@ -68,7 +68,11 @@
|
||||
import { useContextMenu } from '@/hooks/useContextMenu.ts'
|
||||
import { useViewport } from '@/hooks/useViewport.ts'
|
||||
|
||||
const { menu, emoji, specialMenu } = defineProps({
|
||||
const { content, menu, emoji, specialMenu } = defineProps({
|
||||
content: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
menu: {
|
||||
type: Array
|
||||
},
|
||||
@ -80,6 +84,17 @@ const { menu, emoji, specialMenu } = defineProps({
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
// 使用计算属性过滤显示的菜单项
|
||||
const visibleMenu = computed(() => {
|
||||
return menu?.filter((item: any) => {
|
||||
// 检查是否有 visible 属性并作为函数调用
|
||||
if (typeof item.visible === 'function') {
|
||||
return item.visible(content) // 如果 visible 是函数,则调用它
|
||||
}
|
||||
// 如果没有 visible 属性,则默认显示
|
||||
return true
|
||||
})
|
||||
})
|
||||
/** 判断是否传入了menu */
|
||||
const isNull = computed(() => menu === void 0)
|
||||
const containerRef = ref(null)
|
||||
@ -141,7 +156,7 @@ const handleEnter = (el: any) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
el.style.height = `${h}px`
|
||||
el.style.transition = '0.3s'
|
||||
el.style.transition = '0.2s'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
62
src/components/rightBox/ApplyList.vue
Normal file
62
src/components/rightBox/ApplyList.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<n-flex vertical class="select-none">
|
||||
<n-flex align="center" justify="space-between" class="color-[--text-color] px-20px py-10px">
|
||||
<p class="text-16px">好友通知</p>
|
||||
<svg class="size-18px cursor-pointer"><use href="#delete"></use></svg>
|
||||
</n-flex>
|
||||
|
||||
<n-flex
|
||||
vertical
|
||||
:size="10"
|
||||
class="p-[0_30px]"
|
||||
v-for="(item, index) in contactStore.requestFriendsList"
|
||||
:key="index">
|
||||
<n-flex
|
||||
align="center"
|
||||
justify="space-between"
|
||||
class="bg-[--center-bg-color] rounded-10px p-20px box-border border-(1px solid [--bg-popover])">
|
||||
<n-flex align="center" :size="10">
|
||||
<n-avatar round size="large" :src="useUserInfo(item.uid).value.avatar" class="mr-10px" />
|
||||
<n-flex vertical :size="12">
|
||||
<n-flex align="center" :size="10">
|
||||
<n-popover
|
||||
trigger="click"
|
||||
placement="bottom-start"
|
||||
:show-arrow="false"
|
||||
style="padding: 0; background: var(--bg-info); backdrop-filter: blur(10px)">
|
||||
<template #trigger>
|
||||
<p @click="currentUserId = item.uid" class="text-(14px #13987f) cursor-pointer">
|
||||
{{ useUserInfo(item.uid).value.name }}
|
||||
</p>
|
||||
</template>
|
||||
<!-- 用户个人信息框 -->
|
||||
<InfoPopover v-if="currentUserId === item.uid" :uid="item.uid" />
|
||||
</n-popover>
|
||||
|
||||
<p class="text-(14px [--text-color])">请求加为好友</p>
|
||||
</n-flex>
|
||||
<p v-show="item.msg" class="text-(12px [--text-color])">留言:{{ item.msg }}</p>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
<n-button
|
||||
secondary
|
||||
v-if="item.status === RequestFriendAgreeStatus.Waiting"
|
||||
@click="contactStore.onAcceptFriend(item.applyId)">
|
||||
接受
|
||||
</n-button>
|
||||
<span class="text-(12px #64a29c)" v-else>已同意</span>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { RequestFriendAgreeStatus } from '@/services/types.ts'
|
||||
|
||||
const contactStore = useContactStore()
|
||||
const currentUserId = ref(0)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
@ -52,7 +52,9 @@
|
||||
</n-flex>
|
||||
|
||||
<!-- 群聊详情 -->
|
||||
<div v-else class="flex flex-col flex-1 mt-60px gap-30px select-none p-[0_40px] box-border">
|
||||
<div
|
||||
v-else-if="content.type === RoomTypeEnum.GROUP"
|
||||
class="flex flex-col flex-1 mt-60px gap-30px select-none p-[0_40px] box-border">
|
||||
<!-- 群聊头像以及简介 -->
|
||||
<n-flex align="center" justify="space-between">
|
||||
<n-flex align="center">
|
||||
@ -124,7 +126,7 @@ const { content } = defineProps<{
|
||||
content: any
|
||||
}>()
|
||||
const item = computed(() => {
|
||||
return useUserInfo(content.value.uid).value
|
||||
return useUserInfo(content.uid).value
|
||||
})
|
||||
|
||||
const footerOptions = ref<OPT.Details[]>([
|
||||
|
@ -85,6 +85,16 @@
|
||||
<div class="pl-20px flex flex-col items-end gap-6px">
|
||||
<MsgInput ref="MsgInputRef" />
|
||||
</div>
|
||||
|
||||
<div v-if="isGuest" class="fuzzy">
|
||||
<n-flex align="center" :size="0" class="pb-60px text-(14px [--text-color])">
|
||||
<p>当前为</p>
|
||||
<p class="color-#c14053 px-2px">游客模式</p>
|
||||
<p>,请</p>
|
||||
<p @click="logout(true)" class="color-#13987f px-4px cursor-pointer">扫码登录</p>
|
||||
<p>后使用</p>
|
||||
</n-flex>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@ -94,12 +104,20 @@ import { LimitEnum, MsgEnum } from '@/enums'
|
||||
import { useCommon } from '@/hooks/useCommon.ts'
|
||||
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
import { useLogin } from '@/hooks/useLogin.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
|
||||
const { open, onChange } = useFileDialog()
|
||||
const { logout } = useLogin()
|
||||
const { open, onChange, reset } = useFileDialog()
|
||||
const { login } = useSettingStore()
|
||||
const MsgInputRef = ref()
|
||||
const msgInputDom = ref()
|
||||
const emojiShow = ref()
|
||||
const { insertNode, triggerInputEvent, getEditorRange, imgPaste, FileOrVideoPaste } = useCommon()
|
||||
/**
|
||||
* 是否为游客模式
|
||||
*/
|
||||
const isGuest = computed(() => login.accountInfo.token === 'test')
|
||||
|
||||
/**
|
||||
* 选择表情,并把表情插入输入框
|
||||
@ -111,7 +129,7 @@ const emojiHandle = (item: string) => {
|
||||
const { range } = getEditorRange()!
|
||||
range?.collapse(false)
|
||||
// 插入表情
|
||||
insertNode(MsgEnum.TEXT, item)
|
||||
insertNode(MsgEnum.TEXT, item, MsgInputRef.value.messageInputDom)
|
||||
triggerInputEvent(msgInputDom.value)
|
||||
}
|
||||
|
||||
@ -145,10 +163,13 @@ onChange((files) => {
|
||||
FileOrVideoPaste(file, MsgEnum.FILE, MsgInputRef.value.messageInputDom)
|
||||
}
|
||||
}
|
||||
reset()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
msgInputDom.value = MsgInputRef.value.messageInputDom
|
||||
if (MsgInputRef.value) {
|
||||
msgInputDom.value = MsgInputRef.value.messageInputDom
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -164,6 +185,13 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.fuzzy {
|
||||
@apply bg-transparent select-none cursor-default size-full absolute-flex-center;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
:deep(.n-input .n-input-wrapper) {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -91,6 +91,7 @@
|
||||
<template #trigger>
|
||||
<ContextMenu
|
||||
@select="$event.click(item, 'Main')"
|
||||
:content="item"
|
||||
:menu="chatStore.isGroup ? optionsList : void 0"
|
||||
:special-menu="report">
|
||||
<n-avatar
|
||||
@ -122,6 +123,7 @@
|
||||
:style="item.fromUser.uid === userUid ? 'flex-direction: row-reverse' : ''">
|
||||
<ContextMenu
|
||||
@select="$event.click(item)"
|
||||
:content="item"
|
||||
:menu="chatStore.isGroup ? optionsList : []"
|
||||
:special-menu="report">
|
||||
<n-flex
|
||||
@ -173,6 +175,7 @@
|
||||
</n-flex>
|
||||
<!-- 气泡样式 -->
|
||||
<ContextMenu
|
||||
:content="item"
|
||||
@contextmenu="handleMacSelect"
|
||||
@mouseenter="handleMouseEnter(item.message.id)"
|
||||
@mouseleave="handleMouseLeave"
|
||||
@ -338,7 +341,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { EventEnum, MittEnum, MsgEnum, RoomTypeEnum } from '@/enums'
|
||||
import { type MessageType, SessionItem } from '@/services/types.ts'
|
||||
import { SessionItem } from '@/services/types.ts'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { usePopover } from '@/hooks/usePopover.ts'
|
||||
import { useWindow } from '@/hooks/useWindow.ts'
|
||||
@ -489,28 +492,28 @@ const jumpToReplyMsg = (key: number) => {
|
||||
* @param index 下标
|
||||
* @param id 用户ID
|
||||
*/
|
||||
const addToDomUpdateQueue = (index: number, id: number) => {
|
||||
// 使用 nextTick 确保虚拟列表渲染完最新的项目后进行滚动
|
||||
nextTick(() => {
|
||||
if (!floatFooter.value || id === userUid.value) {
|
||||
virtualListInst.value?.scrollTo({ position: 'bottom', debounce: true })
|
||||
}
|
||||
/** data-key标识的气泡,添加前缀用于区分用户消息,不然气泡动画会被覆盖 */
|
||||
const dataKey = id === userUid.value ? `U${index}` : `Q${index}`
|
||||
const lastMessageElement = document.querySelector(`[data-key="${dataKey}"]`) as HTMLElement
|
||||
if (lastMessageElement) {
|
||||
// 添加动画类
|
||||
lastMessageElement.classList.add('bubble-animation')
|
||||
// 监听动画结束事件
|
||||
const handleAnimationEnd = () => {
|
||||
lastMessageElement.classList.remove('bubble-animation')
|
||||
lastMessageElement.removeEventListener('animationend', handleAnimationEnd)
|
||||
}
|
||||
lastMessageElement.addEventListener('animationend', handleAnimationEnd)
|
||||
}
|
||||
})
|
||||
chatStore.clearNewMsgCount()
|
||||
}
|
||||
// const addToDomUpdateQueue = (index: number, id: number) => {
|
||||
// // 使用 nextTick 确保虚拟列表渲染完最新的项目后进行滚动
|
||||
// nextTick(() => {
|
||||
// if (!floatFooter.value || id === userUid.value) {
|
||||
// virtualListInst.value?.scrollTo({ position: 'bottom', debounce: true })
|
||||
// }
|
||||
// /** data-key标识的气泡,添加前缀用于区分用户消息,不然气泡动画会被覆盖 */
|
||||
// const dataKey = id === userUid.value ? `U${index}` : `Q${index}`
|
||||
// const lastMessageElement = document.querySelector(`[data-key="${dataKey}"]`) as HTMLElement
|
||||
// if (lastMessageElement) {
|
||||
// // 添加动画类
|
||||
// lastMessageElement.classList.add('bubble-animation')
|
||||
// // 监听动画结束事件
|
||||
// const handleAnimationEnd = () => {
|
||||
// lastMessageElement.classList.remove('bubble-animation')
|
||||
// lastMessageElement.removeEventListener('animationend', handleAnimationEnd)
|
||||
// }
|
||||
// lastMessageElement.addEventListener('animationend', handleAnimationEnd)
|
||||
// }
|
||||
// })
|
||||
// chatStore.clearNewMsgCount()
|
||||
// }
|
||||
|
||||
/** 点击后滚动到底部 */
|
||||
const scrollBottom = () => {
|
||||
@ -534,7 +537,7 @@ const closeMenu = (event: any) => {
|
||||
if (!event.target.matches('.bubble', 'bubble-oneself')) {
|
||||
activeBubble.value = -1
|
||||
// 解决mac右键会选中文本的问题
|
||||
if (isMac.value) {
|
||||
if (isMac.value && recordEL.value) {
|
||||
recordEL.value.classList.remove('select-none')
|
||||
}
|
||||
}
|
||||
@ -560,24 +563,15 @@ onMounted(() => {
|
||||
// 滚动到底部
|
||||
virtualListInst.value?.scrollTo({ position: 'bottom', debounce: true })
|
||||
})
|
||||
/**! 启动图标闪烁 需要设置"resources": ["sec-tauri/图标放置的文件夹"]*/
|
||||
// invoke('tray_blink', {
|
||||
// isRun: true,
|
||||
// ms: 500,
|
||||
// iconPath1: 'tray/msg.png',
|
||||
// iconPath2: 'tray/msg-sub.png'
|
||||
// }).catch((error) => {
|
||||
// console.error('设置图标失败:', error)
|
||||
// Mitt.on(MittEnum.SEND_MESSAGE, (event: MessageType) => {
|
||||
// nextTick(() => {
|
||||
// addToDomUpdateQueue(event.message.id, event.fromUser.uid)
|
||||
// })
|
||||
// })
|
||||
Mitt.on(MittEnum.SEND_MESSAGE, (event: MessageType) => {
|
||||
nextTick(() => {
|
||||
addToDomUpdateQueue(event.message.id, event.fromUser.uid)
|
||||
})
|
||||
})
|
||||
Mitt.on(`${MittEnum.INFO_POPOVER}-Main`, (event: any) => {
|
||||
selectKey.value = event
|
||||
selectKey.value = event.uid
|
||||
infoPopover.value = true
|
||||
handlePopoverUpdate(event)
|
||||
handlePopoverUpdate(event.uid)
|
||||
})
|
||||
Mitt.on(MittEnum.MSG_BOX_SHOW, (event: any) => {
|
||||
activeItemRef.value = event.item
|
||||
|
@ -20,12 +20,13 @@
|
||||
|
||||
<n-flex v-if="!isSearch" align="center" justify="space-between" class="pr-8px pl-8px h-42px">
|
||||
<span class="text-14px">群聊成员 {{ userList.length }}</span>
|
||||
<svg @click="handleSearch" class="size-14px"><use href="#search"></use></svg>
|
||||
<svg @click="handleSelect" class="size-14px"><use href="#search"></use></svg>
|
||||
</n-flex>
|
||||
<!-- 搜索框 -->
|
||||
<n-flex v-else align="center" class="pr-8px h-42px">
|
||||
<n-input
|
||||
@blur="isSearch = false"
|
||||
:on-input="handleSearch"
|
||||
@blur="handleBlur"
|
||||
ref="inputInstRef"
|
||||
v-model:value="searchRef"
|
||||
clearable
|
||||
@ -47,7 +48,7 @@
|
||||
style="max-height: calc(100vh - 130px)"
|
||||
item-resizable
|
||||
:item-size="42"
|
||||
:items="userList">
|
||||
:items="filteredUserList">
|
||||
<template #default="{ item }">
|
||||
<n-popover
|
||||
@update:show="handlePopoverUpdate(item.uid)"
|
||||
@ -57,7 +58,11 @@
|
||||
v-model:show="infoPopover"
|
||||
style="padding: 0; background: var(--bg-info); backdrop-filter: blur(10px)">
|
||||
<template #trigger>
|
||||
<ContextMenu @select="$event.click(item, 'Sidebar')" :menu="optionsList" :special-menu="report">
|
||||
<ContextMenu
|
||||
:content="item"
|
||||
@select="$event.click(item, 'Sidebar')"
|
||||
:menu="optionsList"
|
||||
:special-menu="report">
|
||||
<n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item">
|
||||
<n-avatar
|
||||
lazy
|
||||
@ -99,6 +104,7 @@ import { useGroupStore } from '@/stores/group.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import type { UserItem } from '@/services/types.ts'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
|
||||
const groupStore = useGroupStore()
|
||||
const globalStore = useGlobalStore()
|
||||
@ -113,6 +119,7 @@ const userList = computed(() => {
|
||||
}
|
||||
})
|
||||
})
|
||||
const filteredUserList = shallowRef(userList.value)
|
||||
const isGroup = computed(() => globalStore.currentSession?.type === RoomTypeEnum.GROUP)
|
||||
/** 是否是搜索模式 */
|
||||
const isSearch = ref(false)
|
||||
@ -124,18 +131,35 @@ const isCollapsed = ref(true)
|
||||
const { optionsList, report, selectKey } = useChatMain()
|
||||
const { handlePopoverUpdate } = usePopover(selectKey, 'image-chat-sidebar')
|
||||
|
||||
const handleSearch = () => {
|
||||
const handleSelect = () => {
|
||||
isSearch.value = !isSearch.value
|
||||
nextTick(() => {
|
||||
inputInstRef.value?.select()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置搜索状态
|
||||
*/
|
||||
const handleBlur = () => {
|
||||
isSearch.value = false
|
||||
searchRef.value = ''
|
||||
filteredUserList.value = userList.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听搜索输入过滤用户
|
||||
* @param value 输入值
|
||||
*/
|
||||
const handleSearch = useDebounceFn((value: string) => {
|
||||
filteredUserList.value = userList.value.filter((user) => user.name.toLowerCase().includes(value.toLowerCase()))
|
||||
}, 10)
|
||||
|
||||
onMounted(() => {
|
||||
Mitt.on(`${MittEnum.INFO_POPOVER}-Sidebar`, (event: any) => {
|
||||
selectKey.value = event
|
||||
selectKey.value = event.uid
|
||||
infoPopover.value = true
|
||||
handlePopoverUpdate(event)
|
||||
handlePopoverUpdate(event.uid)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
@ -84,7 +84,6 @@ import { useAlwaysOnTopStore } from '@/stores/alwaysOnTop.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { emit, listen } from '@tauri-apps/api/event'
|
||||
import { CloseBxEnum, EventEnum, MittEnum } from '@/enums'
|
||||
import { PersistedStateOptions } from 'pinia-plugin-persistedstate'
|
||||
import { exit } from '@tauri-apps/plugin-process'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
|
||||
@ -190,7 +189,7 @@ const handleConfirm = async () => {
|
||||
}
|
||||
|
||||
/** 监听是否按下esc */
|
||||
const isEsc = (e: PersistedStateOptions) => {
|
||||
const isEsc = (e: KeyboardEvent) => {
|
||||
// 判断按下的是否是esc
|
||||
if (e.key === 'Escape' && escClose.value) {
|
||||
handleCloseWin()
|
||||
|
@ -62,6 +62,8 @@ export enum MittEnum {
|
||||
SHRINK_WINDOW,
|
||||
/** 详情页面显示 */
|
||||
DETAILS_SHOW,
|
||||
/** 好友申请页面显示 */
|
||||
APPLY_SHOW,
|
||||
/** 消息列表被清空或者暂无消息 */
|
||||
NOT_MSG,
|
||||
/** 回复消息 */
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { useCommon } from '@/hooks/useCommon.ts'
|
||||
import { MittEnum, MsgEnum } from '@/enums'
|
||||
import { MittEnum, MsgEnum, PowerEnum } from '@/enums'
|
||||
import { MessageType, SessionItem } from '@/services/types.ts'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { useChatStore } from '@/stores/chat.ts'
|
||||
import apis from '@/services/apis.ts'
|
||||
import { useContactStore } from '@/stores/contacts'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import { isDiffNow } from '@/utils/ComputedTime.ts'
|
||||
|
||||
export const useChatMain = (activeItem?: SessionItem) => {
|
||||
const { removeTag, userUid } = useCommon()
|
||||
const globalStore = useGlobalStore()
|
||||
const chatStore = useChatStore()
|
||||
const userInfo = useUserStore()?.userInfo
|
||||
// const userInfo = useUserStore()?.userInfo
|
||||
// const chatMessageList = computed(() => chatStore.chatMessageList)
|
||||
const messageOptions = computed(() => chatStore.currentMessageOptions)
|
||||
@ -80,6 +86,14 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
return
|
||||
}
|
||||
chatStore.updateRecallStatus({ msgId: item.message.id })
|
||||
},
|
||||
visible: (item: MessageType) => {
|
||||
// 判断当前选择的信息的发送时间是否超过2分钟
|
||||
if (isDiffNow({ time: item.message.sendTime, unit: 'minute', diff: 2 })) return
|
||||
// 判断自己是否是发送者或者是否是管理员
|
||||
const isCurrentUser = item.fromUser.uid === userUid.value
|
||||
const isAdmin = userInfo?.power === PowerEnum.ADMIN
|
||||
return isCurrentUser || isAdmin
|
||||
}
|
||||
}
|
||||
])
|
||||
@ -153,7 +167,7 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
}
|
||||
])
|
||||
/** 右键用户信息菜单(群聊的时候显示) */
|
||||
const optionsList = ref([
|
||||
const optionsList = ref<OPT.RightMenu[]>([
|
||||
{
|
||||
label: '发送信息',
|
||||
icon: 'message-action',
|
||||
@ -170,13 +184,19 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
label: '查看资料',
|
||||
icon: 'notes',
|
||||
click: (item: any, type: string) => {
|
||||
Mitt.emit(`${MittEnum.INFO_POPOVER}-${type}`, item.key)
|
||||
// 如果是聊天框内的资料就使用的是消息的key,如果是群聊成员的资料就使用的是uid
|
||||
const uid = item.uid || item.message.id
|
||||
Mitt.emit(`${MittEnum.INFO_POPOVER}-${type}`, { uid: uid, type: type })
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '添加好友',
|
||||
icon: 'people-plus',
|
||||
click: () => {}
|
||||
click: (item: any) => {
|
||||
globalStore.addFriendModalInfo.show = true
|
||||
globalStore.addFriendModalInfo.uid = item.uid || item.fromUser.uid
|
||||
},
|
||||
visible: (item: any) => canAddFriend(item.uid || item.fromUser.uid)
|
||||
}
|
||||
])
|
||||
/** 举报选项 */
|
||||
@ -207,6 +227,19 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
}
|
||||
])
|
||||
|
||||
/**
|
||||
* 判断用户是否可以添加好友
|
||||
* @param uid 用户 ID
|
||||
* @returns {boolean} 如果可以添加好友返回 true,否则返回 false
|
||||
*/
|
||||
const canAddFriend = (uid: number): boolean => {
|
||||
const contactStore = useContactStore()
|
||||
const userStore = useUserStore()
|
||||
const myUid = userStore.userInfo.uid
|
||||
// 好友和自己不显示添加好友菜单
|
||||
return !(contactStore.contactsList.some((item) => item.uid === uid) || uid === myUid)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理复制事件
|
||||
* @param content 复制的内容
|
||||
@ -249,12 +282,14 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
// 计算距离底部的距离
|
||||
// const distanceFromBottom = scrollHeight - scrollTop.value - clientHeight
|
||||
// 判断是否滚动到顶部
|
||||
if (scrollTop.value === 0) {
|
||||
// 记录顶部最后一条消息的下标
|
||||
// historyIndex.value = chatMessageList.value[0].message.id
|
||||
if (messageOptions.value?.isLoading) return
|
||||
chatStore.loadMore()
|
||||
}
|
||||
requestAnimationFrame(async () => {
|
||||
if (scrollTop.value === 0) {
|
||||
// 记录顶部最后一条消息的下标
|
||||
// historyIndex.value = chatMessageList.value[0].message.id
|
||||
if (messageOptions.value?.isLoading) return
|
||||
await chatStore.loadMore()
|
||||
}
|
||||
})
|
||||
// // 判断是否大于100
|
||||
// if (distanceFromBottom > 100) {
|
||||
// floatFooter.value = true
|
||||
|
@ -87,7 +87,7 @@ export const useCommon = () => {
|
||||
* @param { MsgEnum } type 插入的类型
|
||||
* @param dom dom节点
|
||||
*/
|
||||
const insertNode = (type: MsgEnum, dom: any) => {
|
||||
const insertNode = (type: MsgEnum, dom: any, target: HTMLElement) => {
|
||||
const { selection, range } = getEditorRange()!
|
||||
// 删除选中的内容
|
||||
range?.deleteContents()
|
||||
@ -258,7 +258,7 @@ export const useCommon = () => {
|
||||
range?.insertNode(spaceNode)
|
||||
range?.collapse(false)
|
||||
} else {
|
||||
range?.insertNode(dom)
|
||||
target.appendChild(dom)
|
||||
}
|
||||
// 将光标移到选中范围的最后面
|
||||
selection?.collapseToEnd()
|
||||
@ -279,7 +279,7 @@ export const useCommon = () => {
|
||||
img.style.maxWidth = '140px'
|
||||
img.style.marginRight = '6px'
|
||||
// 插入图片
|
||||
insertNode(MsgEnum.IMAGE, img)
|
||||
insertNode(MsgEnum.IMAGE, img, dom)
|
||||
triggerInputEvent(dom)
|
||||
}
|
||||
nextTick(() => {}).then(() => {
|
||||
@ -298,7 +298,7 @@ export const useCommon = () => {
|
||||
// 使用函数
|
||||
createFileOrVideoDom(file).then((imgTag) => {
|
||||
// 将生成的img标签插入到页面中
|
||||
insertNode(type, imgTag)
|
||||
insertNode(type, imgTag, dom)
|
||||
triggerInputEvent(dom)
|
||||
})
|
||||
nextTick(() => {}).then(() => {
|
||||
@ -340,7 +340,7 @@ export const useCommon = () => {
|
||||
} else {
|
||||
// 如果没有文件,而是文本,处理纯文本粘贴
|
||||
const plainText = e.clipboardData.getData('text/plain')
|
||||
insertNode(MsgEnum.TEXT, plainText)
|
||||
insertNode(MsgEnum.TEXT, plainText, dom)
|
||||
triggerInputEvent(dom)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
import axios from 'axios'
|
||||
import { EventEnum } from '@/enums'
|
||||
import { useWindow } from '@/hooks/useWindow.ts'
|
||||
|
||||
@ -15,19 +14,22 @@ export const useLogin = () => {
|
||||
await emit('login_success')
|
||||
}
|
||||
|
||||
/** 登出账号 */
|
||||
|
||||
const logout = async () => {
|
||||
/**
|
||||
* 登出账号
|
||||
* @param isToQrcode 是否返回到二维码页面
|
||||
*/
|
||||
const logout = async (isToQrcode = false) => {
|
||||
const { createWebviewWindow } = useWindow()
|
||||
localStorage.removeItem('USER_INFO')
|
||||
localStorage.removeItem('TOKEN')
|
||||
// 清空axios请求头
|
||||
const instance = axios.create()
|
||||
instance.defaults.headers.common.Authorization = ''
|
||||
// todo 退出账号 需要关闭其他的全部窗口
|
||||
await createWebviewWindow('登录', 'login', 320, 448, 'home', false, 320, 448).then(() => {
|
||||
emit(EventEnum.LOGOUT)
|
||||
emit('logout_success')
|
||||
// 用于跳转到二维码页面
|
||||
if (isToQrcode) {
|
||||
localStorage.setItem('isToQrcode', '1')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
|
||||
if (clipboardItem.types.includes('text/plain')) {
|
||||
// 如果是文本,使用 readText() 读取文本内容
|
||||
navigator.clipboard.readText().then((text) => {
|
||||
insertNode(MsgEnum.TEXT, text)
|
||||
insertNode(MsgEnum.TEXT, text, {} as HTMLElement)
|
||||
triggerInputEvent(messageInputDom.value)
|
||||
})
|
||||
} else if (clipboardItem.types.find((type) => type.startsWith('image/'))) {
|
||||
@ -122,7 +122,11 @@ export const useMsgInput = (messageInputDom: Ref) => {
|
||||
if (messageInputDom.value) {
|
||||
nextTick().then(() => {
|
||||
messageInputDom.value.focus()
|
||||
insertNode(MsgEnum.REPLY, { accountName: accountName, content: event.message.body.content })
|
||||
insertNode(
|
||||
MsgEnum.REPLY,
|
||||
{ accountName: accountName, content: event.message.body.content },
|
||||
{} as HTMLElement
|
||||
)
|
||||
triggerInputEvent(messageInputDom.value)
|
||||
})
|
||||
}
|
||||
@ -277,7 +281,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
|
||||
if (!isWindows && chat.value.sendKey === 'Enter' && e.metaKey && e.key === 'Enter') {
|
||||
// 就进行换行操作
|
||||
e.preventDefault()
|
||||
insertNode(MsgEnum.TEXT, '\n')
|
||||
insertNode(MsgEnum.TEXT, '\n', {} as HTMLElement)
|
||||
triggerInputEvent(messageInputDom.value)
|
||||
}
|
||||
if (msgInput.value === '' || msgInput.value.trim() === '' || ait.value) {
|
||||
@ -313,7 +317,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
|
||||
range?.setStart(textNode, <number>expRes?.index)
|
||||
/** 设置范围的结束位置为光标的位置 */
|
||||
range?.setEnd(textNode, endOffset!)
|
||||
insertNode(MsgEnum.AIT, item.name)
|
||||
insertNode(MsgEnum.AIT, item.name, {} as HTMLElement)
|
||||
triggerInputEvent(messageInputDom.value)
|
||||
ait.value = false
|
||||
}
|
||||
|
@ -168,6 +168,9 @@ const doDrag = (e: MouseEvent) => {
|
||||
const newWidth = startWidth.value + e.clientX - startX.value
|
||||
// 如果新宽度不等于最大宽度,则更新宽度值
|
||||
if (newWidth !== maxWidth) {
|
||||
// 给聊天框添加 select-none 样式,防止在拖动改变布局时选中文本
|
||||
const chatMain = document.querySelector('#image-chat-main')
|
||||
chatMain?.classList.add('select-none')
|
||||
initWidth.value = clamp(newWidth, minWidth, maxWidth) // 使用 clamp 函数限制宽度值在最小值和最大值之间
|
||||
}
|
||||
})
|
||||
@ -188,6 +191,9 @@ const initDrag = (e: MouseEvent) => {
|
||||
}
|
||||
|
||||
const stopDrag = () => {
|
||||
// 松开鼠标后,移除聊天框的 select-none 样式
|
||||
const chatMain = document.querySelector('#image-chat-main')
|
||||
chatMain?.classList.remove('select-none')
|
||||
document.removeEventListener('mousemove', doDrag, false)
|
||||
document.removeEventListener('mouseup', stopDrag, false)
|
||||
isDragging.value = false
|
||||
|
@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div class="flex size-full min-w-310px">
|
||||
<div id="layout" class="flex size-full min-w-310px">
|
||||
<Left />
|
||||
<Center />
|
||||
<Right v-if="!shrinkStatus" />
|
||||
</div>
|
||||
|
||||
<AddFriendsModal />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -13,7 +15,13 @@ import Right from './right/index.vue'
|
||||
import Mitt from '@/utils/Bus'
|
||||
import { MittEnum } from '@/enums'
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const contactStore = useContactStore()
|
||||
// 清空未读消息
|
||||
globalStore.unReadMark.newMsgUnreadCount = 0
|
||||
const shrinkStatus = ref(false)
|
||||
/**
|
||||
* event默认如果没有传递值就为true,所以shrinkStatus的值为false就会发生值的变化
|
||||
@ -23,6 +31,12 @@ Mitt.on(MittEnum.SHRINK_WINDOW, (event) => {
|
||||
shrinkStatus.value = event as boolean
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
// 默认执行一次
|
||||
contactStore.getContactList(true)
|
||||
contactStore.getRequestFriendsList(true)
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await getCurrentWebviewWindow().show()
|
||||
})
|
||||
|
@ -43,7 +43,11 @@
|
||||
</n-flex>
|
||||
</n-popover>
|
||||
<!-- 该选项无提示时展示 -->
|
||||
<n-badge v-else :max="99" :value="item.badge">
|
||||
<n-badge
|
||||
v-else
|
||||
:max="99"
|
||||
:value="unReadMark.newMsgUnreadCount"
|
||||
:show="item.icon.includes('message') && unReadMark.newMsgUnreadCount > 0">
|
||||
<svg class="size-22px">
|
||||
<use
|
||||
:href="`#${activeUrl === item.url || openWindowsList.has(item.url) ? item.iconAction : item.icon}`"></use>
|
||||
@ -249,11 +253,14 @@ import { PluginEnum, ShowModeEnum } from '@/enums'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const pluginsStore = usePluginsStore()
|
||||
const { showMode } = storeToRefs(useSettingStore())
|
||||
const { menuTop } = useMenuTopStore()
|
||||
const { plugins } = storeToRefs(pluginsStore)
|
||||
const unReadMark = computed(() => globalStore.unReadMark)
|
||||
// const headerRef = useTemplateRef('header')
|
||||
// const actionListRef = useTemplateRef('actionList')
|
||||
//const { } = toRefs(getCurrentInstance) // 所有菜单的外层div
|
||||
|
@ -120,11 +120,7 @@ export const leftHook = () => {
|
||||
window.$message.error('改名次数不足')
|
||||
return
|
||||
}
|
||||
apis.modifyUserName(editInfo.value.content.name).then((res: any) => {
|
||||
if (!res) {
|
||||
window.$message.error(res)
|
||||
return
|
||||
}
|
||||
apis.modifyUserName(editInfo.value.content.name).then(() => {
|
||||
// 更新本地缓存的用户信息
|
||||
login.accountInfo.name = editInfo.value.content.name!
|
||||
updateCurrentUserCache('name', editInfo.value.content.name) // 更新缓存里面的用户信息
|
||||
|
@ -8,7 +8,7 @@
|
||||
<!-- 导航选项按钮模块 -->
|
||||
<ActionList />
|
||||
<!-- 编辑资料弹窗 -->
|
||||
<InfoPopover />
|
||||
<InfoEdit />
|
||||
|
||||
<!-- 弹出框 -->
|
||||
<component :is="componentMap" />
|
||||
@ -18,7 +18,7 @@
|
||||
<script lang="tsx" setup>
|
||||
import LeftAvatar from './components/LeftAvatar.vue'
|
||||
import ActionList from './components/ActionList.vue'
|
||||
import InfoPopover from './components/InfoPopover.vue'
|
||||
import InfoEdit from './components/InfoEdit.vue'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { lock, LockScreen, CheckUpdate } from './model.tsx'
|
||||
import { DefineComponent, DefineSetupFnComponent } from 'vue'
|
||||
|
@ -220,14 +220,12 @@ export const CheckUpdate = defineComponent(() => {
|
||||
switch (event.event) {
|
||||
case 'Started':
|
||||
total.value = event.data.contentLength ? event.data.contentLength : 0
|
||||
console.log(`started downloading ${event.data.contentLength} bytes`)
|
||||
break
|
||||
case 'Progress':
|
||||
downloaded.value += event.data.chunkLength
|
||||
percentage.value = parseFloat(((downloaded.value / total.value) * 100 + '').substring(0, 4))
|
||||
break
|
||||
case 'Finished':
|
||||
console.log('download finished')
|
||||
window.$message.success('安装包下载成功,3s后重启并安装')
|
||||
setTimeout(() => {
|
||||
updating.value = false
|
||||
|
@ -1,16 +1,19 @@
|
||||
<template>
|
||||
<main data-tauri-drag-region class="flex-1 bg-[--right-bg-color] h-full w-100vw min-w-600px">
|
||||
<div class="size-full" style="background: var(--right-theme-bg-color)" data-tauri-drag-region>
|
||||
<div class="size-full" :style="{ background: isChat ? 'var(--right-theme-bg-color)' : '' }" data-tauri-drag-region>
|
||||
<ActionBar :current-label="appWindow.label" />
|
||||
<!-- 需要判断当前路由是否是信息详情界面 -->
|
||||
<ChatBox :active-item="activeItem" v-if="msgBoxShow && isChat && activeItem !== -1" />
|
||||
|
||||
<Details :content="DetailsContent" v-else-if="detailsShow && isDetails" />
|
||||
<Details :content="DetailsContent" v-else-if="detailsShow && isDetails && DetailsContent.type !== 'apply'" />
|
||||
|
||||
<!-- 好友申请列表 -->
|
||||
<ApplyList v-else-if="DetailsContent && isDetails && DetailsContent.type === 'apply'" />
|
||||
|
||||
<!-- 聊天界面背景图标 -->
|
||||
<div v-else class="flex-center size-full select-none">
|
||||
<img
|
||||
v-if="imgTheme === ThemeEnum.DARK && themes.versatile === 'default'"
|
||||
v-if="imgTheme === ThemeEnum.DARK && themes.versatile === 'default' && !isDetails"
|
||||
class="w-110px h-100px"
|
||||
src="@/assets/img/hula_bg_d.svg"
|
||||
alt="" />
|
||||
@ -73,6 +76,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
if (isDetails) {
|
||||
Mitt.on(MittEnum.APPLY_SHOW, (event: any) => {
|
||||
DetailsContent.value = event.context
|
||||
})
|
||||
Mitt.on(MittEnum.DETAILS_SHOW, (event: any) => {
|
||||
DetailsContent.value = event.context
|
||||
detailsShow.value = event.detailsShow as boolean
|
||||
|
@ -1,8 +1,6 @@
|
||||
// import { createAxios } from '@/services/request'
|
||||
import urls from '@/services/urls'
|
||||
import type {
|
||||
Response,
|
||||
// BadgeType,
|
||||
BadgeType,
|
||||
CacheBadgeItem,
|
||||
CacheBadgeReq,
|
||||
CacheUserItem,
|
||||
@ -22,14 +20,8 @@ import type {
|
||||
UserItem
|
||||
} from '@/services/types'
|
||||
|
||||
// const request = createAxios()
|
||||
import request from '@/services/request'
|
||||
|
||||
// const GET = <T>(url: string, params?: any) => request.get<T, Response>(url, params)
|
||||
// const POST = <T>(url: string, params?: any) => request.post<T, Response>(url, params)
|
||||
// const PUT = <T>(url: string, params?: any) => request.put<T, Response>(url, params)
|
||||
// const DELETE = <T>(url: string, params?: any) => request.delete<T, Response>(url, params)
|
||||
|
||||
const GET = <T>(url: string, params?: any) => request.get<T>(url, params)
|
||||
const POST = <T>(url: string, params?: any) => request.post<T>(url, params)
|
||||
const PUT = <T>(url: string, params?: any) => request.put<T>(url, params)
|
||||
@ -57,7 +49,7 @@ export default {
|
||||
/** 获取用户详细信息 */
|
||||
getUserDetail: () => GET<UserInfoType>(urls.getUserInfoDetail, {}),
|
||||
/** 获取徽章列表 */
|
||||
getBadgeList: (): Promise<Response> => GET(urls.getBadgeList),
|
||||
getBadgeList: (): Promise<BadgeType> => GET(urls.getBadgeList),
|
||||
/** 设置用户勋章 */
|
||||
setUserBadge: (badgeId: number) => PUT<void>(urls.setUserBadge, { badgeId }),
|
||||
/** 修改用户名 */
|
||||
@ -83,7 +75,7 @@ export default {
|
||||
POST<EmojiItem[]>(urls.sendAddFriendRequest, params),
|
||||
/** 同意好友申请 */
|
||||
applyFriendRequest: (params: { applyId: number }) => PUT(urls.sendAddFriendRequest, params),
|
||||
/** 同意好友申请 */
|
||||
/** 删除好友 */
|
||||
deleteFriend: (params: { targetUid: number }) => DELETE(urls.deleteFriend, params),
|
||||
/** 好友申请未读数 */
|
||||
newFriendCount: () => GET<{ unReadCount: number }>(urls.newFriendCount),
|
||||
@ -102,11 +94,11 @@ export default {
|
||||
/** 删除群成员 */
|
||||
removeGroupMember: (params: { roomId: number; uid: number }) => DELETE(urls.inviteGroupMember, params),
|
||||
/** 群组详情 */
|
||||
groupDetail: (params: { id: number }) => GET<GroupDetailReq>(urls.groupDetail, { params }),
|
||||
groupDetail: (params: { id: number }) => GET<GroupDetailReq>(urls.groupDetail, params),
|
||||
/** 会话详情 */
|
||||
sessionDetail: (params: { id: number }) => GET<SessionItem>(urls.sessionDetail, { params }),
|
||||
/** 会话详情(联系人列表发消息用) */
|
||||
sessionDetailWithFriends: (params: { uid: number }) => GET<SessionItem>(urls.sessionDetailWithFriends, { params }),
|
||||
sessionDetailWithFriends: (params: { uid: number }) => GET<SessionItem>(urls.sessionDetailWithFriends, params),
|
||||
/** 添加群管理 */
|
||||
addAdmin: ({ roomId, uidList }: { roomId: number; uidList: number[] }) =>
|
||||
PUT<boolean>(urls.addAdmin, {
|
||||
|
@ -82,77 +82,3 @@ async function Http<T>(
|
||||
}
|
||||
|
||||
export default Http
|
||||
|
||||
// import { fetch } from '@tauri-apps/plugin-http';
|
||||
// import * as qs from 'qs';
|
||||
|
||||
// const isAbsoluteURL = (url: string) => {
|
||||
// return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
|
||||
// };
|
||||
|
||||
// const combineURLs = (baseURL: string, relativeURL: string) => {
|
||||
// return relativeURL
|
||||
// ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
|
||||
// : baseURL;
|
||||
// };
|
||||
|
||||
// const buildFullPath = (baseURL: string, requestedURL: string) => {
|
||||
// if (baseURL && !isAbsoluteURL(requestedURL)) {
|
||||
// return combineURLs(baseURL, requestedURL);
|
||||
// }
|
||||
// return requestedURL;
|
||||
// };
|
||||
|
||||
// const buildURL = (url: string | string[], params: any) => {
|
||||
// if (!params) {
|
||||
// return url;
|
||||
// }
|
||||
// const serializedParams = qs.stringify(params);
|
||||
// if (serializedParams) {
|
||||
// url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
|
||||
// }
|
||||
// return url;
|
||||
// };
|
||||
|
||||
// const server = '';
|
||||
// const baseURL = `${server}/api/`;
|
||||
|
||||
// const BODY_TYPE = {
|
||||
// Form: 'Form',
|
||||
// Json: 'Json',
|
||||
// Text: 'Text',
|
||||
// Bytes: 'Bytes',
|
||||
// };
|
||||
|
||||
// const commonOptions = {
|
||||
// timeout: 60,
|
||||
// };
|
||||
|
||||
// const http = (url: string, options: any = {}) => {
|
||||
// const params = { ...options.params };
|
||||
// if (!options.headers) options.headers = {};
|
||||
// // todo 可以往 headers 中添加 token 或 cookie 等信息
|
||||
|
||||
// if (options?.body) {
|
||||
// if (options.body.type === BODY_TYPE.Form) {
|
||||
// options.headers['Content-Type'] = 'multipart/form-data';
|
||||
// }
|
||||
// }
|
||||
|
||||
// options = { ...commonOptions, ...options };
|
||||
// let fetchUrl:string = buildFullPath(baseURL, url)
|
||||
// return fetch(<string>buildURL(fetchUrl, params), options)
|
||||
// .then((res: any) => {
|
||||
// const { status, data } = res
|
||||
// if (status >= 200 && status < 400) {
|
||||
// return { data };
|
||||
// }
|
||||
// return Promise.reject({ status, data });
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.error(err);
|
||||
// return Promise.reject(err);
|
||||
// });
|
||||
// };
|
||||
|
||||
// export default http;
|
||||
|
@ -1,11 +1,6 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import Http, { HttpParams } from './http.ts'
|
||||
|
||||
/** 是否是测试环境 */
|
||||
const isTest = computed(() => {
|
||||
return useSettingStore().login.accountInfo.token === 'test'
|
||||
})
|
||||
import { ServiceResponse } from '@/services/types.ts'
|
||||
|
||||
function getToken() {
|
||||
let tempToken = ''
|
||||
@ -26,123 +21,6 @@ function getToken() {
|
||||
|
||||
export const computedToken = getToken()
|
||||
|
||||
//请求配置
|
||||
export const createAxios = (config?: AxiosRequestConfig): AxiosInstance => {
|
||||
const instance = axios.create({
|
||||
//请求头
|
||||
// baseURL: import.meta.env.VITE_SERVICE_URL,
|
||||
baseURL: '/api',
|
||||
//超时配置
|
||||
timeout: 10000,
|
||||
//跨域携带cookie
|
||||
withCredentials: true,
|
||||
// 自定义配置覆盖基本配置
|
||||
...config
|
||||
})
|
||||
|
||||
// 添加请求拦截器
|
||||
instance.interceptors.request.use(
|
||||
function (config: any) {
|
||||
//判断是否有token 根据自己的需求判断
|
||||
const token = useSettingStore().login.accountInfo.token
|
||||
if (isTest.value) {
|
||||
// 如果token为'test',阻止请求并返回一个错误对象
|
||||
return Promise.reject(
|
||||
window.$message.create('当前为测试环境,请注意辨别', {
|
||||
type: 'warning',
|
||||
closable: true
|
||||
})
|
||||
)
|
||||
}
|
||||
if (token != void 0) {
|
||||
// //如果要求携带在参数中
|
||||
// config.params = Object.assign({}, config.params, token)
|
||||
// 如果要求携带在请求头中
|
||||
// config.headers = Object.assign({}, config.headers, operate.uploadParameters())
|
||||
config.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
// 设置请求头
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
function (error) {
|
||||
// 请求错误
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 添加响应拦截器
|
||||
instance.interceptors.response.use(
|
||||
(response) => {
|
||||
//返回参数
|
||||
let res = response.data
|
||||
// 如果是返回的文件
|
||||
if (response.config.responseType === 'blob') {
|
||||
return res
|
||||
}
|
||||
// 兼容服务端返回的字符串数据
|
||||
if (typeof (<string>res) === 'string') {
|
||||
res = res ? JSON.parse(res) : res
|
||||
}
|
||||
return res
|
||||
},
|
||||
(error) => {
|
||||
/***** 接收到异常响应的处理开始 *****/
|
||||
if (error && error.response) {
|
||||
// 1.公共错误处理
|
||||
// 2.根据响应码具体处理
|
||||
switch (error.response.status) {
|
||||
case 400:
|
||||
error.message = '错误请求'
|
||||
break
|
||||
case 401:
|
||||
error.message = '未授权,请重新登录'
|
||||
break
|
||||
case 403:
|
||||
error.message = '拒绝访问'
|
||||
break
|
||||
case 404:
|
||||
error.message = '请求错误,未找到该资源'
|
||||
window.location.href = '/NotFound'
|
||||
break
|
||||
case 405:
|
||||
error.message = '请求方法未允许'
|
||||
break
|
||||
case 408:
|
||||
error.message = '请求超时'
|
||||
break
|
||||
case 500:
|
||||
error.message = '服务器端出错'
|
||||
break
|
||||
case 501:
|
||||
error.message = '网络未实现'
|
||||
break
|
||||
case 502:
|
||||
error.message = '网络错误'
|
||||
break
|
||||
case 503:
|
||||
error.message = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
error.message = '网络超时'
|
||||
break
|
||||
case 505:
|
||||
error.message = 'http版本不支持该请求'
|
||||
break
|
||||
default:
|
||||
error.message = `连接错误${error.response.status}`
|
||||
}
|
||||
}
|
||||
if (isTest) return Promise.resolve(error.response)
|
||||
window.$message.error(error.message)
|
||||
/***** 处理结束 *****/
|
||||
return Promise.resolve(error.response)
|
||||
}
|
||||
)
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
// fetch 请求响应拦截器
|
||||
const responseInterceptor = async <T>(
|
||||
url: string,
|
||||
@ -179,7 +57,9 @@ const responseInterceptor = async <T>(
|
||||
const data = await Http(url, httpParams, true)
|
||||
|
||||
const resp = data.resp
|
||||
|
||||
const serviceData = (await data.data) as ServiceResponse
|
||||
console.log(data)
|
||||
//检查发送请求是否成功
|
||||
if (resp.status > 400) {
|
||||
let message = ''
|
||||
switch (resp.status) {
|
||||
@ -225,9 +105,12 @@ const responseInterceptor = async <T>(
|
||||
}
|
||||
return Promise.reject(`err: ${message}, status: ${resp.status}`)
|
||||
}
|
||||
|
||||
const res: any = await data.data
|
||||
return Promise.resolve(res.data)
|
||||
//检查服务端返回是否成功,并且中断请求
|
||||
if (!serviceData.success) {
|
||||
window.$message.error(serviceData.errMsg)
|
||||
return Promise.reject(`http error: ${serviceData.errMsg}`)
|
||||
}
|
||||
return Promise.resolve(serviceData.data)
|
||||
} catch (err) {
|
||||
return Promise.reject(`http error: ${err}`)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
import { ActEnum, IsYetEnum, MarkEnum, MsgEnum, OnlineEnum, RoomTypeEnum, SexEnum } from '@/enums'
|
||||
|
||||
/**响应请求体*/
|
||||
export type Response = {
|
||||
export type ServiceResponse = {
|
||||
/** 成功标识true or false */
|
||||
success: boolean
|
||||
/** 错误码 */
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { URLEnum } from '@/enums'
|
||||
|
||||
const { PROD, VITE_SERVICE_URL } = import.meta.env
|
||||
const { VITE_SERVICE_URL } = import.meta.env
|
||||
// 本地配置到 .env.development 里面修改。生产配置在 .env.production 里面
|
||||
const prefix = PROD ? VITE_SERVICE_URL : ''
|
||||
const prefix = VITE_SERVICE_URL
|
||||
|
||||
export default {
|
||||
getUserInfo: `${prefix + URLEnum.USER}/userInfo`, // 获取用户信息
|
||||
|
@ -5,7 +5,6 @@ import type { MarkItemType, MessageType, RevokedMsgType, SessionItem } from '@/s
|
||||
import { MarkEnum, MsgEnum, RoomTypeEnum } from '@/enums'
|
||||
import { computedTimeBlock } from '@/utils/ComputedTime.ts'
|
||||
import { useCachedStore } from '@/stores/cached'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useGlobalStore } from '@/stores/global'
|
||||
import { useGroupStore } from '@/stores/group'
|
||||
import { useContactStore } from '@/stores/contacts'
|
||||
@ -18,7 +17,7 @@ let isFirstInit = false
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const route = useRoute()
|
||||
const cachedStore = useCachedStore()
|
||||
const userStore = useUserStore()
|
||||
// const userStore = useUserStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const groupStore = useGroupStore()
|
||||
const contactStore = useContactStore()
|
||||
@ -125,7 +124,7 @@ export const useChatStore = defineStore('chat', () => {
|
||||
if (currentRoomType.value === RoomTypeEnum.GROUP) {
|
||||
groupStore.getGroupUserList(true)
|
||||
groupStore.getCountStatistic()
|
||||
cachedStore.getGroupAtUserBaseInfo()
|
||||
// cachedStore.getGroupAtUserBaseInfo()
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +218,7 @@ export const useChatStore = defineStore('chat', () => {
|
||||
// 请求第一个群成员列表
|
||||
currentRoomType.value === RoomTypeEnum.GROUP && (await groupStore.getGroupUserList(true))
|
||||
// 初始化所有用户基本信息
|
||||
userStore.isSign && (await cachedStore.initAllUserBaseInfo())
|
||||
// userStore.isSign && (await cachedStore.initAllUserBaseInfo())
|
||||
// 联系人列表
|
||||
await contactStore.getContactList(true)
|
||||
}
|
||||
@ -279,8 +278,7 @@ export const useChatStore = defineStore('chat', () => {
|
||||
detailResponse = await apis.sessionDetail({ id: msg.message.roomId })
|
||||
}
|
||||
if (detailResponse) {
|
||||
const data = detailResponse
|
||||
updateSessionLastActiveTime(msg.message.roomId, data)
|
||||
updateSessionLastActiveTime(msg.message.roomId, detailResponse)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,11 @@ export const useContactStore = defineStore('contact', () => {
|
||||
const requestFriendsList = reactive<RequestFriendItem[]>([])
|
||||
const contactsOptions = reactive({ isLast: false, isLoading: false, cursor: '' })
|
||||
const requestFriendsOptions = reactive({ isLast: false, isLoading: false, cursor: '' })
|
||||
|
||||
/**
|
||||
* 获取联系人列表
|
||||
* @param isFresh 是否刷新
|
||||
*/
|
||||
const getContactList = async (isFresh = false) => {
|
||||
if (!isFresh) {
|
||||
if (contactsOptions.isLast || contactsOptions.isLoading) return
|
||||
@ -45,6 +50,10 @@ export const useContactStore = defineStore('contact', () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取好友申请列表
|
||||
* @param isFresh 是否刷新
|
||||
*/
|
||||
const getRequestFriendsList = async (isFresh = false) => {
|
||||
if (!isFresh) {
|
||||
if (requestFriendsOptions.isLast || requestFriendsOptions.isLoading) return
|
||||
|
@ -112,8 +112,7 @@ export const useGroupStore = defineStore('group', () => {
|
||||
|
||||
// 获取群成员数量统计
|
||||
const getCountStatistic = async () => {
|
||||
const data = await apis.groupDetail({ id: currentRoomId.value })
|
||||
countInfo.value = data
|
||||
countInfo.value = await apis.groupDetail({ id: currentRoomId.value })
|
||||
}
|
||||
|
||||
// 加载更多群成员
|
||||
|
@ -14,6 +14,8 @@
|
||||
caret-color: #13987f; /** 光标颜色,可根据需求调整 */
|
||||
white-space: pre-wrap; /** 保留空白符号并正常换行 */
|
||||
word-break: break-word; /** 在长单词或URL地址内部进行换行 */
|
||||
-webkit-white-space: pre-wrap; /** 兼容webkit浏览器 */
|
||||
-webkit-word-break: break-word;
|
||||
}
|
||||
.ait {
|
||||
@apply w-200px h-fit max-h-190px bg-[--center-bg-color] rounded-8px p-[5px_0_5px_5px] border-(1px solid [--box-shadow-color]);
|
||||
|
4
src/typings/components.d.ts
vendored
4
src/typings/components.d.ts
vendored
@ -8,6 +8,8 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ActionBar: typeof import('./../components/windows/ActionBar.vue')['default']
|
||||
AddFriendsModal: typeof import('./../components/common/AddFriendsModal.vue')['default']
|
||||
ApplyList: typeof import('./../components/rightBox/ApplyList.vue')['default']
|
||||
ChatBox: typeof import('./../components/rightBox/chatBox/index.vue')['default']
|
||||
ChatFooter: typeof import('./../components/rightBox/chatBox/ChatFooter.vue')['default']
|
||||
ChatHeader: typeof import('./../components/rightBox/chatBox/ChatHeader.vue')['default']
|
||||
@ -34,6 +36,7 @@ declare module 'vue' {
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NFlex: typeof import('naive-ui')['NFlex']
|
||||
NGradientText: typeof import('naive-ui')['NGradientText']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NIconWrapper: typeof import('naive-ui')['NIconWrapper']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
@ -57,6 +60,7 @@ declare module 'vue' {
|
||||
NTab: typeof import('naive-ui')['NTab']
|
||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||
NTabs: typeof import('naive-ui')['NTabs']
|
||||
NText: typeof import('naive-ui')['NText']
|
||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||
NVirtualList: typeof import('naive-ui')['NVirtualList']
|
||||
RenderMessage: typeof import('./../components/rightBox/renderMessage/index.vue')['default']
|
||||
|
2
src/typings/options.d.ts
vendored
2
src/typings/options.d.ts
vendored
@ -63,11 +63,13 @@ declare namespace OPT {
|
||||
* @param label 选项名称
|
||||
* @param icon 选项图标
|
||||
* @param click 点击事件
|
||||
* @param visible 显示条件
|
||||
*/
|
||||
type RightMenu = {
|
||||
label: string
|
||||
icon: string
|
||||
click?: (...args: any[]) => void
|
||||
visible?: (...args: any[]) => void
|
||||
} | null
|
||||
|
||||
/**
|
||||
|
@ -101,7 +101,7 @@
|
||||
|
||||
<n-flex v-if="!isLogining && !isWrongPassword" justify="space-around" align="center" :size="0" class="options">
|
||||
<p class="text-(14px #fefefe)" @click="isUnlockPage = false">返回</p>
|
||||
<p class="text-(14px #fefefe)" @click="logout">退出登录</p>
|
||||
<p class="text-(14px #fefefe)" @click="logout()">退出登录</p>
|
||||
<p class="text-(14px #fefefe)">忘记密码</p>
|
||||
<p class="text-(14px #fff)" @click="unlock">进入系统</p>
|
||||
</n-flex>
|
||||
|
@ -1,5 +1,13 @@
|
||||
<template>
|
||||
<n-scrollbar style="max-height: calc(100vh - 70px)">
|
||||
<n-flex
|
||||
@click="handleApply"
|
||||
align="center"
|
||||
justify="space-between"
|
||||
class="my-10px p-12px hover:(bg-[--list-hover-color] cursor-pointer)">
|
||||
<div class="text-(14px [--text-color])">好友通知</div>
|
||||
<svg class="size-16px rotate-270 color-[--text-color]"><use href="#down"></use></svg>
|
||||
</n-flex>
|
||||
<n-tabs type="segment" animated class="mt-4px p-[4px_10px_0px_8px]">
|
||||
<n-tab-pane name="1" tab="好友">
|
||||
<n-scrollbar style="max-height: calc(100vh - 126px)">
|
||||
@ -7,7 +15,7 @@
|
||||
<ContextMenu @contextmenu="showMenu($event)" @select="handleSelect($event.label)" :menu="menuList">
|
||||
<n-collapse-item title="我的好友" name="1">
|
||||
<template #header-extra>
|
||||
<span class="text-(10px #707070)">0/0</span>
|
||||
<span class="text-(10px #707070)"> {{ onlineCount }}/{{ contactStore.contactsList.length }} </span>
|
||||
</template>
|
||||
|
||||
<!-- 用户框 多套一层div来移除默认的右键事件然后覆盖掉因为margin空隙而导致右键可用 -->
|
||||
@ -25,6 +33,8 @@
|
||||
bordered
|
||||
:color="'#fff'"
|
||||
:size="44"
|
||||
class="grayscale"
|
||||
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
|
||||
:src="useUserInfo(item.uid).value.avatar"
|
||||
fallback-src="/logo.png" />
|
||||
|
||||
@ -33,9 +43,15 @@
|
||||
useUserInfo(item.uid).value.name
|
||||
}}</span>
|
||||
|
||||
<span class="text leading-tight text-12px flex-1 truncate">
|
||||
[⛅今日天气] 说的很经典哈萨克的哈萨克看到贺卡上
|
||||
</span>
|
||||
<div class="text leading-tight text-12px flex-y-center gap-2px flex-1 truncate">
|
||||
[
|
||||
<img
|
||||
class="size-14px"
|
||||
:src="`/status/${item.activeStatus === OnlineEnum.ONLINE ? 'online.png' : 'offline.png'}`"
|
||||
alt="离线" />
|
||||
{{ item.activeStatus === OnlineEnum.ONLINE ? '在线' : '离线' }}
|
||||
]
|
||||
</div>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
@ -64,7 +80,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { MittEnum, RoomTypeEnum } from '@/enums'
|
||||
import { MittEnum, OnlineEnum, RoomTypeEnum } from '@/enums'
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
|
||||
@ -78,6 +94,10 @@ const activeItem = ref(0)
|
||||
const detailsShow = ref(false)
|
||||
const shrinkStatus = ref(false)
|
||||
const contactStore = useContactStore()
|
||||
/** 统计在线用户人数 */
|
||||
const onlineCount = computed(() => {
|
||||
return contactStore.contactsList.filter((item) => item.activeStatus === OnlineEnum.ONLINE).length
|
||||
})
|
||||
/** 监听独立窗口关闭事件 */
|
||||
watchEffect(() => {
|
||||
Mitt.on(MittEnum.SHRINK_WINDOW, async (event) => {
|
||||
@ -106,6 +126,15 @@ const handleSelect = (event: MouseEvent) => {
|
||||
console.log(event)
|
||||
}
|
||||
|
||||
const handleApply = () => {
|
||||
Mitt.emit(MittEnum.APPLY_SHOW, {
|
||||
context: {
|
||||
type: 'apply'
|
||||
}
|
||||
})
|
||||
activeItem.value = 0
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
detailsShow.value = false
|
||||
Mitt.emit(MittEnum.DETAILS_SHOW, detailsShow.value)
|
||||
@ -126,7 +155,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.active {
|
||||
background: var(--bg-active-msg);
|
||||
background: var(--msg-active-color);
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
.text {
|
||||
|
@ -71,6 +71,7 @@ const globalStore = useGlobalStore()
|
||||
const { userUid } = useCommon()
|
||||
const scrollbar = ref()
|
||||
const { handleMsgClick, activeIndex, menuList, specialMenuList, handleMsgDblclick } = useMessage()
|
||||
// TODO 艾特我提醒
|
||||
const sessionList = computed(() =>
|
||||
chatStore.sessionList.map((item) => {
|
||||
// 最后一条消息内容
|
||||
|
@ -142,8 +142,8 @@ import { invoke } from '@tauri-apps/api/core'
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const { themes, tips, escClose, chat, page } = settingStore
|
||||
const { showMode } = storeToRefs(settingStore)
|
||||
const { themes, tips, chat, page } = settingStore
|
||||
const { showMode, escClose } = storeToRefs(settingStore)
|
||||
const activeItem = ref<string>(themes.pattern)
|
||||
|
||||
const showText = computed({
|
||||
|
@ -264,6 +264,13 @@ const closeMenu = (event: MouseEvent) => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 判断是否需要马上跳转到二维码登录页面
|
||||
if (localStorage.getItem('isToQrcode')) {
|
||||
router.push('/qrCode')
|
||||
await nextTick(() => {
|
||||
localStorage.removeItem('isToQrcode')
|
||||
})
|
||||
}
|
||||
await getCurrentWebviewWindow().show()
|
||||
if (login.value.autoLogin && login.value.accountInfo.password !== '') {
|
||||
autoLogin()
|
||||
|
Loading…
Reference in New Issue
Block a user