聊天页面基本布局

This commit is contained in:
bob
2024-09-05 10:49:44 +08:00
parent 2396e13cdc
commit 2a890132a6
14 changed files with 729 additions and 61 deletions

View File

@@ -14,6 +14,7 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueup/vue-quill": "^1.2.0",
"axios": "^1.7.4",
"crypto-js": "^4.2.0",
"element-plus": "^2.8.0",

285
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@element-plus/icons-vue':
specifier: ^2.3.1
version: 2.3.1(vue@3.4.38)
'@vueup/vue-quill':
specifier: ^1.2.0
version: 1.2.0(vue@3.4.38)
axios:
specifier: ^1.7.4
version: 1.7.4
@@ -458,6 +461,11 @@ packages:
'@vue/shared@3.4.38':
resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==}
'@vueup/vue-quill@1.2.0':
resolution: {integrity: sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==}
peerDependencies:
vue: ^3.2.41
'@vueuse/core@9.13.0':
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
@@ -536,6 +544,10 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
call-bind@1.0.7:
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
engines: {node: '>= 0.4'}
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -560,6 +572,10 @@ packages:
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
engines: {node: '>=18'}
clone@2.1.2:
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
engines: {node: '>=0.8'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -611,9 +627,21 @@ packages:
supports-color:
optional: true
deep-equal@1.1.2:
resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==}
engines: {node: '>= 0.4'}
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -638,6 +666,14 @@ packages:
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
engines: {node: '>=18'}
es-define-property@1.0.0:
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -719,6 +755,9 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
eventemitter3@2.0.3:
resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==}
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
@@ -726,9 +765,18 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-diff@1.1.2:
resolution: {integrity: sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==}
fast-diff@1.2.0:
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
@@ -785,10 +833,20 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
get-east-asian-width@1.2.0:
resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
engines: {node: '>=18'}
get-intrinsic@1.2.4:
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
@@ -809,6 +867,9 @@ packages:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@@ -816,6 +877,25 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
has-proto@1.0.3:
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
engines: {node: '>= 0.4'}
has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
@@ -846,10 +926,18 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
is-arguments@1.1.1:
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
engines: {node: '>= 0.4'}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-date-object@1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -874,6 +962,10 @@ packages:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
is-regex@1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -935,6 +1027,12 @@ packages:
lodash: '*'
lodash-es: '*'
lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
@@ -1013,6 +1111,14 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
object-is@1.1.6:
resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
engines: {node: '>= 0.4'}
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -1036,6 +1142,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
parchment@1.1.4:
resolution: {integrity: sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==}
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -1122,10 +1231,24 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
quill-delta@3.6.3:
resolution: {integrity: sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==}
engines: {node: '>=0.10'}
quill-delta@4.2.2:
resolution: {integrity: sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==}
quill@1.3.7:
resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
regexp.prototype.flags@1.5.2:
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
engines: {node: '>= 0.4'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -1166,6 +1289,14 @@ packages:
engines: {node: '>=10'}
hasBin: true
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
set-function-name@2.0.2:
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
engines: {node: '>= 0.4'}
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -1686,6 +1817,12 @@ snapshots:
'@vue/shared@3.4.38': {}
'@vueup/vue-quill@1.2.0(vue@3.4.38)':
dependencies:
quill: 1.3.7
quill-delta: 4.2.2
vue: 3.4.38
'@vueuse/core@9.13.0(vue@3.4.38)':
dependencies:
'@types/web-bluetooth': 0.0.16
@@ -1770,6 +1907,14 @@ snapshots:
dependencies:
fill-range: 7.1.1
call-bind@1.0.7:
dependencies:
es-define-property: 1.0.0
es-errors: 1.3.0
function-bind: 1.1.2
get-intrinsic: 1.2.4
set-function-length: 1.2.2
callsites@3.1.0: {}
chalk@4.1.2:
@@ -1800,6 +1945,8 @@ snapshots:
slice-ansi: 5.0.0
string-width: 7.2.0
clone@2.1.2: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@@ -1836,8 +1983,29 @@ snapshots:
dependencies:
ms: 2.1.2
deep-equal@1.1.2:
dependencies:
is-arguments: 1.1.1
is-date-object: 1.0.5
is-regex: 1.1.4
object-is: 1.1.6
object-keys: 1.1.1
regexp.prototype.flags: 1.5.2
deep-is@0.1.4: {}
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.0
es-errors: 1.3.0
gopd: 1.0.1
define-properties@1.2.1:
dependencies:
define-data-property: 1.1.4
has-property-descriptors: 1.0.2
object-keys: 1.1.1
delayed-stream@1.0.0: {}
doctrine@3.0.0:
@@ -1871,6 +2039,12 @@ snapshots:
environment@1.1.0: {}
es-define-property@1.0.0:
dependencies:
get-intrinsic: 1.2.4
es-errors@1.3.0: {}
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -2004,6 +2178,8 @@ snapshots:
esutils@2.0.3: {}
eventemitter3@2.0.3: {}
eventemitter3@5.0.1: {}
execa@8.0.1:
@@ -2018,8 +2194,14 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
extend@3.0.2: {}
fast-deep-equal@3.1.3: {}
fast-diff@1.1.2: {}
fast-diff@1.2.0: {}
fast-diff@1.3.0: {}
fast-glob@3.3.2:
@@ -2072,8 +2254,20 @@ snapshots:
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
functions-have-names@1.2.3: {}
get-east-asian-width@1.2.0: {}
get-intrinsic@1.2.4:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
has-proto: 1.0.3
has-symbols: 1.0.3
hasown: 2.0.2
get-stream@8.0.1: {}
glob-parent@5.1.2:
@@ -2097,10 +2291,30 @@ snapshots:
dependencies:
type-fest: 0.20.2
gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.4
graphemer@1.4.0: {}
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.0
has-proto@1.0.3: {}
has-symbols@1.0.3: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.0.3
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
human-signals@5.0.0: {}
husky@8.0.3: {}
@@ -2123,10 +2337,19 @@ snapshots:
inherits@2.0.4: {}
is-arguments@1.1.1:
dependencies:
call-bind: 1.0.7
has-tostringtag: 1.0.2
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-date-object@1.0.5:
dependencies:
has-tostringtag: 1.0.2
is-extglob@2.1.1: {}
is-fullwidth-code-point@4.0.0: {}
@@ -2143,6 +2366,11 @@ snapshots:
is-path-inside@3.0.3: {}
is-regex@1.1.4:
dependencies:
call-bind: 1.0.7
has-tostringtag: 1.0.2
is-stream@3.0.0: {}
isexe@2.0.0: {}
@@ -2211,6 +2439,10 @@ snapshots:
lodash: 4.17.21
lodash-es: 4.17.21
lodash.clonedeep@4.5.0: {}
lodash.isequal@4.5.0: {}
lodash.merge@4.6.2: {}
lodash@4.17.21: {}
@@ -2281,6 +2513,13 @@ snapshots:
dependencies:
boolbase: 1.0.0
object-is@1.1.6:
dependencies:
call-bind: 1.0.7
define-properties: 1.2.1
object-keys@1.1.1: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -2310,6 +2549,8 @@ snapshots:
dependencies:
p-limit: 3.1.0
parchment@1.1.4: {}
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@@ -2371,10 +2612,38 @@ snapshots:
queue-microtask@1.2.3: {}
quill-delta@3.6.3:
dependencies:
deep-equal: 1.1.2
extend: 3.0.2
fast-diff: 1.1.2
quill-delta@4.2.2:
dependencies:
fast-diff: 1.2.0
lodash.clonedeep: 4.5.0
lodash.isequal: 4.5.0
quill@1.3.7:
dependencies:
clone: 2.1.2
deep-equal: 1.1.2
eventemitter3: 2.0.3
extend: 3.0.2
parchment: 1.1.4
quill-delta: 3.6.3
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
regexp.prototype.flags@1.5.2:
dependencies:
call-bind: 1.0.7
define-properties: 1.2.1
es-errors: 1.3.0
set-function-name: 2.0.2
resolve-from@4.0.0: {}
restore-cursor@5.1.0:
@@ -2426,6 +2695,22 @@ snapshots:
semver@7.6.3: {}
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
es-errors: 1.3.0
function-bind: 1.1.2
get-intrinsic: 1.2.4
gopd: 1.0.1
has-property-descriptors: 1.0.2
set-function-name@2.0.2:
dependencies:
define-data-property: 1.1.4
es-errors: 1.3.0
functions-have-names: 1.2.3
has-property-descriptors: 1.0.2
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

View File

@@ -37,11 +37,11 @@ const onMouseMove = (e) => {
case 'right':
width = dragData.value.width + e.pageX - dragData.value.pageX
break
case 'up':
height = dragData.value.height + dragRef.value.pageY - e.pageY
case 'top':
height = dragData.value.height + dragData.value.pageY - e.pageY
break
case 'down':
height = dragData.value.height + e.pageY - dragRef.value.pageY
case 'botton':
height = dragData.value.height + e.pageY - dragData.value.pageY
break
}
@@ -83,7 +83,7 @@ onUnmounted(() => {
background-color: #409eff;
}
&.drag-line-up {
&.drag-line-top {
top: 0;
left: 0;
height: 2px;
@@ -91,7 +91,7 @@ onUnmounted(() => {
cursor: row-resize;
}
&.drag-line-down {
&.drag-line-botton {
bottom: 0;
left: 0;
height: 2px;

View File

@@ -10,6 +10,7 @@ const searchValue = ref('')
<style lang="scss" scoped>
.el-input {
height: 30px;
margin-left: 10px;
margin-right: 10px;
}

View File

@@ -0,0 +1,47 @@
<script setup>
import { ref } from 'vue'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
const content = ref('')
const options = {
debug: false,
modules: {
toolbar: false
},
placeholder: 'Enter发送/Shift+Enter换行',
theme: 'snow'
}
</script>
<template>
<QuillEditor
v-model:content="content"
:options="options"
style="height: 100%; border: none"
></QuillEditor>
</template>
<style lang="scss">
.ql-editor {
padding: 8px;
font-size: 14px;
&::-webkit-scrollbar {
width: 3px;
height: 3px;
background-color: unset;
}
&::-webkit-scrollbar-thumb {
border-radius: 3px;
background-color: unset;
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: #409eff;
}
}
}
</style>

View File

@@ -0,0 +1,44 @@
<script setup>
import { ref } from 'vue'
defineProps(['tips'])
const tooltipVisible = ref(false)
const showTooltip = () => {
tooltipVisible.value = true
}
const hideTooltip = () => {
tooltipVisible.value = false
}
</script>
<template>
<div class="tool-icon-wrapper" @mouseenter="showTooltip" @mouseleave="hideTooltip">
<el-icon class="tool-icon" :size="20">
<slot name="iconSlot"></slot>
</el-icon>
<span v-if="tooltipVisible" class="tooltip">{{ tips }}</span>
</div>
</template>
<style lang="scss" scoped>
.tool-icon-wrapper {
width: 30px;
height: 30px;
margin: 5px;
border-radius: 4px;
display: flex;
justify-content: center;
align-items: center;
&:hover {
background-color: #c6e2ff;
}
.tooltip {
position: absolute;
top: 36px;
font-size: 12px;
z-index: 1;
}
}
</style>

View File

@@ -1,15 +1,23 @@
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import AvatarIcon from './AvatarIcon.vue'
import SessionTag from './SessionTag.vue'
import UserCard from '../user/UserCard.vue'
import { Top, Bottom, MuteNotification, Bell } from '@element-plus/icons-vue'
const props = defineProps(['user'])
const props = defineProps(['user', 'sessionId'])
const emit = defineEmits(['exportData'])
const isPinToTop = ref(false)
const isMute = ref(false)
const isShowUserCard = ref(false)
const sessionInfo = computed(() => {
return {
sessionId: props.sessionId,
chatObj: props.user
}
})
const handleUserCard = (flag) => {
isShowUserCard.value = flag
}
@@ -18,7 +26,7 @@ const handleUserCard = (flag) => {
<template>
<div class="session-box">
<AvatarIcon :user="props.user" @click="isShowUserCard = true"></AvatarIcon>
<div class="content-box">
<div class="content-box" @click="emit('exportData', sessionInfo)">
<div class="header">
<div class="title">
<span class="nickname">{{ props.user.nickName }}</span>

View File

@@ -123,6 +123,7 @@ defineExpose({
text-align: center;
color: black;
font-weight: bold;
user-select: text;
}
.signature {
@@ -134,6 +135,7 @@ defineExpose({
justify-content: flex-start;
align-items: flex-start;
white-space: normal; //允许文本内容自动换行
user-select: text;
}
}
}

View File

@@ -52,12 +52,7 @@ onUnmounted(() => {
<div v-if="isShow" class="overlay"></div>
</transition>
<transition name="fade">
<div
class="user-card"
v-if="isShow"
@update:isShow="emit('update:isShow', false)"
@click.self="preventClose($event)"
>
<div class="user-card" v-if="isShow" @click.self="preventClose($event)">
<div class="header">
<el-icon class="close-button" @click="onClose"><Close /></el-icon>
<div class="main">
@@ -76,19 +71,23 @@ onUnmounted(() => {
</el-text>
<div class="info-item phone">
<span class="label">手机</span>
<space class="value">{{ props.user.phoneNum || '-' }}</space>
<span class="value">{{ props.user.phoneNum || '-' }}</span>
</div>
<div class="info-item email">
<span class="label">邮箱</span>
<space class="value">{{ props.user.email || '-' }}</space>
<span class="value">{{ props.user.email || '-' }}</span>
</div>
<div class="info-item email">
<span class="label">驻地</span>
<space class="value">{{ props.user.base || '-' }}</space>
<span class="value">{{ props.user.base || '-' }}</span>
</div>
<div class="info-item nickname">
<span class="label">部门</span>
<space class="value">{{ props.user.organize || '-' }}</space>
<span class="value">{{ props.user.organize || '-' }}</span>
</div>
<div class="info-item remark">
<span class="label">备注</span>
<span class="value">{{ props.user.remark || 'TODO' }}</span>
</div>
</div>
</div>
@@ -110,6 +109,7 @@ onUnmounted(() => {
right: 0;
bottom: 0;
margin: auto;
z-index: 1;
.header {
width: 100%;
@@ -177,6 +177,7 @@ onUnmounted(() => {
text-align: center;
color: black;
font-weight: bold;
user-select: text;
}
}
}
@@ -207,7 +208,7 @@ onUnmounted(() => {
margin-top: 10px;
width: 80%;
display: flex;
font-size: 15px;
font-size: 14px;
.label {
color: #909399;
@@ -217,6 +218,7 @@ onUnmounted(() => {
.value {
margin-left: 10px;
color: #409eff;
user-select: text;
}
}
}
@@ -229,6 +231,7 @@ onUnmounted(() => {
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.fade-enter-active,

View File

@@ -8,3 +8,4 @@ export default pinia
export * from './user'
export * from './group'
export * from './setting'
export * from './message'

29
src/stores/message.js Normal file
View File

@@ -0,0 +1,29 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 消息功能相关需要缓存的数据
export const messageStore = defineStore(
'anyim-message',
() => {
const lastSessionId = ref('')
const lastChatObj = ref({})
const setLastSessionId = (sessionId) => {
lastSessionId.value = sessionId
}
const setLastChatObj = (obj) => {
lastChatObj.value = obj
}
return {
lastSessionId,
lastChatObj,
setLastSessionId,
setLastChatObj
}
},
{
persist: true
}
)

View File

@@ -6,14 +6,21 @@ export const settingStore = defineStore(
'anyim-setting',
() => {
const sessionListDrag = ref(0)
const inputBoxDrag = ref(0)
const setSessionListDrag = (width) => {
sessionListDrag.value = width
}
const setInputBoxDrag = (height) => {
inputBoxDrag.value = height
}
return {
sessionListDrag,
setSessionListDrag
inputBoxDrag,
setSessionListDrag,
setInputBoxDrag
}
},
{

View File

@@ -1,50 +1,105 @@
<!-- eslint-disable prettier/prettier -->
<script setup>
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import {
Phone,
VideoCamera,
Position,
CirclePlus,
Setting,
LocationInformation,
Clock,
Picture,
FolderAdd,
CreditCard,
PictureRounded
} from '@element-plus/icons-vue'
import DragLine from '@/components/common/DragLine.vue'
import SearchBox from '@/components/common/SearchBox.vue'
import AddBotton from '@/components/common/AddBotton.vue'
import SessionBox from '@/components/message/SessionBox.vue'
import { settingStore } from '@/stores'
import InputTool from '@/components/message/InputTool.vue'
import InputEditor from '@/components/message/InputEditor.vue'
import { settingStore, messageStore } from '@/stores'
import backgroupImage from '@/assets/messagebx_bg.webp'
const settingData = settingStore()
const asideWidth = ref(settingData.sessionListDrag || 200)
const widthMin = 200
const widthMax = 500
const messageData = messageStore()
const onDragUpdate = ({ width }) => {
const asideWidth = ref(settingData.sessionListDrag || 200)
const asideWidthMin = 200
const asideWidthMax = 500
const inputBoxHeight = ref(settingData.inputBoxDrag || 200)
const inputBoxHeightMin = 150
const inputBoxHeightMax = 400
const curSessionId = ref('')
const curChatObject = ref({})
onMounted(() => {
curSessionId.value = messageData.lastSessionId
curChatObject.value = messageData.lastChatObj
})
const onAsideDragUpdate = ({ width }) => {
asideWidth.value = width
settingData.setSessionListDrag(width)
}
const testUsers = [
const onInputBoxDragUpdate = ({ height }) => {
inputBoxHeight.value = height
settingData.setInputBoxDrag(height)
}
const handleExportData = (data) => {
curSessionId.value = data.sessionId
curChatObject.value = data.chatObj
messageData.setLastSessionId(data.sessionId)
messageData.setLastChatObj(data.chatObj)
}
const testItems = [
{
account: 'a123456',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
birthday: '2000-01-01',
email: '312777916@qq.com',
level: 1,
nickName: '我是Bob呀',
phoneNum: '13511111111',
sex: 1,
signature: '真的要坚持,才会有希望啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊',
organize: '消费者BG/2012实验室/海斯开发部/运营部/西安项目组/第五小组',
base: '西安'
session_id: '00000001',
user:
{
account: 'a123456',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
birthday: '2000-01-01',
email: '312777916@qq.com',
level: 1,
nickName: '我是Bob呀',
phoneNum: '13511111111',
sex: 1,
signature: '真的要坚持,才会有希望啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊',
organize: '消费者BG/2012实验室/海斯开发部/运营部/西安项目组/第五小组',
base: '西安'
}
},
{
account: 'Asdasdasd',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
birthday: '2000-01-01',
email: '312777916@qq.com',
level: 1,
nickName: '我是A',
phoneNum: '13511111111',
sex: 1,
signature: ''
session_id: '00000002',
user:
{
account: 'Asdasdasd',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
birthday: '2000-01-01',
email: '312777916@qq.com',
level: 1,
nickName: '我是A',
phoneNum: '13511111111',
sex: 1,
signature: ''
}
},
{
session_id: '00000003',
user:
{
account: 'Bsdasdasd',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
@@ -55,8 +110,12 @@ const testUsers = [
phoneNum: '13511111111',
sex: 1,
signature: 'AAAAAAAAAAAA'
}
},
{
session_id: '00000004',
user:
{
account: 'Csdasdasd',
avatar: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/fc0eff1f-ac2e-4a09-abd0-f834615137e7/微信图片_20240327170045.jpg',
avatarThumb: 'http://127.0.0.1:9001/anyim/IMAGE/20240831/e1c5b5d3-17d5-4603-9a3e-6985142455e3/微信图片_20240327170045-thumb.jpg',
@@ -67,34 +126,116 @@ const testUsers = [
phoneNum: '13511111111',
sex: 1,
signature: 'AAAAAAAAAAAA'
},
]
}
}]
</script>
<template>
<el-container class="msg-container-hole">
<el-aside class="msg-aside bdr-r" :style="{ width: asideWidth + 'px' }">
<div class="msg-aside-main">
<div class="header bdr-b">
<div class="header">
<SearchBox></SearchBox>
<AddBotton></AddBotton>
</div>
<div class="session-list">
<SessionBox v-for="user in testUsers" :key="user.account" :user="user"></SessionBox>
<SessionBox
v-for="item in testItems"
:key="item.session_id"
:user="item.user"
:sessionId="item.session_id"
@exportData="handleExportData"
></SessionBox>
</div>
</div>
<DragLine
direction="right"
:min="widthMin"
:max="widthMax"
:min="asideWidthMin"
:max="asideWidthMax"
:origin-size="asideWidth"
@drag-update="onDragUpdate"
@drag-update="onAsideDragUpdate"
></DragLine>
</el-aside>
<el-main>
<div>聊天主体</div>
<el-main class="msg-box">
<el-image
class="backgroup-image"
v-if="!curSessionId"
:src="backgroupImage"
fit="cover"
></el-image>
<el-container class="container">
<el-header class="header bdr-b">
<span class="show-nickname">{{ curChatObject.nickName }}</span>
<div class="action-set">
<el-button class="action-button" :icon="Phone" circle />
<el-button class="action-button" :icon="VideoCamera" circle />
<el-button class="action-button" :icon="Position" circle />
<el-button class="action-button" :icon="CirclePlus" circle />
<el-button class="action-button" :icon="Setting" circle />
</div>
</el-header>
<el-main class="body">
<div class="show-box"></div>
<div class="input-box bdr-t" :style="{ height: inputBoxHeight + 'px' }">
<el-container class="input-box-container">
<el-header class="input-box-header">
<DragLine
direction="top"
:min="inputBoxHeightMin"
:max="inputBoxHeightMax"
:origin-size="inputBoxHeight"
@drag-update="onInputBoxDragUpdate"
></DragLine>
<div class="tool-set">
<div class="left-tools">
<InputTool tips="表情">
<template #iconSlot>
<PictureRounded />
</template>
</InputTool>
<InputTool tips="图片">
<template #iconSlot>
<Picture />
</template>
</InputTool>
<InputTool tips="文件">
<template #iconSlot>
<FolderAdd />
</template>
</InputTool>
<InputTool tips="代码">
<template #iconSlot>
<CreditCard />
</template>
</InputTool>
<InputTool tips="位置">
<template #iconSlot>
<LocationInformation />
</template>
</InputTool>
</div>
<div class="right-tools">
<InputTool tips="历史记录">
<template #iconSlot>
<Clock />
</template>
</InputTool>
</div>
</div>
</el-header>
<el-main class="input-box-main">
<InputEditor></InputEditor>
</el-main>
<el-footer class="input-box-footer">
<el-button type="primary">发送</el-button>
</el-footer>
</el-container>
</div>
</el-main>
</el-container>
</el-main>
</el-container>
</template>
@@ -111,8 +252,107 @@ const testUsers = [
.msg-aside-main {
.header {
display: flex;
margin-top: 5px;
padding-bottom: 5px;
margin-top: 10px;
margin-bottom: 10px;
}
}
}
.msg-box {
padding: 0;
.backgroup-image {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
.header {
width: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
.show-nickname {
font-size: 16px;
font-weight: bold;
}
.action-set {
margin-right: 20px;
.action-button {
border: 0;
}
}
}
.body {
width: 100%;
height: 100%;
padding: 0;
display: flex;
flex-direction: column;
.show-box {
width: 100%;
flex: 1;
}
.input-box {
width: 100%;
display: flex;
position: relative;
.input-box-header {
width: 100%;
height: 45px;
padding: 0;
.tool-set {
display: flex;
justify-content: space-between;
.left-tools {
display: flex;
}
.right-tools {
margin-right: 10px;
}
.tool-icon {
margin: 10px;
&:hover {
background-color: red;
}
}
}
}
.input-box-main {
width: 100%;
padding: 0;
// flex: 1;
}
.input-box-footer {
width: 100%;
height: 32px;
padding: 0px;
display: flex;
justify-content: flex-end;
.el-button {
margin-right: 0px;
}
}
}
}
}
}