Compare commits

...

4 Commits

Author SHA1 Message Date
张 元山
8eb0f0b4f2 处理@
Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run
2025-03-20 11:02:29 +08:00
d7c813977d Merge branch 'wyfMain-dev'
Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run
2025-03-19 09:13:35 +08:00
2642a885f0 处理本地缓存没有时,聊天记录的跳转,并处理直接调起相机、文件查看等问题 2025-03-18 20:00:41 +08:00
026e4fa3e6 处理搜索不同条件、不同类型跳转对应聊天记录 2025-03-17 19:54:43 +08:00
17 changed files with 1440 additions and 801 deletions

View File

@ -31,15 +31,16 @@
"@uni-helper/axios-adapter": "^1.5.2",
"@uni-helper/localforage-adapter": "^1.0.2",
"@uni-helper/uni-use": "^0.19.12",
"@vueup/vue-quill": "^1.2.0",
"@vueuse/core": "^9.13.0",
"@vueup/vue-quill": "^1.2.0",
"quill": "^1.3.7",
"quill-mention": "^4.1.0",
"axios": "^1.7.2",
"dayjs": "^1.11.12",
"less": "^4.2.0",
"lodash": "^4.17.21",
"nzh": "^1.0.13",
"pinia-plugin-persistedstate": "^4.1.3",
"quill-mention": "^6.0.2",
"vconsole": "^3.15.1",
"vue": "^3.3.8",
"vue-i18n": "11.0.0-rc.1"

View File

@ -86,9 +86,12 @@ importers:
pinia-plugin-persistedstate:
specifier: ^4.1.3
version: 4.1.3(pinia@2.0.36(typescript@5.5.4)(vue@3.4.35(typescript@5.5.4)))(rollup@4.19.2)
quill:
specifier: ^1.3.7
version: 1.3.7
quill-mention:
specifier: ^6.0.2
version: 6.0.2
specifier: ^4.1.0
version: 4.1.0
vconsole:
specifier: ^3.15.1
version: 3.15.1
@ -2997,9 +3000,6 @@ packages:
fast-diff@1.2.0:
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
@ -3986,9 +3986,6 @@ packages:
parchment@1.1.4:
resolution: {integrity: sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==}
parchment@3.0.0:
resolution: {integrity: sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==}
parse-bmfont-ascii@1.0.6:
resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==}
@ -4262,20 +4259,12 @@ packages:
quill-delta@4.2.2:
resolution: {integrity: sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==}
quill-delta@5.1.0:
resolution: {integrity: sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==}
engines: {node: '>= 12.0.0'}
quill-mention@6.0.2:
resolution: {integrity: sha512-ZyiEzLxtoNJ/hAjMyfVsugpXAcOdD2fbHmJT3yKuwpUxiDHdmutVJqOzpItqiVbcjUecnjAF+/Yo1IN3/W6iAg==}
quill-mention@4.1.0:
resolution: {integrity: sha512-dT8HLYeuGU8yjjUr5SgdOusFSqQ7FQt/DWefz4V/L2omJsZ9CVYWepg3GyqV/evNDV7LQtfM7cadxtYD2bi2ew==}
quill@1.3.7:
resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==}
quill@2.0.2:
resolution: {integrity: sha512-QfazNrhMakEdRG57IoYFwffUIr04LWJxbS/ZkidRFXYCQt63c1gK6Z7IHUXMx/Vh25WgPBU42oBaNzQ0K1R/xw==}
engines: {npm: '>=8.2.3'}
range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
@ -8956,8 +8945,6 @@ snapshots:
fast-diff@1.2.0: {}
fast-diff@1.3.0: {}
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@ -10153,8 +10140,6 @@ snapshots:
parchment@1.1.4: {}
parchment@3.0.0: {}
parse-bmfont-ascii@1.0.6: {}
parse-bmfont-binary@1.0.6: {}
@ -10407,15 +10392,9 @@ snapshots:
lodash.clonedeep: 4.5.0
lodash.isequal: 4.5.0
quill-delta@5.1.0:
quill-mention@4.1.0:
dependencies:
fast-diff: 1.3.0
lodash.clonedeep: 4.5.0
lodash.isequal: 4.5.0
quill-mention@6.0.2:
dependencies:
quill: 2.0.2
quill: 1.3.7
quill@1.3.7:
dependencies:
@ -10426,13 +10405,6 @@ snapshots:
parchment: 1.1.4
quill-delta: 3.6.3
quill@2.0.2:
dependencies:
eventemitter3: 5.0.1
lodash-es: 4.17.21
parchment: 3.0.0
quill-delta: 5.1.0
range-parser@1.2.1: {}
raw-body@2.5.2:

View File

@ -45,3 +45,12 @@ export const ServeTalkDate = (data) => {
data,
})
}
//获取会话Id
export const ServeGetSessionId = (data) => {
return request({
url: '/api/v1/talk/session/getId',
method: 'POST',
data,
})
}

