feat(theme): 将主色调从#1890ff更改为#462AA0

统一修改多处UI组件的主色调,从蓝色(#1890ff)变更为紫色(#462AA0),以保持视觉一致性。同时优化了文件上传逻辑和滚动到底部功能。

refactor(dom): 提取滚动相关操作为工具函数
将滚动到底部逻辑封装为可复用的工具函数,并在多处调用位置进行替换,提高代码复用性。

fix(upload): 修复上传中文件点击打开问题
增加上传状态判断,避免在上传过程中点击文件时打开新窗口。

chore(deps): 更新依赖包版本
升级@types/node和watchpack等依赖包版本。
This commit is contained in:
Phoenix 2025-05-28 11:29:13 +08:00
parent 44a1dd0986
commit 2c1ae41c3e
24 changed files with 90 additions and 62 deletions

View File

@ -883,8 +883,8 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@18.19.101':
resolution: {integrity: sha512-Ykg7fcE3+cOQlLUv2Ds3zil6DVjriGQaSN/kEpl5HQ3DIGM6W0F2n9+GkWV4bRt7KjLymgzNdTnSKCbFUUJ7Kw==}
'@types/node@18.19.103':
resolution: {integrity: sha512-hHTHp+sEz6SxFsp+SA+Tqrua3AbmlAw+Y//aEwdHrdZkYVRWdvWD3y5uPZ0flYOkgskaFWqZ/YGFm3FaFQ0pRw==}
'@types/node@18.19.99':
resolution: {integrity: sha512-tNGqoGjjI4vY5jfm3lnqgR6yS8wyT76SfsWefLWRyh/cEK4UHmPVyqHZdafI/SNu1PQzfo2JLBWfG8eMmD7KrQ==}
@ -3517,8 +3517,8 @@ packages:
warning@4.0.3:
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
watchpack@2.4.3:
resolution: {integrity: sha512-adBYQLivcg1jbdKEJeqScJJFvgm4qY9+3tXw+jdG6lkVeqRJEtiQmSWjmth8GKmDZuX7sYM4YFxQsf0AzMfGGw==}
watchpack@2.4.4:
resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==}
engines: {node: '>=10.13.0'}
web-worker@1.5.0:
@ -3528,8 +3528,8 @@ packages:
resolution: {integrity: sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
webpack-sources@3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
webpack-sources@3.3.0:
resolution: {integrity: sha512-77R0RDmJfj9dyv5p3bM5pOHa+X8/ZkO9c7kpDstigkC4nIDobadsfSGCwB4bKhMVxqAok8tajaoR8rirM7+VFQ==}
engines: {node: '>=10.13.0'}
webpack-virtual-modules@0.6.2:
@ -4228,7 +4228,7 @@ snapshots:
'@types/ms@2.1.0': {}
'@types/node@18.19.101':
'@types/node@18.19.103':
dependencies:
undici-types: 5.26.5
@ -5895,7 +5895,7 @@ snapshots:
jest-worker@27.5.1:
dependencies:
'@types/node': 18.19.101
'@types/node': 18.19.103
merge-stream: 2.0.0
supports-color: 8.1.1
@ -7244,7 +7244,7 @@ snapshots:
dependencies:
loose-envify: 1.4.0
watchpack@2.4.3:
watchpack@2.4.4:
dependencies:
glob-to-regexp: 0.4.1
graceful-fs: 4.2.11
@ -7256,7 +7256,7 @@ snapshots:
deepmerge: 1.5.2
javascript-stringify: 1.6.0
webpack-sources@3.2.3: {}
webpack-sources@3.3.0: {}
webpack-virtual-modules@0.6.2: {}
@ -7284,8 +7284,8 @@ snapshots:
schema-utils: 4.3.2
tapable: 2.2.2
terser-webpack-plugin: 5.3.14(webpack@5.99.8)
watchpack: 2.4.3
webpack-sources: 3.2.3
watchpack: 2.4.4
webpack-sources: 3.3.0
transitivePeerDependencies:
- '@swc/core'
- esbuild

View File

@ -29,7 +29,7 @@ html {
// 黑色主题
html[theme-mode='dark'] {
--im-primary-color: #1890ff;
--im-primary-color: #462AA0;
--im-bg-color: #202124;
--line-border-color: rgb(255 255 255 / 9%);
--border-color: rgb(255 255 255 / 9%);

View File

@ -12,7 +12,7 @@
&:hover,
&.dropsize-resizing {
background-color: #1890ff;
background-color: #462AA0;
}
&.dropsize-line-top {

View File

@ -44,7 +44,7 @@
font-feature-settings: 'tnum';
position: absolute;
display: none;
color: #1890ff;
color: #462AA0;
text-align: center;
vertical-align: middle;
opacity: 0;
@ -177,7 +177,7 @@
display: block;
width: 9px;
height: 9px;
background-color: #1890ff;
background-color: #462AA0;
border-radius: 100%;
-webkit-transform: scale(0.75);
transform: scale(0.75);

View File

@ -143,6 +143,7 @@ const editorOption = {
},
//
source: function (searchTerm: string, renderList: any) {
console.log("source")
if (!props.members.length) {
return renderList([])
}

View File

@ -990,7 +990,7 @@ const handleEditGroupNameConfirm = () => {
margin: 3px 0;
&:hover {
.nickname {
color: #1890ff;
color: #462AA0;
}
}
}

View File

@ -86,12 +86,14 @@ const strokeDashoffset = computed(() =>
//
const handleClick = () => {
console.log('handleClick')
window.open(
if(!props.extra.is_uploading){
window.open(
`${window.location.origin}/office?url=${props.extra.path}`,
'_blank',
'width=1200,height=900,left=200,top=200,toolbar=no,menubar=no,scrollbars=yes,resizable=yes,location=no,status=no'
);
}
}
function downloadFileWithProgress(resourceUrl, filename) {

View File

@ -27,7 +27,7 @@ let textContent = props.extra?.content || ''
textContent = textReplaceLink(textContent)
if (props.data.talk_type == 2) {
textContent = textReplaceMention(textContent, '#1890ff')
textContent = textReplaceMention(textContent, '#462AA0')
}
textContent = textReplaceEmoji(textContent)

View File

@ -17,7 +17,7 @@ let textContent = props.extra?.content || ''
textContent = textReplaceLink(textContent)
if (props.data.talk_type == 2) {
textContent = textReplaceMention(textContent, '#1890ff')
textContent = textReplaceMention(textContent, '#462AA0')
}
textContent = textReplaceEmoji(textContent)

View File

@ -121,7 +121,7 @@ onMounted(() => {
:height="5"
:show-indicator="false"
:percentage="parseInt(option.progress)"
color="#1890ff"
color="#462AA0"
/>
</p>
</div>

View File

@ -28,7 +28,7 @@
font-weight: 400;
&:hover {
color: #1890ff;
color: #462AA0;
}
}
}

View File

@ -1514,7 +1514,7 @@ const numWidth = computed(() => {
.x-upload-preview-button:hover {
background-color: #e6f7ff;
color: #1890ff;
color: #462AA0;
}
.x-upload-download-button:hover {

View File

@ -45,7 +45,7 @@
font-feature-settings: 'tnum';
position: absolute;
display: none;
color: #1890ff;
color: #462AA0;
text-align: center;
vertical-align: middle;
opacity: 0;
@ -103,7 +103,7 @@
display: block;
width: 9px;
height: 9px;
background-color: #1890ff;
background-color: #462AA0;
border-radius: 100%;
transform: scale(0.75);
transform-origin: 50% 50%;

View File

@ -7,6 +7,7 @@ import { formatTalkItem, palyMusic, formatTalkRecord } from '@/utils/talk'
import { isElectronMode } from '@/utils/common'
import { ServeClearTalkUnreadNum, ServeCreateTalkList } from '@/api/chat'
import { useTalkStore, useDialogueStore, useSettingsStore } from '@/store'
import { isScrollAtBottom, scrollToBottom } from '@/utils/dom'
/**
* 好友状态事件
@ -189,12 +190,10 @@ class Talk extends Base {
if (!el) return
// 判断的滚动条是否在底部
const isBottom = Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight
const isBottom = isScrollAtBottom(el)
if (isBottom || record.user_id == this.getAccountId()) {
nextTick(() => {
el.scrollTop = el.scrollHeight + 1000
})
scrollToBottom()
} else {
useDialogueStore().setUnreadBubble()
}

View File

@ -3,7 +3,7 @@ import { ServeTalkRecords } from '@/api/chat'
import { useDialogueStore } from '@/store'
import { ITalkRecord } from '@/types/chat'
import { formatTalkRecord } from '@/utils/talk'
import { addClass, removeClass } from '@/utils/dom'
import { addClass, removeClass, scrollToBottom, isScrollAtBottom } from '@/utils/dom'
interface Params {
receiver_id: number
@ -137,16 +137,8 @@ export const useTalkRecord = (uid: number) => {
if (el) {
if (request.cursor == 0) {
el.scrollTop = el.scrollHeight
setTimeout(() => {
console.log('el.scrollHeight',el.scrollHeight)
console.log('request.cursor == 0')
el.scrollTop = el.scrollHeight + 1000
}, 500)
scrollToBottom()
} else {
console.log('request.cursor !== 0')
el.scrollTop = el.scrollHeight - scrollHeight
}
}
@ -222,7 +214,7 @@ export const useTalkRecord = (uid: number) => {
addClass(target, 'border')
setTimeout(() => removeClass(target, 'border'), 3000)
} else if (el) {
el.scrollTop = el.scrollHeight
scrollToBottom()
}
}, 50)
})

View File

@ -119,7 +119,7 @@ const isActive = (menu) => {
<component
:is="nav.icon"
:theme="isActive(nav) ? 'filled' : 'outline'"
:fill="isActive(nav) ? '#1890ff' : color"
:fill="isActive(nav) ? '#462AA0' : color"
:strokeWidth="2"
:size="22"
/>

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22ab23a552e0c3f606946dcb914a52b692e10d823cc7f43027127359e7ee8555d956e7e095946931ceaa3877675584b0a0a4fc690c8018712b306050ebbdea92037aea31d66d65004be26d3c696abc4c29'
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d227de310c4e6f5d7ff11a9e1ea73aba3f6c749f75a50a2aeaed07b14bc0d8b1db6428caf891f0a0b0c84a49697f4a4e7c8b87d972340ecbf02ddbc4d4f1e51b057c822f8351524e19d52a3ec5ce8c83e2f'
}
/**

View File

@ -52,7 +52,12 @@ export function throttle(fn, delay, call = function () {}) {
* @param {Function} callback 复制成功回调方法
*/
export function clipboard(text, callback) {
navigator.clipboard
// 在wujie环境下使用主应用的clipboard
const clipboardObj = window.__POWERED_BY_WUJIE__
? window.parent.navigator.clipboard
: navigator.clipboard
clipboardObj
.writeText(text)
.then(() => {
callback && callback()

View File

@ -1,3 +1,5 @@
import { nextTick } from 'vue'
function trim(string: string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
}
@ -54,3 +56,26 @@ export function removeClass(el: Element, cls: string) {
el.className = trim(curClass)
}
}
/**
*
* @param el DOM元素
* @returns boolean
*/
export function isScrollAtBottom(el: HTMLElement): boolean {
return Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight
}
/**
*
* @param id DOM id 'imChatPanel'
* @param offset 0
*/
export function scrollToBottom(id = 'imChatPanel', offset = 0) {
nextTick(() => {
const el = document.getElementById(id)
if (el) {
el.scrollTop = el.scrollHeight + offset
}
})
}

View File

@ -95,7 +95,6 @@ const onPanelScroll = (e: any) => {
if (!skipBottom.value && dialogueStore.unreadBubble) {
dialogueStore.setUnreadBubble(0)
}
//
if (skipBottom.value == false) {
let len = dialogueStore.records.length
@ -232,7 +231,7 @@ const onClickNickname = (data: ITalkRecord) => {
//
const onContextMenu = (e: any, item: ITalkRecord) => {
console.log('item',item)
if (!dialogueStore.isShowEditor || dialogueStore.isOpenMultiSelect) {
return e.preventDefault()
}
@ -243,7 +242,7 @@ const onContextMenu = (e: any, item: ITalkRecord) => {
}
const onConvertText = async (data: ITalkRecord) => {
console.log('data', data)
data.is_convert_text = 1
const res = await voiceToText({ msgId: data.msg_id, voiceUrl: data.extra.url })
if (res.code == 200) {

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, nextTick } from 'vue'
import {
useTalkStore,
useDialogueStore,
@ -15,7 +15,8 @@ import { parseTime } from '@/utils/datetime'
import Editor from '@/components/editor/Editor.vue'
import MultiSelectFooter from './MultiSelectFooter.vue'
import HistoryRecord from '@/components/talk/HistoryRecord.vue'
import { uploadImg } from '@/api/upload'
import {scrollToBottom} from '@/utils/dom.ts'
import SimpleEditorExample from '@/components/editor/SimpleEditorExample.vue'
const userStore = useUserStore()
const talkStore = useTalkStore()
const editorStore = useEditorStore()
@ -135,6 +136,9 @@ const onSendVideoEvent = async ({ data }) => {
//
dialogueStore.addDialogueRecord(tempMessage)
nextTick(()=>{
scrollToBottom()
})
uploadsStore.initUploadFile(
data,
props.talk_type,
@ -145,6 +149,7 @@ const onSendVideoEvent = async ({ data }) => {
},
async () => {
dialogueStore.batchDelDialogueRecord([uploadId])
}
)
}
@ -185,13 +190,16 @@ const onSendFileEvent = ({ data }) => {
float: 'right'
}
dialogueStore.addDialogueRecord(tempMessage)
nextTick(()=>{
scrollToBottom()
})
uploadsStore.initUploadFile(data, props.talk_type, props.receiver_id,clientUploadId,
async (percentage) => {
dialogueStore.updateUploadProgress(clientUploadId, percentage)
},
async () => {
dialogueStore.batchDelDialogueRecord([clientUploadId])
}
)
}
@ -282,6 +290,7 @@ onMounted(() => {
<template>
<footer class="el-footer">
<MultiSelectFooter v-if="dialogueStore.isOpenMultiSelect" />
<Editor v-else @editor-event="onEditorEvent" :vote="talk_type == 2" :members="members" />
</footer>

View File

@ -156,7 +156,7 @@ const onSetMenu = () => {
text-align: center;
&.color {
color: #1890ff;
color: #462AA0;
}
.online-status {
@ -168,7 +168,7 @@ const onSetMenu = () => {
vertical-align: middle;
border-radius: 50%;
position: relative;
background-color: #1890ff;
background-color: #462AA0;
margin-right: 5px;
&:after {
@ -177,7 +177,7 @@ const onSetMenu = () => {
left: -1px;
width: 100%;
height: 100%;
border: 1px solid #1890ff;
border: 1px solid #462AA0;
border-radius: 50%;
-webkit-animation: antStatusProcessing 1.2s ease-in-out infinite;
animation: antStatusProcessing 1.2s ease-in-out infinite;

View File

@ -1,6 +1,8 @@
<script lang="ts" setup>
import { useDialogueStore } from '@/store'
import { DoubleDown } from '@icon-park/vue-next'
import { scrollToBottom } from '@/utils/dom'
defineProps(['modelValue'])
const dialogueStore = useDialogueStore()
@ -8,13 +10,7 @@ const dialogueStore = useDialogueStore()
//
const onSkipBottom = () => {
console.log('onSkipBottom')
let el = document.getElementById('imChatPanel')
if (el) {
el.scrollTo({
top: el.scrollHeight + 1000,
behavior: 'smooth'
})
}
scrollToBottom()
}
</script>
@ -35,7 +31,7 @@ const onSkipBottom = () => {
min-width: 100px;
height: 28px;
font-size: 12px;
background-color: #1ebafc;
background-color: #462AA0;
color: #ffffff;
display: flex;
align-items: center;

View File

@ -47,7 +47,7 @@ export default defineConfig(({ mode }) => {
compressPlugin(),
UnoCSS(),
vueDevTools({
launchEditor: 'cursor',
launchEditor: 'trae',
})
],
define: {