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/components/conversationList.vue

393 lines
15 KiB
Vue

2 weeks ago
<template>
6 days ago
<view class="g_pb_24 rcosa">
6 days ago
<div style="width: calc(100vw - 20px);margin: 10px auto;border-radius: 8px;">
<div v-for="(item, index) in machineList" :key="index" class="customitem imitems g_bg_f">
<Tooltip ref="tooltipRef" color="white" :isSelf="true" :top="150">
<div class="g_flex_row_start" hover-class="thover" style="padding: 12px 16px" @click="goChatPage(item)" :style="{ backgroundColor: item.stickTop ? '#f5f5f5' : '#fff' }">
<div
class="g_flex_none"
style="border-radius: 50%; width: 48px; height: 48px; background-size: cover; background-repeat: no-repeat; position: relative"
:style="{
'background-image': item.userinfo && item.userinfo[0].avatar ? 'url(' + item.userinfo[0].avatar + ')' : 'none',
}"
>
<div v-if="item.waitcount" style="position: absolute; right: -6px; top: -6px; background-color: #f5222d; width: 20px; height: 20px; border-radius: 50%; text-align: center; line-height: 20px; font-size: 12px; color: #fff">
{{ item.waitcount > 99 ? "99+" : item.waitcount }}
2 weeks ago
</div>
6 days ago
<div style="position: absolute;bottom: 0;left: 50%;transform: translateX(-50%);width: 36px;height: 16px;border-radius: 4px;color: #ffffff;line-height: 16px;"
:style="{
'backgroundColor':index == 0 ? '#0091FF' : '#6ED400'
}"
v-if="index == 0 || index == 1"
class="g_flex_row_center"
>
<div style="width: 100%;height: 100%;position: relative;">
<div style="font-size: 12px;zoom: 0.75;text-align: center;position: absolute;top: 50%;left: 50%;transform: translateX(-50%) translateY(-50%);">
{{index == 0 ? '上游' : '下游'}}
</div>
</div>
2 weeks ago
</div>
</div>
6 days ago
<div class="bottom-line g_flex_column_center g_flex_1" style="padding-left: 10px">
<div class="g_fs_17 g_flex_row_between" v-if="item.userinfo && item.userinfo[0].name">
<div class="g_ell_1 g_flex_1" style="color: #333;font-size: 16px;">
{{ item.userinfo[0].name }} <span v-if="item.subtitle" style="color: orange;font-size: 14px;position: relative;top: -1px;">@{{ item.subtitle }}</span>
</div>
<div class="g_flex_none g_fs_12 g_ml_10" style="color: #999">
{{ item.time }}
</div>
2 weeks ago
</div>
6 days ago
<!-- 普通文本 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="item.lastMessage && item.lastMessage.messageType == 0">
{{ item.lastMessage.text }}
2 weeks ago
</div>
6 days ago
<!-- tip通知 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="item.lastMessage && item.lastMessage.messageType == 10">
2 weeks ago
{{ item.lastMessage.text }}
</div>
6 days ago
<!-- 图片消息 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="item.lastMessage && item.lastMessage.messageType == 1 && item.lastMessage.attachment && item.lastMessage.attachment.raw">[]</div>
<!-- 图片消息 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="item.lastMessage && item.lastMessage.messageType == 3 && item.lastMessage.attachment && item.lastMessage.attachment.raw">[]</div>
<!-- 自定义消息 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="item.lastMessage && item.lastMessage.messageType == 100 && item.lastMessage.attachment && item.lastMessage.attachment.raw">
<!-- 100001 商家后台 职位卡片 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).type == 100001">
{{ JSON.parse(item.lastMessage.attachment.raw).obj.jobName }}
</div>
<!-- 1000011 职位列表 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).type == 100011">[]</div>
<!-- 200001 系统提醒 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).type == 200001">
用户[
<span class="viewdetails">
{{ item.lastMessage && item.lastMessage.attachment && item.lastMessage.attachment.raw && JSON.parse(item.lastMessage.attachment.raw).userName }}
</span>
]询单需要人工介入请尽快回复
</div>
<!-- 200002 系统通知 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).type == 200002">
<span class="">
{{ item.lastMessage && item.lastMessage.text }}
</span>
</div>
<!-- 未知 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).name">
{{ JSON.parse(item.lastMessage.attachment.raw).name }}
</div>
<!-- 未知 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).type == 100002">
{{ "工单" }}
</div>
<!-- 常用回复 -->
<div v-if="JSON.parse(item.lastMessage.attachment.raw).typs == 'msg'">
{{ item.lastMessage.text }}
</div>
<!-- 100000 移动端职位卡片 -->
<div v-else>
{{ JSON.parse(item.lastMessage.attachment.raw).title }}
</div>
2 weeks ago
</div>
6 days ago
<!-- 暂无新消息 -->
<div class="g_fs_14 g_ell_1" style="color: #999; font-size: 12px" v-if="!item.lastMessage"></div>
2 weeks ago
</div>
</div>
6 days ago
<template #content>
<view class="g_fs_16" style="">
<view class="g_flex_column_center g_h_32" @click="topMessage(item, index)">
<view>{{ item.stickTop ? "取消置顶" : "置顶消息" }} </view>
</view>
<view class="g_flex_column_center g_h_32" @click="deleteMessage(item, index)">
<view>不显示</view>
</view>
2 weeks ago
</view>
6 days ago
</template>
</Tooltip>
</div>
2 weeks ago
</div>
</view>
6 days ago
<view class="" v-if="machineList && machineList.length == 0">
<view
style="width: calc(100% - 20px); margin: 0 auto"
class=""
:style="{
'padding-top': '260rpx',
}"
>
<rh-empty text="暂无消息"></rh-empty>
</view>
</view>
2 weeks ago
<view v-show="firstLoad" style="position: fixed; width: 100%; height: 100vh; left: 0px; top: 0px; z-index: 9" class="u-skeleton">
<view v-for="i in 10" :key="i" style="width: 100%; height: 72px; padding: 16px 12px" class="g_flex_row_between">
<view class="u-skeleton-fillet g_w_48 g_h_48 g_mr_8"> </view>
<view class="g_flex_1">
<view class="u-skeleton-fillet g_w_all g_h_20"></view>
<view class="u-skeleton-fillet g_w_all g_h_20 g_mt_4"></view>
</view>
</view>
<!-- </template> -->
</view>
<u-skeleton :loading="firstLoad" :animation="true" el-color="#ededed" bg-color="#fff"></u-skeleton>
</template>
<script setup>
import { ref, onMounted, onUnmounted, getCurrentInstance, watch, defineEmits, defineProps } from "vue";
const props = defineProps({});
const G = getCurrentInstance().appContext.app.config.globalProperties.G;
import Tooltip from "./Tooltip.vue";
const tooltipRef = ref(null);
let firstLoad = ref(false);
const machineList = ref([]);
onMounted(async () => {
uni.$on("updateConversationList", () => {
console.log("监听到事件");
getConversationListAndHideLoading();
});
uni.$on("deleteConversationList", (conversationIds) => {
console.log("监听到事件");
machineList.value.splice(
machineList.value.findIndex((item) => item.conversationId === conversationIds[0]),
1,
);
});
if (uni.getStorageSync("apply-token")) {
await checkLoginStatusAndGetConversations();
}
});
// 抽离:获取会话列表并隐藏加载的核心逻辑
const getConversationListAndHideLoading = async () => {
try {
const result = await G.nim.V2NIMConversationService.getConversationList(0, 100);
console.log("会话列表获取成功", JSON.parse(JSON.stringify(result)));
if (result.conversationList && result.conversationList.length > 0) {
await Promise.all(
result.conversationList.map(async (item, index) => {
item.userinfo = await G.nim.V2NIMUserService.getUserListFromCloud([item.conversationId.split("|")[2]]);
console.log("debg item.conversationId", item.conversationId);
item.waitcount = await G.nim.V2NIMConversationService.getUnreadCountByIds([item.conversationId]);
if (item.userinfo[0].serverExtension) {
item.subtitle = JSON.parse(item.userinfo[0].serverExtension).fullName;
} else {
item.subtitle = "";
}
item.time = formatTime(item.lastMessage?.messageRefer.createTime || item.updateTime);
}),
);
}
// 置顶会话和普通会话分别排序
let stickTopList = result?.conversationList
.filter((item) => {
return item.stickTop == true;
})
.sort((a, b) => {
if (a.lastMessage?.messageRefer.createTime && b.lastMessage?.messageRefer.createTime) {
return b.lastMessage?.messageRefer.createTime - a.lastMessage?.messageRefer.createTime;
} else if (a.lastMessage?.messageRefer.createTime || b.lastMessage?.messageRefer.createTime) {
if (a.lastMessage?.messageRefer.createTime) {
return a.lastMessage?.messageRefer.createTime - b.createTime;
} else {
return a.createTime - b.lastMessage?.messageRefer.createTime;
}
} else {
return a.updateTime - b.updateTime;
}
});
let defaultList = result?.conversationList
.filter((item) => {
return item.stickTop != true;
})
.sort((a, b) => {
if (a.lastMessage?.messageRefer.createTime && b.lastMessage?.messageRefer.createTime) {
return b.lastMessage?.messageRefer.createTime - a.lastMessage?.messageRefer.createTime;
} else if (a.lastMessage?.messageRefer.createTime || b.lastMessage?.messageRefer.createTime) {
if (a.lastMessage?.messageRefer.createTime) {
return a.lastMessage?.messageRefer.createTime - b.createTime;
} else {
return a.createTime - b.lastMessage?.messageRefer.createTime;
}
} else {
return a.updateTime - b.updateTime;
}
});
machineList.value = stickTopList.concat(defaultList) || []; // 空值保护
} catch (error) {
console.error("获取会话列表失败", error);
machineList.value = []; // 报错时置空,避免页面异常
} finally {
// 无论成功/失败,都隐藏加载状态(移除固定 2 秒延迟,按需可保留短延迟)
firstLoad.value = false;
}
};
// 核心:检查登录状态并处理
const checkLoginStatusAndGetConversations = async () => {
try {
// 2. 获取登录状态
const loginStatus = G?.nim && (await G.nim.V2NIMLoginService.getLoginStatus());
console.log("当前登录状态", loginStatus);
if (loginStatus === 1) {
// 3. 已登录(状态码 1直接获取会话列表
await getConversationListAndHideLoading();
} else {
// 4. 未登录:延迟 2 秒重试一次(可根据需求调整重试次数/延迟)
setTimeout(async () => {
const retryLoginStatus = G?.nim && (await G.nim.V2NIMLoginService.getLoginStatus());
console.log("重试登录状态", retryLoginStatus);
if (retryLoginStatus === 1) {
await getConversationListAndHideLoading();
} else {
// 重试仍未登录:兜底隐藏加载状态,避免一直加载
console.log("重试后仍未登录,停止获取会话列表");
firstLoad.value = false;
}
}, 2000);
}
} catch (error) {
// 捕获所有异步错误,兜底处理加载状态
console.error("检查登录状态/获取会话列表失败", error);
firstLoad.value = false;
}
};
// 格式化时间
const formatTime = (time, separator = "-") => {
// 1. 处理入参转为Date对象兼容时间戳/Date
let targetDate;
if (typeof time === "number") {
// 处理毫秒/秒级时间戳网易云信等SDK可能返回秒级
targetDate = new Date(time.toString().length === 10 ? time * 1000 : time);
} else if (time instanceof Date) {
targetDate = new Date(time); // 重新创建,避免修改原对象
} else {
console.error("formatSmartTime入参格式错误需传入时间戳或Date对象");
return "";
}
// 2. 获取当前时间的基准值
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()); // 今天0点
const todayEnd = new Date(todayStart.getTime() + 24 * 60 * 60 * 1000 - 1); // 今天23:59:59
const currentYear = now.getFullYear(); // 当前年份
// 3. 提取目标时间的年/月/日/时/分(补零)
const year = targetDate.getFullYear();
const month = String(targetDate.getMonth() + 1).padStart(2, "0"); // 月份从0开始补零
const day = String(targetDate.getDate()).padStart(2, "0");
const hour = String(targetDate.getHours()).padStart(2, "0");
const minute = String(targetDate.getMinutes()).padStart(2, "0");
// 4. 按规则格式化
if (targetDate >= todayStart && targetDate <= todayEnd) {
// 当天:仅显示时分
return `${hour}:${minute}`;
} else if (year === currentYear) {
// 当年非当天:月日 时分
return `${month}${separator}${day} ${hour}:${minute}`;
} else {
// 非当年:年月日 时分
return `${year}${separator}${month}${separator}${day} ${hour}:${minute}`;
}
};
const goChatPage = async (_item) => {
console.log(_item);
try {
console.log("debg _item.conversationId", _item.conversationId);
const res = await G.nim.V2NIMConversationService.clearUnreadCountByIds([_item.conversationId]);
console.log("V2NIMConversationService.clearUnreadCountByIds", res);
} catch (error) {
console.log("error", error);
}
uni.navigateTo({
url: "/root/NEUIKit/index?item=" + _item.conversationId,
});
};
/**
* 置顶或取消置顶会话
*/
const topMessage = async (_item, _index) => {
console.log(_item);
try {
if (_item && _item.stickTop) {
G.nim.V2NIMConversationService.stickTopConversation(_item.conversationId, false);
} else {
G.nim.V2NIMConversationService.stickTopConversation(_item.conversationId, true);
}
console.log("tooltipRef.value", tooltipRef.value);
} catch (error) {
uni.showToast({
title: error,
icon: "none",
});
console.log("errorerror", error);
}
tooltipRef.value[_index].close();
// let res1 = await G.nim.V2NIMConversationService.getStickTopConversationList();
// console.log("res1res1", res1);
};
/**
* 删除会话
*/
const deleteMessage = async (_item, _index) => {
console.log(_item);
G.handleConfirm({
content: "不显示该聊天?",
confirmText: "不显示",
cancelText: "取消",
success(res) {
if (res.confirm) {
try {
G.nim.V2NIMConversationService.deleteConversation(_item.conversationId, false);
} catch (error) {
console.log("errorerror", error);
uni.showToast({
title: error,
icon: "none",
});
}
}
},
});
tooltipRef.value[_index].close();
};
onUnmounted(() => {
uni.$off("updateConversationList");
});
</script>
<style lang="less" scoped>
6 days ago
.imitems{
.bottom-line {
position: relative;
&::after {
content: "";
width: 100%;
height: 1px;
background-color: #ededed;
position: absolute;
left: 10px;
top: -12px;
}
}
&:first-child{
.bottom-line {
&::after {
background-color: transparent;
}
}
2 weeks ago
}
}
6 days ago
.rcosa{
.customitem{
&:first-child{
border-radius: 8px 8px 0 0;
}
&:last-child{
border-radius: 0 0 8px 8px;
}
}
}
2 weeks ago
</style>