feat: 圈子对接

This commit is contained in:
kaizheng(郑凯) 2025-02-08 23:02:24 +08:00
parent f1370ded8b
commit a84dcb0fc7
16 changed files with 561 additions and 797 deletions

37
src/api/circle.js Normal file
View File

@ -0,0 +1,37 @@
import request from "../utils/request";
//app首页查询交易圈列表
export function getCircleList(data) {
return request({
url: "/app/group/info/list",
method: "post",
data,
});
}
// app查询交易圈详情
export function getCircleDetail(data) {
return request({
url: "/app/group/info/get",
method: "post",
data,
});
}
// APP获取交易圈互动消息
export function getMessageList(data) {
return request({
url: "/app/group/message/getMessageList",
method: "post",
data,
});
}
// APP发送交易圈互动消息
export function sendMessage(data) {
return request({
url: "/app/group/message/sendMessage",
method: "post",
data,
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -49,7 +49,7 @@ export default function ({ id, subMessage, chatMessage, saleUserId }) {
stompClient.value = new Client({
brokerURL: `${
process.env.NODE_ENV === "development"
? "ws://lczqvideodev.test.upchina.com/tgim/chat"
? "ws://8.138.144.54:8080/tgim/chat"
: brokerUrl
}`,
connectHeaders: {

View File

@ -9,7 +9,7 @@ export default createStore({
token:
process.env.NODE_ENV !== "development"
? terminalType === "Browser" && localStorage.getItem("token")
: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiYWNrZW5kVXNlciI6IntcImNsaWVudFR5cGVcIjo0LFwiY29va2llXCI6XCJjZjNjZWFlZjFmOGM5Y2I3MGE4OWQzMmM3ZTE5MmQyN1wiLFwiaW1nVXJsXCI6XCJodHRwczovL3RoaXJkd3gucWxvZ28uY24vbW1vcGVuL3ZpXzMyL3Q1TzZidFZsaWJDZWhveHRaV1hjNEFZZWZwOTJweEdXb3JDTnNrQm82aExzajNNSmNsa1BweW9JMGQ1T1c1UURzcWZhblM1SWRpY2ZQZkV2WXZRNlM3dVEvMTMyXCIsXCJyZUNvb2tpZVwiOlwiNDQ3MTM3QUJGMjY5NEFDMDYzMTI2NDdENjQ5Nzk0N0FcIixcInVzZXJJZFwiOlwiY3NodDAwM1wiLFwidXNlck5hbWVcIjpcImNzaHQwMDNcIn0iLCJleHAiOjE3Mzg0MDUxNzV9.pCk-eYx_RXL23oFW9LMfJ3Gp76dzJVjVuU1tFqFoHE0",
: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiYWNrZW5kVXNlciI6IntcImNsaWVudFR5cGVcIjo0LFwiY29va2llXCI6XCIwZDdkMjM5MzU3YWI1ZDdmYjcxNTcxMDM4MjNkNjQwNFwiLFwiaW1nVXJsXCI6XCJodHRwczovL3RoaXJkd3gucWxvZ28uY24vbW1vcGVuL3ZpXzMyL3Q1TzZidFZsaWJDZWhveHRaV1hjNEFZZWZwOTJweEdXb3JDTnNrQm82aExzajNNSmNsa1BweW9JMGQ1T1c1UURzcWZhblM1SWRpY2ZQZkV2WXZRNlM3dVEvMTMyXCIsXCJyZUNvb2tpZVwiOlwiNDUwRTRGQTZBMkMyNzYzMTNGOUEzRDk1QzEzQUU0M0JcIixcInVzZXJJZFwiOlwiY3NodDAwM1wiLFwidXNlck5hbWVcIjpcImNzaHQwMDNcIn0iLCJleHAiOjE3MzkxMDU1NzZ9.gWJx20imXC4_B3qloXDlyH7Zle9VvfVQNhFp5lTM0Jo",
userInfo:
process.env.NODE_ENV !== "development"
? terminalType === "Browser" && localStorage.getItem("userInfo")

View File

@ -30,3 +30,12 @@ export const PRICING_FEE = {
4: "半年",
5: "年",
};
// 风险等级
export const RISK_LEVEL = [
{ label: '低风险', value: 1 },
{ label: '中低风险', value: 2 },
{ label: '中风险', value: 3 },
{ label: '中高风险', value: 4 },
{ label: '高风险', value: 5 }
]

View File

@ -1,14 +1,9 @@
<template>
<div class="date-select">
<p>日期2024-19-22</p>
<van-icon name="arrow" @click="showCalendar = true"/>
<van-icon name="arrow" @click="showCalendar = true" />
</div>
<van-notice-bar
left-icon="volume-o"
mode="closeable"
text="无论我们能活多久,我们能够享受的只有无法分割的此刻,此外别无其他。"
/>
<div class="interact-scroll" ref="container">
<div :class="[`interact-scroll`, `interact-scroll${props.type}`]">
<div class="p20">
<div class="pulldown-wrapper">
<div v-if="hasNext">
@ -21,79 +16,121 @@
<!-- isOpen 2: 不公开 1公开 -->
<ul class="interact-msg" ref="msgListRef">
<li
v-for="(item) in informMsgList"
v-for="item in msgList"
:class="[
`li${item.id}`,
item.phone === store.state.userInfo.account ? 'row-reverse' : '',
item.userId === store.state.userInfo.account ? 'row-reverse' : '',
]"
:key="item.id"
>
<div>
<div class="chat-time" v-if="(isTg && item.tgChatTime) || (!isTg && item.chatTime)">{{ isTg ? item.tgChatTime : item.chatTime }}</div>
<div class="chat-time" v-if="item.chatTime">
{{ item.chatTime }}
</div>
<div
:class="[
'flex',
item.phone === store.state.userInfo.account ? 'row-reverse' : '',
item.userId === store.state.userInfo.account
? 'row-reverse'
: '',
]"
>
<div class="photo">
<img
v-if="item.userType === 1"
:src="
item.advisorId
? item.advisorBasic && item.advisorBasic.avatar
? item.advisorBasic.avatar
: defaultPhoto
: item.userId
? item.imgUrl
: tgDefaultPhoto
item.advisor ? item.advisor.avatar : defaultAvatar.teacher
"
alt=""
/>
<img
v-else-if="item.userType === 3"
:src="defaultAvatar.assistant"
/>
<img
v-else-if="item.userType === 2"
:src="defaultAvatar.student"
/>
</div>
<div class="news-content-wrap">
<div class="user-info">
<h3>
{{
item.userId
? item.phone === store.state.userInfo.account
item.userType === 2
? item.userId === store.state.userInfo.account
? "我"
: detail.showNickname === 2 ? maskUserName(item.userName) : item.userName
: item.createUserVO ? item.createUserVO.name : item.advisorBasic?.showName
: detail.showNickname === 2
? maskUserName(item.userName)
: item.userName
: item.userName
}}
<span v-if="item.advisorId">讲师</span>
<span v-else-if="item.createUserVO">助教</span>
<span v-if="item.userType === 1">讲师</span>
<span v-else-if="item.userType === 3">助教</span>
</h3>
</div>
<div v-if="item.type === 1 && item.replyBasic">
<div v-if="[1, 2].includes(item.contentType) && item.replyId">
<div>
<div class="reply-content">
<div class="reply">
<span style="color: rgba(154, 164, 182, 1)">回复</span
><label>{{ item.replyBasic.userId === store.state.userInfo.account
? "我" : detail.showNickname === 2 ? maskUserName(item.replyBasic.userName) : item.replyBasic.userName }}</label>
{{ item.content }}
><label
>{{
item.replyMessage?.userId ===
store.state.userInfo.account
? "我"
: detail.showNickname === 2
? maskUserName(item.replyMessage?.userName)
: item.replyMessage?.userName
}}</label
>
<template v-if="item.contentType === 1">
{{ item.content }}
</template>
<template v-else-if="item.contentType === 2">
<img
class="img"
@click="imagePreview(item.content)"
:src="item.content"
/>
</template>
</div>
<div class="reply" style="color: rgba(154, 164, 182, 1)">
{{ item.replyBasic.userId === store.state.userInfo.account
? "我" : detail.showNickname === 2 ? maskUserName(item.replyBasic.userName) : item.replyBasic.userName }}{{
item.replyBasic.content
}}
{{
item.replyMessage?.userId ===
store.state.userInfo.account
? "我"
: detail.showNickname === 2
? maskUserName(item.replyMessage?.userName)
: item.replyMessage?.userName
}}
<template v-if="item.replyMessage?.contentType === 1">
{{ item.replyMessage?.content }}
</template>
<template
v-else-if="item.replyMessage?.contentType === 2"
>
<img
class="reply-img"
@click="imagePreview(item.replyMessage.content)"
:src="item.replyMessage.content"
/>
</template>
</div>
</div>
<div class="license">{{ item.advisorBasic?.name }}<i v-if="detail.advisorBasic.license">{{item.advisorBasic?.license}}</i></div>
</div>
</div>
<div v-else-if="item.type === 1 && !item.replyBasic">
<div v-else-if="item.contentType === 1 && !item.replyId">
<div>
<p class="text" v-if="!item.content.includes('upImg')">
<p class="text">
{{ item.content }}
</p>
</div>
</div>
<div v-else-if="item.contentType === 2 && !item.replyId">
<div>
<img
v-else
class="img"
@click="imagePreview(item.content.split('upImg-')[1])"
:src="item.content.split('upImg-')[1]"
@click="imagePreview(item.content)"
:src="item.content"
/>
</div>
</div>
@ -105,655 +142,80 @@
</div>
</div>
<van-calendar v-model:show="showCalendar" />
<img class="refresh" src="@/assets/images/refresh.png">
<img class="refresh" @click="refreshMsg" src="@/assets/images/refresh.png" />
</template>
<script setup>
import { ref } from "vue"
import { ref, defineProps, watch, nextTick } from "vue";
import { useRoute } from "vue-router";
import { useStore } from "vuex";
import { showImagePreview } from "vant";
import useChatData from "../hooks/useChatData";
const store = useStore();
const informMsgList = ref([
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "问卷1",
"createTime": "2025-01-24 15:20:52",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700418,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": "",
"questionId": 617,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 11,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "upImg-https://advisorimg.test.upchina.com/group1/M00/02/F9/rBAIx2eTPjaAFpSuAAH8dF_J2Lc574.png",
"createTime": "2025-01-24 15:16:10",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700415,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "阿事实上事实上事实上",
"createTime": "2025-01-24 15:16:02",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700414,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "产品1",
"createTime": "2025-01-24 15:15:08",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700413,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": {
"authorityId": null,
"content": "三等奖付款时间打客服介绍上课的见风使舵看风使舵",
"id": 1,
"name": "产品1",
"productType": 111,
"typeLabel": null,
"url": "https://blog.csdn.net/weixin_45911857/article/details/132300931"
},
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 2,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "十点多的点点滴滴滴答滴答",
"createTime": "2025-01-24 15:15:02",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700412,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "回复的是iOS发布的查看看安卓的显示是否自动显示",
"createTime": "2025-01-24 15:09:57",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700408,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": {
"content": "哈哈白白净净斤斤计较",
"id": 700407,
"isOpen": 1,
"replyTime": "2025-01-24 15:09:21",
"userId": "up0206900",
"userName": "向日葵🌻"
},
"replyId": 700407,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "收到滴答滴答滴答滴答哒哒哒哒哒哒哒哒哒多大,手打付款时间打开福建师大开发机四大分三大发开始的福建省大多数咖啡机",
"createTime": "2025-01-24 15:08:58",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700406,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": {
"content": "把喜不喜欢报道",
"id": 700405,
"isOpen": 1,
"replyTime": "2025-01-24 15:08:43",
"userId": "up0206900",
"userName": "向日葵🌻"
},
"replyId": 700405,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "回复三等奖防水防汗水电费还是洞口防护",
"createTime": "2025-01-24 15:08:22",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700403,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": {
"content": "需要公开今生今世你说你睡觉",
"id": 700402,
"isOpen": 1,
"replyTime": "2025-01-24 15:05:51",
"userId": "up0206900",
"userName": "向日葵🌻"
},
"replyId": 700402,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "水电费水电费是的防守打法",
"createTime": "2025-01-24 15:01:29",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700395,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
},
{
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"content": "水电费水电费水电费手动阀是打发水电费水电费水电费",
"createTime": "2025-01-24 15:01:00",
"createUserId": 116,
"createUserVO": {
"comId": null,
"comName": null,
"createTime": "2024-11-12 15:51:18",
"deptId": "2",
"deptName": null,
"id": 116,
"loginId": 116,
"mobile": null,
"name": "测测1",
"roleList": [],
"staffNo": null,
"status": 1,
"upId": null,
"userType": null
},
"deleteTime": null,
"deleteUserId": null,
"id": 700394,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"isCurrentUser": null,
"isForbid": null,
"isOpen": null,
"messageCount": null,
"online": null,
"phone": null,
"productBasic": null,
"questionDesc": null,
"questionId": null,
"replyBasic": null,
"replyId": null,
"status": 1,
"type": 1,
"userAdminVO": null,
"userId": null,
"userName": null,
"videoId": 21484
}
])
const detail = ref({
"advisorBasic": {
"avatar": "https://advisorimg.test.upchina.com/group1/M00/02/E5/rBAIx2czCRmAPCDfAAHFYtfoEBs588.png",
"deptName": "营业部3",
"id": 66,
"license": "sz232423423",
"name": "测测1",
"profile": "sdfsdfsdfsd",
"showName": "测测一",
"userId": 116
},
"advisorId": 66,
"auditTime": "2025-01-24 14:28:16",
"authIds": [],
"authResultVo": {
"auth": true,
"contractUrl": null,
"riskUrl": null
},
"authorityId": "",
"createTime": "2025-01-24 14:28:02",
"currentTime": "2025-01-31 19:37:20",
"detail": "<p>详情水电费合适的尽快发货受打击发哈,阿是嘉华大厦接电话十九大三打哈,撒记得哈时间的哈时间段撒酒疯哈时间的哈数据库,撒即可哈就是的哈时间段</p>",
"duration": 3467,
"endTime": "2025-01-24 15:47:58",
"exkey": null,
"favorUserCount": 9,
"guestInfo": null,
"id": 21484,
"imgUrl": "https://advisorimg.test.upchina.com/group1/M00/02/F9/rBAIx2eTMkCAC51tAAlK4YqQ09A911.png",
"infoVO": null,
"interactType": 1,
"isCart": 1,
"isDisplay": 1,
"isFavor": 2,
"isFinishRead": null,
"isGenerateRecord": 1,
"isSpeak": 1,
"isSubAdvisor": 2,
"isSubscribe": 2,
"joinUserCount": 0,
"libraryList": [
{
"duration": 3467,
"fileId": "1397757903546390815",
"id": 1208,
"liveIndex": 1,
"name": "测试1月24号横屏1",
"size": 1225081635,
"transStatus": 1
}
],
"limitType": 1,
"listCoverUrl": "https://advisorimg.test.upchina.com/group1/M00/02/F9/rBAIx2eTMoOAXV6EAAPlF6mEQcM893.png",
"liveStatus": 4,
"messageAudit": 2,
"online": 1,
"openQw": 1,
"playStyle": 2,
"playType": 1,
"readCount": 57,
"readDuration": null,
"readUserCount": 0,
"resizeUrl": "http://lczqvideodev.test.upchina.com/s/IuffWKn",
"riskLevel": 2,
"riskLevelLabel": "中低风险",
"showNickname": 1,
"size": null,
"startTime": "2025-01-24 14:50:08",
"status": 3,
"subCount": 0,
"subscribeUserCount": 2,
"teacherId": 66,
"title": "测试1月24号横屏1",
"videoAuthId": null,
"viewPoint": "看点圣诞节发货束带结发",
"weight": 0
})
const showCalendar = ref(false)
const { msgListRef } = useChatData({id: 21484});
const route = useRoute();
const props = defineProps({
type: {
type: Number,
default: 1,
},
bsRefresh: {
type: Boolean,
default: false,
},
detail: {
type: Object,
default: () => {},
},
newMsg: {
type: Object,
default: () => {},
},
});
const defaultAvatar = {
teacher: require("@/assets/images/defaultAvatar/teacher.png"),
student: require("@/assets/images/defaultAvatar/student.png"),
assistant: require("@/assets/images/defaultAvatar/assistant.png"),
};
watch(
() => props.bsRefresh,
(value) => {
if (value && bs) {
nextTick(() => {
bs.value.refresh();
});
}
}
);
watch(
() => props.newMsg,
(data) => {
if (
(props.type === 1 && data.interactiveType === 1) ||
(props.type === 5 && data.interactiveType === 2) ||
(props.type === 2 && data.userType === 1) ||
(props.type === 4 && data.isRecommend === 1)
) {
pushNewMsg(data);
}
}
);
const imagePreview = (url) => {
showImagePreview({
images: [url],
closeable: true,
});
};
const showCalendar = ref(false);
const { bs, msgListRef, msgList, pushNewMsg, refreshMsg } = useChatData({
className: `.interact-scroll${props.type}`,
id: route.query.id,
type: props.type,
});
</script>
<style scoped lang="scss">
.interact-scroll {
@ -763,7 +225,7 @@ const { msgListRef } = useChatData({id: 21484});
height: 100%;
box-sizing: border-box;
background: #f5f6fa;
.p20{
.p20 {
padding: 20px;
}
li {
@ -827,7 +289,7 @@ const { msgListRef } = useChatData({id: 21484});
}
}
}
li:last-child{
li:last-child {
margin-bottom: 0;
}
.row-reverse {
@ -893,8 +355,8 @@ const { msgListRef } = useChatData({id: 21484});
text-align: justify;
line-height: 30px;
}
.license{
padding:0;
.license {
padding: 0;
color: #c6c7c9;
line-height: 24px;
font-size: 24px;
@ -902,6 +364,8 @@ const { msgListRef } = useChatData({id: 21484});
margin: 12px 0 1px 1px;
}
.reply {
display: flex;
align-items: start;
line-height: 40px;
margin-right: 10px;
}
@ -1035,37 +499,27 @@ const { msgListRef } = useChatData({id: 21484});
}
}
}
.new-msg-tip{
.new-msg-tip {
position: absolute;
left: 0;
bottom: 0px;
color: #2e78fa;
background: #fff;
border: 1px solid rgba(204,204,204,0.2);
border: 1px solid rgba(204, 204, 204, 0.2);
font-size: 24px;
padding: 8px 12px;
border-radius: 20px;
}
.refresh{
.refresh {
position: fixed;
right: 24px;
bottom: 180px;
width: 64px;
}
.date-select{
.date-select {
display: flex;
justify-content: space-between;
font-size: 28px;
padding: 20px;
}
.van-notice-bar{
position: absolute;
top: 156px;
left:0;
right:0;
font-size: 24px;
line-height: 48px;
height: 48px;
z-index: 2;
}
</style>

View File

@ -1,6 +1,5 @@
import { ref, onMounted, nextTick } from "vue";
import { useStore } from "vuex";
import { queryLiveHisMsg, queryLiveTgHisMsg } from "@/api/video";
import { getMessageList } from "@/api/circle";
import BScroll from "@better-scroll/core";
import PullDown from "@better-scroll/pull-down";
import MouseWheel from "@better-scroll/mouse-wheel";
@ -9,45 +8,30 @@ import useDisableScroll from "@/hooks/useDisableScroll";
BScroll.use(PullDown);
BScroll.use(MouseWheel);
export default function useChatData({ id, className, isTg }) {
export default function useChatData({ id, className, type }) {
const { addScrollEvent } = useDisableScroll();
const store = useStore();
const hasNext = ref(true);
let bs = ref();
let firsLoad = ref("");
const isPullingDown = ref(false);
const msgListRef = ref();
const msgList = ref([])
const getLiveHisMsg = async () => {
if (isPullingDown.value) return;
isPullingDown.value = true;
let preHisHeight
let ret = isTg
? await queryLiveTgHisMsg({
id: id,
lastId: store.state.interactMsgObj.tgInteractMsgList[0]?.id,
size: 20,
status: 1,
let ret = await getMessageList({
groupId: id,
lastId: msgList.value[0]?.id,
size: 10,
type,
})
: await queryLiveHisMsg({
id: id,
lastId: store.state.interactMsgObj.userInteractMsgList[0]?.id,
size: 20,
status: 1,
});
if (ret.code === 0) {
firsLoad.value = true
let list = ret.data.list || []
let list = ret.data.list.reverse() || []
hasNext.value = ret.data.hasNext;
preHisHeight = msgListRef.value.clientHeight;
store.commit('setInteractMsg', {
type: 2,
isTg,
hasNext: hasNext.value,
data: list
})
msgList.value = list.concat(msgList.value)
if (!hasNext.value) {
bs.value && bs.value.closePullDown();
}
@ -60,16 +44,30 @@ export default function useChatData({ id, className, isTg }) {
bs.value && bs.value.finishPullDown();
nextTick(() => {
bs.value && bs.value.refresh();
if (!firsLoad.value) {
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0);
} else {
const curHisHeight = msgListRef.value.clientHeight;
const toY = preHisHeight - curHisHeight;
preHisHeight && bs.value && bs.value.scrollTo(0, toY, 0);
}
const curHisHeight = msgListRef.value.clientHeight;
const toY = preHisHeight - curHisHeight;
bs.value && bs.value.scrollTo(0, toY, 0);
});
};
// WebSocket推送的消息
const pushNewMsg = (msg) => {
msgList.value.push(msg)
nextTick(()=>{
let isBottom = bs.value.maxScrollY+20 >= bs.value.y
bs.value && bs.value.refresh();
if(isBottom) {
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0);
}
})
}
// 刷新消息
const refreshMsg = () => {
msgList.value = []
getLiveHisMsg()
}
let wrapper;
onMounted(async () => {
wrapper = document.querySelector(
@ -108,5 +106,8 @@ export default function useChatData({ id, className, isTg }) {
msgListRef,
hasNext,
bs,
msgList,
pushNewMsg,
refreshMsg
};
}

View File

@ -0,0 +1,135 @@
import { ref, onBeforeUnmount } from "vue";
import { Client } from "@stomp/stompjs";
import { showToast } from "vant";
import store from "@/store/index";
import { userLogin } from "@/utils/login";
import lifecycle from "page-lifecycle";
import dayjs from "dayjs";
import emitter from "@/utils/emitter";
import { getSystem } from "@/utils/index";
export default function ({ id, privateMessage, chatMessage }) {
onBeforeUnmount(() => {
stompClient.value && stompClient.value.deactivate();
});
const stompClient = ref();
let playCtxObj = null; // 播放器对象
let closeNum = 0; // WebSocket关闭次数
let connectNum = 0; // 程序去主动连接次数
let connectTime = null;
let sessionId = "";
const system = getSystem();
const connect = async () => {
console.log("connect建立连接");
const frontToken = store.state.token;
if (
localStorage.getItem(`sessionId-${store.state.userInfo.account}-${id}`)
) {
sessionId = localStorage.getItem(
`sessionId-${store.state.userInfo.account}-${id}`
);
} else {
sessionId = Math.random().toString(36).substring(2, 8);
localStorage.setItem(
`sessionId-${store.state.userInfo.account}-${id}`,
sessionId
);
}
console.log("frontToken", frontToken);
const brokerUrl = `${location.protocol === "http:" ? "ws://" : "wss://"}${
location.host
}/tgim/chat`;
stompClient.value = new Client({
brokerURL: `${
process.env.NODE_ENV === "development"
? "ws://8.138.144.54:8080/tgim/chat"
: brokerUrl
}`,
connectHeaders: {
sessionId,
token: store.state.token,
productType: 41, // 3 直播 41交易圈
productId: id,
},
debug: function (str) {
console.log("debug: " + dayjs().format("YYYY-MM-DD HH:mm:ss") + str);
},
reconnectDelay: 5000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000,
discardWebsocketOnCommFailure: true,
});
stompClient.value.onConnect = async (frame) => {
// setConnected(true);
console.log("链接成功");
console.log("Connected: ", frame);
closeNum = 0;
connectNum = 0;
clearTimeout(connectTime);
emitter.emit("cancelGetNewMsg");
// 接收群聊接收消息路径
chatMessage &&
(await stompClient.value.subscribe(`/app/group/topic/${id}`, chatMessage));
// APP端私聊消息
privateMessage &&
(await stompClient.value.subscribe(`/app/private/topic/${id}/${store.state.userInfo.account}`, privateMessage));
};
stompClient.value.onStompError = (error) => {
console.log(error.body);
if (
error.body.includes("2007") ||
error.body.includes("2000") ||
error.body.includes("2003")
) {
userLogin();
} else {
showToast(`${error.body}`);
}
};
stompClient.value.onDisconnect = (error) => {
console.log("onDisconnect", error);
stompClient.value = null;
};
const anewConnectFn = () => {
clearTimeout(connectTime);
connectTime = setTimeout(() => {
if (connectNum < 5) connectNum++;
connect();
anewConnectFn();
}, connectNum * 60 * 1000);
};
stompClient.value.onWebSocketClose = (error) => {
console.log("onWebSocketClose", closeNum, error);
if (closeNum > 3) {
closeNum = 0;
stompClient.value && stompClient.value.deactivate();
emitter.emit("getNewMsg");
anewConnectFn();
} else {
closeNum++;
}
};
stompClient.value.activate();
};
connect()
window.addEventListener("unload", function (event) {
stompClient.value && stompClient.value.deactivate();
console.log("stompClient.value", stompClient.value);
event.returnValue = "你确定要离开这个页面吗?";
});
lifecycle.addEventListener("statechange", function (event) {
console.log("statechange", event.newState, playCtxObj);
if (system === "ios") {
if (event.newState === "hidden" && playCtxObj) {
playCtxObj.pause();
} else if (playCtxObj) {
playCtxObj.play();
}
}
});
}

View File

@ -2,28 +2,26 @@
<div>
<Nav title="直播视频"></Nav>
<div class="circle-base-info">
<img src="" class="banner">
<img :src="detail.coverImage" class="banner">
<div class="circle-name">
<h3>独立圈子</h3>
<span>中风险</span>
<h3>{{ detail.name }}</h3>
<span>{{ detail.riskLevel ? RISK_LEVEL[detail.riskLevel].label : '' }}</span>
</div>
<div class="tg-info">
<div class="flex">
<img class="photo" src="" alt="" srcset="">
<label>六七</label>
<img class="photo" :src="detail.advisor.avatar" alt="" srcset="">
<label>{{ detail.advisor.showName }}</label>
</div>
<span>名字</span>
<span class="user-name">{{ store.state.userInfo.userName }}</span>
</div>
</div>
<div class="introduce">
<h4>交易圈简介</h4>
<p>1.奥斯卡的骄傲卡的萨克反馈说发的是个电视柜</p>
<p>2.水电费克里斯发的是个发的是水电费快乐时光反馈说</p>
<p>3.水电费克里斯发的是个发的是水电费快乐时光反馈说</p>
<p>{{ detail.remark }}</p>
</div>
<div class="introduce">
<h4>使用人群</h4>
<p>零基础小白用户</p>
<p>{{ detail.applicableUser }}</p>
</div>
<div class="tip">风险提示投资顾问提供的观点和投资建议仅供参考不作为客户投资决策依据客户需独立做出投资决策风险自担市场有风险投资须谨慎</div>
<div class="footer">
@ -35,14 +33,36 @@
</ul>
<p><span>谁谁</span>正在火热抢购中</p>
</div>
<div class="sub">
<button>立即开通</button>
</div>
<button @click="toPaymentUrl">立即开通</button>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useRoute } from "vue-router";
import { getCircleDetail } from "@/api/circle";
import Nav from "@/components/NavBar.vue";
import { RISK_LEVEL } from "@/utils/contant"
import { useStore } from "vuex";
// const router = useRouter();
const route = useRoute();
const store = useStore();
const detail = ref({
advisor: {}
})
const queryCircleDetail = async ()=> {
const ret = await getCircleDetail({id: route.query.id})
if(ret && ret.code === 0){
detail.value = ret.data
}
}
queryCircleDetail()
const toPaymentUrl = () => {
location.href = detail.value.page.paymentUrl
}
</script>
<style lang="scss" scoped>
@ -85,6 +105,9 @@ import Nav from "@/components/NavBar.vue";
span{
font-size: 28px;
}
.user-name {
color: #2e78fa;
}
}
}
.introduce{

View File

@ -1,27 +1,60 @@
<template>
<Nav title="圈子互动">
<img class=set src="@/assets/images/set.png" @click="router.push('./set')"/>
<img
class="set"
src="@/assets/images/set.png"
@click="router.push('./set')"
/>
</Nav>
<van-notice-bar left-icon="volume-o" mode="closeable" :text="detail.notice" />
<van-tabs v-model:active="active" line-width="0.4rem">
<van-tab title="互动" :name="0">
<ChatFrame/>
<ChatFrame
:type="1"
:bsRefresh="active === 0"
detail="detail"
:newMsg="newMsg"
/>
</van-tab>
<van-tab title="老师" :name="1">
<ChatFrame
:type="2"
:bsRefresh="active === 1"
detail="detail"
:newMsg="newMsg"
/>
</van-tab>
<van-tab title="私聊" :name="2">
<ChatFrame
:type="5"
:bsRefresh="active === 2"
detail="detail"
:newMsg="newMsg"
/>
</van-tab>
<van-tab title="精选" :name="3">
<ChatFrame
:type="4"
:bsRefresh="active === 3"
detail="detail"
:newMsg="newMsg"
/>
</van-tab>
</van-tabs>
<div class="input-area">
<input
type="text"
v-model="content"
maxlength="200"
:disabled="detail.interactiveStatus === 2"
:placeholder="
detail.interactiveStatus === 2 ? '暂不允许互动' : '请输入您想发送的内容'
"
@keyup.enter="sendMsg(1, { text })"
/>
<button
class="send"
:disabled="!text || sendTextLoading"
:disabled="!content || sendTextLoading || detail.interactiveStatus === 2"
@click="sendMsg(1, { text })"
>
发送
@ -29,22 +62,75 @@
</div>
</template>
<script setup>
import { ref } from "vue"
import { ref } from "vue";
import Nav from "@/components/NavBar.vue";
import ChatFrame from "./components/ChatFrame.vue";
import { useRouter } from "vue-router";
import { useRouter, useRoute } from "vue-router";
import { sendMessage } from "@/api/circle";
import { getCircleDetail } from "@/api/circle";
import useWebSocket from "./hooks/useWebSocket";
const active = ref(0)
const active = ref(0);
const router = useRouter();
const route = useRoute();
const sendTextLoading = ref(false);
const content = ref("");
const detail = ref({
advisor: {},
});
const queryCircleDetail = async () => {
const ret = await getCircleDetail({ id: route.query.id });
if (ret && ret.code === 0) {
detail.value = ret.data;
}
};
queryCircleDetail();
const privateMessage = (msg) => {
console.log("privateMessage", msg);
};
const newMsg = ref({}); // ws
const chatMessage = (msg) => {
const body = JSON.parse(msg.body);
const data = body.data;
console.log("data", data);
// interactiveType :1;2;3
if ([1].includes(body.type)) {
newMsg.value = data;
} else if (body.type === 6) {
detail.value.interactiveStatus = data;
} else if (body.type === 16) {
//
detail.value.showNickName = data;
} else if (body.type === 19) {
//
detail.value.showMemberCount = data;
}
};
useWebSocket({ id: route.query.id, privateMessage, chatMessage });
const sendMsg = async () => {
let ret = await sendMessage({
content: content.value,
groupId: route.query.id,
interactiveType: active.value === 2 ? 2 : 1,
});
if (ret && ret.code === 0) {
content.value = "";
}
};
</script>
<style lang="scss" scoped>
.set{
.set {
width: 50px;
}
::v-deep .van-nav-bar {
background: #fff;
}
.van-tabs{
.van-tabs {
height: calc(100% - 200px);
::v-deep .van-tabs__content {
height: calc(100% - 156px);
@ -131,4 +217,14 @@ const router = useRouter();
}
}
}
</style>
.van-notice-bar {
position: absolute;
top: 232px;
left: 0;
right: 0;
font-size: 24px;
line-height: 48px;
height: 48px;
z-index: 2;
}
</style>

View File

@ -8,14 +8,17 @@
error-text="加载错误,请点击重新加载"
@load="onLoad"
>
<CircleItem/>
<CircleItem
v-for="(item, index) in list"
:key="index"
:item="item"/>
</van-list>
</van-pull-refresh>
</template>
<script setup>
import { ref, defineProps } from "vue";
import { queryLivePlan } from "@/api/index";
import { getCircleList } from "@/api/circle";
import CircleItem from "./components/CircleItem.vue";
const props = defineProps({
@ -45,33 +48,18 @@ const onRefresh = () => {
};
const onLoad = async () => {
//
let ret = await queryLivePlan({
type: 3,
size: 10,
current: current.value,
lastAuditTime:
refreshing.value || !list.value.length
let ret = await getCircleList({
id: props.id,
lastId: refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].id,
lastPublishTime: refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].auditTime,
lastStartTime:
refreshing.value || !list.value.length
lastWeight: refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].startTime,
lastStatus:
refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].liveStatus,
advisorId: props.id,
lastIsRecommend:
refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].isRecommend,
lastLibCount:
refreshing.value || !list.value.length
? ""
: list.value[list.value.length - 1].libraryList
? list.value[list.value.length - 1].libraryList.length
: 0,
: list.value[list.value.length - 1].isRecommend,
size: 10,
});
if (ret.code === 0) {
if (refreshing.value) {

View File

@ -1,26 +1,46 @@
<template>
<div class="circle-item">
<div class="circle-item"
@click="toCircleDetail">
<img class="cover" src="" alt="">
<div class="circle-info">
<h3>主力行为读心术</h3>
<p>收款方都开始到放款是否都开始开发三方的考试费打开时</p>
<h3>{{ item.name }}</h3>
<p>{{ item.remark }}</p>
<div class="price">
<div class="tg-info">
<img class="photo" src="" alt="" srcset="">
<span>六七</span>
<img class="photo" :src="item.advisor.avatar" alt="" srcset="">
<span>{{ item.showName }}</span>
</div>
<!-- <h5><strong>19333</strong>/6个月</h5> -->
<h5>免费</h5>
<h5>{{ item.authorityId?'收费':'免费' }}</h5>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
<script setup>
import { defineProps } from "vue";
import { useRouter, useRoute } from "vue-router";
/**
* 路由实例
*/
const router = useRouter();
const route = useRoute();
}
const props = defineProps({
item: {
type: Object,
default: () => {},
},
});
const toCircleDetail = () => {
if(props.item.authorityId) {
router.push(
`/circle?id=${props.item.id}&saleUserId=${route.query.saleUserId || ''}`
)
} else {
router.push(
`/circle/interact?id=${props.item.id}&saleUserId=${route.query.saleUserId || ''}`
)
}
}
</script>
@ -38,6 +58,7 @@ export default {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
h3{
line-height: 58px;
font-size: 36px;

View File

@ -49,7 +49,7 @@
>
<LivePlayList v-if="active === 3" :id="route.query.id" />
<ShotVideoList v-else-if="active === 35" :id="route.query.id" />
<CircleList v-else-if="active === 1"/>
<CircleList v-else-if="active === 1" :id="route.query.id"/>
<Empty text="暂无内容" v-else />
</van-tab>
</van-tabs>

View File

@ -18,7 +18,7 @@ module.exports = defineConfig({
devServer: {
proxy: {
"/app": {
target: "http://lczqvideodev.test.upchina.com",
target: "http://8.138.144.54:8080",
changeOrigin: true,
},
"/admin": {