View File

@ -21,9 +21,20 @@
<script setup>
import { defineProps, defineEmits, reactive, watch } from 'vue'
const props = defineProps({
searchText: String,
first_talk_record_infos: Object,
disabled: Boolean,
searchText: {
type: String,
default: ''
},
first_talk_record_infos: {
type: Object,
default(){
return {}
}
},
disabled: {
type: Boolean,
default: false
},
})
const state = reactive({
searchText: '', //

View File

@ -25,33 +25,33 @@ const getFileTypeIMG = computed(() => {
let objT = {
finishedImg: '',
blankImg: '',
progressColor: ''
};
progressColor: '',
}
switch (suffix) {
case 'pdf':
objT.finishedImg = filePaperPDF
objT.blankImg = filePaperPDFBlank
objT.progressColor = '#DE4E4E'
break;
break
case 'doc':
case 'docx':
objT.finishedImg = filePaperWord
objT.blankImg = filePaperWordBlank
objT.progressColor = '#2750B2'
break;
break
case 'xls':
case 'xlsx':
objT.finishedImg = filePaperExcel
objT.blankImg = filePaperExcelBlank
objT.progressColor = '#3C7F4B'
break;
break
case 'ppt':
case 'pptx':
objT.finishedImg = filePaperPPT
objT.blankImg = filePaperPPTBlank
objT.progressColor = '#B74B2B'
break;
break
default:
objT.finishedImg = filePaperOther
objT.blankImg = filePaperOtherBlank
@ -60,34 +60,92 @@ const getFileTypeIMG = computed(() => {
return objT
})
const previewPDF = () => {
if (typeof plus !== 'undefined') {
downloadAndOpenFile()
} else {
document.addEventListener('plusready', () => {
downloadAndOpenFile()
})
}
}
const downloadAndOpenFile = () => {
uni.showLoading({ title: '加载中...', mask: true })
const downloadUrl = props?.extra?.path
if (!downloadUrl) {
uni.hideLoading()
uni.showToast({ title: '文件路径无效', icon: 'none' })
return
}
const options = {
filename: '_doc/downloads/', //
}
const dtask = plus.downloader.createDownload(downloadUrl, options, function (
d,
status,
) {
if (status === 200) {
uni.hideLoading()
const filePath = d.filename
if (filePath) {
plus.runtime.openFile(filePath, {}, function () {})
} else {
uni.showToast({ title: '文件路径无效', icon: 'none' })
}
} else {
uni.hideLoading()
}
})
dtask.start()
}
</script>
<template>
<section
class="file-message"
@click="previewPDF"
:class="{ left: data.float === 'left', right: data.float === 'right' }"
>
<div class="flex justify-between">
<div class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis file_name">
<div
class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis file_name"
>
{{ extra.name }}
</div>
<div v-if="data.uploadStatus === 2 || !data.uploadStatus" class="w-[95rpx]">
<tm-image :width="95" :height="95" :src="getFileTypeIMG.finishedImg"></tm-image>
<div
v-if="data.uploadStatus === 2 || !data.uploadStatus"
class="w-[95rpx]"
>
<tm-image
:width="95"
:height="95"
:src="getFileTypeIMG.finishedImg"
></tm-image>
</div>
<div v-if="data.uploadStatus === 1 || data.uploadStatus === 3" class="w-[95rpx]">
<tm-image :width="95" :height="95" :src="getFileTypeIMG.blankImg"></tm-image>
<wd-circle
customClass="circleProgress"
:modelValue="data.uploadCurrent"
layerColor="#E3E3E3"
:color="getFileTypeIMG.progressColor"
:strokeWidth="3"
:size="20"
></wd-circle>
<div
v-if="data.uploadStatus === 1 || data.uploadStatus === 3"
class="w-[95rpx]"
>
<tm-image
:width="95"
:height="95"
:src="getFileTypeIMG.blankImg"
></tm-image>
<wd-circle
customClass="circleProgress"
:modelValue="data.uploadCurrent"
layerColor="#E3E3E3"
:color="getFileTypeIMG.progressColor"
:strokeWidth="3"
:size="20"
></wd-circle>
</div>
</div>
<div class="divider mt-[28rpx]"></div>
<div class="text-[24rpx] text-[#747474] mt-[10rpx]">{{ fileFormatSize(extra.size) }}</div>
<div class="text-[24rpx] text-[#747474] mt-[10rpx]">
{{ fileFormatSize(extra.size) }}
</div>
<!-- <div class="main">
<div class="ext">{{ getFileNameSuffix(extra.name) }}</div>
<div class="file-box">
@ -124,11 +182,11 @@ const getFileTypeIMG = computed(() => {
border-radius: 16rpx 0 16rpx 16rpx;
}
.file_name{
.file_name {
word-break: break-all; /* 在任意字符间断行 */
word-wrap: break-word; /* 允许长单词换行到下一行 */
}
.main {
height: 45px;
display: flex;
@ -217,7 +275,7 @@ const getFileTypeIMG = computed(() => {
}
.divider {
background-color: #E7E7E7;
background-color: #e7e7e7;
height: 1rpx;
}

View File

@ -379,6 +379,12 @@ const handleClickItem = (item) => {
}
return
}
if(props?.manageType === 'searchRecord'){
uni.navigateTo({
url: '/pages/search/searchByCondition/index?condition=member'
})
return
}
let itemList = dialogueParams.memberList
if (
props?.manageType === 'admin' &&

View File

@ -96,7 +96,9 @@
</div>
</div>
<div class="chat-records-search chat-settings-card">
<customInput :disabled="true"></customInput>
<div @click="toSearchPage">
<customInput :disabled="true"></customInput>
</div>
<div class="record-search-types">
<div
class="record-search-types-each"
@ -151,8 +153,10 @@
@click="showConfirmPrompt(2)"
class="clear-chat-record-btn-each"
v-if="
groupParams?.groupInfo?.is_manager && dialogueParams.type === 2
&& (groupParams?.groupInfo?.group_type === 1 || groupParams?.groupInfo?.group_type === 3)
groupParams?.groupInfo?.is_manager &&
dialogueParams.type === 2 &&
(groupParams?.groupInfo?.group_type === 1 ||
groupParams?.groupInfo?.group_type === 3)
"
>
<span class="text-[32rpx] font-regular">
@ -163,8 +167,10 @@
@click="showConfirmPrompt(3)"
class="clear-chat-record-btn-each"
v-if="
groupParams?.groupInfo?.is_manager && dialogueParams.type === 2
&& (groupParams?.groupInfo?.group_type === 1 || groupParams?.groupInfo?.group_type === 3)
groupParams?.groupInfo?.is_manager &&
dialogueParams.type === 2 &&
(groupParams?.groupInfo?.group_type === 1 ||
groupParams?.groupInfo?.group_type === 3)
"
>
<span class="text-[32rpx] font-regular">
@ -499,10 +505,7 @@ const toSearchByConditionPage = (flag) => {
}
uni.navigateTo({
url:
'/pages/search/searchByCondition/index?condition=' +
condition +
'&receiver_id=' +
state.groupId,
'/pages/search/searchByCondition/index?condition=' + condition
})
}
}
@ -629,6 +632,21 @@ const inviteMembersInGroup = async (memberList) => {
}
}
}
//
const toSearchPage = () => {
// uni.navigateTo({
// url:
// '/pages/search/searchByCondition/index?condition=text'
// })
uni.navigateTo({
url:
'/pages/search/moreResult/moreResultDetail?talk_type=' +
dialogueParams.type +
'&receiver_id=' +
dialogueParams.receiver_id,
})
}
</script>
<style scoped lang="scss">
.outer-layer {

View File

@ -1,25 +1,39 @@
<template>
<div class="emojiRoot">
<div @click="()=>photoActionsSelect(0)" class="flex flex-col items-center">
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
<div
@click="() => photoActionsSelect(0)"
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="photoAlbum"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
</div>
<div @click="()=>photoActionsSelect(1)" class="flex flex-col items-center">
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
<div
@click="() => photoActionsSelect(1)"
class="flex flex-col items-center"
>
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="videoImg"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
</div>
<div @click="takePhoto" class="flex flex-col items-center">
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="photoGraph"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
</div>
<div @click="chooseFile" class="flex flex-col items-center">
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
<div
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
>
<tm-image :width="53" :height="44" :src="folder"></tm-image>
</div>
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
@ -27,10 +41,15 @@
</div>
</template>
<script setup>
import { ref, reactive, defineProps, defineEmits } from "vue"
import dayjs from "dayjs";
import { ref, reactive, defineProps, defineEmits } from 'vue'
import dayjs from 'dayjs'
import { beautifyTime } from '@/utils/datetime'
import { useDialogueListStore, useDialogueStore, useUserStore,useUploadsStore } from '@/store'
import {
useDialogueListStore,
useDialogueStore,
useUserStore,
useUploadsStore,
} from '@/store'
import { useSessionMenu } from '@/hooks'
import photoAlbum from '@/static/image/chatList/photoAlbum.png'
import photoGraph from '@/static/image/chatList/photoGraph.png'
@ -43,26 +62,34 @@ const props = defineProps({
sendUserInfo: {
type: Object,
default: {},
required: true
required: true,
},
talkParams: {
type: Object,
default: {},
required: true
}
});
required: true,
},
})
const state = reactive({
base64Url: ''
})
const uploadsStore = useUploadsStore()
const { addDialogueRecord, virtualList, updateUploadProgress } = useDialogueListStore()
const {
addDialogueRecord,
virtualList,
updateUploadProgress,
} = useDialogueListStore()
const dialogueStore = useDialogueStore()
const userStore = useUserStore()
const emit = defineEmits(['selectImg'])
const onProgressFn = (progress, id) => {
console.log(progress.loaded / progress.total * 100, 'progress');
console.log((progress.loaded / progress.total) * 100, 'progress')
updateUploadProgress(id, progress.loaded / progress.total * 100)
updateUploadProgress(id, (progress.loaded / progress.total) * 100)
}
const photoActionsSelect = (index) => {
@ -71,28 +98,31 @@ const photoActionsSelect = (index) => {
sourceType: ['album'],
count: 9,
success: async (res) => {
console.log(res,'res');
console.log(res, 'res')
res.tempFiles.forEach(async (file) => {
let data = await onUploadImageVideo(file, 'image')
emit('selectImg', data, data.file_num)
})
}
},
})
}else{
} else {
uni.chooseVideo({
sourceType: ['album'],
success: async (res) => {
console.log(res,'res');
let data = await onUploadImageVideo(res.tempFile, 'video',res.tempFilePath)
console.log(res, 'res')
let data = await onUploadImageVideo(
res.tempFile,
'video',
res.tempFilePath,
)
emit('selectImg', data, data.file_num)
}
},
})
}
}
const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
console.log(file, 'file');
const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
console.log(file, 'file')
return new Promise(async (resolve) => {
if (type === 'image') {
let image = new Image()
@ -100,20 +130,20 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
image.onload = () => {
const form = new FormData()
form.append('file', file)
form.append("source", "fonchain-chat");
form.append("urlParam", `width=${image.width}&height=${image.height}`);
form.append('source', 'fonchain-chat')
form.append('urlParam', `width=${image.width}&height=${image.height}`)
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
height: image.height,
name: "",
name: '',
size: 0,
url: image.src,
width: image.width
width: image.width,
},
float: "right",
float: 'right',
isCheck: false,
is_mark: 0,
is_read: 0,
@ -127,80 +157,84 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 2 3
uploadStatus: 1, // 1 2 3
}
virtualList.value.unshift(newItem)
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
if (status == 0) {
resolve({
type: 'image',
url: data.ori_url,
size: file.size,
width: image.width,
height: image.height,
file_num: randomId,
})
} else {
resolve('')
message.error(msg)
}
})
uploadImg(form, (e) => onProgressFn(e, randomId)).then(
({ status, data, msg }) => {
if (status == 0) {
resolve({
type: 'image',
url: data.ori_url,
size: file.size,
width: image.width,
height: image.height,
file_num: randomId,
})
} else {
resolve('')
message.error(msg)
}
},
)
}
} else {
uni.getVideoInfo({
src:fileUrl,
success:(resp)=>{
console.log(resp);
form.append('file', file)
form.append("source", "fonchain-chat");
form.append("type", "video");
form.append("urlParam", `width=${resp.width}&height=${resp.height}`);
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
duration: parseInt(resp.duration),
height: resp.height,
name: "",
url: fileUrl,
width: resp.width
},
float: "right",
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 5,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 2 3
}
virtualList.value.unshift(newItem)
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
if (status == 0) {
console.log(data);
resolve({
type: 'video',
url: data.ori_url,
cover: data.cover_url,
src: fileUrl,
success: (resp) => {
console.log(resp)
form.append('file', file)
form.append('source', 'fonchain-chat')
form.append('type', 'video')
form.append('urlParam', `width=${resp.width}&height=${resp.height}`)
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
duration: parseInt(resp.duration),
size: file.size,
file_num: randomId,
})
} else {
// resolve('')
// message.error(msg)
height: resp.height,
name: '',
url: fileUrl,
width: resp.width,
},
float: 'right',
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 5,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 2 3
}
})
}
virtualList.value.unshift(newItem)
uploadImg(form, (e) => onProgressFn(e, randomId)).then(
({ status, data, msg }) => {
if (status == 0) {
console.log(data)
resolve({
type: 'video',
url: data.ori_url,
cover: data.cover_url,
duration: parseInt(resp.duration),
size: file.size,
file_num: randomId,
})
} else {
// resolve('')
// message.error(msg)
}
},
)
},
})
const form = new FormData()
}
@ -209,132 +243,181 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
const base64ToFile = (base64) => {
// base64file
const [header, base64String] = base64.split(";base64,");
const imageType = header.split(":")[1];
const byteCharacters = atob(base64String);
const [header, base64String] = base64.split(';base64,')
const imageType = header.split(':')[1]
const byteCharacters = atob(base64String)
const byteArray = new Uint8Array(
Array.from(byteCharacters, (char) => char.charCodeAt(0))
);
return new File(
[new Blob([byteArray], { type: imageType })],
"example.png",
{ type: imageType }
);
Array.from(byteCharacters, (char) => char.charCodeAt(0)),
)
return new File([new Blob([byteArray], { type: imageType })], 'example.png', {
type: imageType,
})
}
const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
window.plus?.gallery.pick((res) => {
console.log(res);
res.files.reverse()
res.files.forEach(async (filePath) => {
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
if (['jpg', 'png'].includes(suffix)) {
console.log("进入图片")
window.plus?.io?.resolveLocalFileSystemURL(filePath, async (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader();
fileReader.readAsDataURL(file);
fileReader.onloadend = async (e) => {
const base64Url = e.target.result;
const fileObj = base64ToFile(base64Url);
let data = await onUploadImageVideo(fileObj, 'image')
emit('selectImg', data)
};
})
},
(err) => {
console.log(err);
}
)
}
if (['mp4', 'flv'].includes(suffix)) {
console.log(filePath,"进入视频")
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
// console.log(localUrl);
plus.io.getVideoInfo({
filePath:filePath,
success:(event)=>{
console.log(event);
},
fail:(err)=>{
console.log(err);
window.plus?.gallery.pick(
(res) => {
console.log(res)
res.files.reverse()
res.files.forEach(async (filePath) => {
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
if (['jpg', 'png'].includes(suffix)) {
console.log('进入图片')
window.plus?.io?.resolveLocalFileSystemURL(
filePath,
async (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.readAsDataURL(file)
fileReader.onloadend = async (e) => {
const base64Url = e.target.result
const fileObj = base64ToFile(base64Url)
let data = await onUploadImageVideo(fileObj, 'image')
emit('selectImg', data)
}
})
},
(err) => {
console.log(err)
},
)
}
});
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
// entry.file((file) => {
// console.log(file,'file');
// const fileReader = new plus.io.FileReader();
// fileReader.readAsDataURL(file);
// fileReader.onloadend = async (e) => {
// const base64Url = e.target.result;
// const fileObj = base64ToFile(base64Url);
// let data = await onUploadImageVideo(fileObj, 'video')
// emit('selectImg', data)
// };
// })
// },
// (err) => {
// console.log(err);
// }
// )
}
})
}, (err) => {
console.log(err);
},
if (['mp4', 'flv'].includes(suffix)) {
console.log(filePath, '进入视频')
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
// console.log(localUrl);
plus.io.getVideoInfo({
filePath: filePath,
success: (event) => {
console.log(event)
},
fail: (err) => {
console.log(err)
},
})
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
// entry.file((file) => {
// console.log(file,'file');
// const fileReader = new plus.io.FileReader();
// fileReader.readAsDataURL(file);
// fileReader.onloadend = async (e) => {
// const base64Url = e.target.result;
// const fileObj = base64ToFile(base64Url);
// let data = await onUploadImageVideo(fileObj, 'video')
// emit('selectImg', data)
// };
// })
// },
// (err) => {
// console.log(err);
// }
// )
}
})
},
(err) => {
console.log(err)
},
{
filter: filter,
maximum: maximum,
multiple: multiple,
}
},
)
}
const takePhoto = () => {
if (typeof plus !== 'undefined') {
getCamera()
} else {
document.addEventListener('plusready', () => {
getCamera()
})
}
}
const chooseFile = () => {
uni.chooseFile({
count: 1,
extension:[''],
success: (res) => {
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
drive: 3,
name: res.tempFiles[0].name,
size: res.tempFiles[0].size,
path: res.tempFilePaths[0],
},
float: "right",
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 6,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 2 3
}
virtualList.value.unshift(newItem)
uploadsStore.initUploadFile(res.tempFiles[0], props.talkParams,randomId)
}
const getCamera = () => {
const cmr = plus.camera.getCamera()
cmr.captureImage(
(p) => {
plus.io.resolveLocalFileSystemURL(
p,
(entry) => {
compressAndShowImage(entry.toLocalURL(), entry.name)
},
(err) => {
console.log(err)
},
)
},
() => {},
{ index: '2' },
)
}
const compressAndShowImage = (url, filename) => {
const dst = `_doc/upload/${filename}`
plus.zip.compressImage(
{ src: url, dst, quality: 10, overwrite: true },
(zip) => displayImage(zip.target),
(err) => {
console.log(err)
},
)
}
const displayImage = (url) => {
plus.io.resolveLocalFileSystemURL(url, (entry) => {
entry.file((file) => {
const fileReader = new plus.io.FileReader()
fileReader.readAsDataURL(file)
fileReader.onloadend = async (e) => {
state.base64Url = e.target.result
const imageFile = base64ToFile(state.base64Url)
let data = await onUploadImageVideo(imageFile, 'image')
emit('selectImg', data, data.file_num)
}
})
})
}
const chooseFile = () => {
uni.chooseFile({
count: 1,
extension: [''],
success: (res) => {
let randomId = uniqueId()
let newItem = {
avatar: userStore.avatar,
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
extra: {
drive: 3,
name: res.tempFiles[0].name,
size: res.tempFiles[0].size,
path: res.tempFilePaths[0],
},
float: 'right',
isCheck: false,
is_mark: 0,
is_read: 0,
is_revoke: 0,
msg_id: randomId,
file_num: randomId,
msg_type: 6,
nickname: userStore.nickname,
receiver_id: dialogueStore.talk.receiver_id,
sequence: -1,
talk_type: dialogueStore.talk.talk_type,
user_id: userStore.uid,
uploadCurrent: 0,
uploadStatus: 1, // 1 2 3
}
virtualList.value.unshift(newItem)
uploadsStore.initUploadFile(res.tempFiles[0], props.talkParams, randomId)
},
})
}
</script>
<style lang="scss" scoped>
.emojiRoot {

File diff suppressed because it is too large Load Diff

View File

@ -136,7 +136,7 @@ const cellClick = () => {
});
}
uni.navigateTo({
url: `/pages/dialog/index?sessionId=${props.data.id}&talkType=${props.data.talk_type}&receiverId=${props.data.receiver_id}&indexName=${props.data.index_name}`,
url: `/pages/dialog/index?sessionId=${props.data.id}`,
});
};

