Browse Source

分屏

master
py 9 months ago
parent
commit
4e67a6d983
  1. 11
      src/views/Banner/BannerForm.vue
  2. 202
      src/views/Board/components/welcome.vue

11
src/views/Banner/BannerForm.vue

@ -129,10 +129,10 @@ const formItemList = computed(()=>{
selectData: dataCategory
},
{label: '背景图片', prop: 'backgroundImages', type: 'image'},
{label: '一屏', prop: 'oneScreen', type: 'image', limit: 6,hide:true,show:formData.value.category === 1},
{label: '二屏', prop: 'twoScreen', type: 'image', limit: 6,hide:true,show:formData.value.category === 2},
{label: '三屏', prop: 'threeScreen', type: 'image', limit: 6,hide:true,show:formData.value.category === 3},
{label: '四屏', prop: 'fourScreen', type: 'image', limit: 6,hide:true,show:formData.value.category === 4}
{label: '一屏', prop: 'oneScreen', type: 'image', limit: 6,hide:true,show:true},
{label: '二屏', prop: 'twoScreen', type: 'image', limit: 6,hide:true,show:formData.value.category >= 2},
{label: '三屏', prop: 'threeScreen', type: 'image', limit: 6,hide:true,show:formData.value.category >= 3},
{label: '四屏', prop: 'fourScreen', type: 'image', limit: 6,hide:true,show:formData.value.category >= 4}
]
}
})
@ -149,8 +149,7 @@ const getAIContent = async () => {
if (AILoading.value) return
try {
AILoading.value = true
const res = await BannerApi.getContentBanner(`帮我生成生日祝福,返回数组格式,一个大数组,嵌套2个数组,里面的数组是生成的祝福语句,可以混一起,其他多余的字符不要,前面加个类似🎉 🌼 🎂 🎈 🌟 💐 这种小图标,数组格式不是字符串,姓名叫${formData.value.fullName},一人两条祝福,,名字可能为空,空就直接三条生日祝福。`)
console.log(res, '===')
const res = await BannerApi.getContentBanner(`帮我生成生日祝福语带上姓名,姓名叫${formData.value.fullName},返回数组格式,一个大数组,嵌套2个数组存放所有祝福语,一人两条祝福,两个数组各一条,前面加个类似🎉 🌼 🎂 🎈 🌟 💐 这种小图标,其余字符全部不要。`)
formData.value.barrage = res
AILoading.value = false
} catch {

202
src/views/Board/components/welcome.vue

@ -14,110 +14,152 @@
</swiper-slide>
</swiper>
<div class="text-box" v-if="[1].includes(boardData.type)">
<div class="title">{{boardData.title}}</div>
<div class="content">{{boardData.content}}</div>
<div class="title">{{ boardData.title }}</div>
<div class="content">{{ boardData.content }}</div>
</div>
<template v-if="boardData.type === 3">
<template v-else-if="boardData.type === 3">
<div class="qr-box">
<Qrcode :options="{margin:0}" :width="60" :text="previewUrl" logo="/logo.png" />
<Qrcode :options="{ margin: 0 }" :width="60" :text="previewUrl" logo="/logo.png" />
<span>扫码送祝福</span>
</div>
<!-- 弹幕容器 -->
<div class="barrage-container">
<marquee direction="left" scrollamount="10" v-for="(item,index) in barrageList" :key="index">
<marquee
direction="left"
scrollamount="10"
v-for="(item, index) in barrageList"
:key="index"
>
<div class="div-box">
<span v-for="(v,i) in item" :key="i">{{ v }}</span>
<span v-for="(v, i) in item" :key="i">{{ v }}</span>
</div>
</marquee>
</div>
</template>
<div :class="['screen-box', 'screen-' + boardData.category]" v-if="boardData.type === 4">
<swiper
v-for="item in showScreenList"
:key="item.value"
:modules="[Autoplay]"
:slides-per-view="1"
:loop="true"
:autoplay="{ delay: 5000, disableOnInteraction: false }"
class="my-swiper"
>
<swiper-slide v-for="(slide, index) in boardData[item.prop] || []" :key="index">
<div class="swiper-slide-box">
<img :src="slide" alt="图片" />
</div>
</swiper-slide>
</swiper>
</div>
</div>
</template>
<script setup lang="ts">
import { Autoplay } from "swiper/modules";
import {getAccessToken} from "@/utils/auth";
import { Autoplay } from 'swiper/modules'
import { getAccessToken } from '@/utils/auth'
import { useWebSocket } from '@vueuse/core'
import { isArray } from 'min-dash'
const message = useMessage() //
const props = defineProps({
const props = defineProps({
boardData: {
type: Object,
default: () => ({ backgroundImages: [],code:'' }),
},
});
const server = ref<string | null>(null);
const socket = ref<any>(null);
const previewUrl = computed(()=>{
const baseUrl = window.location.origin;
return `${baseUrl}/#/board?code=${props.boardData.code}&isBarrage=true`;
default: () => ({ backgroundImages: [], code: '' })
}
})
const server = ref<string | null>(null)
const socket = ref<any>(null)
const previewUrl = computed(() => {
const baseUrl = window.location.origin
return `${baseUrl}/#/board?code=${props.boardData.code}&isBarrage=true`
})
const barrageList = ref([])
watch(() => props.boardData, (nv) => {
if (nv) {
if(nv.barrage){
barrageList.value = JSON.parse(nv.barrage) || []
if(isArray(nv.barrages)){
nv.barrages.forEach((v,index)=>{
barrageList.value[index % 2].push(v)
})
const screenProps = [
{ prop: 'oneScreen', value: 1 },
{ prop: 'twoScreen', value: 2 },
{ prop: 'threeScreen', value: 3 },
{ prop: 'fourScreen', value: 4 }
]
const showScreenList = computed(() => {
return screenProps.filter((item) => item.value <= props.boardData.category)
})
watch(
() => props.boardData,
(nv) => {
if (nv) {
if (nv.barrage) {
barrageList.value = JSON.parse(nv.barrage) || []
if (isArray(nv.barrages)) {
nv.barrages.forEach((v, index) => {
barrageList.value[index % 2].push(v)
})
}
}
}
}
}, { immediate: true,deep: true });
},
{ immediate: true, deep: true }
)
// **2. `boardData.code` WebSocket **
watch(() => props.boardData.code, (newCode) => {
if (newCode) {
server.value = (import.meta.env.VITE_WEBSOCKET_URL + "/infra/ws").replace("http", "ws") +
`?token=${getAccessToken()}&code=${newCode}`;
}
}, { immediate: true });
watch(
() => props.boardData.code,
(newCode) => {
if (newCode) {
server.value =
(import.meta.env.VITE_WEBSOCKET_URL + '/infra/ws').replace('http', 'ws') +
`?token=${getAccessToken()}&code=${newCode}`
}
},
{ immediate: true }
)
watchEffect(() => {
if (server.value) {
socket.value = useWebSocket(server.value, {
autoReconnect: true,
heartbeat: false,
immediate: true, // ****
});
immediate: true // ****
})
}
});
})
// **4. WebSocket **
watch(
() => socket.value?.data,
(newData) => {
if (!newData) return;
if (!newData) return
try {
const data = JSON.parse(newData);
console.log("收到 WebSocket 消息:", data);
const data = JSON.parse(newData)
console.log('收到 WebSocket 消息:', data)
if(data.type === 'barrage-push'){
const content = JSON.parse(data.content);
if (data.type === 'barrage-push') {
const content = JSON.parse(data.content)
// barrageList.value
const shortestArray = barrageList.value.reduce((minArr, currentArr) =>
currentArr.length < minArr.length ? currentArr : minArr
);
// content
shortestArray.push(content);
)
// content
shortestArray.push(content)
}
} catch (error) {
message.error("处理消息发生异常:" + newData);
console.error(error);
message.error('处理消息发生异常:' + newData)
console.error(error)
}
}
);
)
</script>
<style scoped lang="scss">
.swiper-slide-box{
img{
.swiper-slide-box {
img {
width: 100%;
height: 100%;
}
}
.text-box{
.text-box {
position: absolute;
z-index: 2;
width: 100%;
@ -127,19 +169,22 @@ watch(
font-family: 宋体;
color: #fdf76d;
font-weight: bold;
.title{
.title {
font-size: 8vw;
margin-bottom: 5vh;
text-align: center;
letter-spacing: 1vw;
}
.content{
.content {
font-size: 4.2vw;
text-align: center;
letter-spacing: 0.5vw;
}
}
.qr-box{
.qr-box {
position: absolute;
z-index: 2;
top: 2vh;
@ -148,10 +193,12 @@ watch(
flex-flow: column;
align-items: center;
font-size: 1vw;
span{
span {
margin-top: 1vh;
}
}
/* 弹幕区域 */
.barrage-container {
position: absolute;
@ -162,12 +209,51 @@ watch(
color: #000;
z-index: 2;
}
marquee{
marquee {
margin-bottom: 2vh;
.div-box{
span{
.div-box {
span {
margin-right: 3vw;
}
}
}
.screen-box {
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
top: 0;
display: grid;
padding: 3%;
gap: 2vw;
box-sizing: border-box;
}
.screen-1 {
grid-template: 1fr / 1fr;
}
/* 二屏:上下平分 */
.screen-2 {
grid-template: repeat(2, 1fr) / 1fr;
}
/* 三屏:上二下一 */
.screen-3 {
grid-template: 1fr 1fr / repeat(2, 1fr);
}
.screen-3 .image:nth-child(3) {
grid-column: span 2; /* 第三个元素跨两列 */
}
.screen-3 .my-swiper:nth-child(3) {
grid-column: 1 / -1; /* 让第三个元素从第1列跨到最后1列 */
}
/* 四屏:2x2 网格 */
.screen-4 {
grid-template: repeat(2, 1fr) / repeat(2, 1fr);
}
</style>

Loading…
Cancel
Save