直播平台app二期开发
16
.env.development
Normal file
@ -0,0 +1,16 @@
|
||||
# 开发环境
|
||||
|
||||
# 指定构建模式
|
||||
VITE_APP_ENV = 'development'
|
||||
|
||||
# base_url
|
||||
# VITE_APP_BASE_URL='http://10.0.0.17:8081/'
|
||||
|
||||
VITE_APP_BASE_URL='https://m.livejinan.cn/platform'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
VITE_APP_TITLE='济南移动直播平台移动端'
|
||||
13
.env.production
Normal file
@ -0,0 +1,13 @@
|
||||
# 生产环境
|
||||
|
||||
# 指定构建模式
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
|
||||
|
||||
# base_url
|
||||
VITE_APP_BASE_URL='https://m.livejinan.cn/platform'
|
||||
|
||||
|
||||
|
||||
VITE_APP_TITLE='济南移动直播平台移动端'
|
||||
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
3
.vs/ProjectSettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"CurrentProjectSetting": null
|
||||
}
|
||||
6
.vs/VSWorkspaceState.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ExpandedNodes": [
|
||||
""
|
||||
],
|
||||
"PreviewInSolutionExplorer": false
|
||||
}
|
||||
BIN
.vs/aijinan-app-newVersion/v17/.wsuo
Normal file
23
.vs/aijinan-app-newVersion/v17/DocumentLayout.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "D:\\dongniTeach\\\u6D4E\u5357\u5E02\u79FB\u52A8\u76F4\u64AD\u5E73\u53F0\\240129\u6700\u65B0\u62C9\u53D6\\aijinan-app-newVersion\\",
|
||||
"Documents": [],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": -1,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{cce594b6-0c39-4442-ba28-10c64ac7e89f}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
.vs/slnx.sqlite
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
||||
10
README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Vue 3 + Vite+vant4 直播平台移动端 App
|
||||
|
||||
<!-- import { login } from "../api/index";
|
||||
// 调用登录接口函数
|
||||
login().then((result) => {
|
||||
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录接口请求失败", error);
|
||||
}); -->
|
||||
17
index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>济南移动直播平台app</title>
|
||||
<link rel="stylesheet" href="https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css" />
|
||||
<script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/aliplayer-h5-min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
3230
package-lock.json
generated
Normal file
33
package.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "vue3-template-js",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build:pro": "vite build --mode production",
|
||||
"build:dev": "vite build --mode development",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"autoprefixer": "^10.4.19",
|
||||
"axios": "^1.7.2",
|
||||
"mescroll.js": "^1.4.2",
|
||||
"path": "^0.12.7",
|
||||
"swiper": "^11.1.4",
|
||||
"vant": "^4.9.1",
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.3.3",
|
||||
"xgplayer": "^3.0.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vant/auto-import-resolver": "^1.2.1",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"postcss-px-to-viewport": "^1.1.1",
|
||||
"sass": "^1.77.6",
|
||||
"unplugin-auto-import": "^0.17.6",
|
||||
"unplugin-vue-components": "^0.27.0",
|
||||
"vite": "^4.4.5"
|
||||
}
|
||||
}
|
||||
22
postcss.config.cjs
Normal file
@ -0,0 +1,22 @@
|
||||
//postcss.config.cjs
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-px-to-viewport': {
|
||||
viewportWidth: 375, // 设计稿的视口宽度
|
||||
viewportUnit: "vw", // 希望使用的视口单位
|
||||
unitPrecision: 5, // 单位转换后保留的精度
|
||||
propList: ["*"], // 能转化为vw的属性列表
|
||||
fontViewportUnit: "vw", // 字体使用的视口单位
|
||||
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
|
||||
minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
|
||||
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
|
||||
replace: true, // 是否直接更换属性值,而不添加备用属性
|
||||
exclude: undefined, // 忽略某些文件夹下的文件或特定文件
|
||||
include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换
|
||||
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件
|
||||
landscapeUnit: "vw", // 横屏时使用的单位
|
||||
landscapeWidth: 568, // 横屏时使用的视口宽度
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/bg1.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
public/bg2.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
public/bg3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/bg4.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/bg5.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/bg6.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
11
src/App.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
87
src/api/index.js
Normal file
@ -0,0 +1,87 @@
|
||||
import request from '../utils/request'
|
||||
|
||||
|
||||
export function scene(params) {
|
||||
return request({
|
||||
url: '/foreign/live/scene/get/' + params.id,
|
||||
method: 'get'
|
||||
// params: params
|
||||
});
|
||||
}
|
||||
|
||||
// 观看人数
|
||||
export function viewshow(params) {
|
||||
return request({
|
||||
url: '/app/live/scene/counts',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
// 有 caster 呼叫 /caster/streamsUrl
|
||||
export function caster(params) {
|
||||
return request({
|
||||
url: '/caster/streamsUrl',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
// 报道
|
||||
export function report(params) {
|
||||
return request({
|
||||
url: '/foreign/live/report/list',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
// 评论
|
||||
export function commentList(params) {
|
||||
return request({
|
||||
url: '/foreign/live/comment/list',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
export function liveList(params) {
|
||||
return request({
|
||||
url: '/index',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
// export function commentList (params) {
|
||||
// return request({
|
||||
// url: '/comment'),
|
||||
// method: 'get',
|
||||
// params: params
|
||||
// });
|
||||
// }
|
||||
|
||||
// 添加评论
|
||||
export function addComment(formData) {
|
||||
return request({
|
||||
url: '/comment/create',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
data: formData
|
||||
});
|
||||
}
|
||||
|
||||
// 获取微信签名
|
||||
export function getWXSig(url) {
|
||||
return request({
|
||||
url: `/weixin/getJsApiTicket?url=${url}`,
|
||||
// https://app.livejinan.cn/platform/foreign/live/weixin/getJsApiTicket?url=http%3A%2F%2F192.168.50.26%3A8080%2Flive%2Fmerge%2Fdetail%2F2057
|
||||
// url: `http://test.zhongkedongxin.com/platform/foreign/live/weixin/getJsApiTicket?url=${url}`,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
}
|
||||
73
src/assets/css/index.scss
Normal file
@ -0,0 +1,73 @@
|
||||
*{
|
||||
margin: 0;
|
||||
padding:0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
p{
|
||||
margin:0;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding:0;
|
||||
#app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.flex1{
|
||||
display:flex;
|
||||
}
|
||||
.flex-s-b{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.live_status{
|
||||
width:55px;
|
||||
padding:3px;
|
||||
text-align: end;
|
||||
background-color: #F12742;
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.live_status::before{
|
||||
width:10px;
|
||||
height:10px;
|
||||
position: absolute;
|
||||
content:'';
|
||||
background: url("@/assets/img/live.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
top:5px;
|
||||
left: 3px;
|
||||
|
||||
}
|
||||
.live_coming {
|
||||
padding:3px;
|
||||
text-align: center;
|
||||
width:55px;
|
||||
font-size: 12px;
|
||||
border-radius: 5px;
|
||||
background-image: linear-gradient(to left, #EFBE26, #F58C05);
|
||||
}
|
||||
|
||||
.live_review {
|
||||
padding:3px;
|
||||
text-align: center;
|
||||
width:55px;
|
||||
font-size: 12px;
|
||||
border-radius: 5px;
|
||||
background-image: linear-gradient(to left, #4BB4FB, #1678ED);
|
||||
}
|
||||
// @media screen and (min-width: 1024px) {
|
||||
// .page {
|
||||
// width: 920px;
|
||||
// margin: 0 auto;
|
||||
// // border:1px solid red;
|
||||
// overflow: hidden;
|
||||
// }
|
||||
|
||||
// }
|
||||
3
src/assets/img/arraw.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.00219 1.21266C4.36969 0.847033 4.96594 0.847033 5.33344 1.21266L10.9941 6.83859C11.2697 7.11234 11.3391 7.51453 11.2012 7.85203C11.1553 7.96453 11.0859 8.07047 10.9941 8.16141L5.33344 13.7883C4.965 14.1539 4.36969 14.1539 4.00219 13.7883C3.63469 13.4227 3.63469 12.8302 4.00219 12.4645L8.99719 7.50047L4.00219 2.53641C3.63469 2.16984 3.63469 1.57828 4.00219 1.21266Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 498 B |
BIN
src/assets/img/bg1.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/assets/img/bg2.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/img/bg3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src/assets/img/bg4.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/img/bg5.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
src/assets/img/bg6.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/assets/img/big1.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
src/assets/img/bigplay.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/img/defineBg.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
src/assets/img/defineBigBg.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/img/grid1.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
src/assets/img/grid2.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
src/assets/img/grid3.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src/assets/img/grid4.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src/assets/img/hot.png
Normal file
|
After Width: | Height: | Size: 861 B |
4
src/assets/img/hot.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="13" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.00259 14.6151C16.0395 10.9613 10.6265 3.38313 9.54389 2.70651C9.94986 3.51846 9.94986 4.73639 9.27324 5.41301C8.19064 0.811952 5.21348 0 5.21348 0C5.61946 2.30053 3.99555 4.73638 2.50697 6.63094C2.50697 5.68366 2.37165 5.14236 1.83035 4.19508C1.69502 5.81899 0.477095 7.17224 0.0711195 8.79614C-0.334856 11.0967 1.0184 13.2619 3.58958 14.3445C3.58958 14.4798 6.56673 15.5624 9.00259 14.6151Z" fill="#F43760"/>
|
||||
<path d="M5.07709 11.0963H4.40046V9.87837H3.18254V11.0963H2.64124V8.11914H3.31786V9.33707H4.53579V8.11914H5.21242L5.07709 11.0963ZM5.61839 9.60772C5.61839 9.20174 5.75372 8.79577 6.02437 8.52512C6.29502 8.25447 6.56567 8.11914 6.97164 8.11914C7.37762 8.11914 7.7836 8.25447 7.91892 8.52512C8.18957 8.79577 8.3249 9.20174 8.3249 9.60772C8.3249 10.0137 8.18957 10.4197 7.91892 10.6903C7.64827 10.961 7.37762 11.0963 6.97164 11.0963C6.56567 11.0963 6.15969 10.961 5.88904 10.6903C5.75372 10.4197 5.61839 10.149 5.61839 9.60772ZM6.15969 9.60772C6.15969 9.87837 6.15969 10.149 6.43034 10.2843C6.56567 10.4197 6.70099 10.555 6.97164 10.555C7.24229 10.555 7.37762 10.4197 7.51295 10.2843C7.64827 10.149 7.7836 9.87837 7.7836 9.60772C7.7836 9.33707 7.7836 9.06642 7.64827 8.93109C7.37762 8.79577 7.24229 8.66044 6.97164 8.66044C6.70099 8.66044 6.56567 8.79577 6.43034 8.93109C6.29502 9.06642 6.15969 9.33707 6.15969 9.60772ZM10.7608 8.66044H9.9488V11.0963H9.27217V8.66044H8.46022V8.11914H10.7608V8.66044Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/img/ijnan_line.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/img/jt_black.png
Normal file
|
After Width: | Height: | Size: 636 B |
BIN
src/assets/img/jt_white.png
Normal file
|
After Width: | Height: | Size: 429 B |
7
src/assets/img/like.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 17.5C-4.84295e-08 19.7981 0.452651 22.0738 1.33211 24.197C2.21157 26.3202 3.50061 28.2493 5.12563 29.8744C6.75066 31.4994 8.67984 32.7884 10.803 33.6679C12.9262 34.5473 15.2019 35 17.5 35C19.7981 35 22.0738 34.5473 24.197 33.6679C26.3202 32.7884 28.2493 31.4994 29.8744 29.8744C31.4994 28.2493 32.7884 26.3202 33.6679 24.197C34.5473 22.0738 35 19.7981 35 17.5C35 15.2019 34.5473 12.9262 33.6679 10.803C32.7884 8.67984 31.4994 6.75066 29.8744 5.12563C28.2493 3.50061 26.3202 2.21157 24.197 1.33211C22.0738 0.452651 19.7981 0 17.5 0C15.2019 0 12.9262 0.452651 10.803 1.33211C8.67984 2.21157 6.75066 3.50061 5.12563 5.12563C3.50061 6.75066 2.21157 8.67984 1.33211 10.803C0.452651 12.9262 -3.42448e-08 15.2019 0 17.5Z" fill="#EEEEEE"/>
|
||||
<path d="M27.8177 13.8536C27.0969 10.4988 24.5325 8.40051 20.8869 9.15407C19.7425 9.39054 18.8384 10.0337 18.036 10.8756C17.9682 10.8456 17.9405 10.8393 17.922 10.8236C17.8712 10.7794 17.8219 10.7337 17.7757 10.6848C16.7299 9.57656 15.4362 9.06736 13.9499 9.00588C12.1725 8.93336 10.6632 9.52927 9.53266 10.9449C7.54737 13.4295 7.495 17.1547 9.35092 19.8189C10.295 21.1747 11.4379 22.335 12.6977 23.3708C13.9946 24.438 15.3207 25.4706 16.6544 26.489C17.4908 27.1275 18.3995 27.1732 19.1819 26.5947C21.4583 24.9078 23.7485 23.2352 25.6506 21.0849C27.4757 19.0165 28.423 16.6723 27.8177 13.8536ZM12.7162 18.4837C12.553 18.6051 12.362 18.6634 12.1741 18.6634C11.8876 18.6634 11.6057 18.5278 11.4255 18.2724C9.65125 15.7674 10.9327 13.5209 10.9866 13.4263C11.049 13.3199 11.1314 13.227 11.2289 13.1532C11.3264 13.0793 11.4372 13.0258 11.5549 12.9958C11.6727 12.9658 11.795 12.9598 11.915 12.9782C12.035 12.9967 12.1502 13.0391 12.2542 13.1031C12.4628 13.2315 12.6135 13.4389 12.6738 13.6803C12.734 13.9217 12.6989 14.1776 12.5761 14.3927C12.5006 14.5314 11.9015 15.7233 12.9211 17.1626C13.2214 17.5851 13.129 18.1763 12.7162 18.4837Z" fill="#F23D4F"/>
|
||||
<path d="M24.7604 9.57141C23.6777 9.02151 22.3569 8.84291 20.8503 9.15311C19.7091 9.38811 18.8076 10.0273 18.0075 10.8639C17.9399 10.8341 17.9123 10.8279 17.8938 10.8122C17.8431 10.7683 17.794 10.7229 17.7479 10.6743C16.7051 9.57298 15.415 9.06694 13.933 9.00584C12.1607 8.93377 10.6556 9.52598 9.52831 10.9328C7.54866 13.4019 7.49644 17.104 9.34708 19.7516C10.2885 21.099 11.4281 22.2521 12.6844 23.2814C13.3939 23.8642 14.1142 24.4344 14.8376 25C20.6491 23.7028 25 18.4247 25 12.1063C25.0009 11.2554 24.9207 10.4064 24.7604 9.57141ZM12.7043 18.4247C12.5416 18.5453 12.3511 18.6033 12.1637 18.6033C11.8781 18.6033 11.597 18.4685 11.4173 18.2147C9.6481 15.7253 10.9259 13.4928 10.9796 13.3988C11.0419 13.293 11.124 13.2007 11.2213 13.1273C11.3185 13.0539 11.429 13.0008 11.5464 12.971C11.6638 12.9411 11.7858 12.9352 11.9054 12.9535C12.025 12.9718 12.14 13.014 12.2436 13.0776C12.4516 13.2052 12.6019 13.4113 12.662 13.6512C12.7221 13.8911 12.6871 14.1454 12.5646 14.3592C12.4893 14.497 11.8919 15.6814 12.9086 17.1118C13.2081 17.5317 13.1159 18.1192 12.7043 18.4247Z" fill="#FC4956"/>
|
||||
<path d="M21.4703 9.14597C20.2742 9.37001 19.3292 9.9794 18.4904 10.777C18.4196 10.7486 18.3906 10.7426 18.3713 10.7277C18.3181 10.6859 18.2666 10.6426 18.2183 10.5963C17.1252 9.54625 15.7729 9.06382 14.2193 9.00557C12.3614 8.93686 10.7837 9.50145 9.60206 10.8427C7.52688 13.1966 7.47214 16.726 9.41209 19.2502C9.6101 19.5086 9.81939 19.7565 10.0335 20C16.2655 19.3682 21.2256 14.8202 22 9.06382C21.8261 9.08622 21.649 9.11311 21.4703 9.14597ZM12.9297 17.9851C12.7591 18.1001 12.5595 18.1554 12.3631 18.1554C12.0636 18.1554 11.769 18.0269 11.5806 17.785C9.72602 15.4116 11.0655 13.2833 11.1218 13.1936C11.1871 13.0928 11.2732 13.0048 11.3751 12.9348C11.477 12.8649 11.5928 12.8142 11.7159 12.7858C11.8389 12.7573 11.9668 12.7517 12.0922 12.7691C12.2176 12.7866 12.3381 12.8268 12.4468 12.8874C12.6648 13.0091 12.8224 13.2055 12.8854 13.4342C12.9484 13.6629 12.9117 13.9055 12.7832 14.1092C12.7044 14.2407 12.0781 15.3698 13.1439 16.7335C13.4578 17.1338 13.3612 17.6939 12.9297 17.9851Z" fill="#FF5C64"/>
|
||||
<path d="M14.4142 9.00527C12.4977 8.94022 10.8702 9.47478 9.6512 10.7447C8.49698 11.9468 7.94893 13.4741 8.00374 15C8.94151 14.8274 9.85588 14.5729 10.7323 14.2406C10.8586 13.4981 11.1924 13.0117 11.2206 12.9706C11.2879 12.8751 11.3767 12.7919 11.4819 12.7256C11.587 12.6593 11.7065 12.6114 11.8334 12.5845C11.9604 12.5575 12.0923 12.5522 12.2217 12.5687C12.351 12.5852 12.4753 12.6233 12.5874 12.6807C12.8 12.7896 12.9461 12.9537 13.0192 13.1389C14.6253 12.1889 15.9811 10.9641 17 9.54266C16.2178 9.20891 15.3525 9.0378 14.4142 9.00527Z" fill="#FF716E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
BIN
src/assets/img/live.png
Normal file
|
After Width: | Height: | Size: 220 B |
BIN
src/assets/img/logo.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
src/assets/img/slide1.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
src/assets/img/slide2.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
src/assets/img/top1.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
122
src/assets/js/weixinShare/index.js
Normal file
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 2020 6 1
|
||||
* 微信分享
|
||||
* 【缺】 调用微信appid相关内容接口 1. 接口 appid ; 2. 时间戳等内容
|
||||
* 参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#111
|
||||
*/
|
||||
|
||||
const wx = require("./weixin-jssdk-1.6.0");
|
||||
const info = require("../../../api/modules/info");
|
||||
// const headLogo = require('../../img/icon-report-name.png');
|
||||
// const headLogo='https://aijinan.media.zhongkedongxin.com/image/default/F94790FC1B29416881B8D64C4EE1F23B-6-2.jpg';
|
||||
|
||||
let link = window.location.href.split("#")[0];
|
||||
if (link.indexOf("&") > -1) {
|
||||
link = link.substring(0, link.indexOf("&"));
|
||||
console.log("!!!!!!!!111新增测试log", link);
|
||||
window.location.href = link;
|
||||
}
|
||||
let shareOpt = {
|
||||
title: "爱济南",
|
||||
desc: "爱济南",
|
||||
link: "",
|
||||
// imgUrl: headLogo,
|
||||
};
|
||||
|
||||
function setShareFunc(opt) {
|
||||
console.log("-------------------------setShareFunc opt", opt.imgUrl);
|
||||
opt.imgUrl = opt.imgUrl.replace(/\?[\w\W]*$/, "").replace(/^https/, "http");
|
||||
// opt.link=encodeURIComponent(opt.link);
|
||||
// 分享给朋友 updateAppMessageShareData
|
||||
wx.updateAppMessageShareData({
|
||||
title: opt.title,
|
||||
desc: opt.desc,
|
||||
link: opt.link,
|
||||
imgUrl: opt.imgUrl + "?x-oss-process=image/resize,w_400",
|
||||
// imgUrl: headLogo,
|
||||
});
|
||||
|
||||
// 分享朋友圈
|
||||
wx.updateTimelineShareData({
|
||||
title: opt.title,
|
||||
desc: opt.desc,
|
||||
link: opt.link,
|
||||
// link: window.location.href,//分享链接 该链接域名或路径必须与当前页面对应的公众号一直
|
||||
imgUrl: opt.imgUrl + "?x-oss-process=image/resize,w_400",
|
||||
// imgUrl: headLogo,
|
||||
});
|
||||
// 分享到微博
|
||||
wx.onMenuShareWeibo({
|
||||
title: opt.title,
|
||||
desc: opt.desc,
|
||||
link: opt.link,
|
||||
imgUrl: opt.imgUrl + "?x-oss-process=image/resize,w_400",
|
||||
// imgUrl: headLogo,
|
||||
});
|
||||
}
|
||||
|
||||
// 后台传值 获取微信签名信息成功后初始化分享功能的部分
|
||||
function initShare(wxSignature, opt) {
|
||||
console.log("initShare opt", opt);
|
||||
wx.config({
|
||||
debug: false, // 上线时记得改为 false
|
||||
appId: wxSignature.appid,
|
||||
timestamp: wxSignature.timeStamp,
|
||||
nonceStr: wxSignature.nonceStr,
|
||||
signature: wxSignature.sign,
|
||||
// ↓ 配置需要用到的微信接口 ↓
|
||||
jsApiList: [
|
||||
"checkJsApi",
|
||||
"updateAppMessageShareData",
|
||||
"updateTimelineShareData",
|
||||
"onMenuShareWeibo",
|
||||
],
|
||||
});
|
||||
wx.ready(function() {
|
||||
setShareFunc(opt);
|
||||
});
|
||||
}
|
||||
|
||||
export default function(opt) {
|
||||
console.log("!!!!!!!!!!!!!!!!!!!!opt", opt);
|
||||
info
|
||||
.getWXSig(encodeURIComponent(link))
|
||||
.then((res) => {
|
||||
console.log("Weixin Signatrue SUCCESS", res);
|
||||
let resData = res.data;
|
||||
if (resData.code === 0) {
|
||||
opt.link = link;
|
||||
// console.log("---------------",link);
|
||||
// opt.link='http://test.zhongkedongxin.com/live/merge/detail/493';
|
||||
initShare(resData.data, opt);
|
||||
} else {
|
||||
console.log("Weixin Signatrue ERROR", resData.msg);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Weixin Signatrue ERROR", error);
|
||||
});
|
||||
}
|
||||
// 导出分享函数
|
||||
// export default function (opt) {
|
||||
// console.log("!!!!!!!!!!!!!!!!!!!!opt",opt);
|
||||
// // 如果微信签名信息已经获取
|
||||
// if (opt.link) {
|
||||
// // 设置分享内容
|
||||
// setShareFunc(opt);
|
||||
// } else {
|
||||
// // 否则,等待微信签名信息获取完成后再初始化分享功能
|
||||
// info.getWXSig(encodeURIComponent(link)).then(res => {
|
||||
// console.log('Weixin Signatrue SUCCESS', res);
|
||||
// let resData = res.data;
|
||||
// if (resData.code === 0) {
|
||||
// opt.link = link;
|
||||
// initShare(resData.data, opt);// 在获取微信签名信息成功后初始化分享功能
|
||||
// } else {
|
||||
// console.log('Weixin Signatrue ERROR', resData.msg);
|
||||
// }
|
||||
// }).catch(error => {
|
||||
// console.log('Weixin Signatrue ERROR', error);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
702
src/assets/js/weixinShare/weixin-jssdk-1.6.0.js
Normal file
@ -0,0 +1,702 @@
|
||||
! function (e, n) {
|
||||
"function" == typeof define && (define.amd || define.cmd) ? define(function () {
|
||||
return n(e)
|
||||
}) : n(e, !0)
|
||||
}(window, function (o, e) {
|
||||
if (!o.jWeixin) {
|
||||
var n, c = {
|
||||
config: "preVerifyJSAPI",
|
||||
onMenuShareTimeline: "menu:share:timeline",
|
||||
onMenuShareAppMessage: "menu:share:appmessage",
|
||||
onMenuShareQQ: "menu:share:qq",
|
||||
onMenuShareWeibo: "menu:share:weiboApp",
|
||||
onMenuShareQZone: "menu:share:QZone",
|
||||
previewImage: "imagePreview",
|
||||
getLocation: "geoLocation",
|
||||
openProductSpecificView: "openProductViewWithPid",
|
||||
addCard: "batchAddCard",
|
||||
openCard: "batchViewCard",
|
||||
chooseWXPay: "getBrandWCPayRequest",
|
||||
openEnterpriseRedPacket: "getRecevieBizHongBaoRequest",
|
||||
startSearchBeacons: "startMonitoringBeacons",
|
||||
stopSearchBeacons: "stopMonitoringBeacons",
|
||||
onSearchBeacons: "onBeaconsInRange",
|
||||
consumeAndShareCard: "consumedShareCard",
|
||||
openAddress: "editAddress"
|
||||
},
|
||||
a = function () {
|
||||
var e = {};
|
||||
for (var n in c) e[c[n]] = n;
|
||||
return e
|
||||
}(),
|
||||
i = o.document,
|
||||
t = i.title,
|
||||
r = navigator.userAgent.toLowerCase(),
|
||||
s = navigator.platform.toLowerCase(),
|
||||
d = !(!s.match("mac") && !s.match("win")),
|
||||
u = -1 != r.indexOf("wxdebugger"),
|
||||
l = -1 != r.indexOf("micromessenger"),
|
||||
p = -1 != r.indexOf("android"),
|
||||
f = -1 != r.indexOf("iphone") || -1 != r.indexOf("ipad"),
|
||||
m = (n = r.match(/micromessenger\/(\d+\.\d+\.\d+)/) || r.match(/micromessenger\/(\d+\.\d+)/)) ? n[1] : "",
|
||||
g = {
|
||||
initStartTime: L(),
|
||||
initEndTime: 0,
|
||||
preVerifyStartTime: 0,
|
||||
preVerifyEndTime: 0
|
||||
},
|
||||
h = {
|
||||
version: 1,
|
||||
appId: "",
|
||||
initTime: 0,
|
||||
preVerifyTime: 0,
|
||||
networkType: "",
|
||||
isPreVerifyOk: 1,
|
||||
systemType: f ? 1 : p ? 2 : -1,
|
||||
clientVersion: m,
|
||||
url: encodeURIComponent(location.href)
|
||||
},
|
||||
v = {},
|
||||
S = {
|
||||
_completes: []
|
||||
},
|
||||
y = {
|
||||
state: 0,
|
||||
data: {}
|
||||
};
|
||||
O(function () {
|
||||
g.initEndTime = L()
|
||||
});
|
||||
var I = !1,
|
||||
_ = [],
|
||||
w = {
|
||||
config: function (e) {
|
||||
B("config", v = e);
|
||||
var t = !1 !== v.check;
|
||||
O(function () {
|
||||
if (t) M(c.config, {
|
||||
verifyJsApiList: C(v.jsApiList),
|
||||
verifyOpenTagList: C(v.openTagList)
|
||||
}, function () {
|
||||
S._complete = function (e) {
|
||||
g.preVerifyEndTime = L(), y.state = 1, y.data = e
|
||||
}, S.success = function (e) {
|
||||
h.isPreVerifyOk = 0
|
||||
}, S.fail = function (e) {
|
||||
S._fail ? S._fail(e) : y.state = -1
|
||||
};
|
||||
var t = S._completes;
|
||||
return t.push(function () {
|
||||
! function () {
|
||||
if (!(d || u || v.debug || m < "6.0.2" || h.systemType < 0)) {
|
||||
var i = new Image;
|
||||
h.appId = v.appId, h.initTime = g.initEndTime - g.initStartTime, h.preVerifyTime = g.preVerifyEndTime - g.preVerifyStartTime, w.getNetworkType({
|
||||
isInnerInvoke: !0,
|
||||
success: function (e) {
|
||||
h.networkType = e.networkType;
|
||||
var n = "https://open.weixin.qq.com/sdk/report?v=" + h.version + "&o=" + h.isPreVerifyOk + "&s=" + h.systemType + "&c=" + h.clientVersion + "&a=" + h.appId + "&n=" + h.networkType + "&i=" + h.initTime + "&p=" + h.preVerifyTime + "&u=" + h.url;
|
||||
i.src = n
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
}), S.complete = function (e) {
|
||||
for (var n = 0, i = t.length; n < i; ++n) t[n]();
|
||||
S._completes = []
|
||||
}, S
|
||||
}()), g.preVerifyStartTime = L();
|
||||
else {
|
||||
y.state = 1;
|
||||
for (var e = S._completes, n = 0, i = e.length; n < i; ++n) e[n]();
|
||||
S._completes = []
|
||||
}
|
||||
}), w.invoke || (w.invoke = function (e, n, i) {
|
||||
o.WeixinJSBridge && WeixinJSBridge.invoke(e, x(n), i)
|
||||
}, w.on = function (e, n) {
|
||||
o.WeixinJSBridge && WeixinJSBridge.on(e, n)
|
||||
})
|
||||
},
|
||||
ready: function (e) {
|
||||
0 != y.state ? e() : (S._completes.push(e), !l && v.debug && e())
|
||||
},
|
||||
error: function (e) {
|
||||
m < "6.0.2" || (-1 == y.state ? e(y.data) : S._fail = e)
|
||||
},
|
||||
checkJsApi: function (e) {
|
||||
M("checkJsApi", {
|
||||
jsApiList: C(e.jsApiList)
|
||||
}, (e._complete = function (e) {
|
||||
if (p) {
|
||||
var n = e.checkResult;
|
||||
n && (e.checkResult = JSON.parse(n))
|
||||
}
|
||||
e = function (e) {
|
||||
var n = e.checkResult;
|
||||
for (var i in n) {
|
||||
var t = a[i];
|
||||
t && (n[t] = n[i], delete n[i])
|
||||
}
|
||||
return e
|
||||
}(e)
|
||||
}, e))
|
||||
},
|
||||
onMenuShareTimeline: function (e) {
|
||||
P(c.onMenuShareTimeline, {
|
||||
complete: function () {
|
||||
M("shareTimeline", {
|
||||
title: e.title || t,
|
||||
desc: e.title || t,
|
||||
BASE_URL: e.imgUrl || "",
|
||||
link: e.link || location.href,
|
||||
type: e.type || "link",
|
||||
data_url: e.dataUrl || ""
|
||||
}, e)
|
||||
}
|
||||
}, e)
|
||||
},
|
||||
onMenuShareAppMessage: function (n) {
|
||||
P(c.onMenuShareAppMessage, {
|
||||
complete: function (e) {
|
||||
"favorite" === e.scene ? M("sendAppMessage", {
|
||||
title: n.title || t,
|
||||
desc: n.desc || "",
|
||||
link: n.link || location.href,
|
||||
BASE_URL: n.imgUrl || "",
|
||||
type: n.type || "link",
|
||||
data_url: n.dataUrl || ""
|
||||
}) : M("sendAppMessage", {
|
||||
title: n.title || t,
|
||||
desc: n.desc || "",
|
||||
link: n.link || location.href,
|
||||
BASE_URL: n.imgUrl || "",
|
||||
type: n.type || "link",
|
||||
data_url: n.dataUrl || ""
|
||||
}, n)
|
||||
}
|
||||
}, n)
|
||||
},
|
||||
onMenuShareQQ: function (e) {
|
||||
P(c.onMenuShareQQ, {
|
||||
complete: function () {
|
||||
M("shareQQ", {
|
||||
title: e.title || t,
|
||||
desc: e.desc || "",
|
||||
BASE_URL: e.imgUrl || "",
|
||||
link: e.link || location.href
|
||||
}, e)
|
||||
}
|
||||
}, e)
|
||||
},
|
||||
onMenuShareWeibo: function (e) {
|
||||
P(c.onMenuShareWeibo, {
|
||||
complete: function () {
|
||||
M("shareWeiboApp", {
|
||||
title: e.title || t,
|
||||
desc: e.desc || "",
|
||||
BASE_URL: e.imgUrl || "",
|
||||
link: e.link || location.href
|
||||
}, e)
|
||||
}
|
||||
}, e)
|
||||
},
|
||||
onMenuShareQZone: function (e) {
|
||||
P(c.onMenuShareQZone, {
|
||||
complete: function () {
|
||||
M("shareQZone", {
|
||||
title: e.title || t,
|
||||
desc: e.desc || "",
|
||||
BASE_URL: e.imgUrl || "",
|
||||
link: e.link || location.href
|
||||
}, e)
|
||||
}
|
||||
}, e)
|
||||
},
|
||||
updateTimelineShareData: function (e) {
|
||||
|
||||
M("updateTimelineShareData", {
|
||||
title: e.title,
|
||||
link: e.link,
|
||||
imgUrl: e.imgUrl
|
||||
}, e)
|
||||
},
|
||||
updateAppMessageShareData: function (e) {
|
||||
M("updateAppMessageShareData", {
|
||||
title: e.title,
|
||||
desc: e.desc,
|
||||
link: e.link,
|
||||
imgUrl: e.imgUrl
|
||||
}, e)
|
||||
},
|
||||
startRecord: function (e) {
|
||||
M("startRecord", {}, e)
|
||||
},
|
||||
stopRecord: function (e) {
|
||||
M("stopRecord", {}, e)
|
||||
},
|
||||
onVoiceRecordEnd: function (e) {
|
||||
P("onVoiceRecordEnd", e)
|
||||
},
|
||||
playVoice: function (e) {
|
||||
M("playVoice", {
|
||||
localId: e.localId
|
||||
}, e)
|
||||
},
|
||||
pauseVoice: function (e) {
|
||||
M("pauseVoice", {
|
||||
localId: e.localId
|
||||
}, e)
|
||||
},
|
||||
stopVoice: function (e) {
|
||||
M("stopVoice", {
|
||||
localId: e.localId
|
||||
}, e)
|
||||
},
|
||||
onVoicePlayEnd: function (e) {
|
||||
P("onVoicePlayEnd", e)
|
||||
},
|
||||
uploadVoice: function (e) {
|
||||
M("uploadVoice", {
|
||||
localId: e.localId,
|
||||
isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1
|
||||
}, e)
|
||||
},
|
||||
downloadVoice: function (e) {
|
||||
M("downloadVoice", {
|
||||
serverId: e.serverId,
|
||||
isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1
|
||||
}, e)
|
||||
},
|
||||
translateVoice: function (e) {
|
||||
M("translateVoice", {
|
||||
localId: e.localId,
|
||||
isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1
|
||||
}, e)
|
||||
},
|
||||
chooseImage: function (e) {
|
||||
M("chooseImage", {
|
||||
scene: "1|2",
|
||||
count: e.count || 9,
|
||||
sizeType: e.sizeType || ["original", "compressed"],
|
||||
sourceType: e.sourceType || ["album", "camera"]
|
||||
}, (e._complete = function (e) {
|
||||
if (p) {
|
||||
var n = e.localIds;
|
||||
try {
|
||||
n && (e.localIds = JSON.parse(n))
|
||||
} catch (e) {}
|
||||
}
|
||||
}, e))
|
||||
},
|
||||
getLocation: function (e) {},
|
||||
previewImage: function (e) {
|
||||
M(c.previewImage, {
|
||||
current: e.current,
|
||||
urls: e.urls
|
||||
}, e)
|
||||
},
|
||||
uploadImage: function (e) {
|
||||
M("uploadImage", {
|
||||
localId: e.localId,
|
||||
isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1
|
||||
}, e)
|
||||
},
|
||||
downloadImage: function (e) {
|
||||
M("downloadImage", {
|
||||
serverId: e.serverId,
|
||||
isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1
|
||||
}, e)
|
||||
},
|
||||
getLocalImgData: function (e) {
|
||||
!1 === I ? (I = !0, M("getLocalImgData", {
|
||||
localId: e.localId
|
||||
}, (e._complete = function (e) {
|
||||
if (I = !1, 0 < _.length) {
|
||||
var n = _.shift();
|
||||
wx.getLocalImgData(n)
|
||||
}
|
||||
}, e))) : _.push(e)
|
||||
},
|
||||
getNetworkType: function (e) {
|
||||
M("getNetworkType", {}, (e._complete = function (e) {
|
||||
e = function (e) {
|
||||
var n = e.errMsg;
|
||||
e.errMsg = "getNetworkType:ok";
|
||||
var i = e.subtype;
|
||||
if (delete e.subtype, i) e.networkType = i;
|
||||
else {
|
||||
var t = n.indexOf(":"),
|
||||
o = n.substring(t + 1);
|
||||
switch (o) {
|
||||
case "wifi":
|
||||
case "edge":
|
||||
case "wwan":
|
||||
e.networkType = o;
|
||||
break;
|
||||
default:
|
||||
e.errMsg = "getNetworkType:fail"
|
||||
}
|
||||
}
|
||||
return e
|
||||
}(e)
|
||||
}, e))
|
||||
},
|
||||
openLocation: function (e) {
|
||||
M("openLocation", {
|
||||
latitude: e.latitude,
|
||||
longitude: e.longitude,
|
||||
name: e.name || "",
|
||||
address: e.address || "",
|
||||
scale: e.scale || 28,
|
||||
infoUrl: e.infoUrl || ""
|
||||
}, e)
|
||||
},
|
||||
getLocation: function (e) {
|
||||
M(c.getLocation, {
|
||||
type: (e = e || {}).type || "wgs84"
|
||||
}, (e._complete = function (e) {
|
||||
delete e.type
|
||||
}, e))
|
||||
},
|
||||
hideOptionMenu: function (e) {
|
||||
M("hideOptionMenu", {}, e)
|
||||
},
|
||||
showOptionMenu: function (e) {
|
||||
M("showOptionMenu", {}, e)
|
||||
},
|
||||
closeWindow: function (e) {
|
||||
M("closeWindow", {}, e = e || {})
|
||||
},
|
||||
hideMenuItems: function (e) {
|
||||
M("hideMenuItems", {
|
||||
menuList: e.menuList
|
||||
}, e)
|
||||
},
|
||||
showMenuItems: function (e) {
|
||||
M("showMenuItems", {
|
||||
menuList: e.menuList
|
||||
}, e)
|
||||
},
|
||||
hideAllNonBaseMenuItem: function (e) {
|
||||
M("hideAllNonBaseMenuItem", {}, e)
|
||||
},
|
||||
showAllNonBaseMenuItem: function (e) {
|
||||
M("showAllNonBaseMenuItem", {}, e)
|
||||
},
|
||||
scanQRCode: function (e) {
|
||||
M("scanQRCode", {
|
||||
needResult: (e = e || {}).needResult || 0,
|
||||
scanType: e.scanType || ["qrCode", "barCode"]
|
||||
}, (e._complete = function (e) {
|
||||
if (f) {
|
||||
var n = e.resultStr;
|
||||
if (n) {
|
||||
var i = JSON.parse(n);
|
||||
e.resultStr = i && i.scan_code && i.scan_code.scan_result
|
||||
}
|
||||
}
|
||||
}, e))
|
||||
},
|
||||
openAddress: function (e) {
|
||||
M(c.openAddress, {}, (e._complete = function (e) {
|
||||
e = function (e) {
|
||||
return e.postalCode = e.addressPostalCode, delete e.addressPostalCode, e.provinceName = e.proviceFirstStageName, delete e.proviceFirstStageName, e.cityName = e.addressCitySecondStageName, delete e.addressCitySecondStageName, e.countryName = e.addressCountiesThirdStageName, delete e.addressCountiesThirdStageName, e.detailInfo = e.addressDetailInfo, delete e.addressDetailInfo, e
|
||||
}(e)
|
||||
}, e))
|
||||
},
|
||||
openProductSpecificView: function (e) {
|
||||
M(c.openProductSpecificView, {
|
||||
pid: e.productId,
|
||||
view_type: e.viewType || 0,
|
||||
ext_info: e.extInfo
|
||||
}, e)
|
||||
},
|
||||
addCard: function (e) {
|
||||
for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) {
|
||||
var r = n[t],
|
||||
a = {
|
||||
card_id: r.cardId,
|
||||
card_ext: r.cardExt
|
||||
};
|
||||
i.push(a)
|
||||
}
|
||||
M(c.addCard, {
|
||||
card_list: i
|
||||
}, (e._complete = function (e) {
|
||||
var n = e.card_list;
|
||||
if (n) {
|
||||
for (var i = 0, t = (n = JSON.parse(n)).length; i < t; ++i) {
|
||||
var o = n[i];
|
||||
o.cardId = o.card_id, o.cardExt = o.card_ext, o.isSuccess = !!o.is_succ, delete o.card_id, delete o.card_ext, delete o.is_succ
|
||||
}
|
||||
e.cardList = n, delete e.card_list
|
||||
}
|
||||
}, e))
|
||||
},
|
||||
chooseCard: function (e) {
|
||||
M("chooseCard", {
|
||||
app_id: v.appId,
|
||||
location_id: e.shopId || "",
|
||||
sign_type: e.signType || "SHA1",
|
||||
card_id: e.cardId || "",
|
||||
card_type: e.cardType || "",
|
||||
card_sign: e.cardSign,
|
||||
time_stamp: e.timestamp + "",
|
||||
nonce_str: e.nonceStr
|
||||
}, (e._complete = function (e) {
|
||||
e.cardList = e.choose_card_info, delete e.choose_card_info
|
||||
}, e))
|
||||
},
|
||||
openCard: function (e) {
|
||||
for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) {
|
||||
var r = n[t],
|
||||
a = {
|
||||
card_id: r.cardId,
|
||||
code: r.code
|
||||
};
|
||||
i.push(a)
|
||||
}
|
||||
M(c.openCard, {
|
||||
card_list: i
|
||||
}, e)
|
||||
},
|
||||
consumeAndShareCard: function (e) {
|
||||
M(c.consumeAndShareCard, {
|
||||
consumedCardId: e.cardId,
|
||||
consumedCode: e.code
|
||||
}, e)
|
||||
},
|
||||
chooseWXPay: function (e) {
|
||||
M(c.chooseWXPay, V(e), e)
|
||||
},
|
||||
openEnterpriseRedPacket: function (e) {
|
||||
M(c.openEnterpriseRedPacket, V(e), e)
|
||||
},
|
||||
startSearchBeacons: function (e) {
|
||||
M(c.startSearchBeacons, {
|
||||
ticket: e.ticket
|
||||
}, e)
|
||||
},
|
||||
stopSearchBeacons: function (e) {
|
||||
M(c.stopSearchBeacons, {}, e)
|
||||
},
|
||||
onSearchBeacons: function (e) {
|
||||
P(c.onSearchBeacons, e)
|
||||
},
|
||||
openEnterpriseChat: function (e) {
|
||||
M("openEnterpriseChat", {
|
||||
useridlist: e.userIds,
|
||||
chatname: e.groupName
|
||||
}, e)
|
||||
},
|
||||
launchMiniProgram: function (e) {
|
||||
M("launchMiniProgram", {
|
||||
targetAppId: e.targetAppId,
|
||||
path: function (e) {
|
||||
if ("string" == typeof e && 0 < e.length) {
|
||||
var n = e.split("?")[0],
|
||||
i = e.split("?")[1];
|
||||
return n += ".html", void 0 !== i ? n + "?" + i : n
|
||||
}
|
||||
}(e.path),
|
||||
envVersion: e.envVersion
|
||||
}, e)
|
||||
},
|
||||
openBusinessView: function (e) {
|
||||
M("openBusinessView", {
|
||||
businessType: e.businessType,
|
||||
queryString: e.queryString || "",
|
||||
envVersion: e.envVersion
|
||||
}, (e._complete = function (n) {
|
||||
if (p) {
|
||||
var e = n.extraData;
|
||||
if (e) try {
|
||||
n.extraData = JSON.parse(e)
|
||||
} catch (e) {
|
||||
n.extraData = {}
|
||||
}
|
||||
}
|
||||
}, e))
|
||||
},
|
||||
miniProgram: {
|
||||
navigateBack: function (e) {
|
||||
e = e || {}, O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "navigateBack",
|
||||
arg: {
|
||||
delta: e.delta || 1
|
||||
}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
navigateTo: function (e) {
|
||||
O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "navigateTo",
|
||||
arg: {
|
||||
url: e.url
|
||||
}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
redirectTo: function (e) {
|
||||
O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "redirectTo",
|
||||
arg: {
|
||||
url: e.url
|
||||
}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
switchTab: function (e) {
|
||||
O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "switchTab",
|
||||
arg: {
|
||||
url: e.url
|
||||
}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
reLaunch: function (e) {
|
||||
O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "reLaunch",
|
||||
arg: {
|
||||
url: e.url
|
||||
}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
postMessage: function (e) {
|
||||
O(function () {
|
||||
M("invokeMiniProgramAPI", {
|
||||
name: "postMessage",
|
||||
arg: e.data || {}
|
||||
}, e)
|
||||
})
|
||||
},
|
||||
getEnv: function (e) {
|
||||
O(function () {
|
||||
e({
|
||||
miniprogram: "miniprogram" === o.__wxjs_environment
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
T = 1,
|
||||
k = {};
|
||||
return i.addEventListener("error", function (e) {
|
||||
if (!p) {
|
||||
var n = e.target,
|
||||
i = n.tagName,
|
||||
t = n.src;
|
||||
if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i)
|
||||
if (-1 != t.indexOf("wxlocalresource://")) {
|
||||
e.preventDefault(), e.stopPropagation();
|
||||
var o = n["wx-id"];
|
||||
if (o || (o = T++, n["wx-id"] = o), k[o]) return;
|
||||
k[o] = !0, wx.ready(function () {
|
||||
wx.getLocalImgData({
|
||||
localId: t,
|
||||
success: function (e) {
|
||||
n.src = e.localData
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}, !0), i.addEventListener("load", function (e) {
|
||||
if (!p) {
|
||||
var n = e.target,
|
||||
i = n.tagName;
|
||||
n.src;
|
||||
if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i) {
|
||||
var t = n["wx-id"];
|
||||
t && (k[t] = !1)
|
||||
}
|
||||
}
|
||||
}, !0), e && (o.wx = o.jWeixin = w), w
|
||||
}
|
||||
|
||||
function M(n, e, i) {
|
||||
o.WeixinJSBridge ? WeixinJSBridge.invoke(n, x(e), function (e) {
|
||||
A(n, e, i)
|
||||
}) : B(n, i)
|
||||
}
|
||||
|
||||
function P(n, i, t) {
|
||||
o.WeixinJSBridge ? WeixinJSBridge.on(n, function (e) {
|
||||
t && t.trigger && t.trigger(e), A(n, e, i)
|
||||
}) : B(n, t || i)
|
||||
}
|
||||
|
||||
function x(e) {
|
||||
return (e = e || {}).appId = v.appId, e.verifyAppId = v.appId, e.verifySignType = "sha1", e.verifyTimestamp = v.timestamp + "", e.verifyNonceStr = v.nonceStr, e.verifySignature = v.signature, e
|
||||
}
|
||||
|
||||
function V(e) {
|
||||
return {
|
||||
timeStamp: e.timestamp + "",
|
||||
nonceStr: e.nonceStr,
|
||||
package: e.package,
|
||||
paySign: e.paySign,
|
||||
signType: e.signType || "SHA1"
|
||||
}
|
||||
}
|
||||
|
||||
function A(e, n, i) {
|
||||
"openEnterpriseChat" != e && "openBusinessView" !== e || (n.errCode = n.err_code), delete n.err_code, delete n.err_desc, delete n.err_detail;
|
||||
var t = n.errMsg;
|
||||
t || (t = n.err_msg, delete n.err_msg, t = function (e, n) {
|
||||
var i = e,
|
||||
t = a[i];
|
||||
t && (i = t);
|
||||
var o = "ok";
|
||||
if (n) {
|
||||
var r = n.indexOf(":");
|
||||
"confirm" == (o = n.substring(r + 1)) && (o = "ok"), "failed" == o && (o = "fail"), -1 != o.indexOf("failed_") && (o = o.substring(7)), -1 != o.indexOf("fail_") && (o = o.substring(5)), "access denied" != (o = (o = o.replace(/_/g, " ")).toLowerCase()) && "no permission to execute" != o || (o = "permission denied"), "config" == i && "function not exist" == o && (o = "ok"), "" == o && (o = "fail")
|
||||
}
|
||||
return n = i + ":" + o
|
||||
}(e, t), n.errMsg = t), (i = i || {})._complete && (i._complete(n), delete i._complete), t = n.errMsg || "", v.debug && !i.isInnerInvoke && alert(JSON.stringify(n));
|
||||
var o = t.indexOf(":");
|
||||
switch (t.substring(o + 1)) {
|
||||
case "ok":
|
||||
i.success && i.success(n);
|
||||
break;
|
||||
case "cancel":
|
||||
i.cancel && i.cancel(n);
|
||||
break;
|
||||
default:
|
||||
i.fail && i.fail(n)
|
||||
}
|
||||
i.complete && i.complete(n)
|
||||
}
|
||||
|
||||
function C(e) {
|
||||
if (e) {
|
||||
for (var n = 0, i = e.length; n < i; ++n) {
|
||||
var t = e[n],
|
||||
o = c[t];
|
||||
o && (e[n] = o)
|
||||
}
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
function B(e, n) {
|
||||
if (!(!v.debug || n && n.isInnerInvoke)) {
|
||||
var i = a[e];
|
||||
i && (e = i), n && n._complete && delete n._complete, console.log('"' + e + '",', n || "")
|
||||
}
|
||||
}
|
||||
|
||||
function L() {
|
||||
return (new Date).getTime()
|
||||
}
|
||||
|
||||
function O(e) {
|
||||
l && (o.WeixinJSBridge ? e() : i.addEventListener && i.addEventListener("WeixinJSBridgeReady", e, !1))
|
||||
}
|
||||
});
|
||||
1
src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
114
src/components/contentList.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="all_list">
|
||||
<div class="grid_list">
|
||||
<div class="list_item" v-for="(item, index) in moreList" :key="index">
|
||||
<img :src="item.img" alt="Event 1" @click="goDetail(item)" />
|
||||
<p>{{item.title}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import pic from '../assets/img/top1.png';
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const moreList =ref([
|
||||
{
|
||||
id: 1,
|
||||
title: "章丘区高官寨甜瓜季乡村好时节活动",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "中华人民共和国第十四届全国人民代表大会",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "泉在济南·龙山文化旅游季活动",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "乡村好时节·花开北市樱花旅游节",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "国际学校名校展",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "爱牙医生来",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "宏观经济形势与政策",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "学在济南·聚在泉城",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "文明济南·礼安齐鲁",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: "民主主题记者会",
|
||||
img:pic,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "学在济南·聚在泉城",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "文明济南·礼安齐鲁",
|
||||
img:pic
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: "民主主题记者会",
|
||||
img:pic,
|
||||
}
|
||||
])
|
||||
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.all_list {
|
||||
width: 90%;
|
||||
margin: 10px auto;
|
||||
height: calc(100vh - 120px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.grid_list {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
.list_item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 102px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
110
src/components/countDown.vue
Normal file
@ -0,0 +1,110 @@
|
||||
//倒计时
|
||||
<template>
|
||||
<!-- <div class="co-main">
|
||||
<div class="co-flex">
|
||||
距离直播开始还有:
|
||||
<div class="border-bar">{{ d }}</div>
|
||||
<span>天</span>
|
||||
<div class="border-bar">{{ h }}</div>
|
||||
<span>时</span>
|
||||
<div class="border-bar">{{ m }}</div>
|
||||
<span>分</span>
|
||||
<div class="border-bar">{{ s }}</div>
|
||||
<span>秒</span>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="main">
|
||||
<div class="main_left">
|
||||
<P> 距离直播开始还有:</P>
|
||||
<p class="time">{{ h }}:{{ m }}:{{ s }}</p>
|
||||
</div>
|
||||
<div class="main_left">
|
||||
<p class="views">500人次观看</p>
|
||||
<button>预告</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||
|
||||
const props = defineProps(["countdownTime"]);
|
||||
const showTime = ref(0);
|
||||
const timeInterval = ref(null);
|
||||
const totalTime = ref(0);
|
||||
const d = ref("00");
|
||||
const h = ref("00");
|
||||
const m = ref("00");
|
||||
const s = ref("00");
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timeInterval.value);
|
||||
});
|
||||
|
||||
function init() {
|
||||
console.log("[init] --> ", props.countdownTime);
|
||||
totalTime.value = props.countdownTime;
|
||||
timeInterval.value = setInterval(() => {
|
||||
parseTime(totalTime.value);
|
||||
|
||||
totalTime.value--;
|
||||
if (totalTime.value < 0) {
|
||||
clearInterval(timeInterval.value);
|
||||
location.replace(location.href);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function parseTime(total) {
|
||||
let day = Math.floor(total / (24 * 60 * 60));
|
||||
let afterDay = total - day * 24 * 60 * 60;
|
||||
let hour = Math.floor(afterDay / (60 * 60));
|
||||
let afterHour = total - day * 24 * 60 * 60 - hour * 60 * 60;
|
||||
let min = Math.floor(afterHour / 60);
|
||||
let second = afterHour % 60;
|
||||
|
||||
d.value = day < 10 ? "0" + day : day;
|
||||
h.value = hour < 10 ? "0" + hour : hour;
|
||||
m.value = min < 10 ? "0" + min : min;
|
||||
s.value = second < 10 ? "0" + second : second;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main{
|
||||
width: 100%;
|
||||
padding:10px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height:80px;
|
||||
|
||||
.main_left{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.time{
|
||||
font-size: 36px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.views{
|
||||
font-size: 12px;
|
||||
}
|
||||
p{
|
||||
font-size: 16px;
|
||||
}
|
||||
button{
|
||||
padding:5px 15px;
|
||||
background-color: #D7000F;
|
||||
border:none;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
76
src/components/header.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="top"></div>
|
||||
<div class="header-content">
|
||||
<div class="logo">
|
||||
<img src="../assets/img/logo.png" alt="" />
|
||||
</div>
|
||||
<p>直播</p>
|
||||
<div class="search">
|
||||
<van-search
|
||||
v-model="value"
|
||||
shape="round"
|
||||
background="transparent"
|
||||
placeholder="请输入搜索关键词"
|
||||
@click="onSearch"
|
||||
></van-search>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from 'vue-router'
|
||||
const value = ref("");
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
const onSearch = () => {
|
||||
console.log("1111111111");
|
||||
// 携带查询参数value到search路由
|
||||
router.push({
|
||||
name: 'Search',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep(.van-search){
|
||||
padding:0;
|
||||
}
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(27, 163, 251, 100%),
|
||||
70%,
|
||||
rgba(27, 163, 251, 45%)
|
||||
);
|
||||
display: flex;
|
||||
.header-content {
|
||||
width: 90%;
|
||||
padding:10px 0;
|
||||
margin:0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.logo {
|
||||
img {
|
||||
width: 30px;
|
||||
height:30px;
|
||||
}
|
||||
}
|
||||
p {
|
||||
width:50px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
.search{
|
||||
width:70%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
95
src/components/moreLive.vue
Normal file
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="moreLive">
|
||||
<p>更多直播</p>
|
||||
<div class="live_list">
|
||||
<div class="moreLive-list" v-for="(item, index) in lives" :key="index" @click="goDetail(item)">
|
||||
<img src="../assets/img/big1.png" />
|
||||
<div class="live_info">
|
||||
<div class="live_title">
|
||||
<!-- <p :class="{ 'live_status': item.status === '直播中', 'live_coming': item.status === '预告', 'live_review': item.status === '精彩回顾' }">{{ item.status }}</p> -->
|
||||
<p :class="{ 'live_status': getStatusClass(item.status) === '直播中', 'live_coming': getStatusClass(item.status) === '预告', 'live_review': getStatusClass(item.status) === '精彩回顾' }">{{ getStatusText(item.status) }}</p>
|
||||
<p class="live_see">{{item.viewers}}人次观看</p>
|
||||
</div>
|
||||
<p>{{item.title}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const lives = ref([
|
||||
{ id:'0',status: '0', viewers: '2347.7万', title: '文明清明·礼安齐鲁1' },
|
||||
{ id:'1',status: '1', viewers: '1536万', title: '文明清明·礼安齐鲁2' },
|
||||
{ id:'2',status: '2', viewers: '58697万', title: '文明清明·礼安齐鲁3' },
|
||||
{ id:'3',status: '0', viewers: '2347.7万', title: '文明清明·礼安齐鲁' }
|
||||
|
||||
])
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
'0': '预告',
|
||||
'1': '直播中',
|
||||
'2': '精彩回顾',
|
||||
};
|
||||
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || '';
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || '';
|
||||
|
||||
const goDetail=(item)=>{
|
||||
console.log(item)
|
||||
// router.push({
|
||||
// name:'Detail',
|
||||
// query:{id:item.id}
|
||||
// })
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.moreLive {
|
||||
padding: 10px;
|
||||
// p{
|
||||
// font-size: 16px;
|
||||
// }
|
||||
.live_list{
|
||||
width:100%;
|
||||
height: calc(100vh - 50px);
|
||||
overflow-y: scroll;
|
||||
.moreLive-list{
|
||||
width:100%;
|
||||
height: 128px;
|
||||
margin:10px 0;
|
||||
position: relative;
|
||||
.live_info{
|
||||
padding:5px;
|
||||
position: absolute;
|
||||
bottom:0px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
.live_title{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap:5px;
|
||||
.live_see{
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
font-size: 10px;
|
||||
padding:3px 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
88
src/components/pageAbstract.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="abstract">
|
||||
<div class="title">{{ title }}济南移动直播平台移动端开发的标题</div>
|
||||
<div class="info">
|
||||
<div class="info-item">
|
||||
<span class="name">直播时间:</span>
|
||||
<span class="info-item-text">2024年5约我接地极{{ infoDate }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">直播地点:</span>
|
||||
<span class="info-item-text">济南{{ infoPlace }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="name">直播简介:</span>
|
||||
<van-text-ellipsis
|
||||
class="info-item-text"
|
||||
style="display: inline;"
|
||||
rows="3"
|
||||
:content="text"
|
||||
expand-text="展开"
|
||||
collapse-text="收起"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const text =
|
||||
"那一天我二十一岁,在我一生的黄金时代。我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云。后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消失,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。";
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.abstract {
|
||||
// border: 1px solid blue;
|
||||
margin-top: 10px;
|
||||
padding: 0 20px;
|
||||
// border-top: 4px solid #eee;
|
||||
// padding-top: 10px;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-stretch: normal;
|
||||
line-height: 21px;
|
||||
letter-spacing: 0px;
|
||||
color: #232323;
|
||||
}
|
||||
.info {
|
||||
margin-top: 10px;
|
||||
font-size: 17px;
|
||||
// font-size: 13px;
|
||||
font-weight: normal;
|
||||
font-stretch: normal;
|
||||
letter-spacing: 0px;
|
||||
color: #5c5c5c;
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 7px;
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
color: #000;
|
||||
}
|
||||
.info-item-text {
|
||||
color: #777882;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 18px;
|
||||
font-size: 17px;
|
||||
// font-size: 13px;
|
||||
color: #5c5c5c;
|
||||
line-height: 1.6;
|
||||
// line-height: 20px;
|
||||
.content-title {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.go-new-page {
|
||||
color: rgb(0, 0, 238);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
272
src/components/pageComment.vue
Normal file
@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<div class="comment">
|
||||
<div class="comment-scroll">
|
||||
<!-- <mescroll-vue class="mescrollPadding" ref="mescroll" :up="mescrollUp" @init="mescrollInit"> -->
|
||||
<div class="scroll-main" id="dataListComment">
|
||||
<div class="comment-card" v-for="(item, index) in commentData" :key="index">
|
||||
<div class="comment-card-main">
|
||||
<!-- 评论头像 -->
|
||||
<div class="headImg">
|
||||
<img v-if="item.headImg" :src="item.headImg" alt />
|
||||
<img v-else :src="imageAvatarUrl" alt />
|
||||
</div>
|
||||
<span class="top-name">{{item.userName||'游客'}}: </span>
|
||||
<span class="content-bottom">{{item.text}}</span>
|
||||
<!-- <div class="content">
|
||||
<div class="content-top">
|
||||
<div class="top-name">{{item.userName||'游客'}}</div>
|
||||
<div class="content-bottom">{{item.text}}</div>
|
||||
</div>
|
||||
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div class="botton-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </mescroll-vue> -->
|
||||
</div>
|
||||
|
||||
<div class="comment-input">
|
||||
<img src="../assets/img/logo.png"/>
|
||||
<form action="/">
|
||||
<van-search
|
||||
class="input-class"
|
||||
v-model="showSubmitMsg"
|
||||
type="text"
|
||||
placeholder="我来说几句......"
|
||||
clearable
|
||||
background="#ededed"
|
||||
left-icon
|
||||
id="vanInput"
|
||||
@search="inputCommentHandler"
|
||||
/>
|
||||
<canvas id="thumsCanvas" width="200" height="1000"></canvas>
|
||||
<div class="iconShare" @click="inputCommentHandler">
|
||||
<img src="../assets/img/like.svg" alt @click="clickLikeThumb" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {onMounted, ref} from 'vue';
|
||||
import {commentList,addComment} from '../api/index';
|
||||
import ThumbsUpAni from '../utils/canvas'
|
||||
const imageAvatarUrl = ref(null);
|
||||
const commentData= ref([]);
|
||||
const showSubmitMsg = ref('');
|
||||
// 获取评论列表
|
||||
const getCommentList = async () => {
|
||||
let params = {
|
||||
sceneId:2057,
|
||||
size: 10,
|
||||
page: 1,
|
||||
|
||||
};
|
||||
commentList(params)
|
||||
.then((res) => {
|
||||
console.log("获取评论列表",res);
|
||||
commentData.value =res.data;
|
||||
imageAvatarUrl.value = res.anonymousUrl
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录接口请求失败", error);
|
||||
});
|
||||
};
|
||||
|
||||
// 点赞功能
|
||||
const clickLikeThumb=()=> {
|
||||
|
||||
const thumbsUpAni = new ThumbsUpAni();
|
||||
console.log("点击",thumbsUpAni);
|
||||
setInterval(() => {
|
||||
thumbsUpAni.start();
|
||||
}, 300);
|
||||
|
||||
}
|
||||
onMounted(()=>{
|
||||
getCommentList();
|
||||
})
|
||||
// 评论输入
|
||||
const inputCommentHandler =()=>{
|
||||
console.log("评论输入",showSubmitMsg.value);
|
||||
// 检测是否填写内容
|
||||
if (showSubmitMsg.value.length < 1) {
|
||||
return false;
|
||||
}
|
||||
let utoken = null;
|
||||
let sceneId = 2057;
|
||||
let text = JSON.parse(JSON.stringify(showSubmitMsg.value));
|
||||
|
||||
// 拼装 formData
|
||||
let formdate = new FormData();
|
||||
formdate.append("utoken", utoken);
|
||||
formdate.append("sceneId", sceneId);
|
||||
formdate.append("text", text);
|
||||
|
||||
let vanInput = document.querySelector("#vanInput");
|
||||
vanInput.blur();
|
||||
window.scroll(0, 0);
|
||||
// 调用api
|
||||
addComment(formdate)
|
||||
.then(({ data }) => {
|
||||
showNotify({ type: "primary", message: "评论成功" });
|
||||
this.mescroll.triggerDownScroll(); // 调用upCallback
|
||||
showSubmitMsg.value = "";
|
||||
})
|
||||
.catch(e => {
|
||||
// 联网失败的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
this.mescroll.endDownScroll();
|
||||
console.log("%c 提交评论 error ", "color:red", e, "提交失败");
|
||||
showNotify({ type: "danger", message: "网络繁忙,请稍后再试。" });
|
||||
showSubmitMsg.value = "";
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
#thumsCanvas {
|
||||
position:fixed;
|
||||
bottom:50px;
|
||||
right:0;
|
||||
width: 100px;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: transparent!important;
|
||||
}
|
||||
|
||||
|
||||
.comment {
|
||||
height: 100%;
|
||||
|
||||
.comment-scroll {
|
||||
height: calc(100vh - 175px);
|
||||
overflow: scroll;
|
||||
.scroll-main {
|
||||
height: 100%;
|
||||
|
||||
.comment-card {
|
||||
// border: 1px solid blue;
|
||||
padding:10px 20px;
|
||||
|
||||
.comment-card-main {
|
||||
display:inline-block;
|
||||
padding:5px 10px;
|
||||
width: auto;
|
||||
background-color: #EEEEEE;
|
||||
border-radius: 10px;
|
||||
|
||||
.headImg {
|
||||
display: inline-block;
|
||||
vertical-align:middle;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
|
||||
}
|
||||
}
|
||||
.top-name{
|
||||
margin-left: 10px;
|
||||
font-size: 16px;
|
||||
color: #777882;
|
||||
|
||||
}
|
||||
.content-bottom {
|
||||
font-family: MicrosoftYaHei-Bold;
|
||||
font-size: 16px;
|
||||
color: rgba(0,0,0,80%);
|
||||
line-height: 19px;
|
||||
letter-spacing: 0px;
|
||||
}
|
||||
// .content {
|
||||
// width: 268px;
|
||||
// .content-top {
|
||||
// display: flex;
|
||||
// justify-content: space-between;
|
||||
// margin-bottom: 10px;
|
||||
// font-size: 15px;
|
||||
// color: #5c5c5c;
|
||||
// }
|
||||
// .content-bottom {
|
||||
// font-family: MicrosoftYaHei-Bold;
|
||||
// font-size: 17px;
|
||||
// color: #454545;
|
||||
// line-height: 19px;
|
||||
// letter-spacing: 0px;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// .botton-line {
|
||||
// height: 1px;
|
||||
// width: 100%;
|
||||
// margin-left: 9px;
|
||||
// background-color: rgba(160, 160, 160, 0.52);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
.comment-input {
|
||||
position: fixed;
|
||||
bottom:0;
|
||||
display: flex;
|
||||
padding:0 10px;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
img{
|
||||
width:40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
width: 85%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// padding: 0 12px;
|
||||
|
||||
.iconShare {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.input-class.van-search {
|
||||
// padding-top: 7px;
|
||||
padding: 0;
|
||||
width: 85%;
|
||||
.van-search__content {
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
|
||||
color: #454545;
|
||||
|
||||
.van-cell {
|
||||
font-size: 12px !important;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.van-pull-refresh__track {
|
||||
height: 100% !important;
|
||||
}
|
||||
</style>
|
||||
615
src/components/pageReport.vue
Normal file
@ -0,0 +1,615 @@
|
||||
<template>
|
||||
<div id="report">
|
||||
<!-- 悬浮框 正序浏览/倒序浏览 -->
|
||||
<!-- <div class="reverseBtn" @click="reverseData">
|
||||
<img :src="isOrder ? inOrderIcon : orderIcon" alt class="isOrder" />
|
||||
</div> -->
|
||||
|
||||
<!-- 上下拉 -->
|
||||
<div class="scroll">
|
||||
<mescroll-vue
|
||||
class="mescrollPadding"
|
||||
ref="mescroll"
|
||||
:up="mescrollUp"
|
||||
@init="mescrollInit"
|
||||
>
|
||||
<div id="liveView" ref="liveView" class="liveView">
|
||||
<div>
|
||||
<van-divider>直播视角</van-divider>
|
||||
<!-- 多个视角 -->
|
||||
<div class="viewSelect liveTab" >
|
||||
<div
|
||||
class="liveTabCell"
|
||||
active-class="selectedTab"
|
||||
v-for="(item, index) in liveList"
|
||||
:key="index"
|
||||
:selected="index === liveTabIndex"
|
||||
@click="goStore(index)"
|
||||
>
|
||||
<div class="selectPicItem" >
|
||||
<div class="select-pic-item-img">
|
||||
<img v-if="item.coverUrl" :src="item.coverUrl" alt />
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
<div class="coverTitle" :title="item.name">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 报道 -->
|
||||
<div class="report" id="dataList" ref="dataList">
|
||||
<page-abstract></page-abstract>
|
||||
<div
|
||||
class="reportCell"
|
||||
v-for="(item, index) in reportDataList"
|
||||
:key="index"
|
||||
>
|
||||
<div class="reportLeft">
|
||||
<img
|
||||
class="reportLeftImg"
|
||||
src="../assets/img/ijnan_line.png"
|
||||
alt
|
||||
/>
|
||||
</div>
|
||||
<div class="reportRight">
|
||||
<div class="reportCellTopInfo">
|
||||
<span class="reportDate">{{ item.reportDate }}</span>
|
||||
<div class="repoterUser">
|
||||
<!-- <div class="userImg">
|
||||
<img class="userImgUrl" :src="userImg" alt />
|
||||
</div>-->
|
||||
<!-- 报道:logo -->
|
||||
<div class="userName">
|
||||
<img class="userImgUrl" :src="imageLogoUrl" alt />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reportRightMain reportBorderLeft">
|
||||
<div class="reportRightMainBg">
|
||||
<!-- 修改各种 reportType 1视频 2音频 3图文 4文字 -->
|
||||
<div v-if="item.reportType === '4'" class="reportRightMainTxt">
|
||||
<!-- <div v-html="changeStr(item.content)"></div> -->
|
||||
<van-text-ellipsis
|
||||
class="imgTxtContant"
|
||||
style="display: inline;"
|
||||
rows="3"
|
||||
:content="item.content"
|
||||
expand-text="展开"
|
||||
collapse-text="收起"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="item.reportType === '3'" class="reportRightMainDefine">
|
||||
<div class="imgTxt" v-if="item.imgList">
|
||||
<div class="singleImg" v-if="item.imgList.length === 1">
|
||||
<img
|
||||
v-if="item.imgList[0]"
|
||||
:src="item.imgList[0]"
|
||||
:οnerrοr="defineBigBg"
|
||||
preview="'groupName'"
|
||||
alt
|
||||
/>
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
<div class="doubleImg" v-else-if=" item.imgList.length === 2">
|
||||
<div class="doubleImgRact">
|
||||
<img
|
||||
v-if="item.imgList[0]"
|
||||
:src="item.imgList[0]"
|
||||
:οnerrοr="defineBigBg"
|
||||
preview="'groupName'"
|
||||
alt
|
||||
/>
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
<div class="doubleImgRact">
|
||||
<img
|
||||
v-if="item.imgList[1]"
|
||||
:src="item.imgList[1]"
|
||||
:οnerrοr="defineBigBg"
|
||||
preview="'groupName'"
|
||||
alt
|
||||
/>
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
</div>
|
||||
<div class="doubleImg" v-else-if="item.imgList.length === 3">
|
||||
<div
|
||||
class="doubleImgRact3"
|
||||
v-for="(imgItem,index) in item.imgList"
|
||||
:key="index"
|
||||
>
|
||||
<img
|
||||
v-if="imgItem"
|
||||
:src="imgItem"
|
||||
:οnerrοr="defineBigBg"
|
||||
preview="'groupName'"
|
||||
alt
|
||||
/>
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
</div>
|
||||
<div class="doubleImgOther" v-else>
|
||||
<div
|
||||
class="doubleImgRact"
|
||||
v-for="(imgItem,index) in item.imgList"
|
||||
:key="index"
|
||||
>
|
||||
<img
|
||||
v-if="imgItem"
|
||||
:src="imgItem"
|
||||
:οnerrοr="defineBigBg"
|
||||
preview="'groupName'"
|
||||
alt
|
||||
/>
|
||||
<img v-else :src="defineBigBg" alt />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="imgTxtContant" v-html="changeStr(item.content)"></div> -->
|
||||
<van-text-ellipsis
|
||||
class="imgTxtContant"
|
||||
style="display: inline;"
|
||||
rows="3"
|
||||
:content="item.content"
|
||||
expand-text="展开"
|
||||
collapse-text="收起"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="item.reportType === '2'" class="reportRightMainDefine">
|
||||
<div class="audioBubble" @click="audioPlay(item.mediaUrl)">
|
||||
<div class="audioIcon">
|
||||
<img :src="icAudio" alt />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="audio-p-time"
|
||||
:ref="'audio-p-'+index"
|
||||
>{{duration2Time(item.audioDuration)}}</div>
|
||||
</div>
|
||||
<!-- <div class="imgTxtContant" v-html="changeStr(item.content)"></div> -->
|
||||
<van-text-ellipsis
|
||||
class="imgTxtContant"
|
||||
style="display: inline;"
|
||||
rows="3"
|
||||
:content="item.content"
|
||||
expand-text="展开"
|
||||
collapse-text="收起"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="item.reportType === '1'" class="reportRightMainDefine">
|
||||
<div class="videoClass">
|
||||
<div
|
||||
class="posterPic"
|
||||
v-if="index!==posterIndex"
|
||||
@click="playIndexVideo(index,item)"
|
||||
>
|
||||
<img v-if="item.imgList" :src="item.imgList[0]" :οnerrοr="defineBg" alt />
|
||||
<img v-else :src="defineBg" alt />
|
||||
</div>
|
||||
<div
|
||||
v-if="index!==posterIndex"
|
||||
class="posterPlay"
|
||||
@click="playIndexVideo(index,item)"
|
||||
>
|
||||
<img :src="iconPlayVideo" alt />
|
||||
</div>
|
||||
<video
|
||||
:src="item.mediaUrl"
|
||||
:poster="item.imgList?item.imgList[0]:''"
|
||||
ref="videoPlay"
|
||||
@play="onVideoPlay"
|
||||
controls
|
||||
x5-playsinline
|
||||
playsinline="true"
|
||||
webkit-playsinline="true"
|
||||
x-webkit-airplay="true"
|
||||
x5-video-player-type="h5"
|
||||
x5-video-player-fullscreen
|
||||
x5-video-orientation="portraint"
|
||||
></video>
|
||||
</div>
|
||||
<!-- <div class="imgTxtContant" v-html="changeStr(item.content)"></div> -->
|
||||
<van-text-ellipsis
|
||||
class="imgTxtContant"
|
||||
style="display: inline;"
|
||||
rows="3"
|
||||
:content="item.content"
|
||||
expand-text="展开"
|
||||
collapse-text="收起"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="item.contentHref!=null&&item.contentHref.length>0" class="crefer">
|
||||
<div class="title">相关报道</div>
|
||||
<divider class="crefer-line"></divider>
|
||||
<div class="crefer-a">
|
||||
<a :href="item.contentHref">{{item.relatedReport?item.relatedReport:'相关链接'}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mescroll-vue>
|
||||
</div>
|
||||
<audio ref="audio" class="audioClass" controls="controls">不支持</audio>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import MescrollVue from 'mescroll.js/mescroll.vue'
|
||||
import defineBigBg from '../assets/img/defineBigBg.png';
|
||||
import {report} from '../api/index';
|
||||
const liveTabIndex = ref(0);
|
||||
const liveList = ref([
|
||||
{
|
||||
"name": "珍珠泉",
|
||||
"coverUrl": "https://v.livejinan.cn/image/default/B861748A8C2144E4B5D495EC2E145E36-6-2.jpg",
|
||||
"playUrl": "https://play.livejinan.cn/caeUaEzv/435e3a9910934a02963efbc816bc6fb5.m3u8?auth_key=1762000667-0-0-978bb1670d6778fafd715add79508ca9"
|
||||
},
|
||||
{
|
||||
"name": "回马泉",
|
||||
"coverUrl": "https://v.livejinan.cn/image/default/A9E4B702DCDD433E9D9F96CC5B547B95-6-2.jpg",
|
||||
"playUrl": "https://play.livejinan.cn/caeUaEzv/af6c1c5167944ae0b17455b475b49ad3.m3u8?auth_key=1762000667-0-0-84ac0c225eec8c42992a278f7398fbe3"
|
||||
},
|
||||
{
|
||||
"name": "黑虎泉",
|
||||
"coverUrl": "https://v.livejinan.cn/image/default/5690007EE0224437A447503EE7833466-6-2.jpg",
|
||||
"playUrl": "https://play.livejinan.cn/caeUaEzv/d8808c0620ca4ea8875bf02a6f48d74b.m3u8?auth_key=1762000667-0-0-871ee007886d35f6239d31547e1ff4fc"
|
||||
},
|
||||
{
|
||||
"name": "趵突泉",
|
||||
"coverUrl": "https://v.livejinan.cn/image/default/5AD9515D81F84C5B81D1AEAA90E52D88-6-2.jpg",
|
||||
"playUrl": "https://play.livejinan.cn/caeUaEzv/62575b41a6bc4e7d9bdeb7930bb60f90.m3u8?auth_key=1762000667-0-0-b78d8b16b6d8f8a1f1231fd03bce22ee"
|
||||
},
|
||||
{
|
||||
"name": "五龙潭泉群",
|
||||
"coverUrl": "https://v.livejinan.cn/image/default/6ADAC0A084CB4A02957C59B5E3E377C1-6-2.jpg",
|
||||
"playUrl": "https://play.livejinan.cn/caeUaEzv/c6d0d2464deb43dd89b0c0d560596fc5.m3u8?auth_key=1762000667-0-0-6e72ab4b79fa2531d0ecfb105101e323"
|
||||
}
|
||||
|
||||
|
||||
])
|
||||
const reportDataList = ref([
|
||||
{
|
||||
reportType: "3",
|
||||
reportDate: "2021-10-09 07:32",
|
||||
mediaUrl: null,
|
||||
relatedReport: "",
|
||||
widthAndHeight: ["1.77:1"],
|
||||
id: "36377",
|
||||
contentHref: "",
|
||||
reporterName: "王晨",
|
||||
content:
|
||||
" 今年入夏以来,随着降雨逐渐增多,济南趵突泉地下水位创56年之最,突破30米“大关”。与此同时,众泉也更加欢畅奔腾。自古有“波涛声震大明湖”、“石激湍声成虎吼”、“水若涌轮”的吟咏,而今天,爱济南通过5G技术和“千里眼”点位,带大家沉浸式体验不一样的泉水下的美丽世界。\n 甘甜的泉水清澈见底,水藻飘摆,水泡咕噜咕噜冒个不停,不时有鱼儿穿梭其间……这里没有主持人,没有解说字幕,也没有配音,更没有绚丽的镜头切换和后期制作,这里只有最真实的泉水下的世界。\n 请你放下所有烦恼和压力,快来近距离地体验和享受这段最美妙的泉城水下世界。",
|
||||
imgList: [
|
||||
"https://v.livejinan.cn/image/default/5D19FFA43A2A436DA89BB5CCFAD776C6-6-2.jpg?x-oss-process=image/resize,w_600",
|
||||
],
|
||||
},
|
||||
{
|
||||
reportType: "3",
|
||||
reportDate: "2021-10-09 09:09",
|
||||
mediaUrl: null,
|
||||
relatedReport: "",
|
||||
widthAndHeight: ["1.33:1"],
|
||||
id: "36378",
|
||||
contentHref: "",
|
||||
reporterName: "张静",
|
||||
content:
|
||||
" 近年来,济南报业坚持“融合赋能,伴生城市成长”理念,聚力内容、平台和技术三方面创新,媒体融合的“济南模式、山东特色”更加鲜明。2020年初,济南报业依托爱济南新闻客户端布局慢直播项目,推出“大型城市形象宣传平台——直播济南”,对济南200多个“点位”进行24小时直播,在全国地方媒体中开创先河。\n\n “直播济南”,根植济南、面向全国、沟通世界,以传播济南好声音、讲好济南故事为己任,以助力建设“大强美富通”现代化国际大都市、塑造良好城市形象为使命。围绕这个使命,“直播济南”运用图文直播、移动直播、短视频直播、航拍直播VR直播等多种直播形态,让受众沉浸式体验,身临其境感受泉城新面貌。\n\n 从图片到视频再到VR,用直观而又有视觉冲击力的表现形式,全方位、立体化展示济南的发展成绩。目前,“大型城市形象宣传平台——直播济南”已陆续推出“重点项目巡礼季”、“文化旅游季”、“电商带货季”、“乡村振兴季”等大型直播。济南报业与人民视频、央视频、学习强国、今日头条、百度等重要媒体平台积极互动,同步直播济南,面向全网传播。同时,济南报业坚持对时政活动、重点工作、市委市政府新闻发布会等进行常态化直播,传播力大幅提升,赢得广泛关注和认可。(王晨 孙明超 苏岭红 张静)",
|
||||
imgList: [
|
||||
"https://v.livejinan.cn/image/default/29002AF6D93C41B7AFC5DC9A882CC476-6-2.png?x-oss-process=image/resize,w_600",
|
||||
],
|
||||
},
|
||||
]);
|
||||
// 引入MescrollVue组件
|
||||
const mescroll = ref(null);
|
||||
|
||||
// Mescroll上拉加载的配置
|
||||
const mescrollUp = {
|
||||
// 是否自动加载第一页
|
||||
auto: true,
|
||||
// 回调函数,用于获取数据
|
||||
// callback: upCallback,
|
||||
// 无数据时的提示文本
|
||||
empty: {
|
||||
tip: '暂无更多数据'
|
||||
},
|
||||
// 加载失败时的提示文本
|
||||
error: {
|
||||
tip: '加载失败,点击重新加载'
|
||||
}
|
||||
};
|
||||
|
||||
// Mescroll初始化完成的回调
|
||||
const mescrollInit = (mescroll) => {
|
||||
console.log('Mescroll 初始化完成');
|
||||
// 这里可以做一些初始化后的操作,比如保存mescroll实例到外部变量
|
||||
// this.mescroll = mescroll;
|
||||
};
|
||||
|
||||
// 上拉加载的回调函数,用于获取数据
|
||||
const upCallback = (page) => {
|
||||
|
||||
};
|
||||
// 获取报道列表
|
||||
|
||||
const getReportList = () => {
|
||||
let params = {
|
||||
sceneId:2057,
|
||||
size: 10,
|
||||
page: 1
|
||||
};
|
||||
report(params)
|
||||
.then((res) => {
|
||||
console.log("获取报道列表",res);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录接口请求失败", error);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
#report {
|
||||
/* min-height: 102vw; */
|
||||
height: 100%;
|
||||
// width:720px;
|
||||
// margin:0 auto;
|
||||
background-color: #fff;
|
||||
overflow-y: scroll;
|
||||
/* padding-top: 30px; */
|
||||
}
|
||||
/* 悬浮框 */
|
||||
.reverseBtn {
|
||||
z-index: 998;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 0;
|
||||
width: 68px;
|
||||
height: 20px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.scroll {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
.mescrollPadding {
|
||||
box-sizing: border-box;
|
||||
/* padding-top: 15px; */
|
||||
}
|
||||
|
||||
/* 直播视角 */
|
||||
.liveView {
|
||||
/* position: absolute; */
|
||||
z-index: 21;
|
||||
/* margin-top: 32px; */
|
||||
// padding-bottom: 15px;
|
||||
// box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.05);
|
||||
background-color: #fff;
|
||||
// margin-bottom: 8px;
|
||||
}
|
||||
// --------------------------
|
||||
.liveTab {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-perspective: 1000;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.liveTabCell {
|
||||
display: inline-block;
|
||||
width: 75px;
|
||||
margin: 0 5px;
|
||||
// border-radius: 5px;
|
||||
}
|
||||
|
||||
.liveTabCell .selectPicItem {
|
||||
width: 100%;
|
||||
// height: 45px;
|
||||
position: relative;
|
||||
/* height: 84px; */
|
||||
// background-color: #ccc;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.liveTabCell .selectPicItem .select-pic-item-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 42.186px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.coverTitle {
|
||||
margin-top: 6px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
width: 75px;
|
||||
// min-height: 20px;
|
||||
font-size: 10px;
|
||||
color: #454545;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.viewNameSpan {
|
||||
font-size: 14px;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
.van-divider {
|
||||
width: 100%;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
#dataList {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 5px;
|
||||
|
||||
}
|
||||
|
||||
.btnReview {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 25px;
|
||||
z-index: 99999;
|
||||
background-color: #fff;
|
||||
}
|
||||
.reportCell {
|
||||
// overflow: hidden;
|
||||
// border:1px solid red;
|
||||
}
|
||||
.reportLeft {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 3px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
// border:1px solid red;
|
||||
}
|
||||
|
||||
.reportLeft .reportLeftImg {
|
||||
display: block;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
|
||||
}
|
||||
|
||||
.reportBorderLeft {
|
||||
border-left: 1px solid rgba(136, 136, 136, 0.42);
|
||||
}
|
||||
|
||||
.reportRight {
|
||||
margin-left: 23px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
}
|
||||
|
||||
.reportCellTopInfo {
|
||||
padding: 10px 0px 0px 20px;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.repoterUser {
|
||||
float: left;
|
||||
color: #279cfb;
|
||||
}
|
||||
|
||||
.userImg {
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.userImg > .userImgUrl {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.userName {
|
||||
width: 45px;
|
||||
height: 12px;
|
||||
margin-left: 5px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.userName > .userImgUrl {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.reportDate {
|
||||
// margin-left: 5px;
|
||||
// font-size: 10px;
|
||||
font-size: 15px;
|
||||
color: #464646;
|
||||
line-height: 16px;
|
||||
float: left;
|
||||
|
||||
}
|
||||
|
||||
.reportRightMain {
|
||||
margin: 8px 0;
|
||||
padding: 0 20px 0 15px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.reportRightMainDefine {
|
||||
padding: 8px 5px;
|
||||
}
|
||||
.singleImg {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
width: 306px;
|
||||
// height: 174px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
// background-color: @imgBgColor;
|
||||
/* padding-bottom: 56.25%; */
|
||||
/* position: relative; */
|
||||
}
|
||||
|
||||
.singleImg img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
/* height: 100%; */
|
||||
/* position: absolute; */
|
||||
/* top: 0; */
|
||||
/* left: 0; */
|
||||
}
|
||||
.imgTxtContant {
|
||||
margin-top: 12px;
|
||||
padding: 1px 3px;
|
||||
text-align: justify;
|
||||
font-family: MicrosoftYaHei-Bold;
|
||||
font-size: 17px;
|
||||
// font-size: 13.5px;
|
||||
font-weight: normal;
|
||||
letter-spacing: 0px;
|
||||
color: #777882;
|
||||
line-height: 1.6;
|
||||
word-break: normal;
|
||||
}
|
||||
.audioClass {
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: -10px;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
</style>
|
||||
150
src/components/swipers/gridSwiper.vue
Normal file
@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<swiper
|
||||
:slidesPerView="2"
|
||||
:grid="{
|
||||
rows: 2,
|
||||
}"
|
||||
:spaceBetween="10"
|
||||
:pagination="{
|
||||
clickable: true,
|
||||
}"
|
||||
:modules="modules"
|
||||
class="mySwiper"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in slides" :key="index">
|
||||
<div class="tri">
|
||||
<img :src="item.imageUrl" alt="" @click="goDetail(item)" />
|
||||
<p class="title">{{ item.title }}</p>
|
||||
</div>
|
||||
<p class="status" :class="{ 'live_status': getStatusClass(item.status) === '直播中', 'live_coming': getStatusClass(item.status) === '预告', 'live_review': getStatusClass(item.status) === '精彩回顾' }">{{ getStatusText(item.status) }}</p>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
// Import Swiper Vue.js components
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import grid1 from '../../assets/img/grid1.png';
|
||||
import grid2 from '../../assets/img/grid2.png';
|
||||
import grid3 from '../../assets/img/grid3.png';
|
||||
import grid4 from '../../assets/img/grid4.png';
|
||||
// Import Swiper styles
|
||||
import "swiper/css";
|
||||
|
||||
import "swiper/css/grid";
|
||||
import "swiper/css/pagination";
|
||||
|
||||
// import required modules
|
||||
import { Grid } from "swiper/modules";
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const modules = [Grid];
|
||||
|
||||
const slides = ref([
|
||||
{
|
||||
id:'0',
|
||||
status: '0',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'1',
|
||||
status: '1',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{
|
||||
id:'2',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'3',
|
||||
status: '0',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
{id:'4',
|
||||
status: '1',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'5',
|
||||
status: '0',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{id:'6',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'7',
|
||||
status: '1',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
|
||||
]);
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
'0': '预告',
|
||||
'1': '直播中',
|
||||
'2': '精彩回顾',
|
||||
};
|
||||
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || '';
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || '';
|
||||
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
background: #fff;
|
||||
height: 204px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 92px;
|
||||
}
|
||||
.tri{
|
||||
position: relative;
|
||||
.title {
|
||||
text-align: left;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.status{
|
||||
top:5px;
|
||||
left:5px;
|
||||
position: absolute;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
146
src/components/swipers/longSlideSwiper.vue
Normal file
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<swiper
|
||||
:slidesPerView="'auto'"
|
||||
:spaceBetween="10"
|
||||
:pagination="{
|
||||
clickable: true,
|
||||
}"
|
||||
class="mySwiper"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in slides" :key="index">
|
||||
<div class="tri">
|
||||
<img :src="item.imageUrl" alt="" @click="goDetail(item)" />
|
||||
<p class="title">{{ item.title }}</p>
|
||||
</div>
|
||||
<p
|
||||
class="status"
|
||||
:class="{
|
||||
live_status: getStatusClass(item.status) === '直播中',
|
||||
live_coming: getStatusClass(item.status) === '预告',
|
||||
live_review: getStatusClass(item.status) === '精彩回顾',
|
||||
}"
|
||||
>
|
||||
{{ getStatusText(item.status) }}
|
||||
</p>
|
||||
</swiper-slide></swiper
|
||||
>
|
||||
</template>
|
||||
<script setup>
|
||||
// Import Swiper Vue.js components
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
|
||||
// Import Swiper styles
|
||||
import "swiper/css";
|
||||
|
||||
import "swiper/css/pagination";
|
||||
import { ref } from "vue";
|
||||
import grid1 from "../../assets/img/slide1.png";
|
||||
import grid2 from "../../assets/img/slide2.png";
|
||||
import grid3 from "../../assets/img/slide1.png";
|
||||
import grid4 from "../../assets/img/slide2.png";
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const slides = ref([
|
||||
{
|
||||
id: "0",
|
||||
status: "0",
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
status: "1",
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
status: "2",
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{ id: "3", status: "0", imageUrl: grid4, title: "防空紧急疏散" },
|
||||
{ id: "4", status: "1", imageUrl: grid1, title: "星海扬帆" },
|
||||
{
|
||||
id: "5",
|
||||
status: "0",
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{ id: "6", status: "2", imageUrl: grid3, title: "泉城广场" },
|
||||
{ id: "7", status: "1", imageUrl: grid4, title: "防空紧急疏散" },
|
||||
]);
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
0: "直播中",
|
||||
1: "预告",
|
||||
2: "精彩回顾",
|
||||
};
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || "";
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || "";
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 315px;
|
||||
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
height: 286px;
|
||||
font-size: 18px;
|
||||
background: #fff;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
width: 100%;
|
||||
height: 286px;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.tri {
|
||||
height: auto;
|
||||
position: relative;
|
||||
.title {
|
||||
text-align: left;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.status {
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(2n) {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(3n) {
|
||||
width: 45%;
|
||||
}
|
||||
</style>
|
||||
67
src/components/swipers/normalSwiper.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<van-swipe :autoplay="3000" lazy-render>
|
||||
<van-swipe-item class="van-swipe-item" v-for="(item,index) in images" :key="index">
|
||||
<img :src="item.image" @click="goDetail(item)" />
|
||||
<p class="status" :class="{ 'live_status': getStatusClass(item.status) === '直播中', 'live_coming': getStatusClass(item.status) === '预告', 'live_review': getStatusClass(item.status) === '精彩回顾' }">{{ getStatusText(item.status) }}</p>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</template>
|
||||
<script setup>
|
||||
import pic from '../../assets/img/top1.png'
|
||||
import {ref} from 'vue';
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const images = ref([
|
||||
{
|
||||
id:'0',
|
||||
status: '0',
|
||||
image:pic
|
||||
},{
|
||||
id:'1',
|
||||
status: '1',
|
||||
image:pic
|
||||
},{
|
||||
id:'2',
|
||||
status: '2',
|
||||
image:pic
|
||||
},
|
||||
])
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
'0': '预告',
|
||||
'1': '直播中',
|
||||
'2': '精彩回顾',
|
||||
};
|
||||
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || '';
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || '';
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.van-swipe-item {
|
||||
width: 100%;
|
||||
height: 212px;
|
||||
position: relative;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.status{
|
||||
top:10px;
|
||||
left:25px;
|
||||
position: absolute;
|
||||
color:#fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
152
src/components/swipers/slideSwiper.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<swiper
|
||||
:slidesPerView="'auto'"
|
||||
:spaceBetween="10"
|
||||
:pagination="{
|
||||
clickable: true,
|
||||
}"
|
||||
|
||||
class="mySwiper"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in slides" :key="index">
|
||||
<div class="tri">
|
||||
<img :src="item.imageUrl" alt="" @click="goDetail(item)" />
|
||||
<p class="title">{{ item.title }}</p>
|
||||
</div>
|
||||
<p class="status" :class="{ 'live_status': getStatusClass(item.status) === '直播中', 'live_coming': getStatusClass(item.status) === '预告', 'live_review': getStatusClass(item.status) === '精彩回顾' }">{{ getStatusText(item.status) }}</p>
|
||||
</swiper-slide> </swiper>
|
||||
</template>
|
||||
<script setup>
|
||||
// Import Swiper Vue.js components
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue';
|
||||
|
||||
// Import Swiper styles
|
||||
import 'swiper/css';
|
||||
|
||||
import 'swiper/css/pagination';
|
||||
import {ref} from 'vue';
|
||||
import grid1 from '../../assets/img/big1.png';
|
||||
import grid2 from '../../assets/img/grid2.png';
|
||||
import grid3 from '../../assets/img/grid3.png';
|
||||
import grid4 from '../../assets/img/grid4.png';
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const slides = ref([
|
||||
{
|
||||
id:'0',
|
||||
status: '0',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'1',
|
||||
status: '1',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{
|
||||
id:'2',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'3',
|
||||
status: '0',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
{id:'4',
|
||||
status: '1',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'5',
|
||||
status: '0',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{id:'6',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'7',
|
||||
status: '1',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
|
||||
]);
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
'0': '预告',
|
||||
'1': '直播中',
|
||||
'2': '精彩回顾',
|
||||
};
|
||||
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || '';
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || '';
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 195px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.tri{
|
||||
position: relative;
|
||||
.title {
|
||||
text-align: left;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
padding-left:20px;
|
||||
}
|
||||
}
|
||||
.status{
|
||||
top:10px;
|
||||
left:25px;
|
||||
position: absolute;
|
||||
color:#fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.swiper-slide {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(2n) {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(3n) {
|
||||
width: 85%;
|
||||
}
|
||||
</style>
|
||||
|
||||
152
src/components/swipers/smallSlideSwiper.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<swiper
|
||||
:slidesPerView="'auto'"
|
||||
:spaceBetween="10"
|
||||
:pagination="{
|
||||
clickable: true,
|
||||
}"
|
||||
class="mySwiper"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in smallSlider" :key="index">
|
||||
<div class="tri">
|
||||
<img :src="item.imageUrl" alt="" @click="goDetail(item)" />
|
||||
<p class="title">{{ item.title }}</p>
|
||||
</div>
|
||||
<p class="status" :class="{ 'live_status': getStatusClass(item.status) === '直播中', 'live_coming': getStatusClass(item.status) === '预告', 'live_review': getStatusClass(item.status) === '精彩回顾' }">{{ getStatusText(item.status) }}</p>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</template>
|
||||
<script setup>
|
||||
// Import Swiper Vue.js components
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
|
||||
// Import Swiper styles
|
||||
import "swiper/css";
|
||||
|
||||
import "swiper/css/pagination";
|
||||
import { ref } from "vue";
|
||||
import grid1 from "../../assets/img/grid1.png";
|
||||
import grid2 from "../../assets/img/grid2.png";
|
||||
import grid3 from "../../assets/img/grid3.png";
|
||||
import grid4 from "../../assets/img/grid4.png";
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const smallSlider = ref([
|
||||
{
|
||||
id:'0',
|
||||
status: '0',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'1',
|
||||
status: '1',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{
|
||||
id:'2',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'3',
|
||||
status: '0',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
{id:'4',
|
||||
status: '1',
|
||||
imageUrl: grid1,
|
||||
title: "星海扬帆",
|
||||
},
|
||||
{
|
||||
id:'5',
|
||||
status: '0',
|
||||
imageUrl: grid2,
|
||||
title: "防空报警试鸣",
|
||||
},
|
||||
{id:'6',
|
||||
status: '2',
|
||||
imageUrl: grid3,
|
||||
title: "泉城广场",
|
||||
},
|
||||
{id:'7',
|
||||
status: '1',
|
||||
imageUrl: grid4,
|
||||
title: "防空紧急疏散",
|
||||
},
|
||||
|
||||
]);
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
'0': '预告',
|
||||
'1': '直播中',
|
||||
'2': '精彩回顾',
|
||||
};
|
||||
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || '';
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || '';
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height:120px;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
background: #fff;
|
||||
height: 92px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 92px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.tri{
|
||||
position: relative;
|
||||
.title {
|
||||
text-align: left;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.status{
|
||||
top:5px;
|
||||
left:5px;
|
||||
position: absolute;
|
||||
color:#fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.swiper-slide {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(2n) {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.swiper-slide:nth-child(3n) {
|
||||
width: 45%;
|
||||
}
|
||||
</style>
|
||||
26
src/components/title.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="title">
|
||||
<p>直播推荐,热门精选</p>
|
||||
<img src="../assets/img/arraw.svg" alt="" @click="goToMore"/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const goToMore=()=>{
|
||||
console.log('跳转到更多直播')
|
||||
router.push({
|
||||
name:'More'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.title{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding:10px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
14
src/main.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import './assets/css/index.scss'
|
||||
import App from './App.vue'
|
||||
// 导入上面新建的路由文件
|
||||
import router from './router/index'
|
||||
|
||||
let app = createApp(App)
|
||||
|
||||
|
||||
app.use(router)
|
||||
|
||||
|
||||
app.mount('#app')
|
||||
24
src/router/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { createWebHashHistory, createRouter } from 'vue-router'
|
||||
//createWebHashHistory
|
||||
import HomeView from '../views/home.vue'
|
||||
import SearchView from '../views/searchVue.vue'
|
||||
import MoreView from '../views/more.vue'
|
||||
import DetailView from '../views/detailVue.vue'
|
||||
|
||||
const routes = [
|
||||
{ path: '/', redirect:'/home' },
|
||||
{ path: '/home', name:'Home', component: HomeView,
|
||||
// children:[
|
||||
// { path: '/search', name:'Search', component: SearchView ,props: true },
|
||||
// ]
|
||||
},
|
||||
{ path: '/search', name:'Search', component: SearchView },
|
||||
{ path: '/more', name:'More', component: MoreView },
|
||||
{ path: '/detail', name:'Detail', component: DetailView },
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
export default router;
|
||||
263
src/utils/app.js
Normal file
@ -0,0 +1,263 @@
|
||||
// 暴露接口给原生用
|
||||
|
||||
var hybrid = {
|
||||
|
||||
};
|
||||
|
||||
window.Hybrid = hybrid;
|
||||
|
||||
if (window.Vue) {
|
||||
window.Vue.use(hybrid);
|
||||
}
|
||||
|
||||
function deviceInfo() {
|
||||
var userAgentInfo = navigator.userAgent;
|
||||
var Agents = ['Android', 'iPhone',
|
||||
'SymbianOS', 'Windows Phone',
|
||||
'iPad', 'iPod'
|
||||
];
|
||||
// console.log('%c 获取型号', 'color:blue', userAgentInfo);
|
||||
for (var v = 0; v < Agents.length; v++) {
|
||||
if (userAgentInfo.indexOf(Agents[v]) > 0) {
|
||||
console.log('%c 获取型号', 'color:orange', Agents[v]);
|
||||
|
||||
return Agents[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function urlParse(url) {
|
||||
let arr = url.split("?");
|
||||
console.log('%c arrrrr---', 'color:blue', arr);
|
||||
if (arr.length < 2) return false
|
||||
let str = arr[1]; //获取参数
|
||||
let items = str.split("&"); //a = xxx,b = xx
|
||||
let obj = {};
|
||||
obj.baseUrl = arr[0] + '?';
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let tempArr = items[i].split("=");
|
||||
console.log('%c 测试---->', 'color:blue', tempArr);
|
||||
if (tempArr[0] === 'lhs_end_human_s_8') {
|
||||
tempArr[0] = 'lhs_vodend_human_s_8';
|
||||
}
|
||||
obj[tempArr[0]] = tempArr[1];
|
||||
|
||||
obj.baseUrl = obj.baseUrl + '&' + tempArr[0] + '=' + tempArr[1]
|
||||
|
||||
}
|
||||
|
||||
if (!obj.aliyunols && obj.aliyunols !== 'on') return false
|
||||
|
||||
obj.lhs_start_human_s_8 = dateParse(obj.lhs_start_human_s_8);
|
||||
obj.lhs_vodend_human_s_8 = dateParse(obj.lhs_vodend_human_s_8);
|
||||
|
||||
|
||||
|
||||
console.log('%c 解析url', 'color:blue', '↓↓↓↓↓', obj.baseUrl);
|
||||
console.table(obj);
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 20200219105943 ---> 转换为 2020-02-19 10:59:43
|
||||
function dateParse(str) {
|
||||
let arr = [];
|
||||
let date = '';
|
||||
arr = str.replace(/\d(?=(\d{2})+$)/g, "$&,").split(',');
|
||||
console.log('%c date...', 'color:blue', arr);
|
||||
|
||||
date = arr[0] + arr[1] + '/' + arr[2] + '/' + arr[3] + ' ' + arr[4] + ':' + arr[5] + ':' + arr[6];
|
||||
console.log('%c date...', 'color:blue', date);
|
||||
return date
|
||||
}
|
||||
|
||||
function BrowserType() {
|
||||
// 权重:系统 + 系统版本 > 平台 > 内核 + 载体 + 内核版本 + 载体版本 > 外壳 + 外壳版本
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
const testUa = regexp => regexp.test(ua);
|
||||
const testVs = regexp => ua.match(regexp)
|
||||
.toString()
|
||||
.replace(/[^0-9|_.]/g, "")
|
||||
.replace(/_/g, ".");
|
||||
// 系统
|
||||
let system = "unknow";
|
||||
if (testUa(/windows|win32|win64|wow32|wow64/g)) {
|
||||
system = "windows"; // windows系统
|
||||
} else if (testUa(/macintosh|macintel/g)) {
|
||||
system = "macos"; // macos系统
|
||||
} else if (testUa(/x11/g)) {
|
||||
system = "linux"; // linux系统
|
||||
} else if (testUa(/android|adr/g)) {
|
||||
system = "android"; // android系统
|
||||
} else if (testUa(/ios|iphone|ipad|ipod|iwatch/g)) {
|
||||
system = "ios"; // ios系统
|
||||
}
|
||||
// 系统版本
|
||||
let systemVs = "unknow";
|
||||
if (system === "windows") {
|
||||
if (testUa(/windows nt 5.0|windows 2000/g)) {
|
||||
systemVs = "2000";
|
||||
} else if (testUa(/windows nt 5.1|windows xp/g)) {
|
||||
systemVs = "xp";
|
||||
} else if (testUa(/windows nt 5.2|windows 2003/g)) {
|
||||
systemVs = "2003";
|
||||
} else if (testUa(/windows nt 6.0|windows vista/g)) {
|
||||
systemVs = "vista";
|
||||
} else if (testUa(/windows nt 6.1|windows 7/g)) {
|
||||
systemVs = "7";
|
||||
} else if (testUa(/windows nt 6.2|windows 8/g)) {
|
||||
systemVs = "8";
|
||||
} else if (testUa(/windows nt 6.3|windows 8.1/g)) {
|
||||
systemVs = "8.1";
|
||||
} else if (testUa(/windows nt 10.0|windows 10/g)) {
|
||||
systemVs = "10";
|
||||
}
|
||||
} else if (system === "macos") {
|
||||
systemVs = testVs(/os x [\d._]+/g);
|
||||
} else if (system === "android") {
|
||||
systemVs = testVs(/android [\d._]+/g);
|
||||
} else if (system === "ios") {
|
||||
systemVs = testVs(/os [\d._]+/g);
|
||||
}
|
||||
// 平台
|
||||
let platform = "unknow";
|
||||
if (system === "windows" || system === "macos" || system === "linux") {
|
||||
platform = "desktop"; // 桌面端
|
||||
} else if (system === "android" || system === "ios" || testUa(/mobile/g)) {
|
||||
platform = "mobile"; // 移动端
|
||||
}
|
||||
// 内核和载体
|
||||
let engine = "unknow";
|
||||
let supporter = "unknow";
|
||||
if (testUa(/applewebkit/g)) {
|
||||
engine = "webkit"; // webkit内核
|
||||
if (testUa(/edge/g)) {
|
||||
supporter = "edge"; // edge浏览器
|
||||
} else if (testUa(/opr/g)) {
|
||||
supporter = "opera"; // opera浏览器
|
||||
} else if (testUa(/chrome/g)) {
|
||||
supporter = "chrome"; // chrome浏览器
|
||||
} else if (testUa(/safari/g)) {
|
||||
supporter = "safari"; // safari浏览器
|
||||
}
|
||||
} else if (testUa(/gecko/g) && testUa(/firefox/g)) {
|
||||
engine = "gecko"; // gecko内核
|
||||
supporter = "firefox"; // firefox浏览器
|
||||
} else if (testUa(/presto/g)) {
|
||||
engine = "presto"; // presto内核
|
||||
supporter = "opera"; // opera浏览器
|
||||
} else if (testUa(/trident|compatible|msie/g)) {
|
||||
engine = "trident"; // trident内核
|
||||
supporter = "iexplore"; // iexplore浏览器
|
||||
}
|
||||
// 内核版本
|
||||
let engineVs = "unknow";
|
||||
if (engine === "webkit") {
|
||||
engineVs = testVs(/applewebkit\/[\d._]+/g);
|
||||
} else if (engine === "gecko") {
|
||||
engineVs = testVs(/gecko\/[\d._]+/g);
|
||||
} else if (engine === "presto") {
|
||||
engineVs = testVs(/presto\/[\d._]+/g);
|
||||
} else if (engine === "trident") {
|
||||
engineVs = testVs(/trident\/[\d._]+/g);
|
||||
}
|
||||
// 载体版本
|
||||
let supporterVs = "unknow";
|
||||
if (supporter === "chrome") {
|
||||
supporterVs = testVs(/chrome\/[\d._]+/g);
|
||||
} else if (supporter === "safari") {
|
||||
supporterVs = testVs(/version\/[\d._]+/g);
|
||||
} else if (supporter === "firefox") {
|
||||
supporterVs = testVs(/firefox\/[\d._]+/g);
|
||||
} else if (supporter === "opera") {
|
||||
supporterVs = testVs(/opr\/[\d._]+/g);
|
||||
} else if (supporter === "iexplore") {
|
||||
supporterVs = testVs(/(msie [\d._]+)|(rv:[\d._]+)/g);
|
||||
} else if (supporter === "edge") {
|
||||
supporterVs = testVs(/edge\/[\d._]+/g);
|
||||
}
|
||||
// 外壳和外壳版本
|
||||
let shell = "none";
|
||||
let shellVs = "unknow";
|
||||
if (testUa(/micromessenger/g)) {
|
||||
shell = "wechat"; // 微信浏览器
|
||||
shellVs = testVs(/micromessenger\/[\d._]+/g);
|
||||
} else if (testUa(/qqbrowser/g)) {
|
||||
shell = "qq"; // QQ浏览器
|
||||
shellVs = testVs(/qqbrowser\/[\d._]+/g);
|
||||
} else if (testUa(/ucbrowser/g)) {
|
||||
shell = "uc"; // UC浏览器
|
||||
shellVs = testVs(/ucbrowser\/[\d._]+/g);
|
||||
} else if (testUa(/qihu 360se/g)) {
|
||||
shell = "360"; // 360浏览器(无版本)
|
||||
} else if (testUa(/2345explorer/g)) {
|
||||
shell = "2345"; // 2345浏览器
|
||||
shellVs = testVs(/2345explorer\/[\d._]+/g);
|
||||
} else if (testUa(/metasr/g)) {
|
||||
shell = "sougou"; // 搜狗浏览器(无版本)
|
||||
} else if (testUa(/lbbrowser/g)) {
|
||||
shell = "liebao"; // 猎豹浏览器(无版本)
|
||||
} else if (testUa(/maxthon/g)) {
|
||||
shell = "maxthon"; // 遨游浏览器
|
||||
shellVs = testVs(/maxthon\/[\d._]+/g);
|
||||
}
|
||||
return Object.assign({
|
||||
engine, // webkit gecko presto trident
|
||||
engineVs,
|
||||
platform, // desktop mobile
|
||||
supporter, // chrome safari firefox opera iexplore edge
|
||||
supporterVs,
|
||||
system, // windows macos linux android ios
|
||||
systemVs
|
||||
}, shell === "none" ? {} : {
|
||||
shell, // wechat qq uc 360 2345 sougou liebao maxthon
|
||||
shellVs
|
||||
});
|
||||
}
|
||||
|
||||
// 对比获取当前时间
|
||||
/* 计算时间差 */
|
||||
function timeDif(nowTime, startLiveTime) {
|
||||
|
||||
|
||||
|
||||
console.log('%c 【倒计时时间计算-------↓↓↓↓↓↓】', 'color:blue');
|
||||
// console.log("%c 当前时间", "color:blue", nowTime);
|
||||
// console.log("%c 开播时间", "color:blue", startLiveTime);
|
||||
startLiveTime = startLiveTime.replace(/-/g,'/')
|
||||
let nowTimeNum = new Date(nowTime);
|
||||
let startLiveTimeNum = new Date(startLiveTime);
|
||||
let s1 = nowTimeNum.getTime(),
|
||||
s2 = startLiveTimeNum.getTime();
|
||||
let total = Math.floor((s2 - s1) / 1000);
|
||||
// console.log('总秒数---', total)
|
||||
console.log('%c 【倒计时时间计算-------↑↑↑↑↑↑】', 'color:blue');
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
function parsTime(total) {//出于性能考虑,改为vue页面中使用
|
||||
let day = parseInt(total / (24 * 60 * 60)); //计算整数天数
|
||||
let afterDay = total - day * 24 * 60 * 60; //取得算出天数后剩余的秒数
|
||||
let hour = parseInt(afterDay / (60 * 60)); //计算整数小时数
|
||||
let afterHour = total - day * 24 * 60 * 60 - hour * 60 * 60; //取得算出小时数后剩余的秒数
|
||||
let min = parseInt(afterHour / 60); //计算整数分
|
||||
let afterMin = total - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60; //取得算出分后剩余的秒数
|
||||
let second = afterMin;
|
||||
// console.log('%c 当前时间', 'color:red', '-----↓↓↓----');
|
||||
// console.log('时间--->', '天: ' + day, ' 小时: ' + hour, ' 分钟 ' + min, ' 秒 ' + second);
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
hybrid,
|
||||
deviceInfo,
|
||||
urlParse,
|
||||
BrowserType,
|
||||
timeDif,
|
||||
parsTime
|
||||
};
|
||||
209
src/utils/canvas.js
Normal file
@ -0,0 +1,209 @@
|
||||
function getRandom(min, max) {
|
||||
return min + Math.floor(Math.random() * (max - min + 1));
|
||||
}
|
||||
|
||||
export default class ThumbsUpAni {
|
||||
constructor() {
|
||||
this.loadImages(); // 预加载图片
|
||||
|
||||
// 读取 canvas
|
||||
const canvas = document.getElementById('thumsCanvas');
|
||||
this.context = canvas.getContext('2d');
|
||||
this.width = canvas.width;
|
||||
this.height = canvas.height;
|
||||
|
||||
this.imgsList = []; // 点赞图像列表
|
||||
this.renderList = []; // 渲染对象雷彪
|
||||
// scaleTime - 百分比。图片从开始放大到最终大小,所用时长。
|
||||
// 设置为 0.1 ,表示总共运行时间前面的 10% 的时间,点赞图片逐步放大
|
||||
this.scaleTime = 0.1;
|
||||
this.scanning = false; // 扫描器扫描标识,防止开启多个扫描器
|
||||
}
|
||||
|
||||
// 预加载图片,获取图片宽高,如果某一图片加载失败,则不显示该图片
|
||||
loadImages() {
|
||||
// const images = [
|
||||
// 'jfs/t1/93992/8/9049/4680/5e0aea04Ec9dd2be8/608efd890fd61486.png',
|
||||
// 'jfs/t1/108305/14/2849/4908/5e0aea04Efb54912c/bfa59f27e654e29c.png',
|
||||
// 'jfs/t1/98805/29/8975/5106/5e0aea05Ed970e2b4/98803f8ad07147b9.png',
|
||||
// 'jfs/t1/94291/26/9105/4344/5e0aea05Ed64b9187/5165fdf5621d5bbf.png',
|
||||
// 'jfs/t1/102753/34/8504/5522/5e0aea05E0b9ef0b4/74a73178e31bd021.png',
|
||||
// 'jfs/t1/102954/26/9241/5069/5e0aea05E7dde8bda/720fcec8bc5be9d4.png',
|
||||
// ];
|
||||
const images = [
|
||||
'./bg1.png',
|
||||
'./bg2.png',
|
||||
'./bg3.png',
|
||||
'./bg4.png',
|
||||
'./bg5.png',
|
||||
'./bg6.png',
|
||||
|
||||
];
|
||||
const promiseAll = [];
|
||||
images.forEach((src) => {
|
||||
const p = new Promise(function(resolve) {
|
||||
const img = new Image();
|
||||
img.onerror = img.onload = resolve.bind(null, img);
|
||||
// img.src = 'https://img12.360buyimg.com/img/' + src;
|
||||
img.src = src;
|
||||
console.log("src",img.src);
|
||||
});
|
||||
promiseAll.push(p);
|
||||
});
|
||||
Promise.all(promiseAll).then((imgsList) => {
|
||||
this.imgsList = imgsList.filter((d) => {
|
||||
if (d && d.width > 0) return true;
|
||||
return false;
|
||||
});
|
||||
if (this.imgsList.length == 0) {
|
||||
dLog('error', 'imgsList load all error');
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createRender() {
|
||||
if (this.imgsList.length == 0) return null;
|
||||
|
||||
// 当运行时间 diffTime 小于设置的 scaleTime 的时候,按比例随着时间增大,scale 变大。超过设置的时间阈值,则返回最终大小。
|
||||
const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)];
|
||||
const getScale = (diffTime) => {
|
||||
// diffTime - 百分比。表示从动画开始运行到当前时间过了多长时间。实际值是从 0 --> 1 逐步增大。
|
||||
// scaleTime - 百分比。图片从开始放大到最终大小,所用时长。
|
||||
if (diffTime < this.scaleTime) {
|
||||
return +(diffTime / this.scaleTime).toFixed(2) * basicScale;
|
||||
} else {
|
||||
return basicScale;
|
||||
}
|
||||
};
|
||||
|
||||
const context = this.context;
|
||||
// 随机读取一个图片,进行渲染
|
||||
const image = this.imgsList[getRandom(0, this.imgsList.length - 1)];
|
||||
const offset = 20; // x轴偏移量
|
||||
const basicX = this.width / 2 + getRandom(-offset, offset);
|
||||
const angle = getRandom(2, 10); // 角度系数
|
||||
let ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1);
|
||||
|
||||
// 随机平滑 X 轴偏移 - 通过正弦( Math.sin )函数来实现均匀曲线
|
||||
const getTranslateX = (diffTime) => {
|
||||
if (diffTime < this.scaleTime) {
|
||||
// 放大期间,不进行摇摆位移
|
||||
return basicX;
|
||||
} else {
|
||||
return basicX + ratio * Math.sin(angle * (diffTime - this.scaleTime));
|
||||
}
|
||||
};
|
||||
|
||||
// Y 轴偏移 - 运行偏移从 this.height --> image.height / 2 ,即从最底部,运行到顶部留下。
|
||||
const getTranslateY = (diffTime) => {
|
||||
return (
|
||||
image.height / 2 + (this.height - image.height / 2) * (1 - diffTime)
|
||||
);
|
||||
};
|
||||
|
||||
// 淡出
|
||||
const fadeOutStage = getRandom(14, 18) / 100;
|
||||
const getAlpha = (diffTime) => {
|
||||
let left = 1 - +diffTime;
|
||||
if (left > fadeOutStage) {
|
||||
return 1;
|
||||
} else {
|
||||
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2);
|
||||
}
|
||||
};
|
||||
|
||||
return (diffTime) => {
|
||||
// diffTime : 百分比。表示从动画开始运行到当前时间过了多长时间。实际值是从 0 --> 1 逐步增大。
|
||||
// diffTime 为 0.4 的时候,说明是已经运行了 40% 的时间
|
||||
// 时间差值满了,即:动画结束了(0 --> 1)
|
||||
if (diffTime >= 1) return true;
|
||||
|
||||
context.save();
|
||||
|
||||
const scale = getScale(diffTime);
|
||||
// const rotate = getRotate();
|
||||
const translateX = getTranslateX(diffTime);
|
||||
const translateY = getTranslateY(diffTime);
|
||||
context.translate(translateX, translateY); // 偏移
|
||||
context.scale(scale, scale); // 缩放
|
||||
// context.rotate(rotate * Math.PI / 180);
|
||||
context.globalAlpha = getAlpha(diffTime); // 淡出
|
||||
|
||||
// 绘制
|
||||
context.drawImage(
|
||||
image,
|
||||
-image.width / 2,
|
||||
-image.height / 2,
|
||||
image.width,
|
||||
image.height
|
||||
);
|
||||
context.restore(); // 恢复画布(canvas)状态。
|
||||
};
|
||||
}
|
||||
|
||||
// 实时绘制扫描器
|
||||
// 开启实时绘制扫描器,将创建的渲染对象放入 renderList 数组,数组不为空,说明 canvas 上还有动画,就需要不停的去执行 scan,直到 canvas 上没有动画结束为止。
|
||||
scan() {
|
||||
this.context.clearRect(0, 0, this.width, this.height);
|
||||
this.context.fillStyle = 'transparent';
|
||||
this.context.fillRect(0, 0, 200, 400);
|
||||
|
||||
let index = 0;
|
||||
let length = this.renderList.length;
|
||||
|
||||
if (length > 0) {
|
||||
requestFrame(this.scan.bind(this));
|
||||
this.scanning = true;
|
||||
} else {
|
||||
this.scanning = false;
|
||||
}
|
||||
|
||||
// diffTime = (Date.now() - render.timestamp) / render.duration
|
||||
// 如果开始的时间戳是 10000,当前是100100,则说明已经运行了 100 毫秒了,如果动画本来需要执行 1000 毫秒,那么 diffTime = 0.1,代表动画已经运行了 10%。
|
||||
while (index < length) {
|
||||
const child = this.renderList[index];
|
||||
if (
|
||||
!child ||
|
||||
!child.render ||
|
||||
child.render.call(null, (Date.now() - child.timestamp) / child.duration)
|
||||
) {
|
||||
// 动画结束,则删除该动画
|
||||
this.renderList.splice(index, 1);
|
||||
length--;
|
||||
} else {
|
||||
// 继续执行动画
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开始/增加动画
|
||||
// 调用一次 start 方法来生成渲染实例,放进渲染实例数组。
|
||||
// 如果当前扫描器未开启,则需要启动扫描器,使用了 scanning 变量,防止开启多个扫描器。
|
||||
start() {
|
||||
const render = this.createRender();
|
||||
const duration = getRandom(1500, 3000);
|
||||
this.renderList.push({
|
||||
render,
|
||||
duration,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
if (!this.scanning) {
|
||||
this.scanning = true;
|
||||
requestFrame(this.scan.bind(this));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
function requestFrame(cb) {
|
||||
return (
|
||||
window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
function(callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
}
|
||||
)(cb);
|
||||
}
|
||||
|
||||
64
src/utils/conf copy.js
Normal file
@ -0,0 +1,64 @@
|
||||
export const conf = {
|
||||
/**
|
||||
* 基础功能配置
|
||||
* */
|
||||
id: 'xgPlayerWrap', // 占位dom元素
|
||||
width: 375, height: 211, // 视频宽高尺寸
|
||||
url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4', // 视频源
|
||||
poster: "http://ashuai.work/static/img/avantar.png", // 视频封面
|
||||
autoplay: false, // 是否自动播放,不自动播放,浏览器有限制规则
|
||||
autoplayMuted: false, // 是否自动播放(静音播放)
|
||||
videoInit: true, // 是否默认初始化video,默认初始化,默认true
|
||||
playsinline: true, // 是否启用内联播放模式,仅移动端生效
|
||||
defaultPlaybackRate: 1, // 默认播放速度(可选:0.5/0.75/1/1.5/2等)
|
||||
volume: 0.72, // 播放音量(可选:0 ~ 1)
|
||||
loop: false, // 是否循环播放,默认不循环播放
|
||||
startTime: 0, // 点播模式下,初始起播时间
|
||||
videoAttributes: {}, // video扩展属性,暂且不配置
|
||||
lang: 'zh-cn', // 播放器初始显示语言,设置为中文
|
||||
fluid: true, // 是否流式布局(宽高优先于流失布局,默认16:9)注掉上方宽高看效果
|
||||
fitVideoSize: 'fixed', // 保持容器宽/高,不做适配,按照容器来
|
||||
videoFillMode: 'auto', // 宽高不够自动底色填充(fill拉伸填充等...)
|
||||
seekedStatus: 'play', // 跳转后继续播放
|
||||
// 播放器进度条故事点信息数组
|
||||
progressDot: [
|
||||
{
|
||||
id: 0, // 唯一标识,用于删除的时候索引
|
||||
time: 30, // 展示的时间点,例子为在播放到10s钟的时候展示
|
||||
text: '进度条信息提示...', // hover的时候展示文案,可以为空
|
||||
duration: 5, // 展示时间跨度,单位为s
|
||||
style: { // 指定样式
|
||||
backgroundColor: '#fff'
|
||||
}
|
||||
},
|
||||
],
|
||||
thumbnail: null, // 进度条预览图配置,普通业务用不到
|
||||
marginControls: false, // 是否开启画面和控制栏分离模式,不开启空间多一些
|
||||
domEventType: 'default', // 响应的事件类型,不用指定,用默认的即可
|
||||
/**
|
||||
* 交互功能配置(一般使用默认即可)
|
||||
* */
|
||||
/**
|
||||
* 插件配置,根据需求自选
|
||||
* */
|
||||
icons: {}, // 使用默认的icon图标
|
||||
i18n: [], // 使用默认的中文
|
||||
// 自定义一些颜色
|
||||
commonStyle: {
|
||||
progressColor: '#fff', // 整个进度条颜色
|
||||
playedColor: 'red', // 已播放的进度条颜色
|
||||
volumeColor: '#fff', // 音量大小竖向滑块颜色
|
||||
},
|
||||
controls: true, // 是否使用底部控制栏,默认使用
|
||||
miniprogress: false, // 是否使用mini进度条(当底部控制栏隐藏时生效)
|
||||
screenShot: false, // 关闭截图功能
|
||||
rotate: false, // 是否使用视频旋转插件,默认不使用
|
||||
download: false, // 是否使用下载按钮,一般不用,一般自定义控制
|
||||
pip: false, // 使用使用画中画模式,默认不用
|
||||
mini: false, // 是否使用小屏幕控件
|
||||
cssFullscreen: true, // 是否使用网页样式全屏按钮开关
|
||||
playbackRate: [0.5, 1, 1.5, 2, 3], //传入倍速可选数组
|
||||
playbackRate: false, //false,禁用倍速播放(即控制栏不显示)
|
||||
keyShortcut: false, // 是否开启快捷键模式
|
||||
|
||||
}
|
||||
84
src/utils/conf.js
Normal file
@ -0,0 +1,84 @@
|
||||
import layout from './layout';
|
||||
export default class VideoPlayer {
|
||||
constructor(props) {
|
||||
this.player;
|
||||
this.props = props;
|
||||
this.props.isLive = false;
|
||||
this._setup();
|
||||
this._bindEvent();
|
||||
}
|
||||
|
||||
loadByUrl(url) {
|
||||
if (this.player) this.player.loadByUrl(url);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
console.log('Setting up the player with props:', this.props);
|
||||
if (this.player) {
|
||||
this.player.dispose();
|
||||
const container = document.getElementById(this.props.id);
|
||||
if (container) {
|
||||
container.innerHTML = ''; // 使用原生 JavaScript 清空 DOM 内容
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_setup() {
|
||||
this.player = new Aliplayer(this.props, function(player) {
|
||||
console.log("player-----------------",player);
|
||||
player._switchLevel = 0;
|
||||
});
|
||||
}
|
||||
|
||||
_bindEvent() {
|
||||
this.player.on('ready', (e) => {
|
||||
console.log('ready');
|
||||
});
|
||||
|
||||
this.player.on('play', (e) => {
|
||||
console.log('play');
|
||||
});
|
||||
|
||||
this.player.on('ended', (e) => {
|
||||
console.log('ended');
|
||||
});
|
||||
|
||||
this.player.on('pause', (e) => {
|
||||
console.log('pause');
|
||||
});
|
||||
|
||||
this.player.on('requestFullScreen', (e) => {
|
||||
layout.adjustLayout(true);
|
||||
// Attempt to exit fullscreen using the appropriate method
|
||||
if (this.player.exitFullscreen) {
|
||||
this.player.exitFullscreen();
|
||||
} else {
|
||||
console.warn('exitFullscreen method is not available.');
|
||||
}
|
||||
});
|
||||
|
||||
// Handle the exit fullscreen event
|
||||
const videoElement = this.player.el();
|
||||
videoElement.addEventListener("webkitfullscreenchange", () => {
|
||||
if (document.webkitIsFullScreen === false) {
|
||||
if (WeixinJSBridge) WeixinJSBridge.call('closeWindow');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure autoplay on iOS
|
||||
document.addEventListener('WeixinJSBridgeReady', () => {
|
||||
const video = videoElement.querySelector('video');
|
||||
if (video) {
|
||||
video.play();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_unbindEvent() {
|
||||
this.player.off('ready');
|
||||
this.player.off('play');
|
||||
this.player.off('ended');
|
||||
this.player.off('pause');
|
||||
}
|
||||
}
|
||||
|
||||
25
src/utils/layout.js
Normal file
@ -0,0 +1,25 @@
|
||||
import util from './util';
|
||||
export default class Layout {
|
||||
static adjustLayout(excludeInputHeight = false) {
|
||||
const height = util.screenHeight(); // 确保调用的是正确的方法
|
||||
|
||||
const commentTextbox = document.querySelector('.comment-textbox');
|
||||
if (commentTextbox) {
|
||||
const inputHeight = commentTextbox.offsetHeight + 18;
|
||||
commentTextbox.style.top = `${height - (excludeInputHeight ? (inputHeight * -1) + 5 : inputHeight)}px`;
|
||||
}
|
||||
|
||||
const commentList = document.querySelector('.comment-list');
|
||||
if (commentList) {
|
||||
const commentListHeight = commentList.offsetHeight;
|
||||
commentList.style.top = `${height - commentListHeight - (commentTextbox ? commentTextbox.offsetHeight + 18 : 0)}px`;
|
||||
}
|
||||
|
||||
const favorite = document.querySelector('.favorite-animation-container');
|
||||
if (favorite) {
|
||||
const favoriteHeight = favorite.offsetHeight;
|
||||
favorite.style.top = `${height - favoriteHeight - (commentTextbox ? commentTextbox.offsetHeight + 18 : 0)}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
src/utils/request.js
Normal file
@ -0,0 +1,38 @@
|
||||
import axios from 'axios';
|
||||
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
|
||||
|
||||
const request = axios.create({
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL:import.meta.env.VITE_APP_BASE_URL,
|
||||
// 超时
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// request拦截器
|
||||
request.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在请求发送之前做些什么
|
||||
// 可以在请求头中添加token等信息
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// response拦截器
|
||||
request.interceptors.response.use(
|
||||
(response) => {
|
||||
// 对响应数据做些什么
|
||||
return response.data;
|
||||
},
|
||||
(error) => {
|
||||
// 对响应错误做些什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
export default request;
|
||||
42
src/utils/util.js
Normal file
@ -0,0 +1,42 @@
|
||||
export default class Util
|
||||
{
|
||||
static prefixedEvent(element, type, callback) {
|
||||
let pfx = ["webkit", "moz", "MS", "o", ""];
|
||||
for (var p = 0; p < pfx.length; p++) {
|
||||
if (!pfx[p]) type = type.toLowerCase();
|
||||
Util.addEvent(element, pfx[p] + type, callback);
|
||||
}
|
||||
}
|
||||
|
||||
static addEvent(ele, type, hander) {
|
||||
if (ele.addEventListener) {
|
||||
ele.addEventListener(type, hander, false);
|
||||
}
|
||||
if (ele.attachEvent) {
|
||||
ele.attachEvent('on' + type, hander);
|
||||
}
|
||||
}
|
||||
|
||||
static screenHeight()
|
||||
{
|
||||
return document.body.clientHeight || document.documentElement.clientHeight || window.screen.height || window.innerHeight ;
|
||||
}
|
||||
|
||||
static isX5()
|
||||
{
|
||||
let agent = navigator.userAgent
|
||||
return (/micromessenger/i).test(agent) || (/qqbrowser/i).test(agent);
|
||||
}
|
||||
|
||||
static encodeHtml (s) {
|
||||
let REGX_HTML_ENCODE = /"|'|<|>|[\x00-\x20]|[\x7F-\xFF]|[\u0100-\u2700]/g
|
||||
return (typeof s != "string") ? null :
|
||||
s.replace(REGX_HTML_ENCODE,
|
||||
function($0){
|
||||
var c = $0.charCodeAt(0), r = ["&#"];
|
||||
c = (c == 0x20) ? 0xA0 : c;
|
||||
r.push(c); r.push(";");
|
||||
return r.join("");
|
||||
})
|
||||
}
|
||||
}
|
||||
169
src/views/detailVue copy.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<!-- <div class="page" v-wechat-title="$route.meta.title"> -->
|
||||
<div class="top">
|
||||
<div id="xgPlayerWrap"></div>
|
||||
</div>
|
||||
<countDown ref="coCountdown" :countdownTime="countdownTime"></countDown>
|
||||
<van-tabs v-model:active="activeName" offset-top="0">
|
||||
<!-- 动态显示简介和评论,当countdownTime有值时 -->
|
||||
<van-tab v-if="countdownTime > 0" title="简介" name="a">
|
||||
<pageAbstract></pageAbstract>
|
||||
</van-tab>
|
||||
<van-tab v-if="countdownTime > 0" title="评论" name="c">
|
||||
<pageComment />
|
||||
</van-tab>
|
||||
<!-- 当countdownTime无值时,显示现场直播 -->
|
||||
<template v-else>
|
||||
<van-tab title="现场直播" name="b">
|
||||
<pageReport />
|
||||
</van-tab>
|
||||
<van-tab title="评论" name="c">
|
||||
<pageComment />
|
||||
</van-tab>
|
||||
</template>
|
||||
</van-tabs>
|
||||
<van-popup
|
||||
v-model:show="showRight"
|
||||
position="right"
|
||||
:style="{ width: '70%', height: '100%' }"
|
||||
>
|
||||
<moreLiveVue />
|
||||
</van-popup>
|
||||
<van-floating-bubble
|
||||
v-model:offset="offset"
|
||||
class="van-floating-bubble"
|
||||
@click="onClick"
|
||||
>
|
||||
<p class="bubble-content">更多直播</p>
|
||||
</van-floating-bubble>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import countDown from "../components/countDown.vue";
|
||||
import pageAbstract from "../components/pageAbstract.vue";
|
||||
import pageReport from "../components/pageReport.vue";
|
||||
import pageComment from "../components/pageComment.vue";
|
||||
import moreLiveVue from "../components/moreLive.vue";
|
||||
import { ref, onMounted } from "vue";
|
||||
import Player, { Events } from "../xgplayer"; // 引入西瓜视频模块
|
||||
import "../xgplayer/dist/index.min.css"; // 引入西瓜视频样式
|
||||
import { scene } from "../api/index";
|
||||
|
||||
import { conf } from "../utils/conf"; // 配置文件单独拎出来一个js文件
|
||||
|
||||
// 动态更新 conf 对象的 poster 属性
|
||||
conf.poster =
|
||||
"https://th.bing.com/th/id/R.9de53f9726576696b318a8d95c0946cb?rik=sWB3V9KSxHbThw&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f95%2f9995_1.jpg&ehk=GcPUjJED69TBvg9XxQr2klzDzfRsQWhAfLKlIAUWHJQ%3d&risl=&pid=ImgRaw&r=0"; // 根据需求动态设置封面图片的 URL
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
getSenceList();
|
||||
});
|
||||
|
||||
let player = null; // 实例
|
||||
|
||||
console.log("Events", Events);
|
||||
|
||||
const init = () => {
|
||||
player = new Player({
|
||||
...conf,
|
||||
});
|
||||
player.on(Events.PLAY, (ev) => {
|
||||
console.log("-播放开始-", ev);
|
||||
});
|
||||
player.on(Events.PAUSE, (ev) => {
|
||||
console.log("-播放结束-", ev);
|
||||
});
|
||||
player.on("loadedmetadata", (ev) => {
|
||||
console.log("-媒体数据加载好了-", ev);
|
||||
});
|
||||
player.on(Events.SEEKED, (ev) => {
|
||||
console.log("-跳着播放-", ev);
|
||||
});
|
||||
// 等各种监听事件
|
||||
};
|
||||
const showRight = ref(false);
|
||||
const hasCountdown = ref(false); //判断是否有倒计时
|
||||
const countdownTime = ref(0);
|
||||
const activeName = ref("b");
|
||||
const offset = ref({ x: 375, y: 350 });
|
||||
const onClick = () => {
|
||||
showRight.value = true;
|
||||
};
|
||||
// 获取sence
|
||||
const getSenceList =()=>{
|
||||
let params = {
|
||||
id:2057
|
||||
};
|
||||
scene(params)
|
||||
.then((res) => {
|
||||
console.log("获取sence",res);
|
||||
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录接口请求失败", error);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.van-floating-bubble {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0 !important;
|
||||
width: 50px;
|
||||
height: 80px;
|
||||
background: #eeeeee;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
z-index: 999;
|
||||
}
|
||||
.van-tabs__content {
|
||||
width: 100%;
|
||||
height: calc(100vh - 130px);
|
||||
/* border:1px solid red; */
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.bubble-content {
|
||||
color: rgba(0, 0, 0, 80%);
|
||||
position: relative;
|
||||
width: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
}
|
||||
.bubble-content::before {
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 30%;
|
||||
background: url("../assets/img/jt_black.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
left: -15px;
|
||||
top: 30%;
|
||||
position: absolute;
|
||||
}
|
||||
// 顶部播放器
|
||||
.top {
|
||||
width: 100%;
|
||||
// height: 211px;
|
||||
// height: 211px;
|
||||
// padding-top: 56.25%; /* 16:9 aspect ratio (9 / 16 * 100) */
|
||||
// position: relative;
|
||||
// overflow: hidden;
|
||||
|
||||
// border: 1px solid black;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
}
|
||||
#xgPlayerWrap {
|
||||
flex: auto;
|
||||
}
|
||||
#xgPlayerWrap video {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
275
src/views/detailVue.vue
Normal file
@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<!-- <div class="page" v-wechat-title="$route.meta.title"> -->
|
||||
<div class="top">
|
||||
<div
|
||||
class="prism-player"
|
||||
id="J_prismPlayer"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
<countDown ref="coCountdown" :countdownTime="countdownTime"></countDown>
|
||||
<van-tabs v-model:active="activeName" offset-top="0">
|
||||
<!-- 动态显示简介和评论,当countdownTime有值时 -->
|
||||
<van-tab v-if="countdownTime > 0" title="简介" name="a">
|
||||
<pageAbstract></pageAbstract>
|
||||
</van-tab>
|
||||
<van-tab v-if="countdownTime > 0" title="评论" name="c">
|
||||
<pageComment />
|
||||
</van-tab>
|
||||
<!-- 当countdownTime无值时,显示现场直播 -->
|
||||
<template v-else>
|
||||
<van-tab title="现场直播" name="b">
|
||||
<pageReport />
|
||||
</van-tab>
|
||||
<van-tab title="评论" name="c">
|
||||
<pageComment />
|
||||
</van-tab>
|
||||
</template>
|
||||
</van-tabs>
|
||||
<van-popup
|
||||
v-model:show="showRight"
|
||||
position="right"
|
||||
:style="{ width: '70%', height: '100%' }"
|
||||
>
|
||||
<moreLiveVue />
|
||||
</van-popup>
|
||||
|
||||
</div>
|
||||
<van-floating-bubble
|
||||
v-model:offset="offset"
|
||||
class="van-floating-bubble"
|
||||
@click="onClick"
|
||||
>
|
||||
<p class="bubble-content">更多直播</p>
|
||||
</van-floating-bubble>
|
||||
</template>
|
||||
<script setup>
|
||||
import countDown from "../components/countDown.vue";
|
||||
import pageAbstract from "../components/pageAbstract.vue";
|
||||
import pageReport from "../components/pageReport.vue";
|
||||
import pageComment from "../components/pageComment.vue";
|
||||
import moreLiveVue from "../components/moreLive.vue";
|
||||
import { ref, onMounted,onBeforeUnmount } from "vue";
|
||||
import { scene } from "../api/index";
|
||||
|
||||
import VideoPlayer from "../utils/conf"; // 配置文件单独拎出来一个js文件
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
getSenceList();
|
||||
});
|
||||
|
||||
let player;
|
||||
const init = () => {
|
||||
const playerProps =
|
||||
{
|
||||
id: "J_prismPlayer",
|
||||
cover:'https://th.bing.com/th/id/R.9de53f9726576696b318a8d95c0946cb?rik=sWB3V9KSxHbThw&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f95%2f9995_1.jpg&ehk=GcPUjJED69TBvg9XxQr2klzDzfRsQWhAfLKlIAUWHJQ%3d&risl=&pid=ImgRaw&r=0',
|
||||
source: "https://player.alicdn.com/resource/player/qupai.mp4",
|
||||
width: "100%",
|
||||
height: "500px",
|
||||
autoplay: true,
|
||||
isLive: false,
|
||||
rePlay: false,
|
||||
playsinline: true,
|
||||
preload: 'auto',
|
||||
useH5Prism: true,
|
||||
useFlashPrism:false,
|
||||
controlBarVisibility: "hover", // 鼠标悬停时显示控制栏
|
||||
controlBarVisibilityOnFs: "hover", // 即使全屏也在鼠标悬停时显示控制栏
|
||||
showBarTime: 5000, // 控制栏显示时间
|
||||
useFlashPrism: false, // 使用 HTML5 播放器而非 Flash 播放器
|
||||
language: "zh-cn", // 设置语言为简体中文
|
||||
x5_video_position:'normal',
|
||||
x5_type:'h5',//通过 video 属性 “x5-video-player-type” 声明启用同层H5播放器
|
||||
skinLayout: [
|
||||
// Specify the UI elements to show/hide
|
||||
{
|
||||
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: 10, // 设置进度条的起始位置
|
||||
y: 44,
|
||||
|
||||
},
|
||||
{
|
||||
name: "playButton",
|
||||
align: "tl",
|
||||
x: 15,
|
||||
y: 12
|
||||
},
|
||||
{
|
||||
name: "timeDisplay",
|
||||
align: "tl",
|
||||
x: 10,
|
||||
y: 7
|
||||
},
|
||||
{
|
||||
name: "fullScreenButton",
|
||||
align: "tr",
|
||||
x: 10,
|
||||
y: 12
|
||||
},
|
||||
{
|
||||
name: "volume",
|
||||
align: "tr",
|
||||
x: 10,
|
||||
y: 10
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
player = new VideoPlayer(playerProps);
|
||||
};
|
||||
onBeforeUnmount(() => {
|
||||
if (player) {
|
||||
player.dispose();
|
||||
}
|
||||
});
|
||||
const showRight = ref(false);
|
||||
const hasCountdown = ref(false); //判断是否有倒计时
|
||||
const countdownTime = ref(0);
|
||||
const activeName = ref("b");
|
||||
const offset = ref({ x: '100%', y: '70%' });
|
||||
const onClick = () => {
|
||||
showRight.value = true;
|
||||
};
|
||||
// 获取sence
|
||||
const getSenceList = () => {
|
||||
let params = {
|
||||
id: 2057,
|
||||
};
|
||||
scene(params)
|
||||
.then((res) => {
|
||||
console.log("获取sence", res);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录接口请求失败", error);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
/* AliPlayer */
|
||||
.prism-player .prism-controlbar .prism-setting,
|
||||
.prism-player .prism-controlbar .prism-subtitle {
|
||||
display: none !important;
|
||||
|
||||
}
|
||||
.prism-player .prism-ErrorMessage
|
||||
{
|
||||
/* top:20%; */
|
||||
display: none !important;
|
||||
|
||||
}
|
||||
|
||||
.prism-player .prism-big-play-btn
|
||||
{
|
||||
top:50%!important;
|
||||
left:50%!important;
|
||||
transform:translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.prism-progress-cursor
|
||||
{
|
||||
margin-left:0px !important;
|
||||
|
||||
}
|
||||
|
||||
.prism-player video
|
||||
{
|
||||
object-fit: cover;
|
||||
object-position: 0 0;
|
||||
}
|
||||
|
||||
|
||||
.van-floating-bubble {
|
||||
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0 !important;
|
||||
transform: translate3d(325.812px, 50vh, 0px)!important;
|
||||
width: 50px;
|
||||
height: 80px;
|
||||
background: #eeeeee;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
z-index: 999;
|
||||
}
|
||||
.van-tabs__content {
|
||||
width: 100%;
|
||||
height: calc(100vh - 130px);
|
||||
/* border:1px solid red; */
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.bubble-content {
|
||||
color: rgba(0, 0, 0, 80%);
|
||||
position: relative;
|
||||
width: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
}
|
||||
.bubble-content::before {
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 30%;
|
||||
background: url("../assets/img/jt_black.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
left: -15px;
|
||||
top: 30%;
|
||||
position: absolute;
|
||||
}
|
||||
// 顶部播放器
|
||||
.top {
|
||||
width: 100%;
|
||||
height: 211px;
|
||||
|
||||
box-sizing: border-box;
|
||||
.prism-player {
|
||||
width: 100%;
|
||||
height: 56.26667vw;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
162
src/views/home.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="homePage">
|
||||
<headerVue></headerVue>
|
||||
<div class="home_scroll">
|
||||
<normalSwiper />
|
||||
<div class="channel bg">
|
||||
<titleVue />
|
||||
<gridSwiper />
|
||||
</div>
|
||||
<div class="channel bg">
|
||||
<titleVue />
|
||||
<smallSlideSwiper />
|
||||
</div>
|
||||
<div class="bg">
|
||||
<titleVue style="padding: 10px 20px" />
|
||||
<slideSwiperVue />
|
||||
</div>
|
||||
<div class="channel bg">
|
||||
<titleVue />
|
||||
<gridSwiper />
|
||||
</div>
|
||||
<div class="bg">
|
||||
<titleVue style="padding: 10px 20px" />
|
||||
<slideSwiperVue />
|
||||
</div>
|
||||
<div class="channel bg">
|
||||
<titleVue />
|
||||
<longSlideSwiper />
|
||||
</div>
|
||||
<div class="channel bg">
|
||||
<titleVue />
|
||||
<smallSlideSwiper />
|
||||
</div>
|
||||
<div
|
||||
class="bg normal_item"
|
||||
v-for="(item, index) in simpleList"
|
||||
:key="index"
|
||||
>
|
||||
<!-- <div class="tri"> -->
|
||||
<img :src="item.img" @click="goDetail(item)" />
|
||||
<p class="title">{{ item.title }}</p>
|
||||
<!-- </div> -->
|
||||
<p
|
||||
class="status"
|
||||
:class="{
|
||||
live_status: getStatusClass(item.status) === '直播中',
|
||||
live_coming: getStatusClass(item.status) === '预告',
|
||||
live_review: getStatusClass(item.status) === '精彩回顾',
|
||||
}"
|
||||
>
|
||||
{{ getStatusText(item.status) }}
|
||||
</p>
|
||||
</div>
|
||||
<p class="more">点击加载更多</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import headerVue from "../components/header.vue";
|
||||
import normalSwiper from "../components/swipers/normalSwiper.vue";
|
||||
import gridSwiper from "../components/swipers/gridSwiper.vue";
|
||||
import slideSwiperVue from "../components/swipers/slideSwiper.vue";
|
||||
import smallSlideSwiper from "../components/swipers/smallSlideSwiper.vue";
|
||||
import longSlideSwiper from "../components/swipers/longSlideSwiper.vue";
|
||||
import titleVue from "../components/title.vue";
|
||||
import grid1 from "../assets/img/top1.png";
|
||||
import grid2 from "../assets/img/top1.png";
|
||||
import grid3 from "../assets/img/top1.png";
|
||||
import grid4 from "../assets/img/top1.png";
|
||||
import {useRouter} from 'vue-router';
|
||||
const router = useRouter();
|
||||
const simpleList = ref([
|
||||
{
|
||||
id: "0",
|
||||
status: "0",
|
||||
img: grid1,
|
||||
title: "防空警报",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
status: "1",
|
||||
img: grid2,
|
||||
title: "防空警报",
|
||||
},
|
||||
{ id: "2", status: "2", img: grid3, title: "防空警报" },
|
||||
{ id: "3", status: "1", img: grid4, title: "防空警报" },
|
||||
]);
|
||||
// 定义状态码与状态文本的映射
|
||||
const statusMap = {
|
||||
0: "直播中",
|
||||
1: "预告",
|
||||
2: "精彩回顾",
|
||||
};
|
||||
|
||||
// 根据状态码返回状态文本
|
||||
const getStatusText = (status) => statusMap[status] || "";
|
||||
|
||||
// 根据状态码返回对应的CSS类名
|
||||
const getStatusClass = (status) => statusMap[status] || "";
|
||||
const goDetail = (item) => {
|
||||
console.log(item)
|
||||
router.push({
|
||||
name: 'Detail',
|
||||
query: { item: item.id }
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.homePage {
|
||||
width: 100%;
|
||||
// width:720px;
|
||||
// margin: 0 auto;
|
||||
height: auto;
|
||||
background-color: #f5f6f8;
|
||||
.home_scroll{
|
||||
height:calc(100vh - 4rem);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.bg {
|
||||
margin-top: 10px;
|
||||
padding:0 0 10px 0;
|
||||
background: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
.normal_item {
|
||||
width: 100%;
|
||||
// height: 212px;
|
||||
// padding: 10px 0;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 212px;
|
||||
}
|
||||
.title {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
.status {
|
||||
top:10px;
|
||||
left:25px;
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.channel {
|
||||
padding: 0 20px;
|
||||
|
||||
}
|
||||
.more {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
color: gray;
|
||||
}
|
||||
</style>
|
||||
13
src/views/more.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<contentList/>
|
||||
</template>
|
||||
<script setup>
|
||||
import contentList from '../components/contentList.vue'
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.grid_list{
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap:20px;
|
||||
}
|
||||
</style>
|
||||
416
src/views/searchVue.vue
Normal file
@ -0,0 +1,416 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="header">
|
||||
<div class="search">
|
||||
<van-search
|
||||
v-model="value"
|
||||
shape="round"
|
||||
background="transparent"
|
||||
placeholder="请输入搜索关键词"
|
||||
:clearable="false"
|
||||
:show-action="true"
|
||||
>
|
||||
<template #action>
|
||||
<van-icon name="clear" class="search-clear-icon" @click="onClear" />
|
||||
</template>
|
||||
</van-search>
|
||||
</div>
|
||||
<p @click="onSearch">搜索</p>
|
||||
</div>
|
||||
|
||||
<van-dropdown-menu ref="menuRef" >
|
||||
<van-dropdown-item @click="onConfirm" v-model="isDropdownOpen" title="筛选" ref="itemRef">
|
||||
<div class="choice_list">
|
||||
<div class="tri">
|
||||
<p>开播时间</p>
|
||||
<div class="grid">
|
||||
<button
|
||||
class="grid_item"
|
||||
@click.stop="selectTime('不限')"
|
||||
:class="{ active: selectedTime === '不限' }"
|
||||
>
|
||||
不限
|
||||
</button>
|
||||
<button
|
||||
class="grid_item"
|
||||
@click.stop="selectTime('最近一天')"
|
||||
:class="{ active: selectedTime === '最近一天' }"
|
||||
>
|
||||
最近一天
|
||||
</button>
|
||||
<button
|
||||
class="grid_item"
|
||||
@click.stop="selectTime('最近一周')"
|
||||
:class="{ active: selectedTime === '最近一周' }"
|
||||
>
|
||||
最近一周
|
||||
</button>
|
||||
<button
|
||||
class="grid_item"
|
||||
@click.stop="selectTime('最近一月')"
|
||||
:class="{ active: selectedTime === '最近一月' }"
|
||||
>
|
||||
最近一月
|
||||
</button>
|
||||
<button
|
||||
@click.stop="selectTime('自定义')"
|
||||
class="grid_item color1"
|
||||
:class="{ active: selectedTime === '自定义' }"
|
||||
>
|
||||
自定义
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tri">
|
||||
<p>专题栏目</p>
|
||||
|
||||
<div class="grid">
|
||||
<button
|
||||
v-for="topic in topics"
|
||||
:key="topic"
|
||||
@click.stop="toggleTopic(topic)"
|
||||
:class="{ active: selectedTopics.includes(topic) }"
|
||||
class="grid_item"
|
||||
>
|
||||
{{ topic }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
<contentList v-show="showSearchList"/>
|
||||
<van-popup
|
||||
v-model:show="showBottom"
|
||||
position="bottom"
|
||||
:style="{ height: '50%' }"
|
||||
>
|
||||
<van-picker-group
|
||||
v-if="showPickerGroup"
|
||||
:tabs="['开始日期', '结束日期']"
|
||||
@confirm="timeConfirm"
|
||||
@cancel="timeCancel"
|
||||
:style="{ height: '100%' }"
|
||||
>
|
||||
<van-date-picker
|
||||
v-model="startDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
/>
|
||||
<van-date-picker
|
||||
v-model="endDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
/>
|
||||
</van-picker-group>
|
||||
</van-popup>
|
||||
<div class="hot_list" v-show="!showSearchList">
|
||||
<div class="hot_title">
|
||||
<img aria-hidden="true" alt="fire-icon" src="../assets/img/hot.svg" />
|
||||
<p>热点榜</p>
|
||||
</div>
|
||||
|
||||
<table cellspacing="0" cellpadding="">
|
||||
<tr v-for="item in topList" :key="item.id">
|
||||
<td class="order" :style="{ color: getColor(item.id) }">
|
||||
{{ item.id }}
|
||||
</td>
|
||||
<td>{{ item.content }}</td>
|
||||
<td>
|
||||
<span :style="{ background: getBgColor(item.id) }" class="bg_color">{{
|
||||
getTipText(item.id)
|
||||
}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref,watch } from "vue";
|
||||
import contentList from "../components/contentList.vue";
|
||||
import { useRoute } from "vue-router";
|
||||
const route = useRoute();
|
||||
const menuRef = ref(null);
|
||||
const itemRef = ref(null);
|
||||
const value = ref(null);
|
||||
const showSearchList = ref(false);
|
||||
const onSearch = () => {
|
||||
console.log("搜索",value.value);
|
||||
showSearchList.value = true;
|
||||
};
|
||||
const onClear = () => {
|
||||
value.value = ""; // 清空搜索框的值
|
||||
showSearchList.value = false; // 显示热点榜
|
||||
};
|
||||
const onConfirm = () => {
|
||||
if( itemRef.value.toggle(false)){
|
||||
// 清空选中的数据
|
||||
selectedTopics.value = [];
|
||||
selectedTime.value = "";
|
||||
};
|
||||
|
||||
};
|
||||
const isDropdownOpen = ref(false); // 初始化下拉菜单状态为关闭
|
||||
const showPickerGroup = ref(false);
|
||||
const topics = ["不限", "推荐", "政务", "综合", "县区", "社会", "活动", "拍客"];
|
||||
const selectedTopics = ref([]);
|
||||
const timeOptions = ["不限", "最近一天", "最近一周", "最近一月", "自定义"];
|
||||
const selectedTime = ref("");
|
||||
const showBottom = ref(false);//底部弹出框
|
||||
const selectTime = (time,event) => {
|
||||
selectedTime.value = time;
|
||||
if (time === "自定义") {
|
||||
|
||||
showBottom.value = true;
|
||||
showPickerGroup.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const startDate = ref(["2024", "05", "01"]);
|
||||
const endDate = ref(["2024", "06", "01"]);
|
||||
|
||||
const timeConfirm = (value) => {
|
||||
// 处理确认逻辑
|
||||
console.log("确认的值:", value);
|
||||
showPickerGroup.value = false; // 隐藏日历
|
||||
showBottom.value = false;
|
||||
};
|
||||
|
||||
const timeCancel = () => {
|
||||
// 取消时的处理
|
||||
showPickerGroup.value = false; // 隐藏日历
|
||||
showBottom.value = false;
|
||||
};
|
||||
|
||||
const topList = ref([
|
||||
{
|
||||
id: 1,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
|
||||
{
|
||||
id: 2,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
content: "75秒看人民海军75年巨变",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
content: "75秒看人民海军",
|
||||
},
|
||||
]);
|
||||
const getColor = (index) => {
|
||||
if (index === 1) {
|
||||
return "#FF3433";
|
||||
} else if (index === 2) {
|
||||
return "#FF6606";
|
||||
} else if (index === 3) {
|
||||
return "#FCA714";
|
||||
} else {
|
||||
return "#B3B3B5";
|
||||
}
|
||||
};
|
||||
const getTipText = (id) => {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return "热";
|
||||
case 2:
|
||||
return "新";
|
||||
case 3:
|
||||
return "荐";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
const getBgColor = (index) => {
|
||||
if (index === 1) {
|
||||
return `linear-gradient(to bottom, #EFBE26 0%, #F58C05 100%)`;
|
||||
} else if (index === 2) {
|
||||
return `linear-gradient(to bottom, #FF809B 0%, #F84670 100%)`;
|
||||
} else if (index === 3) {
|
||||
return `linear-gradient(to bottom, #15D7F1 0%, #07A1C2 100%)`;
|
||||
} else {
|
||||
return "transparent";
|
||||
}
|
||||
};
|
||||
const toggleTopic = (topic) => {
|
||||
if (selectedTopics.value.includes(topic)) {
|
||||
selectedTopics.value = selectedTopics.value.filter((t) => t !== topic);
|
||||
} else {
|
||||
selectedTopics.value.push(topic);
|
||||
}
|
||||
};
|
||||
watch([selectedTopics, selectedTime], () => {
|
||||
|
||||
// 根据选定的筛选条件更新列表
|
||||
// const filteredList = originalList.filter(item => {
|
||||
// // 根据选定的筛选条件进行过滤逻辑
|
||||
// const matchesTopic = selectedTopics.includes(item.topic);
|
||||
// const matchesTime = item.time >= selectedTime.start && item.time <= selectedTime.end;
|
||||
// return matchesTopic && matchesTime;
|
||||
// });
|
||||
showSearchList.value = true;
|
||||
// 更新展示的列表
|
||||
// if (filteredList.length > 0) {
|
||||
// showSearchList.value = true;
|
||||
// contentList.value = filteredList;
|
||||
// } else {
|
||||
// showSearchList.value = false;
|
||||
// contentList.value = originalList; // 如果筛选结果为空,则显示原始列表
|
||||
// }
|
||||
});
|
||||
// 根据选择条件筛选列表
|
||||
const onSearchList = () => {
|
||||
console.log(selectedTopics.value);
|
||||
console.log(selectedTime.value);
|
||||
itemRef.value.toggle(false); // 添加这行代码来关闭下拉菜单
|
||||
showPickerGroup.value = false; // 如果需要,确保时间选择器也同时关闭
|
||||
showBottom.value = false; // 关闭底部弹窗
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep(.van-dropdown-menu__title--active) {
|
||||
color: #004098;
|
||||
}
|
||||
::v-deep(.van-dropdown-menu__item) {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 0 30px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
min-width: 0;
|
||||
}
|
||||
::v-deep(.van-dropdown-menu__bar) {
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
}
|
||||
::v-deep(.van-search__content){
|
||||
background: #fff;
|
||||
}
|
||||
::v-deep(.van-search__action){
|
||||
font-size: 18px;
|
||||
transform: translateX(-30px);
|
||||
color: #cccccc;
|
||||
}
|
||||
.header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// height: 4rem;
|
||||
|
||||
background-color: #F6F6F6;
|
||||
// background-color: red;
|
||||
.search{
|
||||
width: 85%;
|
||||
|
||||
}
|
||||
p{
|
||||
color: #676767;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.choice_list {
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
padding-bottom:10px;
|
||||
height: auto;
|
||||
.tri {
|
||||
// padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
p {
|
||||
padding: 10px 0;
|
||||
}
|
||||
// align-items: center;
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 20px;
|
||||
color:#5B5B5B;
|
||||
.grid_item {
|
||||
padding: 10px 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.grid_item.active {
|
||||
border: 1px solid #183b86 !important;
|
||||
color: #183b86;
|
||||
background: #e4ebf4;
|
||||
}
|
||||
.color1 {
|
||||
color: #f43760;
|
||||
}
|
||||
}
|
||||
}
|
||||
.van_btn {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
border-radius: 50px;
|
||||
background-color: #004098;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.hot_list {
|
||||
width: 90%;
|
||||
margin: 10px auto;
|
||||
.hot_title {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin-bottom: 10px;
|
||||
img{
|
||||
width:20px;
|
||||
height: 20px;
|
||||
}
|
||||
p {
|
||||
color: #f43760;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
border-top: 1px solid #f2f2f2;
|
||||
padding: 15px 5px;
|
||||
|
||||
// width:100%;
|
||||
// height:100px;
|
||||
}
|
||||
.order {
|
||||
font-weight: bolder;
|
||||
font-size: 16px;
|
||||
}
|
||||
.bg_color {
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
53
vite.config.js
Normal file
@ -0,0 +1,53 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path';
|
||||
import AutoImport from 'unplugin-auto-import/vite';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import { VantResolver } from '@vant/auto-import-resolver';
|
||||
// 安装 postcss-pxtorem 和 autoprefixer
|
||||
|
||||
// npm install postcss-pxtorem --save
|
||||
// npm i autoprefixer
|
||||
import pxtoviewport from 'postcss-px-to-viewport';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base:'./',
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
resolvers: [VantResolver()],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [VantResolver()],
|
||||
}),
|
||||
|
||||
|
||||
],
|
||||
// css: {
|
||||
|
||||
// postcss: {
|
||||
// plugins: [
|
||||
// autoprefixer(),
|
||||
// pxtoviewport({
|
||||
// viewportWidth: 375,
|
||||
// }),
|
||||
// ],
|
||||
// },
|
||||
|
||||
// },
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
port: 8123,
|
||||
|
||||
},
|
||||
resolve: {
|
||||
alias:{
|
||||
// 配置src目录
|
||||
"@": path.resolve(__dirname,"src"),
|
||||
// 导入其他目录
|
||||
"components": path.resolve(__dirname, "components")
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||