fix
Some checks failed
Check / lint (push) Has been cancelled
Check / typecheck (push) Has been cancelled
Check / build (build, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Has been cancelled
Some checks failed
Check / lint (push) Has been cancelled
Check / typecheck (push) Has been cancelled
Check / build (build, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Has been cancelled
This commit is contained in:
parent
7101d1cd25
commit
1213ad9b98
335
src/components/deep-bubble/deep-bubble.vue
Normal file
335
src/components/deep-bubble/deep-bubble.vue
Normal file
@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<div id="popover" ref="bubbleRef" class="ui-popover">
|
||||
<view
|
||||
:id="popoverBoxId"
|
||||
class="popover-box"
|
||||
@touchend="onTouchend"
|
||||
@touchstart="onTouchstart"
|
||||
>
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- mode -->
|
||||
<view
|
||||
@click.stop="close(50)"
|
||||
:id="popoverContentId"
|
||||
class="popover-content"
|
||||
:style="data.showStyle"
|
||||
>
|
||||
<div class="menu">
|
||||
<div
|
||||
class="w-full h-[132rpx] text-[24rpx] text-[#FFFFFF] flex items-center justify-around"
|
||||
>
|
||||
<div
|
||||
v-if="props.isShowCopy"
|
||||
@click="() => itemClick('actionCopy')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="copy07"></tm-image>
|
||||
<div>复制</div>
|
||||
</div>
|
||||
<div
|
||||
@click="() => itemClick('multipleChoose')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image
|
||||
:width="40"
|
||||
:height="40"
|
||||
:src="multipleChoices"
|
||||
></tm-image>
|
||||
<div>多选</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.isShowCite"
|
||||
@click="() => itemClick('actionCite')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="cite"></tm-image>
|
||||
<div>引用</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.isShowWithdraw"
|
||||
@click="() => itemClick('actionWithdraw')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="withdraw"></tm-image>
|
||||
<div>撤回</div>
|
||||
</div>
|
||||
<div
|
||||
@click="() => itemClick('actionDelete')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="delete07"></tm-image>
|
||||
<div>删除</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="data.iconStyle" class="icon"></div>
|
||||
</div>
|
||||
</view>
|
||||
<view
|
||||
v-show="data.popoverShow"
|
||||
@touchstart="close"
|
||||
@click="close"
|
||||
class="popover-bg"
|
||||
></view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 组件
|
||||
|
||||
// uniapp & vue
|
||||
import { onLoad, onReady } from "@dcloudio/uni-app";
|
||||
import { defineEmits, defineProps } from "vue";
|
||||
import {
|
||||
reactive,
|
||||
ref,
|
||||
watch,
|
||||
computed,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
onBeforeUnmount
|
||||
} from "vue";
|
||||
import copy07 from "@/static/image/chatList/copy07@2x.png";
|
||||
import multipleChoices from "@/static/image/chatList/multipleChoices@2x.png";
|
||||
import cite from "@/static/image/chatList/cite@2x.png";
|
||||
import withdraw from "@/static/image/chatList/withdraw@2x.png";
|
||||
import delete07 from "@/static/image/chatList/delete@2x.png";
|
||||
|
||||
// pinia
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const bubbleRef = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
isShowCopy: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isShowCite: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isShowWithdraw: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(["clickMenu"]);
|
||||
|
||||
/**
|
||||
* @name 生成UUID
|
||||
*/
|
||||
const uuid = () => {
|
||||
const reg = /[xy]/g;
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
.replace(reg, function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
})
|
||||
.replace(/-/g, "");
|
||||
};
|
||||
|
||||
const popoverBoxId = `ID${uuid()}`;
|
||||
const popoverContentId = `ID${uuid()}`;
|
||||
const instance = getCurrentInstance();
|
||||
const data = reactive({
|
||||
popoverShow: false,
|
||||
defaultStyle: {},
|
||||
showStyle: {
|
||||
left: 0,
|
||||
right: "",
|
||||
transform: "",
|
||||
},
|
||||
iconStyle: {
|
||||
left: "",
|
||||
right: "",
|
||||
transform: "",
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @name 获取DOM
|
||||
*/
|
||||
const getDom = (dom) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(instance);
|
||||
let select = query.select(dom);
|
||||
const boundingClientRect = select.boundingClientRect((data) => {
|
||||
resolve(data);
|
||||
});
|
||||
boundingClientRect.exec();
|
||||
});
|
||||
};
|
||||
|
||||
const itemClick = (item) => {
|
||||
emits("clickMenu", item);
|
||||
};
|
||||
|
||||
// 弹起 长按5
|
||||
let pressDownTime = 0;
|
||||
let time = null;
|
||||
const onTouchstart = () => {
|
||||
time && clearTimeout(time);
|
||||
time = setTimeout(open, 500);
|
||||
};
|
||||
|
||||
const onTouchend = () => {
|
||||
time && clearTimeout(time);
|
||||
};
|
||||
|
||||
const open = async () => {
|
||||
let popoverContent = await getDom(`#${popoverContentId}`);
|
||||
let popoverBox = await getDom(`#${popoverBoxId}`);
|
||||
|
||||
// 缩放中心点
|
||||
let originX = popoverBox.width / 2;
|
||||
// 根据距离 初始化位置 判断是顶部还是底部
|
||||
let isTop = popoverBox.top - 50 > popoverContent.height;
|
||||
// 上面还是下面
|
||||
data.defaultStyle = {
|
||||
top: isTop ? "60rpx" : "auto",
|
||||
bottom: !isTop ? "-20rpx" : "auto",
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(.8)`,
|
||||
};
|
||||
// 左边还是右边
|
||||
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
||||
data.defaultStyle.right = 0;
|
||||
// 动画缩放中心点
|
||||
data.defaultStyle["transform-origin"] = `${
|
||||
popoverContent.width - originX
|
||||
}px ${isTop ? "100%" : "0%"}`;
|
||||
} else {
|
||||
data.defaultStyle.left = 0;
|
||||
// 动画缩放中心点
|
||||
data.defaultStyle["transform-origin"] = `${originX}px ${
|
||||
isTop ? "100%" : "0%"
|
||||
}`;
|
||||
}
|
||||
data.showStyle = { ...data.defaultStyle };
|
||||
// icon位置样式
|
||||
let iconDefsultStyle = {
|
||||
transform: `translate(0%, ${isTop ? "20%" : "-20%"})`,
|
||||
"border-top-color": isTop ? "#333333" : "",
|
||||
"border-bottom-color": !isTop ? "#333333" : "",
|
||||
top: !isTop ? "-20rpx" : "auto",
|
||||
bottom: isTop ? "-20rpx" : "auto",
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
||||
data.showStyle = {
|
||||
// 位置
|
||||
...data.defaultStyle,
|
||||
// 显示
|
||||
opacity: 1,
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
||||
"pointer-events": "auto",
|
||||
};
|
||||
data.iconStyle = {
|
||||
right: `${originX}px`,
|
||||
left: "auto",
|
||||
...iconDefsultStyle,
|
||||
};
|
||||
} else {
|
||||
data.showStyle = {
|
||||
// 位置
|
||||
...data.defaultStyle,
|
||||
// 显示
|
||||
opacity: 1,
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
||||
"pointer-events": "auto",
|
||||
};
|
||||
data.iconStyle = {
|
||||
left: `${originX}px`,
|
||||
right: "auto",
|
||||
...iconDefsultStyle,
|
||||
};
|
||||
}
|
||||
|
||||
if (!data.popoverShow) data.popoverShow = true;
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const close = (time) => {
|
||||
setTimeout(() => {
|
||||
data.popoverShow = false;
|
||||
data.showStyle = data.defaultStyle;
|
||||
}, time || 0);
|
||||
};
|
||||
const handleClickOutside = (event) => {
|
||||
if (data.popoverShow = false) {
|
||||
return false
|
||||
}
|
||||
if (bubbleRef.value && !bubbleRef.value.contains(event.target)) {
|
||||
close();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ui-popover {
|
||||
position: relative;
|
||||
.popover-box {
|
||||
width: fit-content;
|
||||
}
|
||||
.popover-content {
|
||||
width: fit-content;
|
||||
transition: all 0.2s;
|
||||
z-index: 5;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.popover-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 526rpx;
|
||||
height: 132rpx;
|
||||
display: flex;
|
||||
background-color: #333333;
|
||||
display: flex;
|
||||
color: #fff;
|
||||
border-radius: 15rpx;
|
||||
font-size: 26rpx;
|
||||
padding: 0 10rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
.icon {
|
||||
border: 15rpx solid transparent;
|
||||
position: absolute;
|
||||
}
|
||||
.item {
|
||||
flex: 1;
|
||||
height: 120rpx;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
image {
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -63,7 +63,10 @@ const getFileTypeIMG = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="file-message" :class="{ left: data.float === 'left' }">
|
||||
<section
|
||||
class="file-message"
|
||||
: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">
|
||||
{{ extra.name }}
|
||||
@ -109,13 +112,18 @@ const getFileTypeIMG = computed(() => {
|
||||
padding: 28rpx 30rpx 22rpx 30rpx;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
border-radius: 0;
|
||||
|
||||
&.left {
|
||||
background-color: #fff;
|
||||
border-radius: 0 16rpx 16rpx 16rpx;
|
||||
}
|
||||
|
||||
&.right {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: 45px;
|
||||
display: flex;
|
||||
|
@ -16,11 +16,14 @@ const title = computed(() => {
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
isShowRecord.value = true
|
||||
// isShowRecord.value = true
|
||||
uni.navigateTo({
|
||||
url: '/pages/forwardRecord/index?msgId=' + props.data.msg_id
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="im-message-forward pointer" @click="onClick">
|
||||
<section class="im-message-forward pointer" :class="{ left: data.float === 'left' }" @click="onClick">
|
||||
<div class="title">{{ title }} 的会话记录</div>
|
||||
<div class="list" v-for="(record, index) in extra.records" :key="index">
|
||||
<p>
|
||||
@ -28,57 +31,70 @@ const onClick = () => {
|
||||
<span>{{ record.text }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="tips">
|
||||
<span>转发:聊天会话记录 ({{ extra.msg_ids.length }}条)</span>
|
||||
</div>
|
||||
|
||||
<ForwardRecord v-if="isShowRecord" :msg-id="data.msg_id" @close="isShowRecord = false" />
|
||||
<!-- <ForwardRecord v-if="isShowRecord" :msg-id="data.msg_id" @close="isShowRecord = false" /> -->
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.im-message-forward {
|
||||
width: 250px;
|
||||
min-height: 95px;
|
||||
max-height: 150px;
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--im-message-border-color);
|
||||
user-select: none;
|
||||
width: 486rpx;
|
||||
min-height: 180rpx;
|
||||
max-height: 274rpx;
|
||||
border-radius: 0;
|
||||
background-color: #FFFFFF;
|
||||
padding: 22rpx 28rpx 22rpx 30rpx;
|
||||
&.left {
|
||||
background-color: #fff;
|
||||
border-radius: 0 16rpx 16rpx 16rpx;
|
||||
}
|
||||
&.right {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 15px;
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
font-size: 32rpx;
|
||||
color: #1A1A1A;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 400;
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.list p {
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
color: #a8a8a8;
|
||||
height: 34rpx;
|
||||
line-height: 34rpx;
|
||||
font-size: 24rpx;
|
||||
color: #B4B4B4;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.tips {
|
||||
height: 32px;
|
||||
line-height: 35px;
|
||||
color: #8a8888;
|
||||
border-top: 1px solid var(--border-color);
|
||||
font-size: 12px;
|
||||
margin-top: 12px;
|
||||
height: 34rpx;
|
||||
line-height: 34rpx;
|
||||
color: #747474;
|
||||
font-size: 24rpx;
|
||||
margin-top: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background-color: #E7E7E7;
|
||||
}
|
||||
</style>
|
||||
|
@ -52,14 +52,12 @@ const img = computed(() => {
|
||||
<template>
|
||||
<section
|
||||
class="im-message-image"
|
||||
:class="{ left: data.float === 'left' }"
|
||||
:class="{
|
||||
left: data.float === 'left',
|
||||
right: data.float === 'right'
|
||||
}"
|
||||
>
|
||||
<div class="image-container">
|
||||
<!-- <image
|
||||
:src="extra.url"
|
||||
mode="scaleToFill"
|
||||
:width="img.width" :height="img.height"
|
||||
/> -->
|
||||
<tm-image preview :width="img.width" :height="img.height" :src="extra.url" />
|
||||
<wd-circle custom-class="circleProgress" v-if="props.data.uploadCurrent && props.data.uploadCurrent<100" v-model="props.data.uploadCurrent" color="#ffffff" layer-color="#E3E3E3"></wd-circle>
|
||||
</div>
|
||||
@ -69,15 +67,21 @@ const img = computed(() => {
|
||||
.im-message-image {
|
||||
overflow: hidden;
|
||||
padding: 20rpx 18rpx;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
background-color: #46299D;
|
||||
border-radius: 0;
|
||||
background-color: #fff;
|
||||
min-width: 40rpx;
|
||||
min-height: 40rpx;
|
||||
max-width: 532rpx;
|
||||
|
||||
&.left {
|
||||
background-color: #fff;
|
||||
border-radius: 0 16rpx 16rpx 16rpx;
|
||||
}
|
||||
|
||||
&.right {
|
||||
background-color: #46299D;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
}
|
||||
}
|
||||
.image-container {
|
||||
position: relative;
|
||||
|
@ -78,7 +78,13 @@ const img = (src: string, width = 200) => {
|
||||
padding: 20rpx 18rpx;
|
||||
color: #000000;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 0 16rpx 16rpx 16rpx;
|
||||
border-radius: 0;
|
||||
|
||||
&.left{
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border-radius: 0 16rpx 16rpx 16rpx;
|
||||
}
|
||||
|
||||
&.right {
|
||||
background-color: #46299D;
|
||||
|
@ -2,12 +2,16 @@
|
||||
import {ref,nextTick} from 'vue'
|
||||
import WdPopup from "@/uni_modules/wot-design-uni/components/wd-popup/wd-popup.vue";
|
||||
import TmButton from "@/uni_modules/tmui/components/tm-button/tm-button.vue";
|
||||
import {language} from "@/uni_modules/tmui/tool/lib/language"
|
||||
const confirmState=ref(false)
|
||||
const cancel=ref(true)
|
||||
let onConfirm=null
|
||||
let onCancel=null
|
||||
const confirm=ref(true)
|
||||
const contentText=ref('')
|
||||
const imageRef=ref('')
|
||||
const confirmLabel=ref(language('components.confirm.confirmText'))
|
||||
const cancelLabel=ref(language('components.confirm.cancelText'))
|
||||
const sendCancel=()=>{
|
||||
confirmState.value=false
|
||||
if (typeof onCancel==='function'){
|
||||
@ -20,31 +24,70 @@ const sendConfirm=()=>{
|
||||
onConfirm()
|
||||
}
|
||||
}
|
||||
const showConfirm=({content,onConfirm:confirm,onCancel:cancel})=>{
|
||||
const showConfirm=({content,image,onConfirm:confirm,onCancel:cancel,confirmText,cancelText})=>{
|
||||
confirmState.value=true
|
||||
contentText.value=content
|
||||
imageRef.value = image?image:''
|
||||
onConfirm=confirm
|
||||
onCancel=cancel
|
||||
confirmLabel.value = confirmText || confirmLabel.value
|
||||
cancelLabel.value = cancelText || cancelLabel.value
|
||||
}
|
||||
defineExpose({
|
||||
showConfirm
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<wd-popup custom-style="border-radius: 16rpx;" modal-style="background-color: rgba(0,0,0,0.3);" v-model="confirmState">
|
||||
<div class="flex flex-col w-[640rpx] h-[402rpx]">
|
||||
<div class="flex justify-center items-center h-[288rpx] text-[32rpx] font-bold text-[#1A1A1A]">
|
||||
<wd-popup custom-style="border-radius: 16rpx;" modal-style="background-color: #000000;opacity: 0.6;" v-model="confirmState">
|
||||
<div class="flex flex-col w-[640rpx]">
|
||||
<div v-if="imageRef===''" class="flex justify-center items-center h-[288rpx] text-[32rpx] font-bold text-[#1A1A1A]">
|
||||
{{contentText}}
|
||||
</div>
|
||||
<div v-else class="flex flex-col items-center h-[456rpx] text-[32rpx] font-bold text-[#1A1A1A]" >
|
||||
<div class="wrap1 mt-[32rpx] mb-[44rpx]" >
|
||||
<img :src="imageRef" alt="">
|
||||
</div>
|
||||
<div class="mb-[56rpx]" > {{contentText}} </div>
|
||||
</div>
|
||||
<div class="flex flex-grow border-t-solid border-[#E7E7E7] border-1rpx text-[32rpx]">
|
||||
<div class="flex justify-center items-center text-[#1A1A1A]">
|
||||
<tm-button @click="sendCancel" :width="319" @touchstart="cancel=false" @touchend="cancel=true" :fontSize="32" :height="112" :margin="[0]" :font-color="'#1A1A1A'" :transprent="cancel" text label="取消"></tm-button>
|
||||
<tm-button
|
||||
@click="sendCancel"
|
||||
:width="319"
|
||||
@touchstart="cancel=false"
|
||||
@touchend="cancel=true"
|
||||
:fontSize="32"
|
||||
:height="112"
|
||||
:margin="[0]"
|
||||
:font-color="'#1A1A1A'"
|
||||
:transprent="cancel"
|
||||
text
|
||||
:label="cancelLabel"></tm-button>
|
||||
</div>
|
||||
<div class="h-[112rpx] w-[1rpx] bg-[#E7E7E7]"></div>
|
||||
<div class="flex justify-center items-center text-[#CF3050]">
|
||||
<tm-button @click="sendConfirm" @touchstart="confirm=false" @touchend="confirm=true" :width="319" :fontSize="32" :transprent="confirm" :height="112" :margin="[0]" :font-color="'#46299D'" text label="确定"></tm-button>
|
||||
<tm-button
|
||||
@click="sendConfirm"
|
||||
@touchstart="confirm=false"
|
||||
@touchend="confirm=true"
|
||||
:width="319"
|
||||
:fontSize="32"
|
||||
:transprent="confirm"
|
||||
:height="112"
|
||||
:margin="[0]"
|
||||
:font-color="'#46299D'"
|
||||
text
|
||||
:label="confirmLabel"></tm-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wd-popup>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.wrap1 {
|
||||
img {
|
||||
width: 381.59rpx;
|
||||
height: 280.14rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -30,6 +30,14 @@
|
||||
"enablePullDownRefresh":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/forwardRecord/index",
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"type": "page",
|
||||
|
@ -127,7 +127,7 @@ const handleOk = () => {
|
||||
let user_ids = []
|
||||
let group_ids = []
|
||||
|
||||
for (let o of selectItems.value) {
|
||||
for (let o of selectItemsModal.value) {
|
||||
if (o.talk_type == 1) {
|
||||
user_ids.push(o.receiver_id)
|
||||
} else {
|
||||
@ -141,6 +141,7 @@ const handleOk = () => {
|
||||
uids: user_ids,
|
||||
gids: group_ids
|
||||
})
|
||||
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
<div class="dialogBox">
|
||||
<ZPaging :fixed="false" use-chat-record-mode :use-page-scroll="false" :refresher-enabled="false"
|
||||
:show-scrollbar="false" :loading-more-enabled="false" :hide-empty-view="true" height="100%" ref="zpagingRef"
|
||||
:use-virtual-list="true" :preload-page="1" cell-height-mode="dynamic"
|
||||
:use-virtual-list="true" :preload-page="1" cell-height-mode="dynamic" virtual-scroll-fps="80"
|
||||
:loading-more-custom-style="{ display: 'none', height: '0' }" @virtualListChange="virtualListChange"
|
||||
@scrolltolower="onRefreshLoad">
|
||||
<!-- <template #top>
|
||||
@ -70,35 +70,15 @@
|
||||
</div>
|
||||
|
||||
<div class="talk-content" :class="{ pointer: dialogueStore.isOpenMultiSelect }">
|
||||
<tm-popover :position="item.float == 'left' ? 'tl' : 'tr'" :width="526" color="#333333">
|
||||
<component :key="item.zp_index" :is="MessageComponents[item.msg_type] || 'unknown-message'"
|
||||
:extra="item.extra" :data="item" :max-width="true" :source="'panel'"
|
||||
@click="onContextMenu(item)" />
|
||||
<template v-slot:label>
|
||||
<div class="w-full h-[132rpx] text-[24rpx] text-[#FFFFFF] flex items-center justify-around">
|
||||
<div @click="() => actionCopy(item)" class="flex flex-col items-center justify-center">
|
||||
<tm-image :width="40" :height="40" :src="copy07"></tm-image>
|
||||
<div>复制</div>
|
||||
</div>
|
||||
<div @click="() => multipleChoose(item)" class="flex flex-col items-center justify-center">
|
||||
<tm-image :width="40" :height="40" :src="multipleChoices"></tm-image>
|
||||
<div>多选</div>
|
||||
</div>
|
||||
<div @click="() => actionCite(item)" class="flex flex-col items-center justify-center">
|
||||
<tm-image :width="40" :height="40" :src="cite"></tm-image>
|
||||
<div>引用</div>
|
||||
</div>
|
||||
<div @click="() => actionWithdraw(item)" class="flex flex-col items-center justify-center">
|
||||
<tm-image :width="40" :height="40" :src="withdraw"></tm-image>
|
||||
<div>撤回</div>
|
||||
</div>
|
||||
<div @click="() => actionDelete(item)" class="flex flex-col items-center justify-center">
|
||||
<tm-image :width="40" :height="40" :src="delete07"></tm-image>
|
||||
<div>删除</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</tm-popover>
|
||||
<deepBubble
|
||||
@clickMenu="(menuType) => onContextMenu(menuType, item)"
|
||||
:isShowCopy="isShowCopy(item)"
|
||||
:isShowWithdraw="isRevoke(talkParams.uid,item)"
|
||||
>
|
||||
<component class="component-content" :key="item.zp_index"
|
||||
:is="MessageComponents[item.msg_type] || 'unknown-message'" :extra="item.extra" :data="item"
|
||||
:max-width="true" :source="'panel'" />
|
||||
</deepBubble>
|
||||
<!-- <div class="talk-tools">
|
||||
<template v-if="talkParams.type == 1 && item.float == 'right'">
|
||||
<loading theme="outline" size="19" fill="#000" :sxtrokeWidth="1" class="icon-rotate"
|
||||
@ -192,7 +172,15 @@ import { QuillEditor, Quill } from '@vueup/vue-quill'
|
||||
import EmojiBlot from './formats/emoji'
|
||||
import { useChatList } from "@/store/chatList/index.js";
|
||||
import { useAuth } from "@/store/auth";
|
||||
import { useUserStore, useDialogueStore, useUploadsStore, useEditorDraftStore, useTalkStore, useSettingsStore, useDialogueListStore } from '@/store'
|
||||
import {
|
||||
useUserStore,
|
||||
useDialogueStore,
|
||||
useUploadsStore,
|
||||
useEditorDraftStore,
|
||||
useTalkStore,
|
||||
useSettingsStore,
|
||||
useDialogueListStore
|
||||
} from '@/store'
|
||||
import addCircleGray from "@/static/image/chatList/addCircleGray.png";
|
||||
import { MessageComponents, ForwardableMessageType } from '@/constant/message'
|
||||
import { formatTime, parseTime } from '@/utils/datetime'
|
||||
@ -216,6 +204,9 @@ import zu6050 from "@/static/image/chatList/zu6050@2x.png"
|
||||
import zu6051 from "@/static/image/chatList/zu6051@2x.png"
|
||||
import zu6052 from "@/static/image/chatList/zu6052@2x.png"
|
||||
import zu6053 from "@/static/image/chatList/zu6053@2x.png"
|
||||
import deepBubble from "@/components/deep-bubble/deep-bubble.vue"
|
||||
import {isRevoke } from './menu'
|
||||
|
||||
|
||||
|
||||
Quill.register('formats/emoji', EmojiBlot)
|
||||
@ -349,6 +340,22 @@ const getQuill = () => {
|
||||
return editor.value?.getQuill()
|
||||
}
|
||||
|
||||
const isShowCopy = (item) => {
|
||||
switch (item.msg_type) {
|
||||
case 1:
|
||||
return true
|
||||
case 3:
|
||||
return true
|
||||
case 5:
|
||||
return true
|
||||
case 6:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const selectedMessage = computed(() => {
|
||||
return virtualList.value.filter(item => item.isCheck)
|
||||
})
|
||||
@ -488,8 +495,28 @@ const virtualListChange = (vList) => {
|
||||
virtualList.value = vList
|
||||
}
|
||||
|
||||
const onContextMenu = (item) => {
|
||||
console.log(item, 'item');
|
||||
const onContextMenu = (menuType, item) => {
|
||||
console.log(menuType, item, 'item');
|
||||
switch (menuType) {
|
||||
case 'actionCopy':
|
||||
actionCopy(item)
|
||||
break;
|
||||
case 'multipleChoose':
|
||||
multipleChoose(item)
|
||||
break;
|
||||
case 'actionCite':
|
||||
actionCite(item)
|
||||
break;
|
||||
case 'actionWithdraw':
|
||||
actionWithdraw(item)
|
||||
break;
|
||||
case 'actionDelete':
|
||||
actionDelete(item)
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const actionCopy = (item) => {
|
||||
@ -519,16 +546,19 @@ const multipleChoose = (item) => {
|
||||
dialogueStore.setMultiSelect(true)
|
||||
}
|
||||
|
||||
const actionCite = () => {
|
||||
const actionCite = (item) => {
|
||||
console.log('引用');
|
||||
}
|
||||
|
||||
const actionWithdraw = () => {
|
||||
const actionWithdraw = (item) => {
|
||||
console.log('撤回');
|
||||
dialogueStore.ApiRevokeRecord(item.msg_id)
|
||||
}
|
||||
|
||||
const actionDelete = () => {
|
||||
const actionDelete = (item) => {
|
||||
console.log('删除');
|
||||
item.isCheck = true
|
||||
handleDelete()
|
||||
}
|
||||
|
||||
const handleMergeForward = () => {
|
||||
@ -551,6 +581,14 @@ const handleSingleForward = () => {
|
||||
return message.warning('未选择消息')
|
||||
}
|
||||
console.log('逐条转发');
|
||||
dialogueStore.setForwardType(1)
|
||||
dialogueStore.setForwardMessages(selectedMessage.value)
|
||||
uni.navigateTo({
|
||||
url: '/pages/chooseChat/index',
|
||||
success: function (res) {
|
||||
clearMultiSelect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleWechatForward = () => {
|
||||
@ -565,6 +603,10 @@ const handleDelete = () => {
|
||||
return message.warning('未选择消息')
|
||||
}
|
||||
console.log('删除');
|
||||
const msgIds = selectedMessage.value.map(item => item.msg_id)
|
||||
virtualList.value = virtualList.value.filter(item => !msgIds.includes(item.msg_id))
|
||||
dialogueStore.ApiDeleteRecord(msgIds)
|
||||
clearMultiSelect()
|
||||
}
|
||||
|
||||
|
||||
@ -898,4 +940,10 @@ page {
|
||||
:deep(.wd-action-sheet__panel-title) {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.component-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
/* 确保 z-index 低于 deepBubble */
|
||||
}
|
||||
</style>
|
||||
|
68
src/pages/dialog/menu.ts
Normal file
68
src/pages/dialog/menu.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { reactive } from 'vue'
|
||||
|
||||
interface IDropdown {
|
||||
options: any[]
|
||||
show: boolean
|
||||
x: number
|
||||
y: number
|
||||
item: any
|
||||
}
|
||||
|
||||
export const isRevoke = (uid: any, item: any): boolean => {
|
||||
if (uid != item.user_id) {
|
||||
return false
|
||||
}
|
||||
|
||||
const datetime = item.created_at.replace(/-/g, '/')
|
||||
|
||||
const time = new Date().getTime() - Date.parse(datetime)
|
||||
|
||||
return Math.floor(time / 1000 / 60) <= 2
|
||||
}
|
||||
|
||||
export function useMenu() {
|
||||
const dropdown: IDropdown = reactive({
|
||||
options: [],
|
||||
show: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: {}
|
||||
})
|
||||
|
||||
const showDropdownMenu = (e: any, uid: number, item: any) => {
|
||||
dropdown.item = Object.assign({}, item)
|
||||
|
||||
dropdown.options = []
|
||||
if ([1, 3].includes(item.msg_type)) {
|
||||
dropdown.options.push({ label: '复制', key: 'copy' })
|
||||
}
|
||||
|
||||
if (isRevoke(uid, item)) {
|
||||
dropdown.options.push({ label: `撤回`, key: 'revoke' })
|
||||
}
|
||||
|
||||
dropdown.options.push({ label: '回复', key: 'quote' })
|
||||
dropdown.options.push({ label: '删除', key: 'delete' })
|
||||
|
||||
dropdown.options.push({ label: '多选', key: 'multiSelect' })
|
||||
|
||||
if ([3, 4, 5].includes(item.msg_type)) {
|
||||
dropdown.options.push({ label: '下载', key: 'download' })
|
||||
}
|
||||
|
||||
if ([3].includes(item.msg_type)) {
|
||||
dropdown.options.push({ label: '收藏', key: 'collect' })
|
||||
}
|
||||
|
||||
dropdown.x = e.clientX
|
||||
dropdown.y = e.clientY
|
||||
dropdown.show = true
|
||||
}
|
||||
|
||||
const closeDropdownMenu = () => {
|
||||
dropdown.show = false
|
||||
dropdown.item = {}
|
||||
}
|
||||
|
||||
return { dropdown, showDropdownMenu, closeDropdownMenu }
|
||||
}
|
129
src/pages/forwardRecord/index.vue
Normal file
129
src/pages/forwardRecord/index.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ServeGetForwardRecords } from '@/api/chat'
|
||||
import { MessageComponents } from '@/constant/message'
|
||||
import { ITalkRecord } from '@/types/chat'
|
||||
import WdLoading from "@/uni_modules/wot-design-uni/components/wd-loading/wd-loading.vue";
|
||||
import { useInject } from '@/hooks'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const msgId = ref(null)
|
||||
const { showUserInfoModal } = useInject()
|
||||
const isShow = ref(true)
|
||||
const items = ref<ITalkRecord[]>([])
|
||||
const title = ref('会话记录')
|
||||
|
||||
const onMaskClick = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const onLoadData = () => {
|
||||
ServeGetForwardRecords({
|
||||
msg_id: msgId.value
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
items.value = res.data.items || []
|
||||
|
||||
title.value = [...new Set(items.value.map((v) => v.nickname))].join('、')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const pages = getCurrentPages()
|
||||
const page = pages[pages.length - 1]
|
||||
const options = page.$page.options
|
||||
msgId.value = options.msgId
|
||||
console.log(msgId.value,'msgId.value');
|
||||
|
||||
onLoadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="outer-layer">
|
||||
<div>
|
||||
<tm-navbar :hideBack="false" hideHome :title="`${title}的会话记录`" >
|
||||
</tm-navbar>
|
||||
</div>
|
||||
<div class="main-box">
|
||||
<div v-if="items.length === 0" class="flex justify-center items-center w-full mt-[200rpx]">
|
||||
<wd-loading />
|
||||
</div>
|
||||
<div v-else v-for="item in items" :key="item.msg_id" class="message-item">
|
||||
<div class="left-box" @click="showUserInfoModal(item.user_id)">
|
||||
<tm-image v-if="item.avatar !==''" :width="80" :height="80" :round="12" :src="item.avatar"></tm-image>
|
||||
<div v-else class="w-[80rpx] h-[80rpx] text-[28rpx] text-[#fff] bg-[#46299D] leading-[40rpx] rounded-[40rpx] flex justify-center items-center">{{ item.nickname.slice(-2) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="right-box">
|
||||
<div class="msg-header">
|
||||
<span class="name">{{ item.nickname }}</span>
|
||||
<span class="time"> {{ item.created_at }}</span>
|
||||
</div>
|
||||
|
||||
<component
|
||||
:is="MessageComponents[item.msg_type] || 'unknown-message'"
|
||||
:extra="item.extra"
|
||||
:data="item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.outer-layer {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
background-image: url("@/static/image/clockIn/z3280@3x.png");
|
||||
background-size: cover;
|
||||
padding: 0 66rpx 20rpx 50rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.main-box {
|
||||
flex:1;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding-top: 28rpx;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
min-height: 60rpx;
|
||||
display: flex;
|
||||
margin-bottom: 44rpx;
|
||||
|
||||
.left-box {
|
||||
width: 80rpx;
|
||||
display: flex;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.right-box {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
padding-left: 22rpx;
|
||||
box-sizing: border-box;
|
||||
height: fit-content;
|
||||
|
||||
.msg-header {
|
||||
height: 34rpx;
|
||||
line-height: 34rpx;
|
||||
width: 526rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
175
src/pages/forwardRecord/util.ts
Normal file
175
src/pages/forwardRecord/util.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import { Delta } from '@vueup/vue-quill'
|
||||
|
||||
interface Item {
|
||||
type: number
|
||||
content: string
|
||||
}
|
||||
|
||||
interface AnalysisResp {
|
||||
items: Item[]
|
||||
mentions: any[]
|
||||
mentionUids: number[]
|
||||
msgType: number // 1 文本;2:图片;3图文混合消息
|
||||
quoteId: string // 引用的消息ID
|
||||
}
|
||||
|
||||
function removeLeadingNewlines(str: string) {
|
||||
return str.replace(/^[\n\s]+/, '')
|
||||
}
|
||||
|
||||
function removeTrailingNewlines(str: string) {
|
||||
return str.replace(/[\n\s]+$/, '')
|
||||
}
|
||||
|
||||
export function deltaToMessage(delta: Delta): AnalysisResp {
|
||||
const resp: AnalysisResp = {
|
||||
items: [],
|
||||
mentions: [],
|
||||
mentionUids: [],
|
||||
quoteId: '',
|
||||
msgType: 1
|
||||
}
|
||||
|
||||
for (const iterator of delta.ops) {
|
||||
const insert: any = iterator.insert
|
||||
|
||||
let node: any = null
|
||||
if (resp.items.length) {
|
||||
node = resp.items[resp.items.length - 1]
|
||||
}
|
||||
|
||||
if (typeof insert === 'string') {
|
||||
if (!insert || insert == '\n') continue
|
||||
|
||||
if (node && node.type == 1) {
|
||||
node.content = node.content + insert
|
||||
continue
|
||||
}
|
||||
|
||||
resp.items.push({
|
||||
type: 1,
|
||||
content: insert
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// @好友
|
||||
if (insert && insert.mention) {
|
||||
const mention = insert.mention
|
||||
|
||||
resp.mentions.push({
|
||||
name: `${mention.denotationChar}${mention.value}`,
|
||||
atid: parseInt(mention.id)
|
||||
})
|
||||
|
||||
if (node && node.type == 1) {
|
||||
node.content = node.content + ` ${mention.denotationChar}${mention.value}`
|
||||
continue
|
||||
}
|
||||
|
||||
resp.items.push({
|
||||
type: 1,
|
||||
content: `${mention.denotationChar}${mention.value}`
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// 图片
|
||||
if (insert && insert.image) {
|
||||
resp.items.push({
|
||||
type: 3,
|
||||
content: insert.image
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// 表情
|
||||
if (insert && insert.emoji) {
|
||||
const { emoji } = insert
|
||||
|
||||
if (node && node.type == 1) {
|
||||
node.content = node.content + emoji.alt
|
||||
continue
|
||||
}
|
||||
|
||||
resp.items.push({
|
||||
type: 1,
|
||||
content: emoji.alt
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (insert && insert.quote) {
|
||||
resp.quoteId = insert.quote.id
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 去除前后多余空格
|
||||
if (resp.items.length) {
|
||||
if (resp.items[0].type == 1) {
|
||||
resp.items[0].content = removeLeadingNewlines(resp.items[0].content)
|
||||
}
|
||||
|
||||
if (resp.items[resp.items.length - 1].type == 1) {
|
||||
resp.items[resp.items.length - 1].content = removeTrailingNewlines(
|
||||
resp.items[resp.items.length - 1].content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.items.length > 1) {
|
||||
resp.msgType = 12
|
||||
}
|
||||
|
||||
if (resp.items.length == 1) {
|
||||
resp.msgType = resp.items[0].type
|
||||
}
|
||||
|
||||
resp.mentionUids = resp.mentions.map((item) => item.atid)
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
export function deltaToString(delta: Delta): string {
|
||||
let content = ''
|
||||
|
||||
for (const o of delta.ops) {
|
||||
const insert: any = o.insert
|
||||
|
||||
if (typeof insert === 'string') {
|
||||
if (!insert || insert == '\n') continue
|
||||
|
||||
content += insert
|
||||
continue
|
||||
}
|
||||
|
||||
// @好友
|
||||
if (insert && insert.mention) {
|
||||
const { mention } = insert
|
||||
content += ` ${mention.denotationChar}${mention.value} `
|
||||
continue
|
||||
}
|
||||
|
||||
// 图片
|
||||
if (insert && insert.image) {
|
||||
content += '[图片]'
|
||||
continue
|
||||
}
|
||||
|
||||
// 表情
|
||||
if (insert && insert.emoji) {
|
||||
content += insert.emoji.alt
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
export function isEmptyDelta(delta: Delta): boolean {
|
||||
return delta.ops.length == 1 && delta.ops[0].insert == '\n'
|
||||
}
|
@ -1,53 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<wd-swipe-action>
|
||||
<div @click="cellClick" :class="['chatItem', props.data.is_top === 1 ? 'isTop' : '']">
|
||||
<div
|
||||
@click="cellClick"
|
||||
:class="['chatItem', props.data.is_top === 1 ? 'isTop' : '']"
|
||||
>
|
||||
<div class="avatarImg">
|
||||
<tm-badge :count="props.data.unread_num" :maxCount="99" color="#D03050">
|
||||
<tm-image :width="96" :height="96" :round="12" :src="props.data.avatar"></tm-image>
|
||||
<tm-badge
|
||||
:count="props.data.unread_num"
|
||||
:maxCount="99"
|
||||
color="#D03050"
|
||||
>
|
||||
<tm-image
|
||||
:width="96"
|
||||
:height="96"
|
||||
:round="12"
|
||||
:src="avatarCpt"
|
||||
></tm-image>
|
||||
</tm-badge>
|
||||
</div>
|
||||
<div class="chatInfo">
|
||||
<div class="chatInfo_1">
|
||||
<div class="flex items-center">
|
||||
<div class="text-[#000000] text-[32rpx] font-bold opacity-90">{{ props.data.name }}</div>
|
||||
<div class="text-[#000000] text-[32rpx] font-bold opacity-90">
|
||||
{{ props.data.name }}
|
||||
</div>
|
||||
<div>
|
||||
<div class="companyTag">公司</div>
|
||||
<div v-if="props.data.group_type === 2" class="depTag">
|
||||
部门
|
||||
</div>
|
||||
<div v-if="props.data.group_type === 3" class="projectTag">
|
||||
项目
|
||||
</div>
|
||||
<div v-if="props.data.group_type === 4" class="companyTag">
|
||||
公司
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[#000000] text-[28rpx] font-medium opacity-26">{{ beautifyTime(props.data.updated_at) }}
|
||||
<div class="text-[#000000] text-[28rpx] font-medium opacity-26">
|
||||
{{ beautifyTime(props.data.updated_at) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="chatInfo_2 w-full mr-[6rpx]">
|
||||
<div class="w-full chatInfo_2_1 textEllipsis">{{ props.data.msg_text }}</div>
|
||||
<div class="w-full chatInfo_2_1 textEllipsis">
|
||||
{{ props.data.msg_text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #right>
|
||||
<div class="flex flex-row flex-row-center-end">
|
||||
<div @click="handleTop"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center">
|
||||
{{ props.data.is_top === 1 ? '取消置顶' : '置顶' }}</div>
|
||||
<div class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#CF3050] flex items-center justify-center">删除</div>
|
||||
<div
|
||||
@click="handleTop"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
|
||||
>
|
||||
{{ props.data.is_top === 1 ? "取消置顶" : "置顶" }}
|
||||
</div>
|
||||
<div
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#CF3050] flex items-center justify-center"
|
||||
>
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</wd-swipe-action>
|
||||
<div v-if="props.index !== talkStore.talkItems.length - 1" class="divider"></div>
|
||||
<div
|
||||
v-if="props.index !== talkStore.talkItems.length - 1"
|
||||
class="divider"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, defineProps } from "vue"
|
||||
import { ref, reactive, defineProps,computed } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { beautifyTime } from '@/utils/datetime'
|
||||
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
||||
import { useTalkStore, useDialogueStore } from '@/store'
|
||||
import { useSessionMenu } from '@/hooks'
|
||||
import { beautifyTime } from "@/utils/datetime";
|
||||
import { ServeClearTalkUnreadNum } from "@/api/chat";
|
||||
import { useTalkStore, useDialogueStore } from "@/store";
|
||||
import { useSessionMenu } from "@/hooks";
|
||||
import zu4989 from "@/static/image/chatList/zu4989@2x.png";
|
||||
import zu4991 from "@/static/image/chatList/zu4991@2x.png";
|
||||
import zu4992 from "@/static/image/chatList/zu4992@2x.png";
|
||||
import zu5296 from "@/static/image/chatList/zu5296@2x.png";
|
||||
|
||||
const talkStore = useTalkStore()
|
||||
const {
|
||||
onToTopTalk
|
||||
} = useSessionMenu()
|
||||
const dialogueStore = useDialogueStore()
|
||||
const talkStore = useTalkStore();
|
||||
const { onToTopTalk } = useSessionMenu();
|
||||
const dialogueStore = useDialogueStore();
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
@ -58,38 +95,58 @@ const props = defineProps({
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const avatarCpt = computed(() => {
|
||||
let avatar = null;
|
||||
if (props.data.avatar !== "") {
|
||||
avatar = props.data.avatar;
|
||||
} else {
|
||||
switch (props.data.group_type) {
|
||||
case 1:
|
||||
avatar = zu4992;
|
||||
break;
|
||||
case 2:
|
||||
avatar = zu4989;
|
||||
break;
|
||||
case 3:
|
||||
avatar = zu4991;
|
||||
break;
|
||||
case 4:
|
||||
avatar = zu5296;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return avatar;
|
||||
});
|
||||
|
||||
const cellClick = () => {
|
||||
console.log(props.data);
|
||||
// 更新编辑信息
|
||||
dialogueStore.setDialogue(props.data)
|
||||
dialogueStore.setDialogue(props.data);
|
||||
|
||||
// 清空消息未读数
|
||||
if (props.data.unread_num > 0) {
|
||||
ServeClearTalkUnreadNum({
|
||||
talk_type: props.data.talk_type,
|
||||
receiver_id: props.data.receiver_id
|
||||
receiver_id: props.data.receiver_id,
|
||||
}).then(() => {
|
||||
talkStore.updateItem({
|
||||
index_name: props.data.index_name,
|
||||
unread_num: 0
|
||||
})
|
||||
})
|
||||
unread_num: 0,
|
||||
});
|
||||
});
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/dialog/index',
|
||||
})
|
||||
}
|
||||
url: "/pages/dialog/index",
|
||||
});
|
||||
};
|
||||
|
||||
const handleTop = () => {
|
||||
console.log(props.data, 1);
|
||||
onToTopTalk(props.data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
onToTopTalk(props.data);
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chatItem {
|
||||
@ -100,7 +157,7 @@ const handleTop = () => {
|
||||
align-items: center;
|
||||
|
||||
&.isTop {
|
||||
background-color: #F3F3F3;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,17 +188,43 @@ const handleTop = () => {
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
opacity: 40%;
|
||||
|
||||
}
|
||||
|
||||
.companyTag {
|
||||
width: 76rpx;
|
||||
height: 38rpx;
|
||||
border: 1px solid #7A58DE;
|
||||
line-height: 38rpx;
|
||||
border: 1px solid #7a58de;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 6rpx;
|
||||
color: #7A58DE;
|
||||
color: #7a58de;
|
||||
font-weight: bold;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.depTag {
|
||||
width: 76rpx;
|
||||
height: 38rpx;
|
||||
line-height: 38rpx;
|
||||
border: 1px solid #377ec6;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 6rpx;
|
||||
color: #377ec6;
|
||||
font-weight: bold;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.projectTag {
|
||||
width: 76rpx;
|
||||
height: 38rpx;
|
||||
line-height: 38rpx;
|
||||
border: 1px solid #c1681c;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 6rpx;
|
||||
color: #c1681c;
|
||||
font-weight: bold;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {uniStorage} from "@/utils/uniStorage.js"
|
||||
import {ref} from 'vue'
|
||||
export const useAuth = createGlobalState(() => {
|
||||
// const token = useStorage('token', '', uniStorage)
|
||||
const token = ref('30119d9978a6f3321fb4779c0040e997df4dd0dd0cf6b71119657617d2249ed783f940b0050d5be7e758740ea467afdf3eeb4d28fb5ea234af60ebe51fb218ff6a0563074f3084b41c1bc8dc0733d06bfbb433a8d5a1d13eb6227adbf50a5da566a4cacdbf91899e563f10864fe2acfeee36e90ceb1aa03bbcca63f1bf5514d416827d0ea543bd8e02552fbd612d801b4b827977f6fe7d6201838456049083706a6e48004fc0ad99eddea3a8875f6583e959fd172a7cfb40f877bc0741a259520e9b6f524d04ee175bdc99c32eef4ef52c1ed38ed1034df8695c62ff44933644')
|
||||
const token = ref('30119d9978a6f3321fb4779c0040e997df4dd0dd0cf6b71119657617d2249ed783f940b0050d5be7e758740ea467afdf3eeb4d28fb5ea234af60ebe51fb218ff6a0563074f3084b41c1bc8dc0733d06bfbb433a8d5a1d13eb6227adbf50a5da566a4cacdbf91899e563f10864fe2acfe9526343f2c27f726448f6cf9ac172a9716f21a7079e22f4ded14f57418364bea07bfd33259ff97ca4c3c4a54cd90e529b1ac523444d29485f9ee637bb0ca5dfdd87125a1161291696084029bc0cc6bbcf690e3d99787d75eabd8906b6f79035c23391abf12bbabf10ab7b1a0ca998c38')
|
||||
const refreshToken = useStorage('refreshToken', '', uniStorage)
|
||||
const userInfo = useStorage('userInfo', {}, uniStorage)
|
||||
const leaderList = useStorage('leaderList', [], uniStorage)
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
} from '@/api/chat/index'
|
||||
import { ServeGetGroupMembers } from '@/api/group/index'
|
||||
import { useEditorStore } from './editor'
|
||||
import { useDialogueListStore } from './dialogueList'
|
||||
|
||||
// 键盘消息事件定时器
|
||||
// let keyboardTimeout = null
|
||||
@ -186,6 +187,7 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
|
||||
// 删除聊天记录
|
||||
ApiDeleteRecord(msgIds = []) {
|
||||
const { batchDelDialogueRecord } = useDialogueListStore()
|
||||
ServeRemoveRecords({
|
||||
talk_type: this.talk.talk_type,
|
||||
receiver_id: this.talk.receiver_id,
|
||||
@ -193,6 +195,7 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.batchDelDialogueRecord(msgIds)
|
||||
batchDelDialogueRecord(msgIds)
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
|
@ -103,6 +103,12 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
}
|
||||
}
|
||||
|
||||
const batchDelDialogueRecord=(msgIds)=>{
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
const item = getDialogueList(dialogue.index_name)
|
||||
item.records = item.records.filter(item=>!msgIds.includes(item.msg_id))
|
||||
}
|
||||
|
||||
return {
|
||||
dialogueList,
|
||||
zpagingRef,
|
||||
@ -115,5 +121,6 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
zpagingComplete,
|
||||
addChatRecord,
|
||||
virtualList,
|
||||
batchDelDialogueRecord,
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user