更新组件和API,新增NImage支持,优化文件上传功能,调整主题颜色,删除不必要的图片,改进用户界面和交互体验。
1
components.d.ts
vendored
@ -52,6 +52,7 @@ declare module 'vue' {
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NModal: typeof import('naive-ui')['NModal']
|
||||
NoticeEditor: typeof import('./src/components/group/manage/NoticeEditor.vue')['default']
|
||||
|
@ -25,3 +25,7 @@ export const ServeRefreshToken = () => {
|
||||
export const ServeForgetPassword = (data) => {
|
||||
return post('/api/v1/auth/forget', data)
|
||||
}
|
||||
// 获取用户信息服务
|
||||
export const GetUserInfo = (data) => {
|
||||
return post('/api/v1/users/info', data)
|
||||
}
|
@ -45,10 +45,12 @@ export const ServeFindFriendApplyNum = () => {
|
||||
}
|
||||
|
||||
// 搜索用户信息服务接口
|
||||
// export const ServeSearchUser = (data) => {
|
||||
// return get('/api/v1/contact/detail', data)
|
||||
// }
|
||||
export const ServeSearchUser = (data) => {
|
||||
return get('/api/v1/contact/detail', data)
|
||||
return post('/api/v1/users/info', data)
|
||||
}
|
||||
|
||||
// 搜索用户信息服务接口
|
||||
export const ServeContactGroupList = (data) => {
|
||||
return get('/api/v1/contact/group/list', data)
|
||||
|
@ -1,6 +1,6 @@
|
||||
// 默认主题
|
||||
html {
|
||||
--im-primary-color: #1890ff;
|
||||
--im-primary-color: #462AA0;
|
||||
--im-bg-color: #ffffff;
|
||||
--line-border-color: #f5f5f5;
|
||||
--border-color: #eeeaea;
|
||||
|
BIN
src/assets/image/excel-icon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/excel-text.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/assets/image/file-icon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/file-text.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/pdf-text.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/image/ppt-icon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/ppt-text.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/image/word-icon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/word-text.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
@ -1,7 +1,12 @@
|
||||
<script setup>
|
||||
import { fileFormatSize } from '@/utils/strings'
|
||||
import { download, getFileNameSuffix } from '@/utils/functions'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useUploadsStore } from '@/store'
|
||||
import pptText from '@/assets/image/ppt-text.png'
|
||||
import excelText from '@/assets/image/excel-text.png'
|
||||
import wordText from '@/assets/image/word-text.png'
|
||||
import pdfText from '@/assets/image/pdf-text.png'
|
||||
import fileText from '@/assets/image/file-text.png'
|
||||
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
@ -22,54 +27,76 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
// 控制文件上传时的播放状态
|
||||
const uploadsStore = useUploadsStore()
|
||||
const isPlaying = ref(false)
|
||||
|
||||
/**
|
||||
* 切换播放状态
|
||||
* 在上传过程中可以暂停/继续
|
||||
*/
|
||||
const togglePlay = () => {
|
||||
isPlaying.value = !isPlaying.value
|
||||
console.log('播放状态:', isPlaying.value ? '播放中' : '暂停')
|
||||
// 文件类型配置
|
||||
const fileTypes = {
|
||||
PDF: { icon: pdfText, color: '#DE4E4E', type: 'PDF' },
|
||||
PPT: { icon: pptText, color: '#B74B2B', type: 'PPT' },
|
||||
EXCEL: { icon: excelText, color: '#3C7F4B', type: 'EXCEL' },
|
||||
WORD: { icon: wordText, color: '#2750B2', type: 'WORD' },
|
||||
DEFAULT: { icon: fileText, color: '#747474', type: '文件' }
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件URL中提取并返回大写的文件扩展名
|
||||
* @param {string} url - 文件的URL或名称
|
||||
* @returns {string} 大写的文件扩展名
|
||||
*/
|
||||
function getFileExtensionUpperCase(url) {
|
||||
// 从URL提取文件名
|
||||
const fileName = url.split('/').pop()
|
||||
// 提取扩展名并转换为大写
|
||||
return fileName.split('.').pop().toUpperCase()
|
||||
// Excel文件扩展名映射
|
||||
const EXCEL_EXTENSIONS = ['XLS', 'XLSX', 'CSV']
|
||||
// Word文件扩展名映射
|
||||
const WORD_EXTENSIONS = ['DOC', 'DOCX', 'RTF', 'DOT', 'DOTX']
|
||||
// PPT文件扩展名映射
|
||||
const PPT_EXTENSIONS = ['PPT', 'PPTX', 'PPS', 'PPSX']
|
||||
|
||||
// 获取文件类型信息
|
||||
const fileInfo = computed(() => {
|
||||
const extension = getFileExtension(props.extra.name)
|
||||
if (EXCEL_EXTENSIONS.includes(extension)) {
|
||||
return fileTypes.EXCEL
|
||||
}
|
||||
if (WORD_EXTENSIONS.includes(extension)) {
|
||||
return fileTypes.WORD
|
||||
}
|
||||
if (PPT_EXTENSIONS.includes(extension)) {
|
||||
return fileTypes.PPT
|
||||
}
|
||||
return fileTypes[extension] || fileTypes.DEFAULT
|
||||
})
|
||||
|
||||
// 获取文件扩展名
|
||||
function getFileExtension(filename) {
|
||||
const parts = filename.split('.')
|
||||
return parts.length > 1 ? parts.pop().toUpperCase() : ''
|
||||
}
|
||||
|
||||
// 切换播放状态
|
||||
const togglePlay = () => {
|
||||
isPlaying.value = !isPlaying.value
|
||||
|
||||
if (props.extra.is_uploading && props.extra.upload_id) {
|
||||
const action = isPlaying.value ? 'resumeUpload' : 'pauseUpload'
|
||||
uploadsStore[action](props.extra.upload_id)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算SVG圆环进度条的参数
|
||||
const radius = 9 // 圆环半径
|
||||
const circumference = computed(() => 2 * Math.PI * radius) // 计算圆周长
|
||||
// 根据上传百分比计算描边偏移量
|
||||
const radius = 9
|
||||
const circumference = computed(() => 2 * Math.PI * radius)
|
||||
const strokeDashoffset = computed(() =>
|
||||
circumference.value * (1 - props.extra.percentage / 100)
|
||||
circumference.value * (1 - (props.extra.percentage || 0) / 100)
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-243px bg-#fff rounded-8px shadow-md px-14px pointer">
|
||||
<div class="file-message">
|
||||
<!-- 文件头部信息 -->
|
||||
<div class="flex py-14px pr-5px justify-between w-full" style="border-bottom: 1px solid #EEEEEE;">
|
||||
<div class="file-header">
|
||||
<!-- 文件名 -->
|
||||
<div class="text-#1A1A1A text-14px">{{ extra.name }}</div>
|
||||
<div class="file-name">{{ extra.name }}</div>
|
||||
<!-- 文件图标区域 -->
|
||||
<div class="relative">
|
||||
<img class="w-47.91px h-47.91px" src="@/assets/image/file-paper-line@2x.png" alt="文件图标">
|
||||
<!-- 文件扩展名显示 - 非上传状态 -->
|
||||
<div v-if="!extra.is_uploading" class="absolute top-11px left-16px text-#DE4E4E text-10px font-bold">
|
||||
{{ getFileExtensionUpperCase(extra.name) }}
|
||||
</div>
|
||||
<div class="file-icon-container">
|
||||
<img class="file-icon" :src="fileInfo.icon" alt="文件图标">
|
||||
|
||||
<!-- 上传进度圆环 - 上传状态 -->
|
||||
<div v-else class="absolute top-9px left-16px w-20px h-20px">
|
||||
<div v-if="extra.is_uploading" class="progress-overlay">
|
||||
<div class="circle-progress-container" @click="togglePlay">
|
||||
<svg class="circle-progress" width="20" height="20" viewBox="0 0 20 20">
|
||||
<!-- 底色圆环 -->
|
||||
@ -87,7 +114,7 @@ const strokeDashoffset = computed(() =>
|
||||
cy="10"
|
||||
r="9"
|
||||
fill="transparent"
|
||||
stroke="#D54C4B"
|
||||
:stroke="fileInfo.color"
|
||||
stroke-width="2"
|
||||
:stroke-dasharray="circumference"
|
||||
:stroke-dashoffset="strokeDashoffset"
|
||||
@ -95,15 +122,13 @@ const strokeDashoffset = computed(() =>
|
||||
class="progress-circle"
|
||||
/>
|
||||
|
||||
<!-- 暂停图标 - 播放中显示 -->
|
||||
<g v-if="isPlaying" class="pause-icon transform-rotate-90">
|
||||
<rect x="7" y="5" width="2" height="10" fill="#D54C4B" />
|
||||
<rect x="11" y="5" width="2" height="10" fill="#D54C4B" />
|
||||
<!-- 暂停/播放图标 -->
|
||||
<g v-if="isPlaying" class="pause-icon">
|
||||
<rect x="7" y="5" width="2" height="10" :fill="fileInfo.color" />
|
||||
<rect x="11" y="5" width="2" height="10" :fill="fileInfo.color" />
|
||||
</g>
|
||||
|
||||
<!-- 播放图标 - 暂停时显示 -->
|
||||
<g v-else class="play-icon">
|
||||
<rect x="6" y="6" width="8" height="8" fill="#D54C4B" />
|
||||
<rect x="6" y="6" width="8" height="8" :fill="fileInfo.color" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -111,11 +136,66 @@ const strokeDashoffset = computed(() =>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文件大小信息 -->
|
||||
<div class="text-#747474 text-12px pt-5px pb-11px">{{ fileFormatSize(extra.size) }}</div>
|
||||
<div class="file-size">{{ fileFormatSize(extra.size) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.file-message {
|
||||
width: 243px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
padding: 0 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.file-header {
|
||||
display: flex;
|
||||
padding: 14px 5px 14px 0;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
color: #1A1A1A;
|
||||
font-size: 14px;
|
||||
word-break: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.file-icon-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.progress-overlay {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 11px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
color: #747474;
|
||||
font-size: 12px;
|
||||
padding: 5px 0 11px;
|
||||
}
|
||||
|
||||
.circle-progress-container {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@ -136,7 +216,7 @@ const strokeDashoffset = computed(() =>
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.transform-rotate-90 {
|
||||
.pause-icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
</style>
|
||||
|
@ -100,7 +100,7 @@ async function onPlay() {
|
||||
function pauseUpload(e) {
|
||||
e.stopPropagation()
|
||||
if (props.extra.is_uploading && props.extra.upload_id) {
|
||||
uploadsStore.pauseVideoUpload(props.extra.upload_id)
|
||||
uploadsStore.pauseUpload(props.extra.upload_id)
|
||||
isPaused.value = true
|
||||
}
|
||||
}
|
||||
@ -110,7 +110,7 @@ function resumeUpload(e) {
|
||||
console.log('resumeUpload')
|
||||
e.stopPropagation()
|
||||
if (props.extra.is_uploading && props.extra.upload_id) {
|
||||
uploadsStore.resumeVideoUpload(props.extra.upload_id)
|
||||
uploadsStore.resumeUpload(props.extra.upload_id)
|
||||
isPaused.value = false
|
||||
}
|
||||
}
|
||||
@ -123,7 +123,7 @@ function retryUpload(e) {
|
||||
uploadFailed.value = false
|
||||
|
||||
// 恢复上传
|
||||
uploadsStore.resumeVideoUpload(props.extra.upload_id)
|
||||
uploadsStore.resumeUpload(props.extra.upload_id)
|
||||
message.success('正在重新上传视频...')
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { NModal, NInput, NScrollbar, NCheckbox, NTabs, NTab } from 'naive-ui'
|
||||
import { Search, Delete } from '@icon-park/vue-next'
|
||||
import { ServeGetContacts } from '@/api/contact'
|
||||
import { ServeGetGroups } from '@/api/group'
|
||||
|
||||
import XNModal from '@/components/x-naive-ui/x-n-modal/index.vue'
|
||||
const emit = defineEmits(['close', 'on-submit'])
|
||||
|
||||
interface Item {
|
||||
@ -130,20 +130,12 @@ onLoad()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
<x-n-modal
|
||||
v-model:show="isShowBox"
|
||||
preset="card"
|
||||
title="选择联系人"
|
||||
class="modal-radius"
|
||||
style="max-width: 650px; height: 550px"
|
||||
style="width: 997px; height: 740px;background-color: #F9F9FD"
|
||||
:on-after-leave="onMaskClick"
|
||||
:segmented="{
|
||||
content: true,
|
||||
footer: true
|
||||
}"
|
||||
:content-style="{
|
||||
padding: 0
|
||||
}"
|
||||
>
|
||||
<section class="el-container launch-box">
|
||||
<aside class="el-aside bdr-r" style="width: 240px">
|
||||
@ -154,6 +146,7 @@ onLoad()
|
||||
<n-tab name="2"> 群聊 </n-tab>
|
||||
<!-- <n-tab name="企业"> 企业 </n-tab> -->
|
||||
</n-tabs>
|
||||
|
||||
</header>
|
||||
|
||||
<header class="el-header sub-header">
|
||||
@ -256,7 +249,7 @@ onLoad()
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</n-modal>
|
||||
</x-n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import { NIcon, NModal, NButton, NInput, NDropdown, NPopover,NImage } from 'naive-ui'
|
||||
import { CloseOne, Male, Female, SendOne } from '@icon-park/vue-next'
|
||||
import { ServeSearchUser } from '@/api/contact'
|
||||
import { ServeCreateContact } from '@/api/contact'
|
||||
@ -8,11 +7,10 @@ import { ServeContactGroupList, ServeContactMoveGroup, ServeEditContactRemark }
|
||||
import { useTalkStore } from '@/store'
|
||||
import { useRouter } from 'vue-router'
|
||||
import xNModal from '@/components/x-naive-ui/x-n-modal/index.vue'
|
||||
import { NSkeleton } from 'naive-ui'
|
||||
const router = useRouter()
|
||||
const talkStore = useTalkStore()
|
||||
|
||||
const emit = defineEmits(['update:show', 'update:uid', 'updateRemark'])
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
@ -26,7 +24,7 @@ const props = defineProps({
|
||||
|
||||
const loading = ref(true)
|
||||
const isOpenFrom = ref(false)
|
||||
const state: any = reactive({
|
||||
const userInfo: any = ref({
|
||||
id: 0,
|
||||
avatar: '',
|
||||
gender: 0,
|
||||
@ -43,26 +41,26 @@ const editCardPopover: any = ref(false)
|
||||
const modelRemark = ref('')
|
||||
|
||||
const options = ref<any>([])
|
||||
const groupName = computed(() => {
|
||||
const item = options.value.find((item: any) => {
|
||||
return item.key == state.group_id
|
||||
})
|
||||
// const groupName = computed(() => {
|
||||
// const item = options.value.find((item: any) => {
|
||||
// return item.key == state.group_id
|
||||
// })
|
||||
|
||||
if (item) {
|
||||
return item.label
|
||||
}
|
||||
// if (item) {
|
||||
// return item.label
|
||||
// }
|
||||
|
||||
return '未设置分组'
|
||||
})
|
||||
// return '未设置分组'
|
||||
// })
|
||||
|
||||
const onLoadData = () => {
|
||||
ServeSearchUser({
|
||||
user_id: props.uid
|
||||
erp_user_id: props.uid
|
||||
}).then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
Object.assign(state, data)
|
||||
userInfo.value = data
|
||||
|
||||
modelRemark.value = state.remark
|
||||
// modelRemark.value = state.remark
|
||||
|
||||
loading.value = false
|
||||
} else {
|
||||
@ -70,15 +68,15 @@ const onLoadData = () => {
|
||||
}
|
||||
})
|
||||
|
||||
ServeContactGroupList().then((res) => {
|
||||
if (res.code == 200) {
|
||||
let items = res.data.items || []
|
||||
options.value = []
|
||||
for (const iter of items) {
|
||||
options.value.push({ label: iter.name, key: iter.id })
|
||||
}
|
||||
}
|
||||
})
|
||||
// ServeContactGroupList().then((res) => {
|
||||
// if (res.code == 200) {
|
||||
// let items = res.data.items || []
|
||||
// options.value = []
|
||||
// for (const iter of items) {
|
||||
// options.value.push({ label: iter.name, key: iter.id })
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
const onToTalk = () => {
|
||||
@ -86,84 +84,84 @@ const onToTalk = () => {
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
const onJoinContact = () => {
|
||||
if (!state.text.length) {
|
||||
return window['$message'].info('备注信息不能为空')
|
||||
}
|
||||
// const onJoinContact = () => {
|
||||
// if (!state.text.length) {
|
||||
// return window['$message'].info('备注信息不能为空')
|
||||
// }
|
||||
|
||||
ServeCreateContact({
|
||||
friend_id: props.uid,
|
||||
remark: state.text
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
isOpenFrom.value = false
|
||||
window['$message'].success('申请发送成功')
|
||||
} else {
|
||||
window['$message'].error(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
// ServeCreateContact({
|
||||
// friend_id: props.uid,
|
||||
// remark: state.text
|
||||
// }).then((res) => {
|
||||
// if (res.code == 200) {
|
||||
// isOpenFrom.value = false
|
||||
// window['$message'].success('申请发送成功')
|
||||
// } else {
|
||||
// window['$message'].error(res.message)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
const onChangeRemark = () => {
|
||||
ServeEditContactRemark({
|
||||
friend_id: props.uid,
|
||||
remark: modelRemark.value
|
||||
}).then(({ code, message }) => {
|
||||
if (code == 200) {
|
||||
editCardPopover.value.setShow(false)
|
||||
window['$message'].success('备注成功')
|
||||
state.remark = modelRemark.value
|
||||
// const onChangeRemark = () => {
|
||||
// ServeEditContactRemark({
|
||||
// friend_id: props.uid,
|
||||
// remark: modelRemark.value
|
||||
// }).then(({ code, message }) => {
|
||||
// if (code == 200) {
|
||||
// editCardPopover.value.setShow(false)
|
||||
// window['$message'].success('备注成功')
|
||||
// state.remark = modelRemark.value
|
||||
|
||||
emit('updateRemark', {
|
||||
user_id: props.uid,
|
||||
remark: modelRemark.value
|
||||
})
|
||||
} else {
|
||||
window['$message'].error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
// emit('updateRemark', {
|
||||
// user_id: props.uid,
|
||||
// remark: modelRemark.value
|
||||
// })
|
||||
// } else {
|
||||
// window['$message'].error(message)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
const handleSelectGroup = (value) => {
|
||||
ServeContactMoveGroup({
|
||||
user_id: props.uid,
|
||||
group_id: value
|
||||
}).then(({ code, message }) => {
|
||||
if (code == 200) {
|
||||
state.group_id = value
|
||||
window['$message'].success('分组修改成功')
|
||||
} else {
|
||||
window['$message'].error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
// const handleSelectGroup = (value) => {
|
||||
// ServeContactMoveGroup({
|
||||
// user_id: props.uid,
|
||||
// group_id: value
|
||||
// }).then(({ code, message }) => {
|
||||
// if (code == 200) {
|
||||
// state.group_id = value
|
||||
// window['$message'].success('分组修改成功')
|
||||
// } else {
|
||||
// window['$message'].error(message)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
const reset = () => {
|
||||
loading.value = true
|
||||
// const reset = () => {
|
||||
// loading.value = true
|
||||
|
||||
Object.assign(state, {
|
||||
id: 0,
|
||||
avatar: '',
|
||||
gender: 0,
|
||||
mobile: '',
|
||||
motto: '',
|
||||
nickname: '',
|
||||
remark: '',
|
||||
email: '',
|
||||
status: 1,
|
||||
text: ''
|
||||
})
|
||||
// Object.assign(state, {
|
||||
// id: 0,
|
||||
// avatar: '',
|
||||
// gender: 0,
|
||||
// mobile: '',
|
||||
// motto: '',
|
||||
// nickname: '',
|
||||
// remark: '',
|
||||
// email: '',
|
||||
// status: 1,
|
||||
// text: ''
|
||||
// })
|
||||
|
||||
isOpenFrom.value = false
|
||||
}
|
||||
// isOpenFrom.value = false
|
||||
// }
|
||||
|
||||
const onUpdate = (value) => {
|
||||
if (!value) {
|
||||
setTimeout(reset, 100)
|
||||
}
|
||||
// const onUpdate = (value) => {
|
||||
// if (!value) {
|
||||
// setTimeout(reset, 100)
|
||||
// }
|
||||
|
||||
emit('update:show', value)
|
||||
}
|
||||
// emit('update:show', value)
|
||||
// }
|
||||
|
||||
const onAfterEnter = () => {
|
||||
onLoadData()
|
||||
@ -171,201 +169,80 @@ const onAfterEnter = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<x-n-modal content-style="padding:0;" :closable="false" class="w-311px min-h-445px" style="border-radius: 10px;overflow:hidden;" :show="show" :on-update:show="onUpdate" :on-after-enter="onAfterEnter">
|
||||
<div class="section relative px-7px pt-82px pb-20px" v-loading="loading">
|
||||
<div class="absolute top-9px right-7px pointer" @click="onUpdate(false)" >
|
||||
<x-n-modal content-style="padding:0;" :closable="false" class="w-311px min-h-445px" style="border-radius: 10px;overflow:hidden;" :show="show" :on-after-enter="onAfterEnter">
|
||||
<div class="section relative px-7px pt-82px pb-20px">
|
||||
<div class="absolute top-9px right-7px pointer z-10" @click="emit('update:show', false)">
|
||||
<img class="w-20px h-20px" src="@/assets/image/close.png" alt="">
|
||||
</div>
|
||||
<div class="flex py-10px bg-#fff px-16px rounded-4px items-center mb-10px">
|
||||
<div class="w-59px h-59px rounded-8px mr-12px overflow-hidden">
|
||||
<n-image width="59" :src="state.avatar" >
|
||||
|
||||
</n-image>
|
||||
|
||||
<template v-if="loading">
|
||||
<div class="flex py-10px bg-#fff px-16px rounded-4px items-center mb-10px">
|
||||
<div class="w-59px h-59px rounded-8px mr-12px overflow-hidden">
|
||||
<n-skeleton circle height="59px" width="59px" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<n-skeleton text style="width: 80%; margin-bottom: 5px;" />
|
||||
<n-skeleton text style="width: 60%;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-#fff rounded-4px mb-20px">
|
||||
<div class="flex px-15px py-9px" v-for="i in 6" :key="i">
|
||||
<n-skeleton text style="width: 30%; margin-right: 10px;" />
|
||||
<n-skeleton text style="width: 60%;" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-#000 text-16px mb-5px">{{ state.nickname }}</div>
|
||||
<div class="text-#ACACAC text-12px">工号:{{ state.job_num }}</div>
|
||||
<n-skeleton text style="width: 100%; height: 42px; border-radius: 4px;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-#fff rounded-4px mb-20px">
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">公司别</div>
|
||||
<div class="text-#747474 text-12px">江苏泰丰文化传播股份有限公司</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">主管</div>
|
||||
<div class="text-#747474 text-12px">江苏泰丰文化传播股份有限公司</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">部门</div>
|
||||
<div class="text-#747474 text-12px">江苏泰丰文化传播股份有限公司</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">手机号</div>
|
||||
<div class="text-#747474 text-12px">{{ state.mobile }}</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">岗位</div>
|
||||
<div class="text-#747474 text-12px">江苏泰丰文化传播股份有限公司</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">入职日期</div>
|
||||
<div class="text-#747474 text-12px">江苏泰丰文化传播股份有限公司</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<n-button block color="#EEE9F8" text-color="#46299D" @click="onToTalk">
|
||||
<div class="flex items-center justify-center py-11px">
|
||||
<img class="w-19.8px h-20px mr-15px" src="@/assets/image/faxi@2x.png" alt="">
|
||||
<span>发送消息</span>
|
||||
</div>
|
||||
</n-button>
|
||||
</div>
|
||||
<!-- <section class="el-container is-vertical">
|
||||
<header class="el-header header">
|
||||
<im-avatar
|
||||
class="avatar"
|
||||
:size="100"
|
||||
:src="state.avatar"
|
||||
:username="state.remark || state.nickname"
|
||||
:font-size="30"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="flex py-10px bg-#fff px-16px rounded-4px items-center mb-10px">
|
||||
<div class="w-59px h-59px rounded-8px mr-12px overflow-hidden">
|
||||
<n-image width="59" :src="userInfo.avatar" >
|
||||
|
||||
<div class="gender" v-show="state.gender > 0">
|
||||
<n-icon v-if="state.gender == 1" :component="Male" color="#508afe" />
|
||||
<n-icon v-if="state.gender == 2" :component="Female" color="#ff5722" />
|
||||
</n-image>
|
||||
</div>
|
||||
|
||||
<div class="close" @click="onUpdate(false)">
|
||||
<close-one theme="outline" size="22" fill="#fff" :strokeWidth="2" />
|
||||
<div>
|
||||
<div class="text-#000 text-16px mb-5px">{{ userInfo.nickname }}</div>
|
||||
<div class="text-#ACACAC text-12px">工号:{{ userInfo.job_num }}</div>
|
||||
</div>
|
||||
|
||||
<div class="nickname text-ellipsis">
|
||||
{{ state.remark || state.nickname || '未设置昵称' }}
|
||||
</div>
|
||||
<div class="bg-#fff rounded-4px mb-20px">
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">公司别</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.company_name }}</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="el-main main me-scrollbar me-scrollbar-thumb">
|
||||
<div class="motto">
|
||||
{{ state.motto || '编辑个签,展示我的独特态度。' }}
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">主管</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.leaders?.map(x=>x.user_name)?.join(',') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="infos">
|
||||
<div class="info-item">
|
||||
<span class="name">工号 :</span>
|
||||
<span class="text">{{ state.job_num}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">手机 :</span>
|
||||
<span class="text">{{ state.mobile }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">昵称 :</span>
|
||||
<span class="text text-ellipsis">{{ state.nickname || '-' }} </span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">性别 :</span>
|
||||
<span class="text">{{
|
||||
state.gender == 1 ? '男' : state.gender == 2 ? '女' : '未知'
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="info-item" v-if="state.friend_status == 2">
|
||||
<span class="name">备注 :</span>
|
||||
<n-popover trigger="click" placement="top-start" ref="editCardPopover">
|
||||
<template #trigger>
|
||||
<span class="text edit pointer text-ellipsis">
|
||||
{{ state.remark || '未设置' }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #header> 设置备注 </template>
|
||||
|
||||
<div style="display: flex">
|
||||
<n-input
|
||||
type="text"
|
||||
placeholder="请填写备注"
|
||||
:autofocus="true"
|
||||
maxlength="10"
|
||||
v-model:value="modelRemark"
|
||||
@keydown.enter="onChangeRemark"
|
||||
/>
|
||||
<n-button
|
||||
type="primary"
|
||||
text-color="#ffffff"
|
||||
class="mt-l5"
|
||||
@click="onChangeRemark"
|
||||
>
|
||||
确定
|
||||
</n-button>
|
||||
</div>
|
||||
</n-popover>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">邮箱 :</span>
|
||||
<span class="text">{{ state.email || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item" v-if="state.friend_status == 2">
|
||||
<span class="name">分组 :</span>
|
||||
<n-dropdown
|
||||
trigger="click"
|
||||
placement="top-start"
|
||||
:show-arrow="true"
|
||||
:options="options"
|
||||
@select="handleSelectGroup"
|
||||
>
|
||||
<span class="text edit pointer">{{ groupName }}</span>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">入职时间 :</span>
|
||||
<span class="text">{{ state.enter_date}}</span>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">部门</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.erp_dept_position?.map(x=>x.department_name)?.join(',') }}</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer v-if="state.friend_status == 2" class="el-footer footer bdr-t flex-center">
|
||||
<n-button
|
||||
round
|
||||
block
|
||||
type="primary"
|
||||
text-color="#ffffff"
|
||||
@click="onToTalk"
|
||||
style="width: 91%"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="SendOne" />
|
||||
</template>
|
||||
发送消息
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">手机号</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.tel_num }}</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">岗位</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.erp_dept_position?.map(x=>x.position_name)?.join(',') }}</div>
|
||||
</div>
|
||||
<div class="flex px-15px py-9px">
|
||||
<div class="text-#000 text-12px w-84px">入职日期</div>
|
||||
<div class="text-#747474 text-12px">{{ userInfo.enter_date }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<n-button block color="#EEE9F8" text-color="#46299D" @click="onToTalk">
|
||||
<div class="flex items-center justify-center py-11px">
|
||||
<img class="w-19.8px h-20px mr-15px" src="@/assets/image/faxi@2x.png" alt="">
|
||||
<span>发送消息</span>
|
||||
</div>
|
||||
</n-button>
|
||||
</footer>
|
||||
|
||||
<footer v-else-if="state.friend_status == 1" class="el-footer footer bdr-t flex-center">
|
||||
<template v-if="isOpenFrom">
|
||||
<n-input
|
||||
type="text"
|
||||
placeholder="请填写申请备注"
|
||||
v-model:value="state.text"
|
||||
@keydown.enter="onJoinContact"
|
||||
/>
|
||||
|
||||
<n-button type="primary" text-color="#ffffff" class="mt-l5" @click="onJoinContact">
|
||||
确定
|
||||
</n-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-button
|
||||
type="primary"
|
||||
text-color="#ffffff"
|
||||
block
|
||||
round
|
||||
style="width: 91%"
|
||||
@click="isOpenFrom = true"
|
||||
>
|
||||
添加好友
|
||||
</n-button>
|
||||
</template>
|
||||
</footer>
|
||||
</section> -->
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</x-n-modal>
|
||||
</template>
|
||||
|
@ -80,26 +80,26 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
return this.items.find((item) => item.client_upload_id === clientUploadId)
|
||||
},
|
||||
|
||||
// 暂停文件上传
|
||||
pauseUpload(uploadId: string) {
|
||||
const item = this.findItem(uploadId)
|
||||
if (!item) return
|
||||
// // 暂停文件上传
|
||||
// pauseUpload(uploadId: string) {
|
||||
// const item = this.findItem(uploadId)
|
||||
// if (!item) return
|
||||
|
||||
item.is_paused = true
|
||||
console.log(`暂停上传: ${uploadId}`)
|
||||
},
|
||||
// item.is_paused = true
|
||||
// console.log(`暂停上传: ${uploadId}`)
|
||||
// },
|
||||
|
||||
// 恢复文件上传
|
||||
resumeUpload(uploadId: string) {
|
||||
const item = this.findItem(uploadId)
|
||||
if (!item) return
|
||||
// resumeUpload(uploadId: string) {
|
||||
// const item = this.findItem(uploadId)
|
||||
// if (!item) return
|
||||
|
||||
item.is_paused = false
|
||||
console.log(`恢复上传: ${uploadId}`)
|
||||
// item.is_paused = false
|
||||
// console.log(`恢复上传: ${uploadId}`)
|
||||
|
||||
// 继续上传
|
||||
this.triggerUpload(uploadId)
|
||||
},
|
||||
// // 继续上传
|
||||
// this.triggerUpload(uploadId)
|
||||
// },
|
||||
|
||||
// 发送上传消息
|
||||
async sendUploadMessage(item: any) {
|
||||
@ -114,7 +114,7 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化视频上传(使用分片上传方式)
|
||||
// 初始化上传(使用分片上传方式)
|
||||
async initUploadFile(
|
||||
file: File,
|
||||
talkType: number,
|
||||
@ -306,16 +306,16 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
}
|
||||
},
|
||||
|
||||
// 暂停视频上传
|
||||
pauseVideoUpload(clientUploadId: string) {
|
||||
|
||||
pauseUpload(clientUploadId: string) {
|
||||
const item = this.findItemByClientId(clientUploadId)
|
||||
if (!item) return
|
||||
|
||||
item.is_paused = true
|
||||
},
|
||||
|
||||
// 恢复视频上传
|
||||
resumeVideoUpload(clientUploadId: string) {
|
||||
// 恢复上传
|
||||
resumeUpload(clientUploadId: string) {
|
||||
const item = this.findItemByClientId(clientUploadId)
|
||||
if (!item) return
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { ServeFindFriendApplyNum } from '@/api/contact'
|
||||
import { ServeGroupApplyUnread } from '@/api/group'
|
||||
import { delAccessToken } from '@/utils/auth'
|
||||
import { storage } from '@/utils/storage'
|
||||
|
||||
import { GetUserInfo } from '@/api/auth'
|
||||
interface UserStoreState {
|
||||
uid: number
|
||||
nickname: string
|
||||
@ -35,7 +35,7 @@ export const useUserStore = defineStore('user', {
|
||||
online: false, // 在线状态
|
||||
isQiye: false,
|
||||
isContactApply: false,
|
||||
isGroupApply: false
|
||||
isGroupApply: false,
|
||||
}
|
||||
},
|
||||
getters: {},
|
||||
|
@ -18,7 +18,7 @@ export function isLoggedIn() {
|
||||
*/
|
||||
export function getAccessToken() {
|
||||
// return storage.get(AccessToken) || ''
|
||||
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b89574a563986daa80674dd774ef18032ee6016a202902c95452e1e81931358d4d3cb7f0db0c6fc66f406f57e411cb1e2aeb77318f7c36b2b61f48c4c645d27920f05c204fe133ab9bfa481e9c1ae2e384c'
|
||||
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d228655b2039673c1108d29c13b75d1fc2bfd3d1071f49b461822d6c2a320ae711492ac514d1a31043c8b7f2d10ff9e3869928844485d0ed575b936311797f3446e4a6c7ee1d9a63aba9445bc8b41c89143'
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,8 @@ import SkipBottom from './SkipBottom.vue'
|
||||
import { ITalkRecord } from '@/types/chat'
|
||||
import { EditorConst } from '@/constant/event-bus'
|
||||
import { useInject, useTalkRecord, useUtil } from '@/hooks'
|
||||
|
||||
import { ExclamationCircleFilled } from '@ant-design/icons-vue';
|
||||
import { useUserStore } from '@/store'
|
||||
const props = defineProps({
|
||||
uid: {
|
||||
type: Number,
|
||||
@ -39,17 +40,20 @@ const { useMessage } = useUtil()
|
||||
const { dropdown, showDropdownMenu, closeDropdownMenu } = useMenu()
|
||||
const { showUserInfoModal } = useInject()
|
||||
const dialogueStore = useDialogueStore()
|
||||
|
||||
const userStore = useUserStore()
|
||||
// const showUserInfoModal = (uid: number) => {
|
||||
// userStore.getUserInfo(uid)
|
||||
// }
|
||||
watch(() => records, (newValue, oldValue) => {
|
||||
console.log(newValue);
|
||||
|
||||
},{deep:true,immediate:true})
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
// 置底按钮
|
||||
const skipBottom = ref(false)
|
||||
setTimeout(()=>{
|
||||
console.log(records.value,'records.value');
|
||||
},1000)
|
||||
setTimeout(() => {
|
||||
console.log(records.value, 'records.value');
|
||||
}, 1000)
|
||||
// 是否显示消息时间
|
||||
const isShowTalkTime = (index: number, datetime: string) => {
|
||||
if (datetime == undefined) {
|
||||
@ -276,11 +280,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<section class="section">
|
||||
<div
|
||||
id="imChatPanel"
|
||||
class="me-scrollbar me-scrollbar-thumb talk-container"
|
||||
@scroll="onPanelScroll($event)"
|
||||
>
|
||||
<div id="imChatPanel" class="me-scrollbar me-scrollbar-thumb talk-container" @scroll="onPanelScroll($event)">
|
||||
<!-- 数据加载状态栏 -->
|
||||
<div class="load-toolbar pointer">
|
||||
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
|
||||
@ -288,88 +288,54 @@ onMounted(() => {
|
||||
<span v-else class="no-more"> 没有更多消息了 </span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="message-item"
|
||||
v-for="(item, index) in records"
|
||||
:key="item.msg_id"
|
||||
:id="item.msg_id"
|
||||
>
|
||||
<div class="message-item" v-for="(item, index) in records" :key="item.msg_id" :id="item.msg_id">
|
||||
<!-- 系统消息 -->
|
||||
<div v-if="item.msg_type >= 1000" class="message-box">
|
||||
<component
|
||||
:is="MessageComponents[item.msg_type] || 'unknown-message'"
|
||||
:extra="item.extra"
|
||||
:data="item"
|
||||
/>
|
||||
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item" />
|
||||
</div>
|
||||
|
||||
<!-- 撤回消息 -->
|
||||
<div v-else-if="item.is_revoke == 1" class="message-box">
|
||||
<revoke-message
|
||||
:login_uid="uid"
|
||||
:user_id="item.user_id"
|
||||
:nickname="item.nickname"
|
||||
:talk_type="item.talk_type"
|
||||
:datetime="item.created_at"
|
||||
/>
|
||||
<revoke-message :login_uid="uid" :user_id="item.user_id" :nickname="item.nickname" :talk_type="item.talk_type"
|
||||
:datetime="item.created_at" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="message-box record-box"
|
||||
:class="{
|
||||
'direction-rt': item.float == 'right',
|
||||
'multi-select': dialogueStore.isOpenMultiSelect,
|
||||
'multi-select-check': item.isCheck
|
||||
}"
|
||||
>
|
||||
<div v-else class="message-box record-box" :class="{
|
||||
'direction-rt': item.float == 'right',
|
||||
'multi-select': dialogueStore.isOpenMultiSelect,
|
||||
'multi-select-check': item.isCheck
|
||||
}">
|
||||
<!-- 多选按钮 -->
|
||||
<aside v-if="dialogueStore.isOpenMultiSelect" class="checkbox-column">
|
||||
<n-checkbox
|
||||
size="small"
|
||||
:checked="item.isCheck"
|
||||
@update:checked="item.isCheck = !item.isCheck"
|
||||
/>
|
||||
<n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" />
|
||||
</aside>
|
||||
|
||||
<!-- 头像信息 -->
|
||||
|
||||
<aside class="avatar-column">
|
||||
<im-avatar
|
||||
class="pointer"
|
||||
:src="item.avatar"
|
||||
:size="42"
|
||||
:username="item.nickname"
|
||||
@click="showUserInfoModal(item.user_id)"
|
||||
/>
|
||||
<im-avatar class="pointer" :src="item.avatar" :size="42" :username="item.nickname"
|
||||
@click="showUserInfoModal(item.erp_user_id)" />
|
||||
</aside>
|
||||
|
||||
<!-- 主体信息 -->
|
||||
<main class="main-column">
|
||||
<div class="talk-title">
|
||||
<span
|
||||
class="nickname pointer"
|
||||
v-show="talk_type == 2 && item.float == 'left'"
|
||||
@click="onClickNickname(item)"
|
||||
>
|
||||
<span class="nickname pointer" v-show="talk_type == 2 && item.float == 'left'"
|
||||
@click="onClickNickname(item)">
|
||||
<span class="at">@</span>{{ item.nickname }}
|
||||
</span>
|
||||
<span>{{ parseTime(item.created_at, '{y}/{m}/{d} {h}:{i}') }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="talk-content"
|
||||
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
|
||||
@click="onRowClick(item)"
|
||||
>
|
||||
<component
|
||||
:is="MessageComponents[item.msg_type] || 'unknown-message'"
|
||||
:extra="item.extra"
|
||||
:data="item"
|
||||
:max-width="true"
|
||||
:source="'panel'"
|
||||
@contextmenu.prevent="onContextMenu($event, item)"
|
||||
/>
|
||||
<div class="talk-content" :class="{ pointer: dialogueStore.isOpenMultiSelect }" @click="onRowClick(item)">
|
||||
|
||||
|
||||
<component :is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item"
|
||||
:max-width="true" :source="'panel'" @contextmenu.prevent="onContextMenu($event, item)" />
|
||||
<div class="mr-10px"> <n-button text style="font-size: 20px">
|
||||
<n-icon color="#CF3050">
|
||||
<ExclamationCircleFilled />
|
||||
</n-icon>
|
||||
</n-button></div>
|
||||
<!-- <div class="talk-tools">
|
||||
<template v-if="talk_type == 1 && item.float == 'right'">
|
||||
<loading
|
||||
@ -385,19 +351,11 @@ onMounted(() => {
|
||||
<span v-show="item.send_status != 1"> 已送达 </span>
|
||||
</template>
|
||||
|
||||
<n-icon
|
||||
class="more-tools pointer"
|
||||
:component="MoreThree"
|
||||
@click="onContextMenu($event, item)"
|
||||
/>
|
||||
</div> -->
|
||||
<n-icon class="more-tools pointer" :component="MoreThree" @click="onContextMenu($event, item)" />
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="item.extra.reply"
|
||||
class="talk-reply pointer"
|
||||
@click="onJumpMessage(item.extra?.reply?.msg_id)"
|
||||
>
|
||||
<div v-if="item.extra.reply" class="talk-reply pointer" @click="onJumpMessage(item.extra?.reply?.msg_id)">
|
||||
<n-icon :component="ToTop" size="14" class="icon-top" />
|
||||
<span class="ellipsis">
|
||||
回复 {{ item.extra?.reply?.nickname }}:
|
||||
@ -418,15 +376,8 @@ onMounted(() => {
|
||||
</section>
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
<n-dropdown
|
||||
:show="dropdown.show"
|
||||
:x="dropdown.x"
|
||||
:y="dropdown.y"
|
||||
style="width: 142px;"
|
||||
:options="dropdown.options"
|
||||
@select="onContextMenuHandle"
|
||||
@clickoutside="closeDropdownMenu"
|
||||
/>
|
||||
<n-dropdown :show="dropdown.show" :x="dropdown.x" :y="dropdown.y" style="width: 142px;" :options="dropdown.options"
|
||||
@select="onContextMenuHandle" @clickoutside="closeDropdownMenu" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -451,6 +402,7 @@ onMounted(() => {
|
||||
text-align: center;
|
||||
line-height: 38px;
|
||||
font-size: 13px;
|
||||
|
||||
.no-more {
|
||||
color: #b9b3b3;
|
||||
}
|
||||
@ -528,6 +480,7 @@ onMounted(() => {
|
||||
color: var(--im-text-color);
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
|
||||
.at {
|
||||
display: none;
|
||||
}
|
||||
|
@ -144,34 +144,32 @@ const onSendVideoEvent = async ({ data }) => {
|
||||
dialogueStore.talk.username,
|
||||
uploadId,
|
||||
async (percentage) => {
|
||||
console.log('percentage', percentage)
|
||||
// 更新消息进度的回调
|
||||
dialogueStore.updateUploadProgress(uploadId, percentage)
|
||||
},
|
||||
async (videoData) => {
|
||||
console.log('videoData', videoData)
|
||||
// 上传完成后的回调
|
||||
if (videoData.code != 0) return
|
||||
async () => {
|
||||
dialogueStore.batchDelDialogueRecord([uploadId])
|
||||
// console.log('videoData', videoData)
|
||||
// // 上传完成后的回调
|
||||
|
||||
// // 更新临时消息为最终消息
|
||||
// dialogueStore.completeUpload(uploadId, {
|
||||
// url: videoData.data.ori_url,
|
||||
// cover: videoData.data.cover_url
|
||||
// })
|
||||
|
||||
// 更新临时消息为最终消息
|
||||
dialogueStore.completeUpload(uploadId, {
|
||||
url: videoData.data.ori_url,
|
||||
cover: videoData.data.cover_url
|
||||
})
|
||||
|
||||
// 上传成功后,发送正式消息给服务端
|
||||
let finalMessage = {
|
||||
type: 'video',
|
||||
url: videoData.data.ori_url,
|
||||
// // 上传成功后,发送正式消息给服务端
|
||||
// let finalMessage = {
|
||||
// type: 'video',
|
||||
// url: videoData.data.ori_url,
|
||||
|
||||
size: data.size
|
||||
}
|
||||
// size: data.size
|
||||
// }
|
||||
|
||||
// 发送真实消息到服务端
|
||||
onSendMessage(finalMessage, () => {
|
||||
// 上传成功且消息发送成功后,删除临时消息
|
||||
dialogueStore.batchDelDialogueRecord([uploadId])
|
||||
})
|
||||
// // 发送真实消息到服务端
|
||||
// onSendMessage(finalMessage, () => {
|
||||
// // 上传成功且消息发送成功后,删除临时消息
|
||||
// dialogueStore.batchDelDialogueRecord([uploadId])
|
||||
// })
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -218,10 +216,8 @@ const onSendFileEvent = ({ data }) => {
|
||||
async (percentage) => {
|
||||
dialogueStore.updateUploadProgress(uploadId, percentage)
|
||||
},
|
||||
async (data) => {
|
||||
console.log('data', data)
|
||||
// 上传完成后的回调
|
||||
if (data.code != 0) return
|
||||
async () => {
|
||||
dialogueStore.batchDelDialogueRecord([uploadId])
|
||||
}
|
||||
)
|
||||
}
|
||||
|