Commit 786ea93e authored by 毛线's avatar 毛线

save

parent d8f0011a
webrtc.js
\ No newline at end of file
webrtc.js
WebRTCPlayer.vue
\ No newline at end of file
......@@ -41,6 +41,11 @@ html {
*:after {
}
* {
user-select: none;
-webkit-user-drag: none;
}
a,
a:focus,
a:hover {
......
<template>
<div class="bg">
<img src="@/assets/images/temp/bg/fish/background.png" alt="" class="bg-img">
<!-- 背景 -->
</div>
</template>
<style lang="scss" scoped>
.bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1px;
.bg-img {
height: 100%;
width: 100%;
object-fit: cover;
}
}
</style>
<template>
<div/>
</template>
<template>
<div class="header">
<div class="left-block">
<img src="./static/logo.png" alt="" class="logo">
<div class="data">
{{ time | filterData }}
</div>
<div class="time">
{{ time | filterTime }}
</div>
</div>
<div class="bar">
<div class="input-box">
<div class="input-img">
<img src="./static/gold-coin.png" alt="">
</div>
<div class="value">
{{ userInfo.goldCredit }}
</div>
</div>
<div class="input-box">
<div class="input-img" style="width: 54px; top: -12px; left: -8px">
<img src="./static/red-coin.png" alt="">
</div>
<div class="value">
{{ userInfo.redCredit }}
</div>
</div>
<div class="center-bg"/>
<div class="profile">
<img src="./static/profile/profile-pic.png" alt="" class="profile-img">
<img src="./static/profile/card.png" alt="" class="card-img">
</div>
</div>
<div class="right-block">
<div class="btn exit" @click="click().quit()">
<img src="./static/exit-button.png" alt="">
</div>
<div class="btn full-screen" @click="click().fullScreen()">
<img src="./static/full-screen-button.png" alt="">
</div>
</div>
</div>
</template>
<script>
import dayjs from 'dayjs'
import screenfull from 'screenfull'
import { mapState } from 'vuex'
export default {
filters: {
filterData(time) {
return dayjs(time).format('dddd,DD,MMMM,YYYY')
},
filterTime(time) {
return dayjs(time).format('HH:mm:ss')
},
},
data() {
return {
time: new Date(),
}
},
computed: {
...mapState([
'userInfo',
]),
},
created() {
this.initTime()
},
methods: {
initTime() {
this.time = new Date()
setTimeout(() => {
this.initTime()
}, 1000)
},
click() {
return {
quit: () => {
const { name } = this.$route
switch (name) {
case 'index-game-id': // 如果是游戏页面
this.quitGame()
break
}
},
fullScreen: () => {
console.log('全屏')
// 如果不允许进入全屏,发出不允许提示
if (!screenfull.enabled) {
this.$message('您的浏览器不能全屏')
return false
}
if (!screenfull.isFullscreen) {
screenfull.toggle()
} else {
screenfull.exit()
}
},
}
},
quitGame() {
const { id } = this.$route.params
const params = {
deviceId: id,
}
this.$request({
url: '/api/app/device/quitDevice',
method: 'get',
params,
}).then(({ data }) => {
this.$router.go(-1)
})
},
},
}
</script>
<style lang="scss" scoped>
.header {
height: 80px;
position: relative;
z-index: 1;
}
.left-block {
position: absolute;
left: 0;
top: 0;
width: 170px;
height: 140px;
background-image: url(./static/left-block-bg.png);
background-size: 100%;
z-index: 1;
.logo {
width: 136px;
margin: 8px 0 0;
}
.data {
color: white;
font-size: 12px;
font-weight: 100;
padding-left: 30px;
text-transform: uppercase;
zoom: 0.7;
}
.time{
color: white;
font-size: 25px;
margin: 4px 14px;
font-weight: bolder;
}
}
.right-block {
position: absolute;
right: 0;
top: 0;
width: 110px;
height: 108px;
background-image: url(./static/right-block-bg.png);
background-size: 100% 100%;
box-sizing: border-box;
z-index: 999;
.btn {
box-sizing: border-box;
opacity: 0.8;
&:hover{
opacity: 1;
}
&.exit {
padding-top: 16px;
padding-left: 50px;
padding-bottom: 4px;
height: 50px;
}
&.full-screen {
padding-top: 4px;
padding-left: 46px;
height: 50px;
}
img {
height: 30px;
/* display: none; */
}
}
}
.bar {
padding-left: 170px;
display: flex;
height: 80px;
background-image: url(./static/bar-background.png);
background-size: auto 100%;
background-position: center;
position: absolute;
top: 0;
left: 0;
right: 0;
.input-box {
padding-left: 28px;
position: relative;
margin-top: 20px;
margin-left: 16px;
.input-img {
position: absolute;
left: 0;
top: -8px;
width: 44px;
height: 44px;
img {
width: 100%;
}
}
.value {
height: 28px;
width: 90px;
background-image: url(./static/value-bg.png);
background-size: 100% 100%;
padding: 6px;
font-size: 14px;
padding-right: 8px;
text-align: right;
color: white;
box-sizing: border-box;
}
}
.center-bg {
background-image: url(./static/bar-content-bg.png);
background-size: 100% 100%;
width: 310px;
height: 76px;
margin-left: 10px;
}
.profile {
margin-left: 8px;
width: 180px;
height: 80px;
background-image: url(./static/profile/bg.png);
background-size: 100% 100%;
position: relative;
.profile-img {
width: 55px;
height: 58px;
position: absolute;
left: 14px;
top: 6px;
}
.card-img{
width: 92px;
height: 58px;
position: absolute;
left: 72px;
top: 7px;
}
}
}
</style>
<template>
<div class="root">
<nuxt />
<div :style="style" class="sceen">
<nuxt />
</div>
</div>
</template>
......@@ -8,15 +10,35 @@
import { mapActions } from 'vuex'
export default {
data() {
return {}
return {
zoom: 1,
}
},
computed: {
style() {
const style = {}
const { zoom } = this
style.zoom = zoom
return style
},
},
created() {
// this.GetConfig()
this.init()
},
methods: {
...mapActions({
GetConfig: 'GetConfig',
}),
init() {
window.onresize = () => {
console.log('window.innerWidth', window.innerWidth)
console.log('window.innerHeight', window.innerHeight)
let zoom = 1
zoom = window.innerWidth / 1080
// this.zoom = zoom
}
},
},
}
</script>
......@@ -29,5 +51,14 @@ export default {
height: 100%;
min-width: 900px;
position: fixed;
display: flex;
flex-direction: column;
justify-content: center;
background: black;
}
.sceen {
width: 1080px;
height: 608px;
position: relative;
}
</style>
......@@ -12,13 +12,14 @@ export default {
title: process.env.project_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
// { name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.project_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
],
script: [
{ src: `http://magic-hand.cy-dev.com/jswebrtc.min.js`, ssr: false },
],
},
env: process.env,
......
......@@ -11858,6 +11858,11 @@
}
}
},
"screenfull": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/screenfull/-/screenfull-4.2.1.tgz",
"integrity": "sha512-PLSp6f5XdhvjCCCO8OjavRfzkSGL3Qmdm7P82bxyU8HDDDBhDV3UckRaYcRa/NDNTYt8YBpzjoLWHUAejmOjLg=="
},
"script-loader": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.2.tgz",
......
<template>
<div>
<nuxt-child
class="main-content"
/>
<div class="main-content">
<Header/>
<div>
<nuxt-child
/>
</div>
<Footer/>
</div>
</template>
<script>
import Header from '@/components/common/header/index'
import Footer from '@/components/common/footer'
import { mapActions, mapMutations, } from 'vuex'
export default {
components: {
Header,
Footer,
},
data() {
return {}
},
mounted() {
this.GetBaseInfo()
this.GetDeviceList()
},
methods: {
...mapActions([
'GetBaseInfo',
'GetDeviceList',
]),
},
}
</script>
<style lang="scss" scoped>
.main-content {
height: 100%;
overflow: auto;
}
</style>
<template>
<div>
{{ id }}
{{ backgroundUrl }}
<img :src="backgroundUrl | img" alt="" style="width: 100px;">
<button @click="click().quit()">退出游戏</button>
<div>
<div>按钮</div>
<div class="game-btn-block">
<div v-for="(item, index) in btnList.filter(i => i.buttonStatus === 1)" :key="index" class="game-btn btn" @click="click().gameBtn(item)">
<div v-if="item.buttonImgN" class="bg">
<img :src="item.buttonImgN | img" alt="">
<Background/>
<div class="live-play">
<img src="@/assets/images/temp/game/video-play.png" alt="" class="bg">
<img v-if="isPlay" src="@/assets/images/temp/game/video-play-state.png" alt="" class="play-state">
<div class="box">
<WebRTCPlayer ref="webrtc" :video-src="player"/>
</div>
</div>
<div class="option-block">
<div class="left-option">
<img src="@/assets/images/temp/game/CREDIT-IN.gif" alt="" class="credit-in btn" @click="creditInShow = true">
<img src="@/assets/images/temp/game/CREDIT-OUT.png" alt="" class="credit-out btn" @click="network().outPoint()">
<!-- credit-in 弹窗 -->
<div :class="creditInShow ? 'show' : ''" class="credit-in-modal">
<div class="credit-in-modal-mark" @click="creditInShow = false"/>
<div class="credit-in-btn-block">
<div v-for="(item, index) in credistList" :key="index" class="btn" @click="click().upPoint(item)">
<img src="@/assets/images/temp/game/credit-in/btn-bg.png" alt="" class="btn-bg">
<div class="value">{{ item }}</div>
<div class="credist">Credist</div>
</div>
<div class="btn" @click="click().allIn()">
<img src="@/assets/images/temp/game/credit-in/allin.png" alt="" class="btn-bg">
</div>
</div>
<button v-else>{{ item.buttonName }} {{ item.buttonStatus }} {{ item.buttonValue }}</button>
</div>
</div>
<div class="right-option">
<!-- 按钮 -->
<div class="btn-block">
<div class="box">
<div v-for="(item, index) in btnList1" :key="index" class="game-btn btn" @click="click().gameBtn(item)">
<div v-if="item.buttonImgN" class="btn">
<img :src="item.buttonImgN | img" alt="">
</div>
</div>
</div>
<div class="box">
<div v-for="(item, index) in btnList2" :key="index" class="game-btn btn" @click="click().gameBtn(item)">
<div v-if="item.buttonImgN" class="btn">
<img :src="item.buttonImgN | img" alt="">
</div>
</div>
</div>
</div>
<!-- play -->
<img src="@/assets/images/temp/game/play-button.png" alt="" class="play-btn btn" @click="network().button({ buttonValue: 2 })">
<!-- 自动下注 -->
<div class="auto">
<img v-show="!isAuto" src="@/assets/images/temp/game/auto-spin-button.png" alt="" class="auto-btn btn" @click="isAuto = !isAuto">
<img v-show="isAuto" src="@/assets/images/temp/game/auto-time-button.png" alt="" class="auto-btn btn" @click="isAuto = !isAuto">
</div>
<!-- bonus -->
<img src="@/assets/images/temp/game/bonus.png" alt="" class="btn bonus">
<!-- lock-button -->
<img src="@/assets/images/temp/game/lock-button.png" alt="" class="btn lock-button">
</div>
</div>
</div>
</template>
<script>
import { WebRTCPlayer } from '@/utils/webrtc'
import Background from '@/components/common/bg/index'
import { mapActions, mapState, } from 'vuex'
import WebRTCPlayer from './components/WebRTCPlayer'
export default {
components: {
WebRTCPlayer,
Background,
},
data() {
return {
player: '',
isAuto: false,
isPlay: false, // 直播是否在播放
deviceButtonPanel: {},
creditInShow: false,
credistList: [50, 100, 200, 500, 1000],
}
},
computed: {
...mapState([
'userInfo',
'deviceList',
]),
id() {
return this.$route.params.id
},
......@@ -37,23 +95,49 @@ export default {
btnList() {
return this.deviceButtonPanel.keyMapping || []
},
btnList1() {
return this.btnList.filter(i => i.buttonStatus === 1 && i.buttonValue >= 9)
},
btnList2() {
return this.btnList.filter(i => i.buttonStatus === 1 && i.buttonValue <= 8)
},
device() {
const { deviceList, id } = this
let device = ''
try {
device = deviceList.filter(i => i.id === id)[0]
} catch (e) {
console.log('error', e)
}
return device
},
},
watch: {
device() {
console.log('watch device', this.device)
this.init().play()
},
},
mounted() {
this.network().getData()
this.network().isSave()
this.init().play()
// this.network().jackpotList()
// console.log('this.device', this.device)
if (this.device) {
this.init().play()
}
},
methods: {
...mapActions([
'GetBaseInfo',
]),
init() {
return {
play: () => {
if (!this.player) {
const player = new WebRTCPlayer()
player.onPlay = () => this.doPlay(player.stream)
player.onStatus = 1
this.player = player
}
this.player.play('webrtc://eslotstreaming.com/hdmi/egm8m')
const url = this.device.videoMainNumber
const webrtc = `webrtc://eslotstreaming.com${url}`
console.log('device', { ...this.device })
this.$refs.webrtc.initVideo(webrtc)
this.isPlay = true
},
}
},
......@@ -69,7 +153,7 @@ export default {
method: 'get',
params,
}).then(({ data }) => {
console.log('getDeviceButtonPanel', data)
this.network().isSave()
data.keyMapping = JSON.parse(data.keyMapping)
this.deviceButtonPanel = data
const { keyMapping } = data
......@@ -117,6 +201,42 @@ export default {
}).then(({ data }) => {
})
},
upPoint: ({ cashable, type = null }) => {
const { id } = this
const params = {
deviceId: id,
cashable,
type,
}
this.$request({
url: '/api/game/upPoint',
method: 'get',
params,
}).then(({ data }) => {
this.GetBaseInfo()
})
this.creditInShow = false
},
outPoint: () => {
const { id } = this
const params = {
deviceId: id,
}
this.$request({
url: '/api/game/outPoint',
method: 'get',
params,
}).then(({ data }) => {
this.GetBaseInfo()
})
},
jackpotList: () => {
this.$request({
url: '/api/app/jackpot/list',
}).then(({ data }) => {
console.log('jackpotList', data)
})
},
}
},
click() {
......@@ -127,6 +247,12 @@ export default {
gameBtn: (item) => {
this.network().button(item)
},
upPoint: (cashable) => {
this.network().upPoint({ cashable })
},
allIn: () => {
this.network().upPoint({ type: 2 })
},
}
},
},
......@@ -134,7 +260,193 @@ export default {
</script>
<style lang="scss" scoped>
.game-btn-block {
.live-play {
width: 560px;
height: 368px;
padding: 15px 15px 10px;
position: relative;
box-sizing: border-box;
left: 200px;
top: 16px;
.bg {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
@keyframes twinkle {
from {
opacity: 1.0;
}
50% {
opacity: 0.4;
}
to {
opacity: 1.0;
}
}
.play-state {
width: 14px;
position: absolute;
right: 53px;
top: 5px;
z-index: 2;
animation: twinkle 2s;
animation-iteration-count: infinite;
}
.box {
height: 100%;
width: 100%;
}
}
.option-block {
position: absolute;
bottom: 0;
height: 150px;
display: flex;
width: 100%;
justify-content: center;
.left-option {
background-image: url(@/assets/images/temp/game/credit-btn-background.png);
background-size: 100% 100%;
width: 188px;
height: 132px;
position: relative;
margin-top: 10px;
.credit-in {
width: 84px;
position: absolute;
top: 16px;
left: 18px;
}
.credit-out {
width: 74px;
position: absolute;
right: -9px;
bottom: 0;
opacity: .8;
&:hover{
opacity: 1;
}
}
.credit-in-modal {
position: absolute;
bottom: 118px;
left: -43px;
display: none;
&.show {
display: block;
}
.credit-in-modal-mark {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* background: #ccc; */
z-index: 1;
}
.credit-in-btn-block {
width: 144px;
display: grid;
grid-template-columns: repeat(2, 66px);
grid-gap: 12px;
padding: 22px 30px;
background-image: url(@/assets/images/temp/game/credit-in/bg.png);
background-size: 100% 100%;
position: relative;
z-index: 2;
.btn {
width: 66px;
height: 54px;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
.btn-bg {
position: absolute;
width: 100%;
height: 100%;
}
.value, .credist {
position: relative;
z-index: 2;
text-align: center;
}
.value{
font-size: 18px;
color: white;
}
.credist{
font-size: 12px;
color: white;
}
}
}
}
}
.right-option {
width: 714px;
margin-left: 20px;
margin-bottom: 4px;
background-image: url(@/assets/images/temp/game/play.png);
background-size: 100% 100%;
position: relative;
.btn-block {
position: absolute;
left: 30px;
top: 14px;
.box {
display: flex;
.btn {
width: 50px;
height: 50px;
margin: 4px;
img {
height: 100%;
width: 100%;
}
}
}
}
.play-btn {
width: 186px;
position: absolute;
right: 149px;
bottom: 15px;
}
.auto {
width: 70px;
height: 700px;
position: absolute;
/* background: #ccc; */
bottom: 68px;
right: 97px;
.auto-btn {
position: absolute;
bottom: 0;
width: 72px;
}
}
.bonus {
position: absolute;
width: 34px;
bottom: 7px;
right: 78px;
}
.lock-button {
position: absolute;
width: 35px;
bottom: 33px;
right: 46px;
}
}
}
/* .game-btn-block {
display: flex;
.game-btn {
width: 80px;
......@@ -150,6 +462,6 @@ export default {
}
}
}
}
} */
</style>
<template>
<video id="jswebrtc" ref="jswebrtc" style="width: 100%;height: 100%;object-fit: fill"/>
</template>
<script>
export default {
name: "WebRTCPlayer",
props: {
videoSrc: {
type: String,
default: ''
}
},
data() {
return {
player: null
}
},
mounted() {
this.$watch('videoSrc', () => {
if (this.videoSrc) {
this.initVideo(this.videoSrc)
}
}, {
immediate: true
})
},
beforeDestroy() {
// 播放器存在清除播放器
if (this.player) {
this.player.destroy()
}
},
methods: {
/**
* 初始化播放器并播放
* 两种调用方式
* 一种通过 watch监听 props 传过来的 src 进行播放
* 一种通过 引用组件上的 ref 直接调用 initVideo 如 this.$refs.webrtc.initVideo('src')
* */
initVideo(url) {
// 播放器存在 清空重置
if (this.player) {
this.player.destroy()
this.player = null
}
// 获取承载元素dom
const videoDom = document.getElementById('jswebrtc')
// 初始化播放器
this.player = new JSWebrtc.Player(url, {
video: videoDom,
autoplay: true,
onPlay: (obj) => {
// 监听video元素状态,可播放时进行播放 。 某些情况下 autoplay 会失效
// mdn https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement/canplay_event
// 菜鸟 https://www.runoob.com/tags/av-event-canplay.html
videoDom.addEventListener('canplay', function(e) {
videoDom.play()
})
console.log(obj, '播放器开始播放!')
}
})
}
},
}
</script>
<template>
<div>
<div v-for="(item, index) in list" :key="index" class="box btn" @click="click().joinGasme(item)">
<div style="overflow: auto;">
<div v-for="(item, index) in deviceList" :key="index" class="box btn" @click="click().joinGasme(item)">
<div>
gameNameEn: {{ item.gameNameEn }}
</div>
......@@ -15,17 +15,20 @@
</template>
<script>
import { mapState, mapActions } from 'vuex'
import { mapState, mapActions, mapMutations } from 'vuex'
export default {
data() {
return {
list: [],
}
},
computed: {
...mapState([
'deviceList',
]),
},
watch: {
},
created() {
this.network().getData()
},
methods: {
click() {
......@@ -48,10 +51,11 @@ export default {
return {
getData: () => {
this.$request({
url: '/api/app/device/topDeviceList',
url: '/api/app/device/list',
method: 'get',
}).then(({ data }) => {
this.list = data
}).then(({ rows }) => {
console.log('list', rows)
this.list = rows
})
},
}
......@@ -65,5 +69,6 @@ export default {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
color: white;
}
</style>
......@@ -24,12 +24,13 @@ import { setToken, removeToken, setUserData } from '@/utils/auth' // 验权
export const state = () => ({
relist: false, // 重新登录
userInfo: '', // 用户信息
userInfo: {}, // 用户信息
cacheNavList: [], // 导航栏缓存的菜单
menuTree: [], // 菜单数据(树状结构)
menuList: [], // 菜单数据(列表结构)
authBtnList: [], // 权限按钮列表
authBtnIdList: [], // 权限按钮id列表
deviceList: [], // 设备列表
appConfig: {
project_name: '——', // 项目名称
img_domain: '', // 图片名称
......@@ -141,6 +142,10 @@ export const mutations = {
state.appConfig = app
state.dictionary = dictionary
},
set_device_list(state, data) {
state.deviceList = data
},
}
export const actions = {
......@@ -199,5 +204,15 @@ export const actions = {
reject(error)
})
})
},
GetDeviceList({ commit }) {
return new Promise((resolve, reject) => {
this.$request.get('/api/app/device/list').then(({ rows }) => {
commit('set_device_list', rows)
resolve(rows)
}).catch(error => {
reject(error)
})
})
}
}
......@@ -108,7 +108,6 @@ export class WebRTCPlayer {
if (res.code) {
throw '网络异常';
}
console.log('webrtc sdp', res.sdp)
this.pc.setRemoteDescription(
new RTCSessionDescription({type: 'answer', sdp: res.sdp})
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment