fix: 直播样式调整
2
.gitignore
vendored
@ -2,7 +2,7 @@
|
||||
node_modules
|
||||
/dist
|
||||
/build
|
||||
|
||||
/test
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
||||
299
src/assets/css/live.css
Normal file
@ -0,0 +1,299 @@
|
||||
body {
|
||||
--bubble_time: 3s;
|
||||
--bubble_scale: 3s;
|
||||
}
|
||||
.bubble {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
left: 50%;
|
||||
left: 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
transform-origin: bottom;
|
||||
}
|
||||
.b1 {
|
||||
background-image: url(../images/liveIcon/bg1.png);
|
||||
}
|
||||
.b2 {
|
||||
background-image: url(../images/liveIcon/bg2.png);
|
||||
}
|
||||
.b3 {
|
||||
background-image: url(../images/liveIcon/bg3.png);
|
||||
}
|
||||
.b4 {
|
||||
background-image: url(../images/liveIcon/bg4.png);
|
||||
}
|
||||
.b5 {
|
||||
background-image: url(../images/liveIcon/bg5.png);
|
||||
}
|
||||
.b6 {
|
||||
background-image: url(../images/liveIcon/bg6.png);
|
||||
}
|
||||
.bl1 {
|
||||
animation: bubble_1 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_1 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl2 {
|
||||
animation: bubble_2 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_2 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl3 {
|
||||
animation: bubble_3 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_1 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl4 {
|
||||
animation: bubble_4 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_2 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl5 {
|
||||
animation: bubble_5 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_1 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl6 {
|
||||
animation: bubble_6 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_3 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl7 {
|
||||
animation: bubble_7 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_1 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl8 {
|
||||
animation: bubble_8 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_3 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl9 {
|
||||
animation: bubble_9 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_2 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl10 {
|
||||
animation: bubble_10 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_1 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
.bl11 {
|
||||
animation: bubble_11 var(--bubble_time) linear 1 forwards,
|
||||
bubble_big_2 var(--bubble_scale) linear 1 forwards,
|
||||
bubble_y var(--bubble_time) linear 1 forwards;
|
||||
}
|
||||
@keyframes bubble_11 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -15px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -15px;
|
||||
}
|
||||
100% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_10 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
100% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_9 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: 10px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 10px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_8 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: 30px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 30px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_7 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: 6px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 2px;
|
||||
}
|
||||
75% {
|
||||
margin-left: 4px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_6 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -6px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -2px;
|
||||
}
|
||||
75% {
|
||||
margin-left: -4px;
|
||||
}
|
||||
100% {
|
||||
margin-left: -6px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_5 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: 10px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -10px;
|
||||
}
|
||||
75% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
100% {
|
||||
margin-left: -40px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_4 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -10px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -10px;
|
||||
}
|
||||
75% {
|
||||
margin-left: 40px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_3 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -40px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 20px;
|
||||
}
|
||||
75% {
|
||||
margin-left: 40px;
|
||||
}
|
||||
100% {
|
||||
margin-left: -20px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_2 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: 40px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 50px;
|
||||
}
|
||||
75% {
|
||||
margin-left: 20px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_1 {
|
||||
0% {
|
||||
}
|
||||
25% {
|
||||
margin-left: -16px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 16px;
|
||||
}
|
||||
75% {
|
||||
margin-left: -30px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_big_1 {
|
||||
0% {
|
||||
/* transform: scale(0.3); */
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
100% {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_big_2 {
|
||||
0% {
|
||||
/* transform: scale(0.3); */
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
100% {
|
||||
/* transform: scale(0.9); */
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_big_3 {
|
||||
0% {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
100% {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
@keyframes bubble_y {
|
||||
0% {
|
||||
top: -10px;
|
||||
}
|
||||
10% {
|
||||
top: -40px;
|
||||
}
|
||||
75% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: -400px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 8.2 KiB |
BIN
src/assets/images/empty1.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/liveIcon/bg1.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/assets/images/liveIcon/bg2.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/images/liveIcon/bg3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src/assets/images/liveIcon/bg4.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/liveIcon/bg5.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
src/assets/images/liveIcon/bg6.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/assets/images/share3.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
22
src/hooks/useContinuousClickLive.js
Normal file
@ -0,0 +1,22 @@
|
||||
export default function useContinuousClickLive() {
|
||||
const addContinuousClickLive = (boxClass) => {
|
||||
const b = Math.floor(Math.random() * 6) + 1
|
||||
const bl = Math.floor(Math.random() * 11) + 1 // bl1~bl11
|
||||
|
||||
let d = document.createElement("div")
|
||||
d.className = `bubble b${b} bl${bl}`
|
||||
d.dataset.t = String(Date.now())
|
||||
const likeBox = document.querySelector(boxClass)
|
||||
likeBox.appendChild(d)
|
||||
;((d) => {
|
||||
d.addEventListener("animationend", () => {
|
||||
debugger
|
||||
if (likeBox.contains(d)) {
|
||||
likeBox.removeChild(d)
|
||||
}
|
||||
})
|
||||
})(d)
|
||||
}
|
||||
|
||||
return addContinuousClickLive
|
||||
}
|
||||
@ -20,12 +20,11 @@
|
||||
detail.advisorBasic && detail.advisorBasic.avatar
|
||||
? detail.advisorBasic.avatar
|
||||
: defaultPhoto
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="news-content-wrap">
|
||||
<div class="user-info">
|
||||
<h3>{{ detail.advisorBasic?.showName }} <span>讲师</span></h3>
|
||||
<h3><span>讲师</span>{{ detail.advisorBasic?.showName }}</h3>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text">
|
||||
@ -49,16 +48,14 @@
|
||||
`li${item.id}`,
|
||||
item.phone === store.state.userInfo.userId ? 'row-reverse' : '',
|
||||
]"
|
||||
:key="item.id"
|
||||
>
|
||||
:key="item.id">
|
||||
<div v-if="item.show">
|
||||
<!-- <div v-if="item.type === 3" class="warn">
|
||||
{{ item.userName }}:进入直播间
|
||||
</div> -->
|
||||
<div
|
||||
class="chat-time"
|
||||
v-if="(isTg && item.tgChatTime) || (!isTg && item.chatTime)"
|
||||
>
|
||||
v-if="(isTg && item.tgChatTime) || (!isTg && item.chatTime)">
|
||||
{{ isTg ? item.tgChatTime : item.chatTime }}
|
||||
</div>
|
||||
<div v-if="item.type === 5" class="warn">
|
||||
@ -72,8 +69,7 @@
|
||||
<button
|
||||
class="share"
|
||||
@click="sendMsg(5)"
|
||||
v-if="item.phone !== store.state.userInfo.userId"
|
||||
>
|
||||
v-if="item.phone !== store.state.userInfo.userId">
|
||||
我也要分享
|
||||
</button>
|
||||
</div>
|
||||
@ -82,8 +78,7 @@
|
||||
:class="[
|
||||
'flex',
|
||||
item.phone === store.state.userInfo.userId ? 'row-reverse' : '',
|
||||
]"
|
||||
>
|
||||
]">
|
||||
<div class="photo">
|
||||
<img
|
||||
:src="
|
||||
@ -95,8 +90,7 @@
|
||||
? item.imgUrl
|
||||
: tgDefaultPhoto
|
||||
"
|
||||
alt=""
|
||||
/>
|
||||
alt="" />
|
||||
</div>
|
||||
<div class="news-content-wrap">
|
||||
<div class="user-info">
|
||||
@ -160,8 +154,7 @@
|
||||
v-else
|
||||
class="img"
|
||||
@click="imagePreview(item.content.split('upImg-')[1])"
|
||||
:src="item.content.split('upImg-')[1]"
|
||||
/>
|
||||
:src="item.content.split('upImg-')[1]" />
|
||||
<div v-if="item.advisorId" class="license">
|
||||
{{ detail.advisorBasic.name
|
||||
}}<i v-if="detail.advisorBasic.license"
|
||||
@ -176,8 +169,7 @@
|
||||
:item="item.productBasic"
|
||||
:liveProductId="detail.id"
|
||||
:tgId="detail.advisorBasic?.id"
|
||||
:isShopCar="true"
|
||||
/>
|
||||
:isShopCar="true" />
|
||||
</div>
|
||||
<div v-else-if="item.type === 4">
|
||||
<p>
|
||||
@ -197,15 +189,13 @@
|
||||
v-if="
|
||||
item.phone !== store.state.userInfo.userId &&
|
||||
detail.isSubAdvisor !== 1
|
||||
"
|
||||
>
|
||||
">
|
||||
我也关注
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="[6, 7, 9, 10].includes(item.type)"
|
||||
style="color: #f46946"
|
||||
>
|
||||
style="color: #f46946">
|
||||
<p>{{ item.content }}</p>
|
||||
</div>
|
||||
<div v-else-if="item.type === 8" style="color: #f46946">
|
||||
@ -264,25 +254,25 @@ import {
|
||||
onMounted,
|
||||
computed,
|
||||
defineEmits,
|
||||
} from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { showToast, showImagePreview } from "vant";
|
||||
} from "vue"
|
||||
import { useStore } from "vuex"
|
||||
import { showToast, showImagePreview } from "vant"
|
||||
import {
|
||||
sendFollowMessage,
|
||||
queryQuestionCheck,
|
||||
queryLiveTgHisMsg,
|
||||
queryLiveHisMsg,
|
||||
} from "@/api/video";
|
||||
import QuestionnairePopup from "../components/QuestionnairePopup.vue";
|
||||
import useChatData from "@/hooks/useChatData";
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj";
|
||||
import ProductItem from "../components/ProductItem.vue";
|
||||
import { attentionTg } from "@/api/index";
|
||||
import emitter from "@/utils/emitter";
|
||||
} from "@/api/video"
|
||||
import QuestionnairePopup from "../components/QuestionnairePopup.vue"
|
||||
import useChatData from "@/hooks/useChatData"
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj"
|
||||
import ProductItem from "../components/ProductItem.vue"
|
||||
import { attentionTg } from "@/api/index"
|
||||
import emitter from "@/utils/emitter"
|
||||
// import dayjs from "dayjs";
|
||||
|
||||
const store = useStore();
|
||||
const $liveStatusObj = useGetLiveStatusObj();
|
||||
const store = useStore()
|
||||
const $liveStatusObj = useGetLiveStatusObj()
|
||||
|
||||
const props = defineProps({
|
||||
className: {
|
||||
@ -302,76 +292,76 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const defaultPhoto = require("@/assets/images/default-photo.png");
|
||||
const tgDefaultPhoto = require("@/assets/images/tg-p.webp");
|
||||
const defaultPhoto = require("@/assets/images/default-photo.png")
|
||||
const tgDefaultPhoto = require("@/assets/images/tg-p.webp")
|
||||
// const productFloatShow = ref(false);
|
||||
const scrollClassName = ref(`interact-scroll-${new Date().getTime()}`);
|
||||
const scrollClassName = ref(`interact-scroll-${new Date().getTime()}`)
|
||||
|
||||
const { msgListRef, bs } = useChatData(
|
||||
Object.assign({ isTg: props.isTg }, props.detail, {
|
||||
className: `.${scrollClassName.value}`,
|
||||
})
|
||||
);
|
||||
)
|
||||
|
||||
const hasNext = computed(() => {
|
||||
return props.isTg
|
||||
? store.state.interactMsgObj.tgHasHisMsg
|
||||
: store.state.interactMsgObj.hasHisMsg;
|
||||
});
|
||||
: store.state.interactMsgObj.hasHisMsg
|
||||
})
|
||||
|
||||
watch(hasNext, (value) => {
|
||||
if (value) bs.value && bs.value.openPullDown();
|
||||
});
|
||||
if (value) bs.value && bs.value.openPullDown()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.informMsgList,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
bs.value && bs.value.refresh();
|
||||
bs.value && bs.value.refresh()
|
||||
if (
|
||||
(props.isTg && store.state.interactMsgObj.isTgScrollToBottom) ||
|
||||
(!props.isTg && store.state.interactMsgObj.isScrollToBottom)
|
||||
) {
|
||||
nextTick(() => {
|
||||
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0);
|
||||
});
|
||||
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0)
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
)
|
||||
|
||||
let intervalTime = null;
|
||||
let intervalTime = null
|
||||
|
||||
const replenishMsg = async () => {
|
||||
let fn = props.isTg ? queryLiveTgHisMsg : queryLiveHisMsg;
|
||||
let fn = props.isTg ? queryLiveTgHisMsg : queryLiveHisMsg
|
||||
let ret = await fn({
|
||||
id: props.detail.id,
|
||||
lastId: "",
|
||||
size: 20,
|
||||
status: 1,
|
||||
});
|
||||
})
|
||||
if (ret.code === 0) {
|
||||
let list = ret.data.list.reverse();
|
||||
emitter.emit("informMsgListPush", list);
|
||||
let list = ret.data.list.reverse()
|
||||
emitter.emit("informMsgListPush", list)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let getNewMsg = (once) => {
|
||||
if (once) {
|
||||
replenishMsg();
|
||||
replenishMsg()
|
||||
} else {
|
||||
clearInterval(intervalTime);
|
||||
intervalTime = setInterval(replenishMsg, 1000 * 30);
|
||||
clearInterval(intervalTime)
|
||||
intervalTime = setInterval(replenishMsg, 1000 * 30)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
emitter.on("getNewMsg", getNewMsg);
|
||||
emitter.on("getNewMsg", getNewMsg)
|
||||
emitter.on("cancelGetNewMsg", () => {
|
||||
clearInterval(intervalTime);
|
||||
});
|
||||
clearInterval(intervalTime)
|
||||
})
|
||||
|
||||
async function subAdvisor() {
|
||||
let ret = await attentionTg({
|
||||
@ -379,11 +369,11 @@ async function subAdvisor() {
|
||||
channel: 2,
|
||||
option: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
videoId: props.detail.id,
|
||||
});
|
||||
})
|
||||
if (ret.code === 0) {
|
||||
emitter.emit("updateVideoDetail", {
|
||||
isSubAdvisor: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
});
|
||||
})
|
||||
props.detail.isSubAdvisor === 1 &&
|
||||
[
|
||||
$liveStatusObj.InLive,
|
||||
@ -393,86 +383,86 @@ async function subAdvisor() {
|
||||
sendFollowMessage({
|
||||
id: props.detail.id,
|
||||
option: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const questionnairePopupRef = ref();
|
||||
const questionId = ref();
|
||||
const questionnairePopupRef = ref()
|
||||
const questionId = ref()
|
||||
const goAnswer = async (item) => {
|
||||
let ret = await queryQuestionCheck({ questionId: item.questionId });
|
||||
let ret = await queryQuestionCheck({ questionId: item.questionId })
|
||||
if (ret.code === 0) {
|
||||
if (ret.data.result) {
|
||||
questionId.value = item.questionId;
|
||||
questionnairePopupRef.value.showPopup = true;
|
||||
questionId.value = item.questionId
|
||||
questionnairePopupRef.value.showPopup = true
|
||||
} else if (ret.data.type === 1) {
|
||||
return showToast("您已完成问卷任务,无须重复填写!");
|
||||
return showToast("您已完成问卷任务,无须重复填写!")
|
||||
} else if (ret.data.type === 2) {
|
||||
return showToast("问卷已删除!");
|
||||
return showToast("问卷已删除!")
|
||||
}
|
||||
}
|
||||
};
|
||||
const emit = defineEmits(["optShare"]);
|
||||
}
|
||||
const emit = defineEmits(["optShare"])
|
||||
const sendMsg = (type, params) => {
|
||||
if (type === 5) {
|
||||
emit("optShare");
|
||||
emit("optShare")
|
||||
}
|
||||
emitter.emit("emSendMsg", {
|
||||
type,
|
||||
params,
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
emitter.off("getNewMsg");
|
||||
emitter.off("cancelGetNewMsg");
|
||||
});
|
||||
emitter.off("getNewMsg")
|
||||
emitter.off("cancelGetNewMsg")
|
||||
})
|
||||
|
||||
const imagePreview = (url) => {
|
||||
showImagePreview({
|
||||
images: [url],
|
||||
closeable: true,
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
const newMsgNum = computed(() => {
|
||||
return props.isTg
|
||||
? store.state.interactMsgObj.temTgInteractShowNum
|
||||
: store.state.interactMsgObj.temUserInteractShowNum;
|
||||
});
|
||||
: store.state.interactMsgObj.temUserInteractShowNum
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
bs.value.on("scrollEnd", () => {
|
||||
let isBottom = bs.value.maxScrollY + 20 >= bs.value.y;
|
||||
let isBottom = bs.value.maxScrollY + 20 >= bs.value.y
|
||||
store.commit("setIsScrollToBottom", {
|
||||
isTg: props.isTg,
|
||||
data: isBottom,
|
||||
});
|
||||
if (isBottom) resetData();
|
||||
});
|
||||
});
|
||||
})
|
||||
if (isBottom) resetData()
|
||||
})
|
||||
})
|
||||
|
||||
const lookNewMsg = () => {
|
||||
resetData();
|
||||
};
|
||||
resetData()
|
||||
}
|
||||
|
||||
const resetData = () => {
|
||||
store.commit("interactMsgMerge", { isTg: props.isTg });
|
||||
store.commit("interactMsgMerge", { isTg: props.isTg })
|
||||
nextTick(() => {
|
||||
bs.value && bs.value.refresh();
|
||||
bs.value && bs.value.refresh()
|
||||
nextTick(() => {
|
||||
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0);
|
||||
});
|
||||
});
|
||||
};
|
||||
bs.value && bs.value.scrollTo(0, bs.value.maxScrollY, 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const maskUserName = (value) => {
|
||||
return value.charAt(0) + "**";
|
||||
};
|
||||
return value.charAt(0) + "**"
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
bs,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.interact-scroll {
|
||||
@ -519,18 +509,19 @@ defineExpose({
|
||||
h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
color: #1b2330;
|
||||
font-size: 24px;
|
||||
color: #666666;
|
||||
line-height: 28px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 600;
|
||||
span {
|
||||
color: #ff6f16;
|
||||
font-size: 22px;
|
||||
line-height: 22px;
|
||||
margin-left: 20px;
|
||||
border: 1px solid #ff3d36;
|
||||
margin-right: 10px;
|
||||
background: linear-gradient(90deg, #66adff, #1472ff);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -568,14 +559,14 @@ defineExpose({
|
||||
}
|
||||
.reply-content,
|
||||
.text {
|
||||
background: #2e78fa;
|
||||
color: #fff;
|
||||
background: #87ee7e;
|
||||
color: #333;
|
||||
}
|
||||
.reply-content,
|
||||
.text,
|
||||
& > img,
|
||||
.share-tip {
|
||||
border-radius: 20px 4px 20px 20px;
|
||||
border-radius: 10px 4px 10px 10px;
|
||||
}
|
||||
.news-content-wrap > div {
|
||||
flex-flow: row-reverse;
|
||||
@ -605,11 +596,11 @@ defineExpose({
|
||||
.reply-content {
|
||||
padding: 16px 24px;
|
||||
background: #fff;
|
||||
border-radius: 4px 20px 20px 20px;
|
||||
font-size: 26px;
|
||||
color: #606877;
|
||||
border-radius: 4px 10px 10px 10px;
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
text-align: justify;
|
||||
line-height: 30px;
|
||||
line-height: 36px;
|
||||
}
|
||||
.license {
|
||||
padding: 0;
|
||||
|
||||
@ -2,37 +2,35 @@
|
||||
<div class="scroll-wrap">
|
||||
<div class="detail-desc">
|
||||
<div class="detail-title fw-5" @click="$egg(3, 1000)">
|
||||
{{ detail.title }}
|
||||
<h4>{{ detail.title }}</h4>
|
||||
<div class="play-count">{{ detail.readCount }}次播放</div>
|
||||
</div>
|
||||
<div class="tag-count flex-ac-sb">
|
||||
<div v-show="detail.infoVO" class="tag">
|
||||
{{ `${detail.infoVO?.productName} 专属服务` }}
|
||||
</div>
|
||||
<div class="count flex-ac">
|
||||
<!-- <div class="count flex-ac">
|
||||
<div class="play-count">{{ detail.readCount }}次播放</div>
|
||||
<div class="star-count flex-ac" v-if="!$shieldConfig.tgLive">
|
||||
<img
|
||||
v-if="detail.isFavor === 1"
|
||||
src="@/assets/images/like-icon3.png"
|
||||
alt=""
|
||||
/>
|
||||
alt="" />
|
||||
<img
|
||||
v-else
|
||||
src="@/assets/images/like-icon.png"
|
||||
alt=""
|
||||
@click="sendLikeVideo(1)"
|
||||
/>
|
||||
@click="sendLikeVideo(1)" />
|
||||
<div
|
||||
class="text-18 fw-5"
|
||||
:class="detail.isFavor === 1 ? 'tc-f13721' : 'tc-1B2330'"
|
||||
>
|
||||
:class="detail.isFavor === 1 ? 'tc-f13721' : 'tc-1B2330'">
|
||||
{{ detail.favorUserCount ? detail.favorUserCount : "" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="author">
|
||||
<div class="mb20">
|
||||
<div>
|
||||
<div class="author-desc flex-ac">
|
||||
<img
|
||||
class="avatar"
|
||||
@ -41,41 +39,38 @@
|
||||
? detail.advisorBasic.avatar
|
||||
: defaultPhoto
|
||||
"
|
||||
alt=""
|
||||
/>
|
||||
alt="" />
|
||||
<label>主讲</label>
|
||||
<div>
|
||||
<div class="text-28 tc-606877">
|
||||
{{ detail.advisorBasic?.showName }}
|
||||
</div>
|
||||
</div>
|
||||
<label>主讲</label>
|
||||
</div>
|
||||
<div class="handle flex-ac no-wrap">
|
||||
<button
|
||||
class="add"
|
||||
@click.stop="subAdvisor"
|
||||
v-if="!$shieldConfig.tgLive"
|
||||
>
|
||||
v-if="!$shieldConfig.tgLive">
|
||||
{{ detail.isSubAdvisor === 1 ? "取消关注" : "关注" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="author-desc flex-ac" v-if="detail.guestInfo">
|
||||
<img class="avatar" :src="detail.guestInfo.avatar" alt="" />
|
||||
<label>嘉宾</label>
|
||||
<div>
|
||||
<div class="text-28 tc-606877">
|
||||
{{ detail.guestInfo.showName }}
|
||||
</div>
|
||||
</div>
|
||||
<label>嘉宾</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div
|
||||
v-if="detail.liveStatus === $liveStatusObj.NotStart"
|
||||
class="countdown-wrapper"
|
||||
>
|
||||
class="countdown-wrapper">
|
||||
<!-- <img class="coupon" src="@/assets/image/coupon@2x.png" alt="" @click="toTicket()" /> -->
|
||||
<div class="title-time flex-ac-sb">
|
||||
<div class="text-36 fw-5 tc-1B2330">
|
||||
@ -93,13 +88,11 @@
|
||||
detail.isSubscribe !== 1 && detail.allowSubscribe !== 2
|
||||
? 'to-preview'
|
||||
: 'previewd'
|
||||
"
|
||||
>
|
||||
">
|
||||
<div
|
||||
v-if="detail.isSubscribe !== 1 && detail.allowSubscribe !== 2"
|
||||
class="flex-ac"
|
||||
v-preReClick="setSubLiveVideo"
|
||||
>
|
||||
v-preReClick="setSubLiveVideo">
|
||||
<img class="status-icon" src="@/assets/images/status2.png" alt="" />
|
||||
<div class="desc tc-2E78FA">
|
||||
{{ detail.playType == 1 ? "预约直播" : "预约视频" }}
|
||||
@ -116,7 +109,7 @@
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="watch-focus">
|
||||
<div class="text-36 tc-1B2330 fw-5">本期看点</div>
|
||||
<div class="text-36 tc-1B2330 fw-5">视频简介</div>
|
||||
<div class="watch-content tc-1B2330">
|
||||
{{ detail.viewPoint }}
|
||||
</div>
|
||||
@ -126,25 +119,25 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, onMounted } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { sendFollowMessage, likeVideo } from "@/api/video";
|
||||
import { attentionTg } from "@/api/index";
|
||||
import emitter from "@/utils/emitter";
|
||||
import CountDown from "./components/CountDown.vue";
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj";
|
||||
import useDisableScroll from "@/hooks/useDisableScroll";
|
||||
import { subLiveVideo } from "@/api/video";
|
||||
import useShieldConfig from "@/hooks/useShieldConfig";
|
||||
import useLoadConsole from "@/hooks/useLoadConsole";
|
||||
const $egg = useLoadConsole();
|
||||
const $liveStatusObj = useGetLiveStatusObj();
|
||||
const route = useRoute();
|
||||
const $shieldConfig = useShieldConfig();
|
||||
const { addScrollEvent } = useDisableScroll();
|
||||
import { defineProps, onMounted } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import { sendFollowMessage } from "@/api/video"
|
||||
import { attentionTg } from "@/api/index"
|
||||
import emitter from "@/utils/emitter"
|
||||
import CountDown from "./components/CountDown.vue"
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj"
|
||||
import useDisableScroll from "@/hooks/useDisableScroll"
|
||||
import { subLiveVideo } from "@/api/video"
|
||||
import useShieldConfig from "@/hooks/useShieldConfig"
|
||||
import useLoadConsole from "@/hooks/useLoadConsole"
|
||||
const $egg = useLoadConsole()
|
||||
const $liveStatusObj = useGetLiveStatusObj()
|
||||
const route = useRoute()
|
||||
const $shieldConfig = useShieldConfig()
|
||||
const { addScrollEvent } = useDisableScroll()
|
||||
onMounted(() => {
|
||||
addScrollEvent(".scroll-wrap");
|
||||
});
|
||||
addScrollEvent(".scroll-wrap")
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
detail: {
|
||||
@ -152,8 +145,8 @@ const props = defineProps({
|
||||
ype: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const defaultPhoto = require("@/assets/images/default-photo.png");
|
||||
})
|
||||
const defaultPhoto = require("@/assets/images/default-photo.png")
|
||||
|
||||
// 关注投顾
|
||||
async function subAdvisor() {
|
||||
@ -162,11 +155,11 @@ async function subAdvisor() {
|
||||
channel: 2,
|
||||
option: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
videoId: props.detail.id,
|
||||
});
|
||||
})
|
||||
if (ret.code === 0) {
|
||||
emitter.emit("updateVideoDetail", {
|
||||
isSubAdvisor: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
});
|
||||
})
|
||||
props.detail.isSubAdvisor === 1 &&
|
||||
[
|
||||
$liveStatusObj.InLive,
|
||||
@ -176,37 +169,37 @@ async function subAdvisor() {
|
||||
sendFollowMessage({
|
||||
id: props.detail.id,
|
||||
option: props.detail.isSubAdvisor === 1 ? 2 : 1,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const sendLikeVideo = async (liveNum) => {
|
||||
const ret = await likeVideo({
|
||||
id: props.detail.id,
|
||||
option: 1,
|
||||
num: liveNum,
|
||||
});
|
||||
if (ret.code === 0) {
|
||||
emitter.emit("updateVideoDetail", {
|
||||
isFavor: 1,
|
||||
favorUserCount: ret.data.count,
|
||||
});
|
||||
}
|
||||
};
|
||||
// const sendLikeVideo = async (liveNum) => {
|
||||
// const ret = await likeVideo({
|
||||
// id: props.detail.id,
|
||||
// option: 1,
|
||||
// num: liveNum,
|
||||
// })
|
||||
// if (ret.code === 0) {
|
||||
// emitter.emit("updateVideoDetail", {
|
||||
// isFavor: 1,
|
||||
// favorUserCount: ret.data.count,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
const setSubLiveVideo = async () => {
|
||||
let ret = await subLiveVideo({
|
||||
id: props.detail.id,
|
||||
option: props.detail.isSubscribe === 1 ? 2 : 1,
|
||||
saleUserId: route.query.saleUserId,
|
||||
});
|
||||
})
|
||||
if (ret.code === 0) {
|
||||
emitter.emit("updateVideoDetail", {
|
||||
isSubscribe: props.detail.isSubscribe === 1 ? 2 : 1,
|
||||
subscribeUserCount: ret.data.count,
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.mb20 {
|
||||
@ -260,11 +253,25 @@ const setSubLiveVideo = async () => {
|
||||
background-color: #fff;
|
||||
text-align: left;
|
||||
.detail-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 36px;
|
||||
line-height: 54px;
|
||||
margin-bottom: 8px;
|
||||
color: #1b2330;
|
||||
font-weight: 500;
|
||||
h4 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
.play-count {
|
||||
margin: 0 20px 0 16px;
|
||||
color: #9aa4b6;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
.tag {
|
||||
padding: 6px 8px;
|
||||
@ -276,9 +283,9 @@ const setSubLiveVideo = async () => {
|
||||
color: #9aa4b6;
|
||||
font-size: 24px;
|
||||
}
|
||||
.play-count {
|
||||
margin: 0 20px 0 16px;
|
||||
}
|
||||
// .play-count {
|
||||
// margin: 0 20px 0 16px;
|
||||
// }
|
||||
.star-count {
|
||||
img {
|
||||
width: 32px;
|
||||
@ -290,6 +297,12 @@ const setSubLiveVideo = async () => {
|
||||
padding: 24px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
& > div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
& > div:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.avatar {
|
||||
margin-right: 12px;
|
||||
width: 60px;
|
||||
@ -314,12 +327,13 @@ const setSubLiveVideo = async () => {
|
||||
}
|
||||
.author-desc {
|
||||
label {
|
||||
font-size: 24px;
|
||||
color: #2e78fa;
|
||||
border: 1px solid #2e78fa;
|
||||
padding: 4px 16px;
|
||||
border-radius: 12px;
|
||||
margin-left: 16px;
|
||||
font-size: 22px;
|
||||
line-height: 22px;
|
||||
margin-right: 10px;
|
||||
background: linear-gradient(90deg, #66adff, #1472ff);
|
||||
padding: 6px 8px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,16 +6,18 @@
|
||||
:overlay="false"
|
||||
:round="false"
|
||||
:lock-scroll="false"
|
||||
:lazy-render="false"
|
||||
>
|
||||
:lazy-render="false">
|
||||
<div class="msg-content">
|
||||
<ChatFrame
|
||||
:informMsgList="detail.interactType === 2 ? store.state.interactMsgObj.userInteractMsgList : store.state.interactMsgObj.tgInteractMsgList"
|
||||
:informMsgList="
|
||||
detail.interactType === 2
|
||||
? store.state.interactMsgObj.userInteractMsgList
|
||||
: store.state.interactMsgObj.tgInteractMsgList
|
||||
"
|
||||
:detail="detail"
|
||||
:isTg="detail.interactType === 1"
|
||||
@optShare="optShare"
|
||||
ref="ChatFrameRef"
|
||||
/>
|
||||
ref="ChatFrameRef" />
|
||||
</div>
|
||||
<div class="input-area">
|
||||
<input
|
||||
@ -27,7 +29,7 @@
|
||||
? '直播结束,暂不支持互动哟~'
|
||||
: isSpeak
|
||||
? '互动已关闭...'
|
||||
: '与老师互动...'
|
||||
: '说点什么...'
|
||||
"
|
||||
v-model.trim="text"
|
||||
@focus="inputMsg"
|
||||
@ -36,13 +38,11 @@
|
||||
isSpeak ||
|
||||
[$liveStatusObj.FinishPlay].includes(detail.liveStatus)
|
||||
"
|
||||
@keyup.enter="sendMsg(1, { text })"
|
||||
/>
|
||||
@keyup.enter="sendMsg(1, { text })" />
|
||||
<button
|
||||
class="send"
|
||||
:disabled="!text || sendTextLoading"
|
||||
@click="sendMsg(1, { text })"
|
||||
>
|
||||
@click="sendMsg(1, { text })">
|
||||
发送
|
||||
</button>
|
||||
</div>
|
||||
@ -51,15 +51,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineProps, watch, defineExpose, nextTick, defineEmits } from "vue";
|
||||
import { showToast } from "vant";
|
||||
import emitter from "@/utils/emitter";
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj";
|
||||
import ChatFrame from "./ChatFrame.vue";
|
||||
import { useStore } from "vuex";
|
||||
const $liveStatusObj = useGetLiveStatusObj();
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
watch,
|
||||
defineExpose,
|
||||
nextTick,
|
||||
defineEmits,
|
||||
} from "vue"
|
||||
import { showToast } from "vant"
|
||||
import emitter from "@/utils/emitter"
|
||||
import useGetLiveStatusObj from "@/hooks/useGetLiveStatusObj"
|
||||
import ChatFrame from "./ChatFrame.vue"
|
||||
import { useStore } from "vuex"
|
||||
const $liveStatusObj = useGetLiveStatusObj()
|
||||
|
||||
const store = useStore();
|
||||
const store = useStore()
|
||||
const props = defineProps({
|
||||
detail: {
|
||||
// 视频详情
|
||||
@ -71,85 +78,85 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
optShare:{
|
||||
optShare: {
|
||||
type: Function,
|
||||
default: ()=>{}
|
||||
}
|
||||
});
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const show = ref(false);
|
||||
const show = ref(false)
|
||||
|
||||
const showRecommend = ref(false); // 展示活动模块
|
||||
const showRecommend = ref(false) // 展示活动模块
|
||||
watch(
|
||||
() => props.activityObj,
|
||||
() => {
|
||||
if (props.activityObj && Object.keys(props.activityObj).length) {
|
||||
showRecommend.value = true;
|
||||
showRecommend.value = true
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const ChatFrameRef = ref();
|
||||
const ChatFrameRef = ref()
|
||||
|
||||
const emit = defineEmits(['bsRefresh'])
|
||||
const emit = defineEmits(["bsRefresh"])
|
||||
watch(
|
||||
() => show.value,
|
||||
(val) => {
|
||||
nextTick(() => {
|
||||
if (val) {
|
||||
if (ChatFrameRef.value && ChatFrameRef.value.bs){
|
||||
ChatFrameRef.value.bs.refresh();
|
||||
ChatFrameRef.value.bs.scrollTo(0, ChatFrameRef.value.bs.maxScrollY, 0);
|
||||
if (ChatFrameRef.value && ChatFrameRef.value.bs) {
|
||||
ChatFrameRef.value.bs.refresh()
|
||||
ChatFrameRef.value.bs.scrollTo(0, ChatFrameRef.value.bs.maxScrollY, 0)
|
||||
}
|
||||
} else {
|
||||
emit('bsRefresh')
|
||||
emit("bsRefresh")
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
function inputMsg() {
|
||||
let bs = ChatFrameRef.value.bs;
|
||||
bs && bs.stop();
|
||||
bs && bs.scrollTo(0, bs.maxScrollY, 0);
|
||||
let bs = ChatFrameRef.value.bs
|
||||
bs && bs.stop()
|
||||
bs && bs.scrollTo(0, bs.maxScrollY, 0)
|
||||
}
|
||||
|
||||
const text = ref();
|
||||
const sendTextLoading = ref(false);
|
||||
const text = ref()
|
||||
const sendTextLoading = ref(false)
|
||||
const sendMsg = (type, params = {}) => {
|
||||
if (![1, 4].includes(type)) {
|
||||
// 不是聊天互动
|
||||
emitter.emit("emSendMsg", { type, params });
|
||||
emitter.emit("emSendMsg", { type, params })
|
||||
}
|
||||
switch (type) {
|
||||
case 1:
|
||||
if (text.value) {
|
||||
sendTextLoading.value = true;
|
||||
sendTextLoading.value = true
|
||||
emitter.emit("emSendMsg", {
|
||||
type,
|
||||
params: {
|
||||
...params,
|
||||
callBack: () => {
|
||||
sendTextLoading.value = false;
|
||||
text.value = "";
|
||||
sendTextLoading.value = false
|
||||
text.value = ""
|
||||
},
|
||||
errorBack: () => {
|
||||
sendTextLoading.value = false;
|
||||
sendTextLoading.value = false
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
} else {
|
||||
showToast("请输入互动内容!");
|
||||
showToast("请输入互动内容!")
|
||||
}
|
||||
break;
|
||||
break
|
||||
default:
|
||||
break;
|
||||
break
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
::v-deep .van-popup {
|
||||
|
||||
@ -9,8 +9,7 @@
|
||||
"
|
||||
:detail="detail"
|
||||
:isTg="detail.interactType === 2"
|
||||
@optShare="optShare"
|
||||
/>
|
||||
@optShare="optShare" />
|
||||
<div class="operate-wrap">
|
||||
<div class="operate" @click="showInteractAction">
|
||||
<img src="@/assets/images/msg-icon.png" alt="" />
|
||||
@ -18,20 +17,17 @@
|
||||
<div
|
||||
class="operate"
|
||||
@click="changeMsgTip"
|
||||
v-show="detail.interactType === 2"
|
||||
>
|
||||
v-show="detail.interactType === 2">
|
||||
<img :src="msgTipIcon[msgTipIndex]" alt="" />
|
||||
</div>
|
||||
<ul
|
||||
class="new-msg-list"
|
||||
v-show="msgTipIndex === 1"
|
||||
v-if="detail.interactType === 2"
|
||||
>
|
||||
v-if="detail.interactType === 2">
|
||||
<li
|
||||
v-for="(item, index) in newMsgTree"
|
||||
:key="index"
|
||||
@click="showInteractAction"
|
||||
>
|
||||
@click="showInteractAction">
|
||||
<div class="content">
|
||||
<p>{{ item.content }}</p>
|
||||
<img :src="item.imgUrl" />
|
||||
@ -43,8 +39,7 @@
|
||||
<div
|
||||
class="recommend-img"
|
||||
v-show="showRecommend"
|
||||
@click="toActivityPage(1)"
|
||||
>
|
||||
@click="toActivityPage(1)">
|
||||
<img :src="activityObj.imgUrl" alt="" srcset="" />
|
||||
<i @click.stop="closeActivity"></i>
|
||||
</div>
|
||||
@ -63,7 +58,7 @@
|
||||
? '直播结束,暂不支持互动哟~'
|
||||
: isSpeak
|
||||
? '互动已关闭...'
|
||||
: '与老师互动...'
|
||||
: '说点什么...'
|
||||
"
|
||||
v-model.trim="text"
|
||||
@focus="inputMsg"
|
||||
@ -72,13 +67,11 @@
|
||||
isSpeak ||
|
||||
[$liveStatusObj.FinishPlay].includes(detail.liveStatus)
|
||||
"
|
||||
@keyup.enter="sendMsg(1, { text })"
|
||||
/>
|
||||
@keyup.enter="sendMsg(1, { text })" />
|
||||
<button
|
||||
class="send"
|
||||
:disabled="!text || sendTextLoading"
|
||||
@click="sendMsg(1, { text })"
|
||||
>
|
||||
@click="sendMsg(1, { text })">
|
||||
发送
|
||||
</button>
|
||||
<button
|
||||
@ -87,13 +80,16 @@
|
||||
v-if="
|
||||
terminalType === 'Browser' ||
|
||||
(terminalType === 'App' && system === 'android')
|
||||
"
|
||||
></button>
|
||||
"></button>
|
||||
<button
|
||||
v-if="detail.liveStatus !== $liveStatusObj.NotStart"
|
||||
:class="['star', favorUserCountObj.isFavor === 1 ? 'active' : '']"
|
||||
@click.stop="sendMsg(4)"
|
||||
>
|
||||
class="star-btn"
|
||||
v-if="detail.liveStatus !== $liveStatusObj.NotStart">
|
||||
<div
|
||||
@click.stop="sendMsg(4)"
|
||||
:class="[
|
||||
'star',
|
||||
favorUserCountObj.isFavor === 1 ? 'active' : '',
|
||||
]"></div>
|
||||
<span v-if="favorUserCountObj.favorUserCount">{{
|
||||
bigNumberTransform(favorUserCountObj.favorUserCount)
|
||||
}}</span>
|
||||
@ -105,8 +101,7 @@
|
||||
couponDetail &&
|
||||
couponDetail.sendTotalNumber - couponDetail.sendGottenNumber > 0
|
||||
"
|
||||
@click="showDiscountCoupon"
|
||||
>
|
||||
@click="showDiscountCoupon">
|
||||
<!-- <p>
|
||||
仅剩{{ couponDetail.sendTotalNumber - couponDetail.sendGottenNumber }}份
|
||||
</p> -->
|
||||
@ -122,8 +117,7 @@
|
||||
ref="InteractRef"
|
||||
:isSpeak="isSpeak"
|
||||
:optShare="optShare"
|
||||
@bsRefresh="bsRefresh"
|
||||
/>
|
||||
@bsRefresh="bsRefresh" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -151,6 +145,7 @@ import ChatFrame from "./ChatFrame.vue"
|
||||
import Interact from "./Interact.vue"
|
||||
import { terminalType } from "@/utils/index"
|
||||
import { getSystem } from "@/utils/index"
|
||||
import useContinuousClickLive from "@/hooks/useContinuousClickLive"
|
||||
// import TgChatFrame from "./TgChatFrame.vue";
|
||||
// import MainInteract from "./MainInteract.vue";
|
||||
import { queryCartRead } from "@/api/video"
|
||||
@ -317,12 +312,12 @@ const closeCarPush = () => {
|
||||
}
|
||||
|
||||
let liveIndex = 0
|
||||
const liveIcon = [
|
||||
require("@/assets/images/liveIcon/icon1.png"),
|
||||
require("@/assets/images/liveIcon/icon2.png"),
|
||||
require("@/assets/images/liveIcon/icon3.png"),
|
||||
require("@/assets/images/liveIcon/icon4.png"),
|
||||
]
|
||||
// const liveIcon = [
|
||||
// require("@/assets/images/liveIcon/icon1.png"),
|
||||
// require("@/assets/images/liveIcon/icon2.png"),
|
||||
// require("@/assets/images/liveIcon/icon3.png"),
|
||||
// require("@/assets/images/liveIcon/icon4.png"),
|
||||
// ]
|
||||
const favorUserCountObj = reactive({
|
||||
favorUserCount: props.detail.favorUserCount,
|
||||
isFavor: props.detail.isFavor,
|
||||
@ -342,18 +337,22 @@ const sendLikeVideo = async (liveNum) => {
|
||||
}
|
||||
let sendLiveTime = null
|
||||
|
||||
const addContinuousClickLive = useContinuousClickLive()
|
||||
console.log(addContinuousClickLive)
|
||||
const dblclickLive = () => {
|
||||
const img = document.createElement("img")
|
||||
img.setAttribute("src", liveIcon[liveIndex % 4])
|
||||
img.setAttribute("class", "live-icon")
|
||||
document.querySelector(".star").appendChild(img)
|
||||
liveIndex++
|
||||
;((img) => {
|
||||
setTimeout(() => {
|
||||
let star = document.querySelector(".star")
|
||||
star && star.removeChild(img)
|
||||
}, 2000)
|
||||
})(img)
|
||||
debugger
|
||||
// const img = document.createElement("img")
|
||||
// img.setAttribute("src", liveIcon[liveIndex % 4])
|
||||
// img.setAttribute("class", "live-icon")
|
||||
// const starBox = document.querySelector(".star-btn")
|
||||
// starBox.appendChild(img)
|
||||
// liveIndex++
|
||||
// ;((img) => {
|
||||
// setTimeout(() => {
|
||||
// starBox && starBox.removeChild(img)
|
||||
// }, 2000)
|
||||
// })(img)
|
||||
addContinuousClickLive(".star-btn")
|
||||
clearTimeout(sendLiveTime)
|
||||
sendLiveTime = setTimeout(() => {
|
||||
sendLikeVideo(liveIndex)
|
||||
@ -443,6 +442,8 @@ defineExpose({
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import url("@/assets/css/live.css");
|
||||
|
||||
::v-deep .user-in-tip {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
@ -522,20 +523,26 @@ defineExpose({
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-left: 20px;
|
||||
background: url(../../../assets/images/share1.png) no-repeat center;
|
||||
background: url(../../../assets/images/share3.png) no-repeat center;
|
||||
background-size: contain;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.star {
|
||||
.star-btn {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
position: relative;
|
||||
background: url(../../../assets/images/h-like.png) no-repeat center;
|
||||
background-size: 52px 52px;
|
||||
margin-left: 20px;
|
||||
&.active {
|
||||
background: url(../../../assets/images/h-like1.png) no-repeat center;
|
||||
background: none;
|
||||
margin-right: 10px;
|
||||
.star {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url(../../../assets/images/h-like.png) no-repeat center;
|
||||
background-size: 52px 52px;
|
||||
margin-left: 20px;
|
||||
&.active {
|
||||
background: url(../../../assets/images/h-like1.png) no-repeat center;
|
||||
background-size: 52px 52px;
|
||||
}
|
||||
}
|
||||
span {
|
||||
position: absolute;
|
||||
|
||||