Files
medicine_app/pages/component/commonComponents/video/index.vue
@fawn-nine dfaa65c7a2 提交
2024-07-23 16:24:52 +08:00

1057 lines
27 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container" style="background-color: #000; position: relative">
<!-- <u-modal :show="show" :title="videoTitle" :content='content'></u-modal> -->
<!-- <u-icon
@click="goBack"
name="arrow-left"
color="#3ab3ae"
size="20"
:style="`display: inline-block; position: absolute; top: ${
statusBarHeight + 2
}px; left: ${10}px;z-index: 999;`"
></u-icon>-->
<!-- <zhimi_aliplayer_view
ref="playerView"
style="width: 100%; height: 300px"
></zhimi_aliplayer_view>
<button type="primary" @click="start()">开始</button>
<button type="primary" @click="pause()">暂停</button> -->
<view style="width: 100%; height: 200px">
<view v-if="show" style="height: 100%;display: flex;align-items:center;justify-content:center;color: #fff;font-size: 38rpx;text-align: center;">
此设备暂不支持观看当前视频<br/>请移步到安卓手机进行学习
</view>
<div class="" v-else style="background-color: #000" ref="videoContent" @tap="renderScript.handleClick"
id="url-player-test" :videoData="videoData" :winWidth="winWidth" :winHeight="winHeight"
:currentVideoList="currentVideoList" :firstTime="firstTime" :isfresh="isfresh" :platform="platform"
:isSetFirstTime="isSetFirstTime" :isChange="isChange" :change:videoData="renderScript.receiveMsg"
:change:winWidth="renderScript.receiveWinWidth" :change:winHeight="renderScript.receiveWinHeight"
:change:firstTime="renderScript.receiveFirstTime"
:change:isSetFirstTime="renderScript.receiveisSetFirstTime"
:change:isfresh="renderScript.receiveIsfresh" :change:platform="renderScript.receiveplatform"
:change:isChange="renderScript.receiveIsChange"
:change:currentVideoList="renderScript.receiveVideoList"></div>
<div @tap="renderScript.emitData" ref="videoContent1" v-show="false">
直接调用renderjs中的emitData的方法,传递当前播放时长
</div>
<div @tap="renderScript.endEmitData" ref="videoContent2" v-show="false">
监听结束方法记录播放时长
</div>
<div @tap="renderScript.changeVideoData" ref="videoContent3" v-show="false">
监听切换视频方法
</div>
<div @tap="renderScript.emitSetData" ref="videoContent4" v-show="false">
监听切换视频方法
</div>
<div @tap="renderScript.emitopenShow" ref="videoContent5" v-show="false">
打开视频提示
</div>
<div class="fullScreenButton-container">
<div :class="`prism-fullscreen-btn ${isFullScreen ? 'fullscreen' : ''}`"
@tap="renderScript.changeVideoScreen"></div>
</div>
</view>
</view>
</template>
<script>
import store from "@/store/index.js";
import $http from "@/config/requestConfig.js";
import {
mapState,
mapMutations
} from "vuex";
export default {
props: ["currentVideo", "currentVideoList","videoTitle"],
data() {
return {
show: false,
content: "此设备暂不支持观看当前视频,请移步到安卓手机进行学习!",
platform: null,
//当前是否是全屏模式
isFullScreen: false,
isfresh: false,
isChange: false,
isControl: true,
timer: null,
// videoTitle: "",
videoList: [],
firstTime: 0,
options: {},
playAuth: "",
currentTime: "",
videoId: "",
videoData: {},
isSetFirstTime: false,
screenType: null,
videoUrl: null,
};
},
computed: {
...mapState(["videoOssList"]),
},
watch: {
currentVideo: {
immediate: true,
handler(newRoute) {},
},
timer(newValue) {
this.$emit("child-event", newValue);
},
},
// //页面显示
mounted() {},
beforeDestroy() {
this.handleEnd();
console.log("是否走啦习销毁");
clearInterval(this.$store.state.videoTimer);
plus.screen.lockOrientation("portrait-primary");
console.log("是否走啦习销毁定时器", this.timer);
},
async onUnload() {
uni.navigateTo({
url: "/pages/curriculum/order/curriculum/back",
});
// #ifdef APP-PLUS
plus.screen.lockOrientation("portrait-primary"); //锁死屏幕方向为竖屏
// #endif
await this.setVideoTime();
},
//第一次加载
onLoad(options) {
},
methods: {
openShow() {
this.show = true;
},
start() {
this.$refs.playerView.start();
},
pause() {
// var playerView = ;
this.$refs.playerView.pause();
},
changeVideoData() {
this.show = false;
this.isChange = false;
},
async changeVideo(data) {
this.currentTime = "";
this.firstTime = 0;
this.isSetFirstTime = false;
this.isChange = false;
await this.init(data, true);
},
screenChange(data) {
console.log(
"status at line 这是当前的状态158:",
data.status,
data.primary
);
this.isFullScreen = !data.status;
this.$emit("changeScreen", this.isFullScreen);
},
// 控制器的显示隐藏
controlChange(e) {
this.isControl = e.detail.show;
},
quitScreen() {
// 退出全屏
const ctx = this.$refs.myVideo;
ctx.exitFullScreen();
},
//
async init(data, isChange) {
this.show = false;
this.platform = this.$platform;
this.isfresh = true;
console.log("at line 59:", "是否先走init这里", this.platform);
if (uni.getStorageSync("videoOssList")) {
this.videoList = JSON.parse(uni.getStorageSync("videoOssList"));
}
this.options = data.currentVideo;
this.videoId = this.options.video;
console.log("这是苹果视屏id", this.videoId);
await this.getLive(isChange);
},
async getVideo() {
var data = {};
var that = this;
$http
.request({
url: `sociology/course/ttt`,
method: "Post", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: {
//默认 无 说明:请求头
"Content-Type": "application/json",
},
})
.then(async (res) => {
console.log(" 视频播放11111111111:", res);
var credentials = res.result.credentials;
that.$refs.playerView.setVidSts({
vid: this.videoData.video,
accessKeyId: credentials.accessKeyId,
securityToken: credentials.securityToken,
accessKeySecret: credentials.accessKeySecret,
expireTime: credentials.expireTime,
Region: "cn-shanghai",
});
let isFullScreen = true;
// fixed fullscreen play on android
if (plus.os.name.toLowerCase() === "android") {
plus.key.addEventListener("backbutton", (e) => {
if (isFullScreen) {
that.$refs.playerView.changeScreenMode(0, false);
isFullScreen = false;
} else {
// 这里由于安卓无法监听返回按键这里只能通过plus监听然后自己模拟退回
uni.navigateBack();
}
});
}
that.$refs.playerView.setPlayerCallBack(({
type,
data
}) => {
switch (type) {
case "isFullScreen":
isFullScreen = Boolean(data);
break;
default:
console.log({
type,
data,
});
}
});
});
},
// 配置播放项
async getData(data, isChange) {
var that = this;
if (!this.isSetFirstTime) {
var netWork = data.userCourseVideoPositionEntity ?
data.userCourseVideoPositionEntity.position :
0;
var list = [];
if (uni.getStorageSync("videoOssList")) {
list = JSON.parse(uni.getStorageSync("videoOssList"));
var index = list.findIndex((e) => e.id == data.id);
console.log('data.id',data.id);
if (netWork) {
if (index >= 0) {
this.firstTime =
list[index].time > netWork ? list[index].time : netWork;
} else {
this.firstTime = netWork ? netWork : 0;
}
} else {
if (index >= 0) {
this.firstTime = list[index].time ? list[index].time : 0;
} else {
this.firstTime = 0;
}
}
} else {
this.firstTime = 0;
}
this.videoData = {
...data,
firstTime : this.firstTime
};
this.isChange = isChange ? isChange : false;
console.log(this.firstTime, "这是第一次播放时长222");
uni.setStorageSync("videoOssList", JSON.stringify(list));
console.log(this.firstTime, "这是第一次播放时长");
}
this.isSetFirstTime = true;
},
// 存储本地播放时间
recordTime(data) {
// console.log('recordTime',data.time);
this.currentTime = data.time;
var list = [];
if (uni.getStorageSync("videoOssList")) {
list = JSON.parse(uni.getStorageSync("videoOssList"));
}
var index = list.findIndex((e) => e.id == this.videoData.id);
if (list.length > 0 && index >= 0) {
list[index] = {
...this.videoData,
time: data.time,
};
} else {
list.push({
...this.videoData,
time: data.time,
});
}
uni.setStorageSync("videoOssList", JSON.stringify(list));
},
// 获取播放凭证
async getLive(isChange) {
var that = this;
this.isfresh = false;
var data = {
...this.options,
};
await $http
.request({
url: `sociology/course/checkVideo`,
method: "Post", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: {
//默认 无 说明:请求头
"Content-Type": "application/json",
},
})
.then(async (res) => {
if (this.$platform == 'ios') {
console.log('不符合播放条件');
if (this.currentVideo.type == 1 && res.video.m3u8Url == null || this.currentVideo.type == 1 && res.video.m3u8Url == '') {
// 只存在私有加密
this.show = true
uni.showModal({
content: '抱歉,苹果手机不支持此加密视频格式,您可以在安卓端观看本视频',
confirmText: '知道了',
showCancel: false,
success: function (res) {
if (res.confirm) {
// uni.navigateBack({delta: 2})
}
}
})
return
}
}
var data = {
...res.video,
};
// console.log("/checkjieguo", data);
// return
if (this.currentVideo.type == 1) {
var playAuth = res.video.playAuth.replace(/=/g, "");
// console.log("这是接口获取的视屏凭证111", playAuth);
data = {
...data,
videoId: res.video.video,
playAuth: playAuth,
};
this.playAuth = playAuth;
await that.getData(data, isChange);
} else {
console.log("这是接口获取的视屏凭证222", res.video, data);
data = {
...data,
playAuth: new Date().getTime(),
};
await that.getData(data, isChange);
}
console.log("是否获取到初始播放值", data);
that.$forceUpdate();
});
},
async handleEnd() {
var list = JSON.parse(uni.getStorageSync("videoOssList"));
var data = list.find((e) => e.id == this.videoData.id);
this.currentTime = data.time;
console.log(
"this.currentTime at line 这是结束的时候掉的存储视频:",
this.currentTime
);
await this.setVideoTime();
clearInterval(this.$store.state.videoTimer);
this.timer = null;
},
// 存储时长到线上
setVideoTime(time) {
var data = {};
console.log("是否走了存储视屏," + this.videoData.id, this.currentTime);
var data = {
videoId: this.videoData.id,
position: this.currentTime, //秒数
loadAnimate: 'none',
};
$http
.request({
url: `sociology/course/saveCoursePosition`,
method: "Post", // POST、GET、PUT、DELETE具体说明查看官方文档
data,
header: {
//默认 无 说明:请求头
"Content-Type": "application/json",
},
})
.then((res) => {
console.log("存储视屏时长接口返回信息", res);
this.$forceUpdate();
});
},
// changePlayerTime(player) {
// console.log("this.firstTime at line 106:", this.firstTime);
// player.seek(this.firstTime);
// },
goBack() {
uni.navigateBack({
delta: 1,
});
},
// 设置初始播放时间 并开启定时器
async setVideoFirtsetTime(time) {
this.currentTime = this.firstTime;
console.log("这里准备开始设置播放时间:", this.currentTime);
store.commit(
"setVideoTimer",
setInterval(async () => {
// if (this.currentTime) {
await this.setVideoTime();
// }
}, 60000)
);
// }, 5000);
},
},
created() {},
};
</script>
<script module="renderScript" lang="renderjs">
var videoData = null
import $ from 'jquery'
export default {
components: {
// MyComponent
},
mounted() {
// 在适合的生命周期通过script和link标签引入播放器sdk、css
console.log(this.options, '这是monted')
this.loadWebPlayerSDK()
},
data() {
return {
player: null,
videoTimer: null,
curTime: null,
// firstTime: null,
curStatus: null,
// currentTime:null,
}
},
watch: {
curTime(val) {
if (this.curTime !== null && this.curStatus !== null) {
this.$refs.videoContent1.click()
}
}
},
methods: {
handleClick(event, ownerInstance) {
console.log('是否了走了点击video事件', event)
},
emitData(event, ownerInstance) {
var that = this;
ownerInstance.callMethod('recordTime', {
time: that.curTime,
status: that.curStatus
})
},
async receiveFirstTime(newValue, oldValue, ownerVm, vm) {
},
async receiveisSetFirstTime(newValue, oldValue, ownerVm, vm) {
console.log('是否刚开始设置播放时间', newValue, this.firstTime, this.player);
},
emitSetData(event, ownerInstance) {
var that = this;
// this.player.seek(this.firstTime)
console.log('是否设置的第一次初始播放', this.firstTime, this.videoData.id);
ownerInstance.callMethod('setVideoFirtsetTime')
},
emitopenShow(event, ownerInstance) {
ownerInstance.callMethod('openShow')
},
changeVideoScreen(event, ownerInstance) {
var that = this;
// this.$emit('changeScreenLoading',true)
var status = this.player.fullscreenService.getIsFullScreen();
ownerInstance.callMethod('screenChange', {
status: status,
primary: status ? 'portrait' : 'landscape'
})
if (status) {
setTimeout(() => {
plus.screen.lockOrientation("portrait-primary"); //锁死屏幕方向为竖屏
this.player.fullscreenService.cancelFullScreen();
}, 100);
} else {
this.player.fullscreenService.requestFullScreen();
setTimeout(() => {
plus.screen.lockOrientation("landscape-primary");
}, 100);
}
},
changeVideoData(event, ownerInstance) {
var that = this;
ownerInstance.callMethod('changeVideoData', )
},
endEmitData(event, ownerInstance) {
var that = this;
ownerInstance.callMethod('handleEnd', )
},
getLive() {
console.log('这是这只只是666666:', this.firstTime, this.videoData)
if (this.player) {
this.player.dispose();
$('#url-player-test').empty();
this.player = null;
}
var fullScreenButtonComponent = Aliplayer.Component({
/**
* 初始函数在new对象时调用
*
* @param {string} adAddress - 广告视频地址
* @param {string} toAddress - 广告链接地址
*/
init: function(status, toAddress) {
this.fullScreenStatus = status
this.$html = $('.fullScreenButton-container');
// this.$html.hide();
},
/**
* 创建广告Dom元素
*/
createEl: function(el) {
this.$html.find('.ad').attr('src', this.adAddress);
var $adWrapper = this.$html.find('.ad-wrapper');
$adWrapper.attr('href', this.toAddress);
$adWrapper.click(function() {
});
$(el).find('.prism-time-display').after(this.$html);
},
ready: function(player, e) {
// this.$html.hide()
},
/**
* 隐藏广告
*/
play: function(player, e) {
// this.$html.show();
},
/**
* 显示广告
*/
pause: function(player, e) {
// this.$html.show();
},
/**
* 隐藏广告
*/
playing: function(player, e) {
this.$html.show();
// this.$html.hide();
},
waiting: function(player, e) {
// this.$html.hide()
},
timeupdate: function(player, e) {},
error: function(player, e) {},
/**
* 显示广告
*/
ended: function(player, e) {
}
});
console.log('这是查看是否获取到hlstoken', this.videoData)
var playerOptions = {
id: "url-player-test",
                width: '100%', //容器的大小
                height: '100%', //容器的大小
                "qualitySort": "asc",
                "cover": "",
                "autoplay": true,
            "isLive": false,
            "rePlay": false,
            "playsinline": true,
            "controlBarVisibility": "hover",
            "useH5Prism": true,
components: [
{
name: 'adComponent',
type: fullScreenButtonComponent,
args: [
'http://101.201.146.165:8088/Pf-EH/statics/uploadFile/2024-05-10/b0f420c7-9178-41ad-9dd6-f59a64a6e190.png'
]
},
{
name: 'RateComponent',
type: AliPlayerComponent.RateComponent
},
],
skinLayout: [{
name: "bigPlayButton",
align: "blabs",
x: 30,
y: 80
},
{
name: "H5Loading",
align: "cc"
},
{
name: "errorDisplay",
align: "tlabs",
x: 0,
y: 0
},
{
name: "infoDisplay"
},
{
name: "tooltip",
align: "blabs",
x: 0,
y: 56
},
{
name: "thumbnail"
},
{
name: "controlBar",
align: "blabs",
x: 0,
y: 0,
children: [{
name: "progress",
align: "blabs",
x: 0,
y: 44
},
{
name: "playButton",
align: "tl",
x: 15,
y: 12
},
{
name: "timeDisplay",
align: "tl",
x: 10,
y: 7
},
{
name: "prism-speed-selector",
align: "tr",
x: 15,
y: 12
},
{
name: "volume",
align: "tr",
x: 5,
y: 10
}
]
}
]
}
if (this.videoData.type == 1) {
if (this.videoData.m3u8Url == null || this.videoData.m3u8Url == '') {
console.log('这是私有加密的视频');
if (this.$platform == 'ios') {
this.$refs.videoContent5.click()
} else {
playerOptions = {
...playerOptions,
"vid": this.videoData
.videoId, // 必选参数,可以通过点播控制台(路径:媒资库>音/视频查询。示例1e067a2831b641db90d570b6480f****。
"playauth": this.videoData.playAuth, // 必选参数参数值可通过调用GetVideoPlayAuth接口获取。
"encryptType": 1, // 必选参数当播放私有加密流时需要设置本参数值为1。其它情况无需设置。
"playConfig": {
"EncryptType": 'AliyunVoDEncryption'
}
}
console.log('这是私有加密的视频');
}
} else if (this.videoData.m3u8Url != null || this.videoData.m3u8Url != '') {
playerOptions = {
...playerOptions,
source: this.videoData.m3u8Url,
// "playConfig": {"EncryptType": "HLSEncryption"}
}
console.log('这是标准加密的视频');
}
} else {
playerOptions = {
...playerOptions,
source: this.videoData.videoUrl
}
console.log('这是没有加密的视频');
}
var player = new Aliplayer(playerOptions, function(player) {});
this.player = player;
console.log('是否拿到第一次初始值呢', this.platform, typeof this.firstTime, this.firstTime)
clearInterval(this.videoTimer);
this.videoTimer = null;
this.videoTimer = setInterval(() => {
var that = this;
that.curTime = parseInt(this.player.getCurrentTime());
that.curStatus = this.player.getStatus()
}, 1000);
this.$refs.videoContent4.click()
player.on('ready', function() {
})
player.one('canplay', function() {
console.log('这是ios数据缓冲初次设置播放位置判断',videoData)
// player.seek(20);
player.seek(videoData.firstTime);
})
this.player.on('playing', function() {
console.log('正在播放')
})
this.player.on('ended', function() {
this.$refs.videoContent2.click()
})
},
showPreview(e) {
// console.log('e at line 56:', e)
let conimg = e.target.dataset.nodes;
let imgs = conimg.match(/<img[^>]+>/g); //选择节点中的img
console.log('imgs at line 59:', imgs)
let imgList = [];
//遍历img标签的src里面的内容放在定义的数组imgList中
for (var j = 0; j < imgs.length; j++) {
imgs[j].replace(/<img[^>]*src=['"]([^'"]+)[^>]*>/gi, function(match, capture) {
imgList.push(capture)
})
}
console.log('imgList.push at line 64:', imgList)
uni.previewImage({
urls: imgList,
longPressActions: {
itemList: ['很抱歉,暂不支持保存图片到本地'],
success: function(res) {
// console.log(res,'+++++')
}
}
});
},
receiveScreenType(newValue) {
},
async receiveIsfresh(newValue) {
console.log('是否走了刷新销毁方法:', this.player)
if (this.player) {
clearInterval(this.$store.state.videoTimer)
// await this.setVideoTime();
this.player.dispose();
}
},
async receiveplatform(newValue) {
},
async receiveIsChange(newValue) {
if (this.isChange) {
this.checkValue()
}
},
receiveVideoList(newValue, oldValue, ownerVm, vm) {
// //数据变化
console.log('currentVideoListcurrentVideoListcurrentVideoList', newValue)
},
receiveMsg(newValue, oldValue, ownerVm, vm) {
//数据变化
videoData = newValue
},
receiveWinWidth(newValue, oldValue, ownerVm, vm) {
//数据变化
console.log('newValue', newValue)
},
receiveWinHeight(newValue, oldValue, ownerVm, vm) {
//数据变化
console.log('newValue', newValue)
},
checkValue() {
console.log(this.videoId, this.authId, this.videoData, "1111888888")
if ((!this.videoData.playAuth || !this.currentVideoList)) {
setTimeout(() => {
this.checkValue();
}, 1000);
} else {
console.log('这是这只只是594:', this.firstTime, this.videoData)
this.getLive();
}
},
loadWebPlayerSDK() {
return new Promise((resolve, reject) => {
const s_tag = document.createElement('script'); // 引入播放器js
s_tag.type = 'text/javascript';
s_tag.src = 'https://g.alicdn.com/apsara-media-box/imp-web-player/2.20.3/aliplayer-min.js';
s_tag.charset = 'utf-8';
s_tag.onload = () => {
const s_tag1 = document.createElement('script'); // 引入播放器js
s_tag1.type = 'text/javascript';
s_tag1.src =
'https://player.alicdn.com/aliplayer/presentation/js/aliplayercomponents.min.js';
s_tag1.charset = 'utf-8';
s_tag1.onload = () => {
this.checkValue();
resolve();
}
document.body.appendChild(s_tag1);
}
document.body.appendChild(s_tag);
const l_tag = document.createElement('link'); // 引入播放器css
l_tag.rel = 'stylesheet';
l_tag.href =
'https://g.alicdn.com/apsara-media-box/imp-web-player/2.20.3/skins/default/aliplayer-min.css';
document.body.appendChild(l_tag);
});
},
loadComponent() {
}
}
}
</script>
<style>
.container {
width: 100vw;
height: auto;
/deep/.pause {
width: 60rpx !important;
height: 60rpx !important;
}
}
.fds {
background-color: blue;
height: 600rpx;
position: fixed;
top: 60rpx;
}
.returnBack {
flex-direction: row;
justify-content: flex-start;
align-items: center;
height: 88rpx;
padding-left: 20rpx;
}
.txt {
color: #fff;
}
.right_title {
background: #000;
height: 96rpx;
justify-content: space-between;
flex-direction: row;
align-items: center;
margin-left: auto;
}
.return {
flex-direction: row;
align-items: center;
color: #fff;
}
.right_handle {
width: 200rpx;
flex-direction: row;
justify-content: flex-end;
padding-right: 20rpx;
}
cover-view {
display: block;
line-height: 1.2;
overflow: hidden;
white-space: nowrap;
pointer-events: auto;
}
cover-view {
visibility: visible !important;
}
cover-image {
visibility: visible !important;
}
.fullScreenButton-container {
color: #fff;
float: right;
height: 35px;
margin-top: 6px;
margin-right: 5px;
display: flex;
align-items: center;
position: relative;
i {
color: #fff;
display: inline-block;
font-size: 22px;
display: block;
margin-top: 7px;
cursor: pointer;
&+i {
margin-left: 3px;
}
@media (min-width: 768px) {
&:hover+.player-tooltip {
display: block;
}
}
}
.player-tooltip {
&.prev {
left: -10px;
}
&.list {
left: 5px;
}
&.next {
right: -12px;
}
}
}
.playlist-content {
position: absolute;
right: 0;
width: 0px;
padding-bottom: 48px;
box-sizing: border-box;
height: 100%;
transition: all 0.38s ease-in-out;
overflow: hidden;
.list {
background-color: #000;
background-color: rgba(0, 0, 0, 0.3);
height: 100%;
overflow: auto;
.video-item {
color: #fff;
padding: 0px 10px;
line-height: 35px;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
&.active {
background-color: #000;
color: #00ddff;
}
@media (min-width: 768px) {
&:hover {
background-color: #000;
color: #00ddff;
}
}
}
}
}
.player-tooltip {
position: absolute;
display: none;
font-size: 12px;
color: #fff;
line-height: 28px;
letter-spacing: 0;
text-align: center;
background: #3c3c3c;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
height: 28px;
top: -48px;
padding: 0 5px;
white-space: nowrap;
}
.playlist-skip-tip {
padding: 5px 15px;
position: absolute;
top: 50%;
left: 50%;
z-index: 30;
line-height: 30px;
font-size: 14px;
border-radius: 4px;
background: rgba(255, 255, 255, 0.8);
color: #000;
text-align: center;
transform: translate(-50%, -50%);
}
#rotating-div {
width: 100vw;
height: 100vh;
background-color: #3498db;
transform: rotate(90deg);
/* 旋转90度 */
transform-origin: center center;
/* 设置旋转中心点在div中心 */
position: fixed;
/* 固定定位,全屏显示 */
left: 0;
top: 0;
bottom: 0;
right: 0;
}
</style>