View File

@ -250,7 +250,7 @@ onLoad((options) => {
})
}
uni.navigateTo({
url: `/pages/dialog/index?sessionId=${openSession.id}&talkType=${openSession.talk_type}&receiverId=${openSession.receiver_id}&indexName=${openSession.index_name}`,
url: `/pages/dialog/index?sessionId=${openSession.id}`,
})
}
})

View File

@ -99,11 +99,26 @@ import { beautifyTime } from '@/utils/datetime'
const { t } = useI18n()
const props = defineProps({
searchItem: Object | Number,
searchResultKey: String,
searchText: String, //
searchRecordDetail: Boolean, //
pointerIconSrc: String, //
conditionType: Number, //
searchResultKey: {
type: String,
default: '',
},
searchText: {
type: String,
default: '',
}, //
searchRecordDetail: {
type: Boolean,
default: false,
}, //
pointerIconSrc: {
type: String,
default: '',
}, //
conditionType: {
type: Number,
default: 0,
}, //
})
// -
const keyMapping = {
@ -193,10 +208,8 @@ const imgText = computed(() => {
})
// -groupType
const groupTypeMapping = {
0: {
},
1: {
},
0: {},
1: {},
2: {
result_type: t('index.mine.department'),
result_type_color: '#377EC6',

View File

@ -19,6 +19,7 @@
'font-size': '28rpx',
'font-weight': 400,
}"
:refresher-enabled="false"
>
<template #top>
<div class="searchRoot">
@ -139,14 +140,37 @@ const state = reactive({
})
const props = defineProps({
searchResultPageSize: Number, //
listLimit: Boolean, //
apiParams: String, //
searchResultPageSize: {
type: Number,
default: 0,
}, //
listLimit: {
type: Boolean,
default: false,
}, //
apiParams: {
type: String,
default: '',
}, //
apiRequest: Function, //
searchText: String, //
isPagination: Boolean, //
searchRecordDetail: Boolean, //
first_talk_record_infos: Object, //
searchText: {
type: String,
default: '',
}, //
isPagination: {
type: Boolean,
default: false,
}, //
searchRecordDetail: {
type: Boolean,
default: false,
}, //
first_talk_record_infos: {
type: Object,
default() {
return {}
},
}, //
})
const { t } = useI18n()
@ -276,7 +300,11 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
)
let total = data.count
if (props.searchRecordDetail) {
total = data.group_record_count
if(state?.first_talk_record_infos?.talk_type === 1){
total = data.user_record_count
} else if (state?.first_talk_record_infos?.talk_type === 2){
total = data.group_record_count
}
}
zPaging.value?.completeByTotal([data], total)
} else {
@ -366,6 +394,12 @@ const getHasMoreResult = (searchResultKey) => {
}
break
case 'general_infos':
if (
state.searchResult['record_count'] &&
state.searchResult['record_count'] > 3
) {
has_more_result = t('has_more') + t('chat.type.record')
}
break
default:
}
@ -379,12 +413,40 @@ const toMoreResultPage = (searchResultKey) => {
//
const clickSearchItem = (searchResultKey, searchItem) => {
console.log(searchResultKey, searchItem)
let talk_type = searchItem.talk_type
let receiver_id = searchItem.receiver_id
if (searchResultKey === 'user_infos') {
talk_type = 1
receiver_id = searchItem.id
} else if (searchResultKey === 'combinedGroup') {
talk_type = searchItem.type || 2
receiver_id = searchItem.group_id || searchItem.id
} else if (searchResultKey === 'general_infos') {
if (searchItem.talk_type === 1) {
if (searchItem.user_id === state.uid) {
//
}
if (searchItem.receiver_id === state.uid) {
//
let temp_id = searchItem.receiver_id
let temp_name = searchItem.receiver_name
let temp_avatar = searchItem.receiver_avatar
searchItem.receiver_id = searchItem.user_id
searchItem.receiver_name = searchItem.user_name
searchItem.receiver_avatar = searchItem.user_avatar
searchItem.user_id = temp_id
searchItem.user_name = temp_name
searchItem.user_avatar = temp_avatar
}
}
}
emits(
'clickSearchItem',
state.searchText,
searchResultKey,
searchItem.talk_type,
searchItem.receiver_id,
talk_type,
receiver_id,
encodeURIComponent(JSON.stringify(searchItem)),
)
}

View File

@ -13,7 +13,7 @@
</template>
<script setup>
import searchList from './components/searchList.vue'
import { ServeSeachQueryAll } from '@/api/search/index'
import { ServeSeachQueryAll, ServeGetSessionId } from '@/api/search/index'
import { onMounted } from 'vue'
import { handleSetWebviewStyle } from '@/utils/common'
@ -37,7 +37,7 @@ const toMoreResultPage = (searchResultKey, searchText) => {
}
//
const clickSearchItem = (
const clickSearchItem = async (
searchText,
searchResultKey,
talk_type,
@ -47,17 +47,25 @@ const clickSearchItem = (
console.log(searchResultKey)
const result = JSON.parse(decodeURIComponent(res))
console.log(result)
console.log(talk_type, receiver_id)
const sessionId = await getSessionId(talk_type, receiver_id)
if (searchResultKey === 'user_infos') {
dialogueStore.setDialogue({
name: result.nickname,
talk_type: 1,
receiver_id: receiver_id,
})
uni.navigateTo({
url: '/pages/dialog/index?sessionId=' + sessionId,
})
} else if (searchResultKey === 'combinedGroup') {
dialogueStore.setDialogue({
name: result.name || result.group_name,
talk_type: result.type || 2,
receiver_id: result.id || result.group_id,
receiver_id: result.group_id || result.id,
})
uni.navigateTo({
url: '/pages/dialog/index',
url: '/pages/dialog/index?sessionId=' + sessionId
})
} else if (searchResultKey === 'general_infos') {
uni.navigateTo({
@ -71,5 +79,25 @@ const clickSearchItem = (
})
}
}
//Id
const getSessionId = (talk_type, receiver_id) => {
return new Promise((resolve, reject) => {
let params = {
talkType: talk_type,
receiverId: receiver_id,
}
const resp = ServeGetSessionId(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
resolve(data?.sessionId)
} else {
}
})
resp.catch(() => {})
})
}
</script>
<style scoped lang="scss"></style>

View File

@ -21,6 +21,7 @@ import {
ServeQueryUser,
ServeQueryGroup,
ServeTalkRecord,
ServeGetSessionId,
} from '@/api/search/index'
import { reactive } from 'vue'
@ -30,9 +31,9 @@ const dialogueStore = useDialogueStore()
const state = reactive({
apiRequest: Function,
apiParams: String,
searchText: String,
searchResultKey: String,
apiParams: '',
searchText: '',
searchResultKey: '',
})
onLoad((options) => {
@ -90,7 +91,7 @@ const lastIdChange = (last_id, last_group_id, last_member_id) => {
}
//
const clickSearchItem = (
const clickSearchItem = async (
searchText,
searchResultKey,
talk_type,
@ -100,21 +101,57 @@ const clickSearchItem = (
console.log(state.searchResultKey)
const result = JSON.parse(decodeURIComponent(res))
console.log(result)
console.log(talk_type, receiver_id)
const sessionId = await getSessionId(talk_type, receiver_id)
if (state.searchResultKey === 'user_infos') {
dialogueStore.setDialogue({
name: result.nickname,
talk_type: 1,
receiver_id: receiver_id,
})
uni.navigateTo({
url: '/pages/dialog/index?sessionId=' + sessionId,
})
} else if (state.searchResultKey === 'combinedGroup') {
dialogueStore.setDialogue({
name: result.name || result.group_name,
talk_type: result.type || 2,
receiver_id: result.id || result.group_id,
receiver_id: result.group_id || result.id,
})
uni.navigateTo({
url: '/pages/dialog/index',
url: '/pages/dialog/index?sessionId=' + sessionId,
})
} else if (state.searchResultKey === 'general_infos') {
uni.navigateTo({
url: '/pages/search/moreResult/moreResultDetail?searchText=' + searchText,
url:
'/pages/search/moreResult/moreResultDetail?searchText=' +
searchText +
'&talk_type=' +
talk_type +
'&receiver_id=' +
receiver_id,
})
}
}
//Id
const getSessionId = (talk_type, receiver_id) => {
return new Promise((resolve, reject) => {
let params = {
talkType: talk_type,
receiverId: receiver_id,
}
const resp = ServeGetSessionId(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
resolve(data?.sessionId)
} else {
}
})
resp.catch(() => {})
})
}
</script>
<style scoped lang="scss"></style>

View File

@ -27,8 +27,8 @@ const dialogueStore = useDialogueStore()
const userStore = useUserStore()
const state = reactive({
apiParams: String,
searchText: String,
apiParams: '',
searchText: '',
uid: computed(() => userStore.uid), //id
})

View File

@ -64,7 +64,8 @@
v-if="
state.condition === 'imgAndVideo' ||
state.condition === 'file' ||
state.condition === 'link'
state.condition === 'link' ||
state.condition === 'member'
"
:style="{
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
@ -72,7 +73,11 @@
>
<div
class="search-by-condition-input"
v-if="state.condition === 'file' || state.condition === 'link'"
v-if="
state.condition === 'file' ||
state.condition === 'link' ||
state.condition === 'member'
"
>
<customInput
:searchText="state.searchText"
@ -173,6 +178,7 @@
</div>
<div
class="condition-each-result-attachments"
@click="previewPDF(item)"
v-if="
state.condition === 'file' || state.condition === 'link'
"
@ -255,7 +261,7 @@ import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZ
import { parseTime } from '@/utils/datetime'
import { onMounted, reactive, computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { ServeTalkDate } from '@/api/search/index'
import { ServeTalkDate, ServeGetSessionId } from '@/api/search/index'
import { ServeFindTalkRecords } from '@/api/chat/index'
import { useDialogueStore } from '@/store'
import { useI18n } from 'vue-i18n'
@ -273,7 +279,6 @@ const dialogueParams = reactive({
let nowDay = new Date().setHours(0, 0, 0, 0)
const state = reactive({
receiver_id: '', //id
pageTitle: '', //
dateStyle: [], //
nowDate: new Date(nowDay), //
@ -289,16 +294,16 @@ const state = reactive({
searchResultList: [], //
cursor: 0, //
msg_type: 0, //
group_member_id: 0, //id
})
onLoad((options) => {
console.log(options)
if (options.receiver_id) {
state.receiver_id = Number(options.receiver_id)
}
if (options.condition) {
state.condition = options.condition
if (options.condition === 'date') {
if (options.condition === 'member') {
// queryAllSearch()
} else if (options.condition === 'date') {
state.showPageTitle = true
state.pageTitle = t('search.condition.date')
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
@ -352,7 +357,7 @@ const ServeQueryTalkDate = (month) => {
let params = {
month: month,
talk_type: dialogueParams.talk_type, //12
receiver_id: state.receiver_id, //id
receiver_id: dialogueParams.receiver_id, //id
}
const resp = ServeTalkDate(params)
console.log(resp)
@ -387,7 +392,7 @@ const ServeQueryTalkDate = (month) => {
}
//
const selectDate = (e) => {
const selectDate = async (e) => {
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
console.log('==今日')
state.dateStyle = [
@ -413,6 +418,37 @@ const selectDate = (e) => {
},
]
}
const sessionId = await getSessionId(
dialogueParams.talk_type,
dialogueParams.receiver_id,
)
uni.navigateTo({
url:
'/pages/dialog/index?sessionId=' +
sessionId +
'&recordDate=' +
parseTime(e, '{y}-{m}-{d}'),
})
}
//Id
const getSessionId = (talk_type, receiver_id) => {
return new Promise((resolve, reject) => {
let params = {
talkType: talk_type,
receiverId: receiver_id,
}
const resp = ServeGetSessionId(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
resolve(data?.sessionId)
} else {
}
})
resp.catch(() => {})
})
}
//
@ -466,7 +502,7 @@ const queryAllSearch = () => {
direction: 'up', //downup
start_time: '',
end_time: '',
group_member_user_id: 0, //id
group_member_user_id: state.group_member_id, //id
file_name: state.msg_type === 6 ? state.searchText : '',
}
console.log(params)
@ -564,6 +600,43 @@ const fileTypeAvatar = (fileType) => {
}
return file_type_avatar
}
const previewPDF = (item) => {
console.log(item)
if (typeof plus !== 'undefined') {
downloadAndOpenFile(item)
} else {
document.addEventListener('plusready', () => {
downloadAndOpenFile(item)
})
}
}
const downloadAndOpenFile = (item) => {
uni.showLoading({ title: '加载中...', mask: true })
const downloadUrl = item?.extra?.path
const options = {
filename: '_doc/downloads/', //
}
const dtask = plus.downloader.createDownload(downloadUrl, options, function (
d,
status,
) {
if (status === 200) {
uni.hideLoading()
const filePath = d.filename
plus.runtime.openFile(
filePath,
{},
function () {},
function (error) {},
)
} else {
uni.hideLoading()
}
})
dtask.start()
}
</script>
<style scoped lang="scss">
.search-by-date {
@ -670,6 +743,7 @@ body::v-deep .round-3 {
span {
line-height: 40rpx;
color: $theme-text;
word-break: break-all;
}
}
.attachment-sub-info {