You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
apply-assistant-v3/pages/NEUIKit/pages/Conversation/conversation-list/conversation-item.vue

451 lines
12 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div
:class="[
'conversation-item-container',
{
'show-action-list': showMoreActions,
'stick-on-top': conversation.stickTop,
},
props.heihei,
]"
class="u-skeleton"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@click="handleConversationItemClick()"
>
<div class="conversation-item-content">
<div class="conversation-item-left">
<div class="unread" v-if="unread">
<div class="dot" v-if="isMute"></div>
<div class="badge" v-else>{{ unread }}</div>
</div>
<Avatar class="u-skeleton-fillet" :account="to" size="48" :avatar="teamAvatar" />
</div>
<div class="conversation-item-right">
<div class="conversation-item-top">
<Appellation class="conversation-item-title u-skeleton-fillet" fontSize="17" v-if="conversation.type === V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P" :account="to" />
<span v-else class="conversation-item-title u-skeleton-fillet">
{{ sessionName }}
</span>
<span class="conversation-item-time" :data-time="date">{{ date }}</span>
</div>
<div class="conversation-item-desc">
<span v-if="beMentioned" class="beMentioned u-skeleton-fillet">
{{ "[" + t("someoneText") + "@" + t("meText") + "]" }}
</span>
<!-- <ConversationItemIsRead v-if="showSessionUnread" :conversation="props.conversation"></ConversationItemIsRead> -->
<span class="conversation-item-desc-content">{{ lastMsgContent }}</span>
<Icon v-if="isMute" iconClassName="conversation-item-desc-state" type="icon-xiaoximiandarao" color="#ccc" />
</div>
</div>
</div>
<div class="right-action-list">
<div v-for="action in moreActions" :key="action.type" :class="['right-action-item', action.class]" @click="() => handleClick(action.type)">
{{ action.name }}
</div>
</div>
<u-skeleton :loading="loading" :animation="true" bgColor="#ededed"></u-skeleton>
</div>
</template>
<script lang="ts" setup>
import Avatar from "../../../components/Avatar.vue";
import Appellation from "../../../components/Appellation.vue";
import Icon from "../../../components/Icon.vue";
import { getMsgContentTipByType } from "../../../utils/msg";
import { computed, onUpdated, withDefaults, onMounted, ref } from "../../../utils/transformVue";
import dayjs from "dayjs";
import { t } from "../../../utils/i18n";
import { V2NIMConst } from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK";
import { V2NIMConversationForUI } from "@xkit-yx/im-store-v2/dist/types/types";
import ConversationItemIsRead from "./conversation-item-isRead.vue";
const props = withDefaults(
defineProps<{
conversation: V2NIMConversationForUI;
showMoreActions?: boolean;
loading: boolean;
heihei: "";
}>(),
{ showMoreActions: false }
);
let pageScroll = ref(false);
onMounted(() => {
uni.$on("pageScroll", (e: any) => {
console.log("pageScroll", e);
if (Math.abs(e.detail.deltaY) > 0) {
pageScroll.value = true;
}
});
});
const emit = defineEmits(["click", "delete", "stickyToTop", "leftSlide"]);
const moreActions = computed(() => {
return [
{
name: props.conversation.stickTop ? t("deleteStickTopText") : t("addStickTopText"),
class: "action-top",
type: "action-top",
},
{
name: t("deleteSessionText"),
class: "action-delete",
type: "action-delete",
},
];
});
const handleClick = (type: string) => {
if (type === "action-top") {
emit("stickyToTop", props.conversation);
} else {
emit("delete", props.conversation);
}
};
// 群头像
const teamAvatar = computed(() => {
if (props.conversation.type === V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM) {
const { avatar } = props.conversation;
return avatar;
}
});
// 对话方
const sessionName = computed(() => {
if (props.conversation.name) {
return props.conversation.name;
}
return props.conversation.conversationId;
});
// 会话最后一条消息内容
const lastMsgContent = computed(() => {
const lastMsg = props.conversation.lastMessage;
if (lastMsg) {
const { sendingState, messageType, lastMessageState } = lastMsg;
if (lastMessageState === V2NIMConst.V2NIMLastMessageState.V2NIM_MESSAGE_STATUS_REVOKE) {
return t("recall");
}
if (messageType === void 0) {
return "";
}
if (messageType === V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_NOTIFICATION) {
return t("conversationNotificationText");
}
if (sendingState === V2NIMConst.V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_SENDING) {
return "";
}
if (sendingState === V2NIMConst.V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_FAILED) {
return t("conversationSendFailText");
}
console.log("lastMsg", lastMsg);
let _str = "[多媒体]";
if (!lastMsg.text && lastMsg.attachment && lastMsg.attachment.raw) {
_str = "[职位] " + JSON.parse(lastMsg.attachment.raw).title;
}
if (!lastMsg.text && lastMsg.attachment && lastMsg.attachment.ext == ".mp3") {
_str = "[语音]";
}
if (!lastMsg.text && lastMsg.attachment && (lastMsg.attachment.ext == ".jpg" || lastMsg.attachment.ext == ".png" || lastMsg.attachment.ext == ".jpeg" || lastMsg.attachment.ext == ".gif")) {
_str = "[图片]";
}
console.log("lastMsg.text", lastMsg.text, " -- ", _str);
return getMsgContentTipByType({
messageType: lastMsg.messageType,
text: lastMsg.text ? lastMsg.text : _str,
});
}
return "";
});
const to = computed(() => {
const res = uni.$UIKitNIM.V2NIMConversationIdUtil.parseConversationTargetId(props.conversation.conversationId);
return res;
});
const date = computed(() => {
const now = dayjs();
// console.log(dayjs(props.conversation.lastMessage?.messageRefer.createTime).format('YYYY-MM-DD HH:mm') +"最后一条消息时间 ");
// console.log(dayjs(props.conversation.updateTime).format('YYYY-MM-DD HH:mm') +"更新时间 ");
const time = props.conversation.lastMessage?.messageRefer.createTime || props.conversation.updateTime;
// const time = props.conversation.updateTime;
if (!time) {
return "";
}
const messageTime = dayjs(time);
// 1. 刚刚1分钟内
if (now.diff(messageTime, "minute") < 1) {
return "刚刚";
}
// 2. 今天的时间,显示格式如 17:45
if (messageTime.isSame(now, "day")) {
return messageTime.format("HH:mm");
}
// 3. 昨天的时间,显示格式如 昨天 17:34
if (messageTime.isSame(now.subtract(1, "day"), "day")) {
return `昨天 ${messageTime.format("HH:mm")}`;
}
// 4. 同一年的日期,显示格式如 5月2日
if (messageTime.isSame(now, "year")) {
const month = messageTime.month() + 1;
const day = messageTime.date();
return `${month}${day}`;
}
// 5. 去年及更早的日期,显示格式如 2024年7月8日
const year = messageTime.year();
const month = messageTime.month() + 1;
const day = messageTime.date();
return `${year}${month}${day}`;
});
const max = 99;
const unread = computed(() => {
return props.conversation.unreadCount > 0 ? (props.conversation.unreadCount > max ? `${max}+` : props.conversation.unreadCount + "") : "";
});
const isMute = computed(() => {
return !!props.conversation.mute;
});
const beMentioned = computed(() => {
return !!props.conversation.beMentioned;
});
const showSessionUnread = computed(() => {
const myUserAccountId = uni.$UIKitNIM.V2NIMLoginService.getLoginUser();
if (props.conversation.type === V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P) {
return props?.conversation?.lastMessage?.messageRefer.senderId === myUserAccountId && props?.conversation?.lastMessage?.messageType !== V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_CALL && props?.conversation?.lastMessage?.messageType !== V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_NOTIFICATION && props?.conversation?.lastMessage?.sendingState === V2NIMConst.V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_SUCCEEDED && props?.conversation?.lastMessage?.lastMessageState !== V2NIMConst.V2NIMLastMessageState.V2NIM_MESSAGE_STATUS_REVOKE;
} else {
return false;
}
});
// 左滑显示 action 动画
let startX = 0,
startY = 0;
// 开始左滑
function handleTouchStart(event: TouchEvent) {
startX = event.changedTouches[0].pageX;
startY = event.changedTouches[0].pageY;
pageScroll.value = false;
}
function handleTouchMove(event: TouchEvent) {
const moveEndX = event.changedTouches[0].pageX;
const moveEndY = event.changedTouches[0].pageY;
const X = moveEndX - startX;
const Y = moveEndY - startY;
// console.log("X", X, "Y", Y);
console.log("pageScroll.value", pageScroll.value);
if (Math.abs(Y) > Math.abs(X) || pageScroll.value == true) {
return;
}
const horizontalThreshold = 50;
const verticalThreshold = 50;
if (Math.abs(X) > Math.abs(Y) && Math.abs(X) > verticalThreshold) {
if (X < -horizontalThreshold) {
emit("leftSlide", props.conversation);
// emit("leftSlide", null);
} else if (X > horizontalThreshold) {
// emit("leftSlide", props.conversation);
emit("leftSlide", null);
}
}
}
function handleConversationItemClick() {
if (props.showMoreActions) {
emit("leftSlide", null);
return;
}
emit("click", props.conversation);
}
onUpdated(() => {
console.log("onUpdated", props.conversation.unreadCount);
});
</script>
<style lang="scss" scoped>
$cellHeight: 72px;
.conversation-item-container {
position: relative;
transition: transform 0.3s;
background-color: #fff;
padding: 0 10px;
&.show-action-list {
transform: translateX(-200px);
}
&.stick-on-top {
background: #efefef;
}
.beMentioned {
color: #ff4d4f;
}
.content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.right-action-list {
position: absolute;
top: 0;
right: -200px;
bottom: 0;
width: 200px;
.right-action-item {
width: 100px;
display: inline-block;
color: #fff;
text-align: center;
height: $cellHeight;
line-height: $cellHeight;
}
.action-top {
background: #337eff;
}
.action-delete {
background: #fa9d3b;
}
}
.conversation-item-content {
display: flex;
align-items: center;
padding: 10px 16px;
height: $cellHeight;
box-sizing: border-box;
// background-color: #fff;
}
.conversation-item-left {
position: relative;
.conversation-item-badge {
position: absolute;
top: 0px;
right: 0px;
z-index: 10;
}
}
.conversation-item-right {
flex: 1;
width: 0;
margin-left: 10px;
&:after {
content: "";
display: block;
height: 1rpx;
width: calc(100% - 80px);
background: #eee;
position: absolute;
top: 0;
right: 0;
}
}
.mmp0 .conversation-item-right::after {
height: 0;
}
.conversation-item-top {
margin-bottom: 5px;
display: flex;
justify-content: space-between;
align-items: center;
.conversation-item-title {
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //溢出用省略号显示
white-space: nowrap; //溢出不换行
}
.conversation-item-time {
font-size: 12px;
color: #cccccc;
text-align: right;
width: 90px;
flex-shrink: 0;
}
}
.conversation-item-desc {
font-size: 14px;
color: #999;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.conversation-item-desc-content {
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //溢出用省略号显示
white-space: nowrap; //溢出不换行
flex: 1;
}
.conversation-item-desc-state {
margin-left: 10px;
}
}
.dot {
background-color: #ff4d4f;
color: #fff;
width: 10px;
height: 10px;
border-radius: 5px;
box-sizing: border-box;
z-index: 99;
}
.badge {
background-color: #ff4d4f;
color: #fff;
font-size: 12px;
min-width: 20px;
height: 20px;
line-height: 19px;
border-radius: 10px;
padding: 0 5px;
box-sizing: border-box;
text-align: center;
z-index: 99;
position: relative;
}
.unread {
position: absolute;
right: -4px;
top: -2px;
z-index: 99;
}
</style>