This commit is contained in:
zoujiandong 2025-12-10 09:05:18 +08:00
commit e9b415d4bd
42 changed files with 7561 additions and 0 deletions

4
.env.development Normal file
View File

@ -0,0 +1,4 @@
VITE_BASE_URL="https://dev-vote.igandan.com/api/v/"
VITE_IMAGE_URL = 'http://dev-vote-system.oss-cn-beijing.aliyuncs.com'
VITE_SHARE_URL = 'https://dev-vote.igandan.com/web/v/'
VITE_WE_URL = 'https://dev-wx.igandan.com'

4
.env.production Normal file
View File

@ -0,0 +1,4 @@
VITE_BASE_URL="https://prod-vote.igandan.com/api/v/"
VITE_IMAGE_URL = 'http://prod-vote-system.oss-cn-beijing.aliyuncs.com'
VITE_SHARE_URL = 'https://prod-vote.igandan.com/web/v/'
VITE_WE_URL = 'https://wx.igandan.com'

4
.env.test Normal file
View File

@ -0,0 +1,4 @@
VITE_BASE_URL="https://dev-vote.igandan.com/api/v/"
VITE_IMAGE_URL = 'http://dev-vote-system.oss-cn-beijing.aliyuncs.com'
VITE_SHARE_URL = 'https://dev-vote.igandan.com/web/v/'
VITE_WE_URL = 'https://dev-wx.igandan.com'

81
.gitignore vendored Normal file
View File

@ -0,0 +1,81 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
/dist
# misc
.DS_Store
*.pem
*.d.ts
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel
# typescript
*.tsbuildinfo
# eslint
.eslintcache
# stylelint
.stylelintcache
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
yarn.lock
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# node_modules
node_modules
package-lock.json
package-lock.json
components.d.ts

0
README.md Normal file
View File

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!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, maximum-scale=1.0, user-scalable=no" />
<title><%- title %></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

14
jsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": [
"node_modules"
]
}

38
package.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "wxapp-home",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"test": "vite --mode=test",
"build": "vite build",
"build-test": "vite build --mode=test",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.5.0",
"lodash": "^4.17.21",
"reset-css": "^5.0.2",
"vant": "^4.9.4",
"vconsole": "^3.15.1",
"vue": "^3.3.4",
"vue-lazyload": "^3.0.0",
"vue-router": "^4.2.4",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"@types/node": "^20.4.5",
"@vant/auto-import-resolver": "^1.2.1",
"@vitejs/plugin-vue": "^4.2.3",
"rollup-plugin-external-globals": "^0.8.0",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.69.5",
"terser": "^5.19.1",
"unplugin-auto-import": "^0.16.7",
"unplugin-vue-components": "^0.25.2",
"vite": "^4.4.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0"
}
}

1
public/vite.svg Normal file
View 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

43
src/App.vue Normal file
View File

@ -0,0 +1,43 @@
<template>
<body ontouchstart="">
<router-view></router-view>
</body>
</template>
<style>
body{max-width: 640px;margin: 0 auto !important;}
:root {
--font-size-12: 12px;
--font-size-14: 14px;
--font-size-16: 16px;
--font-size-18: 18px;
--font-size-20: 20px;
--font-size-title: 17px;
--back-color-01:#F5F5F5FF;
--text-color-normal:#233C4C;
}
strong{
font-weight: bold!important;
}
sup{
vertical-align: super!important;
}
sub{
vertical-align: sub!important;
}
* {
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
user-select: none; /* 标准语法 */
}
/* img{
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-webkit-user-select:none;
-o-user-select:none;
user-select:none;
} */
</style>

BIN
src/assets/bg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
src/assets/closepop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
src/assets/first.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
src/assets/jiesao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/paiming1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/assets/rank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
src/assets/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/assets/second.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
src/assets/shipin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
src/assets/sucess.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src/assets/third.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
src/assets/toupiao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/toupiao1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
src/assets/tuwen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
src/assets/votbutton.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,95 @@
<template>
<div style="background: #06247A;">
<div :style=dynamicStyle >
<!-- <van-image
height="162"
fit="cover"
:src=homebg
/> -->
<div style="height: 114px;"></div>
<div class="numbers00">
<div class="nums00">
<span class="text100">{{ num1 }}</span>
<span class="text200">&nbsp;浏览</span>
</div>
<div style="width: 1px;height: 20px;background: rgba(255,255,255,0.85);"></div>
<div class="nums00">
<span class="text100">{{ num2 }}</span>
<span class="text200">&nbsp;投票</span>
</div>
</div>
</div>
<div style="height: 16px;"></div>
</div>
</template>
<script setup >
const IMG_PATH = import.meta.env.VITE_IMAGE_URL+'/static/images/1178172634346456.png_hd.png'
const props = defineProps({
num1: {
type: Number,
},
num2: {
type: Number,
},
});
const dynamicStyle = ref({
'backgroundImage':'url('+IMG_PATH+')',
'height': '162px',
'background-size': 'cover',
'background-repeat': 'no-repeat',
});
</script>
<style scoped>
/* .hobg{
height: 162px;
background: url('http://dev-vote-system.oss-cn-beijing.aliyuncs.com/static/images/11781726022977_.pic_hd.jpg') no-repeat;
background-size: 100% 100%;
} */
.numbers00{
height: 48px;
margin-left: 16px;
margin-right: 16px;
background: rgba(15,47,134,0.65);
border-radius: 8px;
border: 1px solid rgba(7,187,255,0.24);
display: flex;
align-items: center;
flex-direction: row;
}
.nums00{
display: flex;
flex-direction: row;
flex: 1;
justify-content:center;
z-index: 999;
}
.text100{
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #51EAFF;
line-height: 48px;
text-align: center;
font-style: normal;
}
.text200{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: rgba(255,255,255,0.85);
line-height: 48px;
text-align: center;
font-style: normal;
}
</style>

View File

@ -0,0 +1,73 @@
<template>
<div class="votbg" @click="vote()">
<div>{{ text }}</div>
</div>
</template>
<script setup >
import {goAuth}from '@/utils/authorize.js';
const props = defineProps({
text: {
type: String,
},
});
const emits = defineEmits(["vote-click"]);
function vote(){
// emits('vote-click','1')
// return
const token=localStorage.getItem('bearer-tokens');
if(typeof token === "undefined"||token ==null|| token == ""|| token == "undefined")
{
const ticket= localStorage.getItem('qr-tickets');
if(typeof ticket === "undefined"||ticket ==null|| ticket == ""|| ticket == "undefined")
{
goAuth()
}
else
{
emits('vote-click',ticket)
localStorage.setItem('qr-tickets', "");
}
}
else
{
emits('vote-click','1')
}
}
</script>
<style scoped>
.votbg{
height: 56px;
width: 212px;
margin-bottom: 16px;
background: url('../assets/votbutton.png');
background-repeat: no-repeat;
background-size: cover;
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #FFFFFF;
line-height: 56px;
text-shadow: 0px 2px 2px #00A9E6;
text-align: center;
font-style: normal;
}
</style>

175
src/components/votView.vue Normal file
View File

@ -0,0 +1,175 @@
<template>
<van-overlay :show="show" z-index="9999" >
<div class="wrapper">
<!-- <div class="wrapper" @mousedown="handleMouseDown" @touchstart="handleTouchStart" @mouseup="handleMouseUp" @touchend="handleTouchEnd" > -->
<div class="block">
<div class="tip">杜绝刷票行为投票先请关注
肝胆相照一家人</div>
<van-image width="128" height="128" :src=qrcodeurl+ticket style="margin-top: 10px;" z-index="9999" class="qrimg"
/>
<div class="ttext1">长按二维码关注</div>
</div>
<van-image width="32" height="32" :src=close style="margin-top: 40px;" @click="onChange(false)"
/>
</div>
</van-overlay>
<van-overlay :show="shows" z-index="999" >
<div class="wrapper" >
<div class="blocks">
<van-image width="110" height="110" :src=sucess style="margin-top: 22px;"/>
<div class="ttext3">投票成功</div>
<div class="ttext2" @click="onChange(false)">我知道啦</div>
</div>
</div>
</van-overlay>
</template>
<script setup >
import {qrcodeurl} from '../utils/request.js'
import close from '../assets/closepop.png'
import sucess from '../assets/sucess.png'
const props = defineProps({
show: {
type: Boolean,
default: false,
},
ticket: {
type: String,
default: false,
},
shows: {
type: Boolean,
default: false,
},
});
const emits = defineEmits(["onchange","onchanges"]);
const onChange = (v) => {
emits('onchange', v);
emits('onchanges', v);
localStorage.setItem('qr-tickets', "");
};
// let longPressTimer = null;
// let isTouch = false;
// const handleMouseDown = (event) => {
// // touch
// clearTimeout(longPressTimer);
// //
// longPressTimer = setTimeout(() => {
// //
// console.log('Mouse long press', event);
// localStorage.setItem('qr-tickets', "");
// }, 1000); // 1000
// };
// const handleTouchStart = (event) => {
// // mouse
// clearTimeout(longPressTimer);
// //
// longPressTimer = setTimeout(() => {
// //
// console.log('Touch long press', event);
// localStorage.setItem('qr-tickets', "");
// }, 1000); // 1000
// isTouch = true;
// };
// const handleMouseUp = () => {
// //
// clearTimeout(longPressTimer);
// };
// const handleTouchEnd = () => {
// //
// clearTimeout(longPressTimer);
// isTouch = false;
// };
</script>
<style scoped>
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.block {
width: 247px;
height: 240px;
background-color: #fff;
border-radius: 16px;
display: flex;
flex-direction: column;
align-items: center;
}
.tip{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0E3564;
line-height: 20px;
text-align: center;
font-style: normal;
background-image: url(../assets/bg1.png);
background-size: 100% 100%;
background-repeat: no-repeat;
width: 210px;
height: 44px;
margin-top: 20px;
}
.ttext1{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: rgba(0,0,0,0.65);
line-height: 17px;
text-align: center;
font-style: normal;
margin-top: 8px;;
}
.blocks {
width: 247px;
height: 221px;
background-color: #fff;
border-radius: 16px;
display: flex;
flex-direction: column;
align-items: center;
}
.ttext2{
margin-top: 20px;
width: 120px;
height: 36px;
background: #0E3564;
border-radius: 8px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #FFFFFF;
line-height: 36px;
text-align: center;
font-style: normal;
}
.ttext3{
margin-top: -20px;
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #00B9FF;
line-height: 33px;
text-align: center;
font-style: normal;
/* background: linear-gradient(90deg, #51EAFF 0%, #00B9FF 100%); */
}
.qrimg{
-webkit-user-select: all; /* Safari */
-moz-user-select: all; /* Firefox */
-ms-user-select: all; /* IE10+ */
user-select: all; /* 标准语法 */
}
</style>

21
src/main.js Normal file
View File

@ -0,0 +1,21 @@
import { createApp } from 'vue'
import 'reset-css'
import './style.css'
import App from './App.vue'
import router from "@/router/index.js"
import Vant from 'vant';
import VConsole from 'vconsole';
router.afterEach((to, from, next) => {
window.scrollTo(0, 0);
})
// const vConsole = new VConsole();
const app = createApp(App);
app.use(router);
app.use(Vant);
app.mount('#app')

131
src/router/index.js Normal file
View File

@ -0,0 +1,131 @@
import { createWebHashHistory, createRouter, createWebHistory } from 'vue-router';
import Home from "@/views/home.vue"
import voteList from '@/views/voteList.vue';
import articleDetails from '@/views/articleDetails.vue';
import videoDetails from '@/views/videoDetails.vue';
import { login } from '@/utils/api.js';
const routes = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'home',
component: Home,
},
{
path: '/voteList',
name: 'voteList',
component: voteList,
},
{
path: '/articleDetails',
name: 'articleDetails',
component: articleDetails,
},
{
path: '/videoDetails',
name: 'videoDetails',
component: videoDetails,
},
];
const router = createRouter({
// createWebHashHistory URL 带井号
// createWebHistory URL 去井号
history:createWebHistory('web/v'),
routes: routes,
});
// 全局前置守卫
router.beforeEach((to, from, next) => {
// 在这里编写拦截逻辑
// 例如,检查用户是否已经登录
// if (to.path =='/home') {
const urlToBeAccessed = to.fullPath; // 获取即将跳转的完整URL
// alert(urlToBeAccessed+' 11111')
console.log('即将跳转到:', urlToBeAccessed);
if(urlToBeAccessed.includes('subscribe')){
const token=localStorage.getItem('bearer-tokens');
if(typeof token === "undefined"||token ==null|| token == ""|| token == "undefined")
{
// alert(' 2222')
let queryParams = to.query;
let subscribe = queryParams.subscribe
// alert(subscribe+' 3333')
if(subscribe == '1'){
// let openid = queryParams.openid
let openid = getCookie('wechat_user_openid')
console.log("openid",openid)
localStorage.setItem('qr-tickets', "");
login(openid).then((data) => {
if(200==data.code)
{
localStorage.setItem('bearer-tokens', 'Bearer '+data.data.token);
}
else
{
localStorage.setItem('bearer-tokens', "");
}
next();
});
}
else
{
// alert(subscribe+' 4444')
localStorage.setItem('bearer-tokens', "");
// alert(queryParams.ticket)
localStorage.setItem('qr-tickets', queryParams.ticket);
next();
}
}
else{
next();
}
}
else{
next();
}
});
//设置cookie
function setCookie(name, value) {
document.cookie = name + "=" + escape(value) + "; path=/";
}
//获取cookie
function getCookie(name) {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
}
export default router;

22
src/style.css Normal file
View File

@ -0,0 +1,22 @@
body{
background:#fff;
}
/* @font-face {
font-family: "阿里巴巴普惠体 2.0 65 Medium";font-weight: 500;src: url("//at.alicdn.com/wf/webfont/sgTFboRMJU3n/JxNJC26HiA0D.woff2") format("woff2"),
url("//at.alicdn.com/wf/webfont/sgTFboRMJU3n/T8cUklUUIqA1.woff") format("woff");
font-display: swap;
} */
/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
/* @font-face {
font-family:AlibabaPuHuiTiR;
src:url('../src/assets/font/Alibaba_PuHuiTi_2.0_55_Regular_55_Regular.ttf')
}
@font-face {
font-family:AlibabaPuHuiTiH;
src:url('../src/assets/font/Alibaba_PuHuiTi_2.0_105_Heavy_105_Heavy.ttf')
}
@font-face {
font-family:AlibabaPuHuiTiB;
src:url('../src/assets/font/Alibaba_PuHuiTi_2.0_55_Regular_85_Bold.ttf')
} */

103
src/utils/api.js Normal file
View File

@ -0,0 +1,103 @@
import service from './request';
export function agreement(agreement_type) {
return service({
url:'agreement',
method: 'get',
params:{
agreement_type:agreement_type,
}
})
}
export function votedata() {
return service({
url:'data',
method: 'get'
})
}
export function browse() {
return service({
url:'browse',
method: 'post',
})
}
export function articlepage(page,page_size,keyword) {
return service({
url:'article/page',
method: 'get',
params:{
page:page,
page_size:page_size,
keyword:keyword,
}
})
}
export function videopage(page,page_size,keyword) {
return service({
url:'video/page',
method: 'get',
params:{
page:page,
page_size:page_size,
keyword:keyword,
}
})
}
export function rankarticle() {
return service({
url:'rank/article',
method: 'get',
})
}
export function rankvideo() {
return service({
url:'rank/video',
method: 'get',
})
}
export function votearticle(article_id) {
return service({
url:'vote/article/'+article_id,
method: 'post',
})
}
export function votevideo(video_id) {
return service({
url:'vote/video/'+video_id,
method: 'post',
})
}
export function getarticle(article_id) {
return service({
url:'article/'+article_id,
method: 'get',
})
}
export function getvideo(video_id) {
return service({
url:'video/'+video_id,
method: 'get',
})
}
export function login(openid) {
return service({
url:'login',
method: 'post',
params:{
openid:openid,
}
})
}

49
src/utils/authorize.js Normal file
View File

@ -0,0 +1,49 @@
import {useRoute } from 'vue-router';
export function goAuth() {
const route = useRoute();
var redirectUrl = window.location.href;
const urlParams = new URLSearchParams(window.location.search);
if(redirectUrl.includes('voteList')) {
redirectUrl = import.meta.env.VITE_SHARE_URL+'voteList';
}
else if(redirectUrl.includes('articleDetails')) {
redirectUrl = import.meta.env.VITE_SHARE_URL+'articleDetails?id='+route.query.id+'&name='+encodeURIComponent(route.query.name);
}
else if(redirectUrl.includes('videoDetails')) {
redirectUrl = import.meta.env.VITE_SHARE_URL+'videoDetails?id='+urlParams.get('id')+'&name='+encodeURIComponent(urlParams.get('name'));
// redirectUrl = import.meta.env.VITE_SHARE_URL+'videoDetails?id='+route.query.id+'&name='+encodeURIComponent(route.query.name);
}
else
{
redirectUrl = import.meta.env.VITE_SHARE_URL+'home';
}
redirectUrl = encodeURIComponent(redirectUrl);
window.location.href =import.meta.env.VITE_WE_URL+"/AuthorizeURL/grant?sceneStr=hero-video&follow=1&scope=snsapi_base&back_url=" + redirectUrl;
}
export function saveurl(url,id,name) {
const route = useRoute();
// const urlSearchParams = new URLSearchParams(window.location.search)
// let subscribe = urlSearchParams.get('subscribe')
let subscribe =route.query.subscribe
if(subscribe=='0') {
localStorage.setItem('gotourls', url)
localStorage.setItem('gotourlids', id)
localStorage.setItem('gotourlnames', name)
}
}

1
src/utils/const.js Normal file
View File

@ -0,0 +1 @@
export const title='肝胆英雄榜最具影响力视频投票';

139
src/utils/request.js Normal file
View File

@ -0,0 +1,139 @@
import axios from 'axios';
import {goAuth}from '@/utils/authorize.js';
// create an axios instance
const service = axios.create({
baseURL:import.meta.env.VITE_BASE_URL,
timeout: 8000,
// withCredentials: true,
headers:{
'Content-Type':'application/x-www-form-urlencoded',
// 'Authorization':'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTgzMDQ4NjkyMDYxMDcxMzYwMCIsImV4cCI6MTcyNTM0MzQ2NSwibmJmIjoxNzI1MjU3MDY1LCJpYXQiOjE3MjUyNTcwNjV9.GBkHpVzRb2XeEZmnrjPQ6x57CdHvH8WLxT9Uqc24TRg',
}
});
// request interceptor
service.interceptors.request.use(
(config) => {
// Store 必须在拦截器内部导入,在外部导入会显示 Pinia 未初始化
// 设置请求头部 Authorization
// console.log("333333");
// console.log(config);
const token=localStorage.getItem('bearer-tokens');
if(typeof token === "undefined"||token ==null|| token == ""|| token == "undefined")
{
}
else
{
config.headers['Authorization'] = token;
}
return config;
},
(error) => {
console.error(error);
return Promise.reject(error);
}
);
// response interceptor
service.interceptors.response.use(
(response) => {
// console.log(response)
//var Authorization_token = response.headers.Authorization;
// if (Authorization_token) {
// sessionStorage.setItem('token', Authorization_token); //当token快过期时服务器会返回新token本地刷新
// }
const { code, message } = response.data;
// console.log("code",code);
if(code == 401 || code==405 )
{
localStorage.setItem('bearer-tokens', "");
// let back_url = window.location.href;
// window.location.href="https://wx.igandan.com/hcp/toLogin?back_url="+back_url;
// window.location.href="https://twx.igandan.org/hcp/toLogin?back_url="+back_url;
goAuth();
}
else if (code == 401 || code==403 || code==405 || code==406) {
//Message.clear();
// Message.error({
// content: message,
// duration: 3000
// });
// 重定向路由到登陆页面
}else if(code === 400){
// Message.error({
// content: '缺少参数',
// duration: 3000
// });
}else if(code == 402){
// Message.error({
// content: '请求无权限',
// duration: 3000
// });
}else if(code == 201){
// Message.error({
// content: '账户状态异常',
// duration: 3000
// });
}else if(code==-1){
// Message.error({
// content: message,
// duration: 3000
// });
}
return response.data;
},
(error) => {
console.log("------------------");
console.log(error);
const { code, message } = error.response.data;
// 如果过期则退出登录
if(code == 60003)
{
// let back_url = window.location.href;
// window.location.href="https://wx.igandan.com/hcp/toLogin?back_url="+back_url;
}
else if (code === 401 || code==403 || code==405 || code==406) {
// Message.error({
// content: message,
// duration: 3000
// });
// // 重定向路由到登陆页面
// store.clearInfo();
// window.location.href="/login";
}else if(code === 400){
// Message.error({
// content: '缺少参数',
// duration: 3000
// });
}else if(code === 402){
// Message.error({
// content: '请求无权限',
// duration: 3000
// });
}else if(code === 201){
// Message.error({
// content: '账户状态异常',
// duration: 3000
// });
}else {
// Message.error({
// content: error.message,
// duration: 3000
// })
}
return Promise.reject(message);
}
);
// export const imgurl='http://47.105.52.114:8085/app/';
export const fromwexin='&from=wx';
export const frommywexin='?from=wx';
export const qrcodeurl='https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
export default service;

View File

@ -0,0 +1,97 @@
import wx from 'weixin-js-sdk'
import axios from 'axios'
let share = {
title: "",
desc: "",
link: "",
imgUrl: "",
init: function () {
var path = location.href.split('#')[0];
var url = "";
var appid = "";
if (path.indexOf("//wx.igandan.com") > 1 || path.indexOf("oss")>1||path.indexOf("prod")>1) {
url = "https://app.igandan.com/app/manager/getSignature4bing";
appid = "wxa4132ef4701ac5e4";
} else {
url = "https://dev-app.igandan.com/app/manager/getSignature4bing";
appid = "wx68affaa9d23528f8";
}
axios.get(url, {
params: {
path: encodeURIComponent(window.location.href.split('#')[0]),
appid: appid
}
}).then(json => {
wx.config({
debug:false,
appId: appid,
timestamp: json.data.timestamp,
nonceStr: json.data.nonceStr,
signature: json.data.signature,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage']
});
wx.checkJsApi({
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage'], // 需要检测的JS接口列表所有JS接口列表见附录2,
success: function (res) {
console.log(res)
}
});
wx.ready(function () {
wx.updateAppMessageShareData({
title: share.title,
desc: share.desc,
link: share.link,
imgUrl: share.imgUrl,
success: function () {}
})
wx.updateTimelineShareData({
title: share.title,
desc: share.desc,
link: share.link,
imgUrl: share.imgUrl,
success: function () {}
})
wx.onMenuShareTimeline({
title: share.title,
desc: share.desc,
link: share.link,
imgUrl: share.imgUrl,
success: function () {}
})
wx.onMenuShareAppMessage({
title: share.title,
desc: share.desc,
link: share.link,
imgUrl: share.imgUrl,
success: function () {}
})
});
}).catch((e) => {
console.log('获取数据失败');
});
}
}
function WXSHARE(title, desc, link, imgUrl) {
share.title = title;
share.desc = desc;
share.link = link;
if (imgUrl == undefined || imgUrl == "") {
imgUrl = "https://doc.igandan.com/app/html/img/2016/20160714132557.png";
}
share.imgUrl = imgUrl;
share.init();
};
export {
WXSHARE
}

View File

@ -0,0 +1,249 @@
<template>
<div style="background: #06247A;display: flex;flex-direction: column;min-height: 700px;">
<div>
<van-image
height="102"
fit="cover"
:src=IMG_PATH
/></div>
<div style="display:flex;justify-content: end;">
<div class="ranking">
<div class="no" v-if="rank<16">NO.{{ rank }}</div>
<div class="no" v-else>&nbsp;</div>
<div class="text1">{{ ticket }}</div>
<div class="text2">票数</div>
</div>
</div>
<div class="bg">
<div class="tiltle">{{ tiltles }}</div>
<div class="name">
<div v-for="auther in article_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
<div v-html="content" class="contents"></div>
</div>
</div>
<div class="buttomcla">
<div style="display: flex; justify-content: center;margin-top: 10px;">
<div class="text3" @click="goList()">去首页</div>
<votButton v-text="'投票'" @vote-click="vote" ></votButton>
</div>
</div>
<votView :show =show :shows =shows @onchange="handlechange" @onchanges="handlechange" :ticket=tickets ></votView>
</template>
<script setup >
import { useRouter,useRoute } from 'vue-router';
import { WXSHARE } from '../utils/wxshare-1.6.0';
import {fromwexin}from "@/utils/request"
import {saveurl} from'../utils/authorize.js'
const router = useRouter();
const route = useRoute();
const show = ref(false);
const shows = ref(false);
const rank = ref(1)
const ticket = ref('')
const tickets = ref('')
const tiltles = ref('')
const article_author = ref([]);
const id=ref('')
import {browse,votearticle,getarticle} from '../utils/api.js'
const IMG_PATH = import.meta.env.VITE_IMAGE_URL+'/static/images/1178172634346456.png'
onMounted(()=>{
console.log("ee",route.query.id)
id.value=route.query.id
initData(id.value)
updatBrowse()
saveurl('/articleDetails',route.query.id,route.query.name)
})
const content=ref('')
function goList(){
// if(window.location.href.includes("fromwx"))
// {
// router.push({ path: '/voteList'});
// }
// else
// {
// window.history.back();
// }
router.push({ path: '/voteList'});
}
function handlechange(){
show.value = false;
shows.value = false;
}
function vote(eventData){
if(eventData=='1')
{
votearticle(id.value).then((data) => {
console.log("votearticle",data)
if('200'==data.code)
{
shows.value=true;
}
else
{
showToast(data.message);
}
});
}
else
{
tickets.value = eventData;
show.value = true;
}
}
function initData(id)
{
getarticle(id).then((data) => {
console.log("getarticle",data)
const Share_PATH = import.meta.env.VITE_SHARE_URL+'articleDetails?id='+route.query.id+'&name='+encodeURIComponent(route.query.name);
WXSHARE("投我1票 | "+route.query.name, '2024第九届肝胆英雄榜最具影响力视频投票开始啦', Share_PATH+fromwexin,"");
rank.value = data.data.rank
ticket.value = data.data.vote_num
tiltles.value = data.data.article_title
content.value = data.data.article_content
article_author.value.push(...data.data.article_author)
});
}
function updatBrowse()
{
browse().then((data) => {
console.log("browse",data)
});
}
</script>
<style scoped>
.bg{
margin-top: -100px;
margin-left: 16px;
margin-right: 16px;
padding: 16px 16px 90px 16px;
min-height: 600px;
background: #FFFFFF;
border-radius: 12px 12px 0px 0px;
}
.ranking{
background: url(../assets/rank.png) no-repeat;
background-size: 100% 100%;
width: 80px;
height: 116px;
position: relative;
top: 8px;
margin-right: 32px;
}
.no{
margin-top: 5px;
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #7CEEFF;
line-height: 33px;
text-shadow: inset 1px 1px 0px rgba(255,255,255,0.5);
text-align: center;
font-style: normal;
}
.text1{
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #FFFFFF;
line-height: 33px;
text-shadow: 0px 2px 2px #00A9E6;
text-align: center;
font-style: normal;
}
.text2{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 22px;
text-shadow: 0px 2px 2px #00A9E6;
text-align: center;
font-style: normal;
}
.tiltle{
margin-right: 120px;
font-family: AlimamaShuHeiTi, AlimamaShuHeiTi;
font-weight: bold;
font-size: 20px;
color: #06247A;
line-height: 24px;
text-align: left;
font-style: normal;
}
.name{
margin-top: 8px;
margin-right: 120px;
font-family: AlibabaPuHuiTiR;
font-size: 14px;
color: #06247A;
line-height: 20px;
text-align: left;
font-style: normal;
white-space: pre-wrap;
}
.contents{
margin-top: 50px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0E3564;
line-height: 22px;
text-align: left;
font-style: normal;
word-break:break-all;
}
.buttomcla{
position: fixed;
bottom: 0;
height: 76px;
left: 16px;
right:16px;
background: #FFFFFF;
box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.1);
}
.text3{
width: 98px;
height: 56px;
background: #FFFFFF;
border-radius: 8px;
border: 1px solid #06247A;
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #06247A;
line-height: 56px;
margin-right: 8px;
text-align: center;
font-style: normal;
}
.contents :deep() img{
width:100%!important
}
.contents:deep() table{
width:100%;
}
</style>

196
src/views/home.vue Normal file
View File

@ -0,0 +1,196 @@
<template>
<headTop :num1=num1 :num2=num2 />
<div style="background: #06247A;display: flex;flex-direction: column;align-items: center;min-height: 700px">
<div :style="dynamicStyle">
<div style="display: flex;">
<div :style="style1" @click="changeinfo('大赛介绍')">肝胆英雄榜</div>
<div :style="style2" @click="changeinfo('投票规则')">投票规则</div>
</div>
<div v-html="content" class="contents" id="outerDiv"></div>
</div>
<div style="display: flex; justify-content: center;margin-top: 16px;">
<votButton v-text="'开始投票'" @vote-click="voet"></votButton>
</div>
<votView :show=show :ticket=ticket @onchange="handlechange" ></votView>
</div>
</template>
<script setup>
import jiesao from '../assets/jiesao.png'
import toupiao from '../assets/toupiao.png'
import { useRouter, useRoute } from 'vue-router';
import { agreement, votedata, browse } from '../utils/api.js'
import { WXSHARE } from '../utils/wxshare-1.6.0';
const num1 = ref(0);
const num2 = ref(0);
const router = useRouter();
const route = useRoute();
const show = ref(false);
const ticket =ref('');
const agreement_type = ref('1');
const dynamicStyle = ref({
'backgroundImage': 'url(' + jiesao + ')',
'background-size': '100% 100%',
// 'margin': '0px 16px 16px 16px',
'height': '428px',
'width': '343px',
'background-size': 'contain',
'background-repeat': 'no-repeat',
});
const style1 = ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight': 'bold',
'font-size': '20px',
'color': '#0E3564',
'line-height': '24px',
'flex': '1',
'text-align': 'center',
'margin-top': '11px'
})
const style2 = ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight': 'bold',
'font-size': '20px',
'color': '#FFFFFF',
'line-height': '24px',
'flex': '1',
'text-align': 'center',
'margin-top': '16px'
})
const content = ref('')
function changeinfo(name) {
if (name == '投票规则') {
agreement_type.value = '2'
dynamicStyle.value.backgroundImage = 'url(' + toupiao + ')'
style1.value.color = '#FFFFFF'
style2.value.color = '#0E3564'
style1.value.marginTop = '16px'
style2.value.marginTop = '11px'
} else {
agreement_type.value = '1'
dynamicStyle.value.backgroundImage = 'url(' + jiesao + ')'
style1.value.color = '#0E3564'
style2.value.color = '#FFFFFF'
style1.value.marginTop = '11px'
style2.value.marginTop = '16px'
}
document.getElementById('outerDiv').scrollTop=0;
initData()
}
function initData() {
agreement(agreement_type.value).then((data) => {
console.log("agreement", data)
content.value = data.data.agreement_content
});
votedata().then((data) => {
console.log("votedata", data)
num1.value = data.data.view_num
num2.value = data.data.vote_num
});
}
function updatBrowse() {
browse().then((data) => {
console.log("browse", data)
});
}
const Share_PATH = import.meta.env.VITE_SHARE_URL+'home';
function switchurl()
{
const urll=localStorage.getItem('gotourls');
const id=localStorage.getItem('gotourlids');
if(typeof urll === "undefined"||urll ==null|| urll == ""|| urll == "undefined")
{
}
else
{
if(typeof id === "undefined"||id ==null|| id == ""|| id == "undefined")
{
router.push({ path: urll });
}
else
{
router.push({ path: urll ,query:{id:id,name:localStorage.getItem('gotourlnames')}});
}
localStorage.setItem('gotourls','');
localStorage.setItem('gotourlids','');
localStorage.setItem('gotourlnames','');
return
}
}
onMounted(() => {
if(window.location.href.includes('qrcode'))
{
switchurl()
}
initData()
updatBrowse()
WXSHARE('2024第九届肝胆英雄榜最具影响力视频投票开始啦', '就差你一票~助力喜欢的专家或者视频上"肝胆英雄榜"', Share_PATH,"")
})
function voet(eventData) {
console.log("eventData",eventData)
if(eventData=='1')
{
go()
}
else
{
ticket.value = eventData;
show.value = true;
}
}
function go() {
router.push({ path: '/voteList' });
}
function handlechange() {
show.value = false;
}
</script>
<style scoped>
.contents {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0E3564;
line-height: 22px;
text-align: left;
font-style: normal;
height: 350px;
margin: 20px 16px 16px 16px;
overflow-y: auto;
/* 允许垂直滚动 */
word-wrap: break-word;
/* 防止长单词溢出容器 */
}
.contents :deep() img{
width:100%!important
}
</style>

329
src/views/videoDetails.vue Normal file
View File

@ -0,0 +1,329 @@
<template>
<div style="background: #06247A;display: flex;flex-direction: column;min-height: 700px;">
<div>
<van-image
height="102"
fit="cover"
:src=IMG_PATH
/></div>
<div style="display:flex;justify-content: end;">
<div class="ranking">
<div class="no" v-if="rank<16">NO.{{ rank }}</div>
<div class="no" v-else>&nbsp;</div>
<div class="text1">{{ ticket }}</div>
<div class="text2">票数</div>
</div>
</div>
<div class="bg">
<div class="tiltle">{{ tiltles }}</div>
<div class="name">
<div v-for="auther in article_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
<div id="player" class="contents" ></div>
<div class="contents" v-html="content"></div>
</div>
</div>
<div class="buttomcla">
<div style="display: flex; justify-content: center;margin-top: 10px;">
<div class="text3" @click="goList()">去首页</div>
<votButton v-text="'投票'" @vote-click="vote" ></votButton>
</div>
</div>
<votView :show =show :shows =shows @onchange="handlechange" @onchanges="handlechange" :ticket=tickets ></votView>
</template>
<script setup >
import { useRouter,useRoute } from 'vue-router';
import { WXSHARE } from '../utils/wxshare-1.6.0';
import {fromwexin}from "@/utils/request"
import {saveurl} from'../utils/authorize.js'
const router = useRouter();
const route = useRoute();
const show = ref(false);
const shows = ref(false);
const rank = ref(1)
const ticket = ref('')
const tickets = ref('')
const tiltles = ref('')
const article_author = ref([]);
const id=ref('')
const video_author_t=ref("")
import {browse,votevideo,getvideo} from '../utils/api.js'
const IMG_PATH = import.meta.env.VITE_IMAGE_URL+'/static/images/1178172634346456.png'
const players = ref([])
const playerJs=ref('//player.polyv.net/script/player.js')
const vid = ref('')
function loadPlayerScript(callback) {
if (!window.polyvPlayer) {console.log("首次加载视频信息")
const myScript = document.createElement('script');
myScript.setAttribute('src', playerJs.value);
myScript.onload = callback;
document.body.appendChild(myScript);
}else{
callback()
}
}
function loadPlayer() {
const polyvPlayer = window.polyvPlayer;
const player = polyvPlayer({
wrap: '#player',
width: "100%",
height: 210,
forceH5:true,
height:'',
df:3,
vid: vid.value ,
});
players.value.push(player)
}
onBeforeMount(()=>{
//IOS
// IOS
// let agent = navigator.userAgent
// alert('agent'+agent)
// let isIOS = !!agent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios
// alert('isIOS'+isIOS)
// alert('11'+sessionStorage.getItem('isShareState'))
// if(isIOS && !sessionStorage.getItem('isShareState')){
// alert('777')
// sessionStorage.setItem('isShareState',true)
// window.location.reload();
// }
// else
// {
// alert('666')
// }
})
onMounted(()=>{
console.log("ee",route.query.id)
id.value=route.query.id
// video_author.value=route.query.video_author
initData(id.value)
updatBrowse()
saveurl('/videoDetails',route.query.id,route.query.name)
})
onUnmounted(()=>{
sessionStorage.removeItem('isShareState');
console.log("销毁播放器")
if(players.value.length > 0){
players.value.forEach((item)=>{
item.destroy();
})
}
})
const content=ref('')
function goList(){
// if(window.location.href.includes("fromwx"))
// {
// router.push({ path: '/voteList'});
// }
// else
// {
// window.history.back();
// }
router.push({ path: '/voteList'});
}
function handlechange(){
show.value = false;
shows.value = false;
}
function vote(eventData){
if(eventData=='1')
{
votevideo(id.value).then((data) => {
console.log("votearticle",data)
if('200'==data.code)
{
shows.value=true;
}
else
{
showToast(data.message);
}
});
}
else
{
tickets.value = eventData;
show.value = true;
}
}
function initData(id)
{
getvideo(id).then((data) => {
const Share_PATH = import.meta.env.VITE_SHARE_URL+'videoDetails?id='+route.query.id+'&name='+ encodeURIComponent(route.query.name)
// +'&author='+ encodeURIComponent(route.query.author);
console.log("getvideo",data)
rank.value = data.data.rank
ticket.value = data.data.vote_num
tiltles.value = data.data.video_title
content.value = data.data.video_content
vid.value = data.data.video_no
console.log(vid.value)
article_author.value.push(...data.data.video_author)
video_author_t.value=""
if(article_author.value!=null&&article_author.value!='')
{
article_author.value.forEach((auther)=>{
video_author_t.value=video_author_t.value+ auther.author_name+"、"
})
video_author_t.value=video_author_t.value.slice(0, -1);
}
WXSHARE("投我1票 | "+video_author_t.value+""+route.query.name, '2024第九届肝胆英雄榜最具影响力视频投票开始啦', Share_PATH,"");
}).then(()=>{
console.log("加载视频信息")
loadPlayerScript(loadPlayer);
});
}
function updatBrowse()
{
browse().then((data) => {
console.log("browse",data)
});
}
</script>
<style scoped>
.bg{
margin-top: -100px;
margin-left: 16px;
margin-right: 16px;
padding: 16px 16px 90px 16px;
min-height: 600px;
background: #FFFFFF;
border-radius: 12px 12px 0px 0px;
}
.ranking{
background: url(../assets/rank.png) no-repeat;
background-size: 100% 100%;
width: 80px;
height: 116px;
position: relative;
top: 8px;
margin-right: 32px;
}
.no{
margin-top: 5px;
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #7CEEFF;
line-height: 33px;
text-shadow: inset 1px 1px 0px rgba(255,255,255,0.5);
text-align: center;
font-style: normal;
}
.text1{
font-family: AlibabaPuHuiTiH;
font-size: 24px;
color: #FFFFFF;
line-height: 33px;
text-shadow: 0px 2px 2px #00A9E6;
text-align: center;
font-style: normal;
}
.text2{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 22px;
text-shadow: 0px 2px 2px #00A9E6;
text-align: center;
font-style: normal;
}
.tiltle{
margin-right: 120px;
font-family: AlimamaShuHeiTi, AlimamaShuHeiTi;
font-weight: bold;
font-size: 20px;
color: #06247A;
line-height: 24px;
text-align: left;
font-style: normal;
}
.name{
margin-top: 8px;
margin-right: 120px;
font-family: AlibabaPuHuiTiR;
font-size: 14px;
color: #06247A;
line-height: 20px;
text-align: left;
font-style: normal;
white-space: pre-wrap;
}
.contents{
margin-top: 50px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0E3564;
line-height: 22px;
text-align: left;
font-style: normal;
word-break:break-all;
}
.buttomcla{
position: fixed;
bottom: 0;
height: 76px;
left: 16px;
right:16px;
background: #FFFFFF;
box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.1);
}
.text3{
width: 98px;
height: 56px;
background: #FFFFFF;
border-radius: 8px;
border: 1px solid #06247A;
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #06247A;
line-height: 56px;
margin-right: 8px;
text-align: center;
font-style: normal;
}
.contents :deep() img{
width:100%!important
}
.contents:deep() table{
width:100%;
}
</style>

737
src/views/voteList.vue Normal file
View File

@ -0,0 +1,737 @@
<template>
<headTop :num1=num1 :num2=num2 />
<div style="background: #DEF6FF; ">
<div style="background: #06247A;">
<div :style="dynamicStyle">
<div style="display: flex;" >
<div :style="style1" @click="changeinfo('开始投票')">开始投票</div>
<div :style="style2" @click="changeinfo('线上排名')">线上排名</div>
</div>
</div>
</div>
<div style="display: flex;flex-direction: column;align-items: center;margin-top: 12px;" v-if="1>2" >
<div :style="dynamicStyle1" >
<div style="display: flex;" >
<div :style="style3" @click="changeinfo('图文类投稿')">图文类投稿</div>
<div :style="style4" @click="changeinfo('视频类投稿')">视频类投稿</div>
</div>
</div>
</div>
<div style="display: flex;margin-top: 12px;align-items: center;justify-content: center;margin-left: 16px;margin-right: 16px;"
v-show="voting">
<div class="text1">*每个视频每天限投1票</div>
<div class="divsearch">
<van-image width="20" height="20" :src=search style="margin-left: 12px;" />
<input placeholder="搜索作者、医院、名称或编号" type="text" v-model="inputValue" @input="debouncedInputHandler()">
</div>
</div>
<div v-if="(istuwen&&list.length>0)||(!istuwen&&listvideo.length>0)||needrequestdata">
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=""
@load="onLoad"
>
<div v-for="(item,$index) of list" :key="item.article_id" v-if="istuwen">
<div v-if="voting" class="litme">
<div class="numberss" v-if="$index==0" :style=Style11>{{ item.article_number }}</div>
<div class="numberss" v-else-if="$index==1" :style=Style12>{{ item.article_number }}</div>
<div class="numberss" v-else-if="$index==2" :style=Style13>{{ item.article_number }}</div>
<div class="numberss" v-else :style=Style14>{{ item.article_number }}</div>
<div style="display: flex;margin-top: 6px;padding-bottom: 16px;align-items: center;">
<div class="letfdiv" @click="gotoDetails(item.article_id,item.article_title,item.article_author)">
<div class="title">{{ item.article_title }}</div>
<div>
<div class='name'>
<div v-for="auther in item.article_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
</div>
</div>
<div class="rightdiv" >
<div class="title">{{item.vote_num}}</div>
<div>
<div class='toubg' :style="{background:'linear-gradient( 180deg, #D8D8D8 0%, #959595 100%)'}" v-if="item.is_vote">
投票
</div>
<div class='toubg' :style="{background:'linear-gradient( 180deg, #51EAFF 0%, #00B9FF 100%)'}" @click="vote(item.article_id,$index)" v-else>
投票
</div>
</div>
</div>
</div>
</div>
<div v-else class="litmev">
<div style="display: flex;align-items: center;width: 100%;">
<div class="numbers" v-if="item.rank==1" :style=Style1 ></div>
<div class="numbers" v-else-if="item.rank==2" :style=Style2 ></div>
<div class="numbers" v-else-if="item.rank==3" :style=Style3></div>
<div class="numbers1" v-else >{{ item.rank}}</div>
<div style="display: flex;align-items: center;flex: 1;">
<div class="letfdiv" @click="gotoDetails(item.article_id,item.article_title,item.article_author)">
<div class="title">{{ item.article_title }}</div>
<div>
<div class='name'>
<div v-for="auther in item.article_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
</div>
</div>
<div class="rightdiv">
<div class="toubg1">{{item.vote_num}}</div>
</div>
</div>
</div>
</div>
</div>
<div v-for="(item,$index) of listvideo" :key="item.video_id" v-else>
<div v-if="voting" class="litme">
<div class="numberss" v-if="$index==0" :style=Style11>{{ item.video_number }}</div>
<div class="numberss" v-else-if="$index==1" :style=Style12>{{ item.video_number }}</div>
<div class="numberss" v-else-if="$index==2" :style=Style13>{{ item.video_number }}</div>
<div class="numberss" v-else :style=Style14>{{ item.video_number }}</div>
<div style="display: flex;margin-top: 6px;padding-bottom: 16px;align-items: center;">
<div class="letfdiv" @click="gotoDetails(item.video_id ,item.video_title,item.video_author)">
<div class="title">{{ item.video_title }}</div>
<div>
<div class='name'>
<div v-for="auther in item.video_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
</div>
</div>
<div class="rightdiv">
<div class="title">{{item.vote_num}}</div>
<div>
<div class='toubg' :style="{background:'linear-gradient( 180deg, #D8D8D8 0%, #959595 100%)'}" v-if="item.is_vote">
投票
</div>
<div class='toubg' :style="{background:'linear-gradient( 180deg, #51EAFF 0%, #00B9FF 100%)'}" @click="vote(item.video_id,$index)" v-else>
投票
</div>
</div>
</div>
</div>
</div>
<div v-else class="litmev">
<div style="display: flex;align-items: center;width: 100%;">
<div class="numbers" v-if="item.rank==1" :style=Style1 ></div>
<div class="numbers" v-else-if="item.rank==2" :style=Style2 ></div>
<div class="numbers" v-else-if="item.rank==3" :style=Style3></div>
<div class="numbers1" v-else >{{ item.rank}}</div>
<div style="display: flex;align-items: center;flex: 1;">
<div class="letfdiv" @click="gotoDetails(item.video_id,item.video_title ,item.video_author)">
<div class="title">{{ item.video_title }}</div>
<div>
<div class='name'>
<div v-for="auther in item.video_author">
<div>{{ auther.author_name}}&nbsp;{{ auther.hospital_name }}</div>
</div>
</div>
</div>
</div>
<div class="rightdiv" >
<div class="toubg1">{{item.vote_num}}</div>
</div>
</div>
</div>
</div>
</div>
</van-list>
</van-pull-refresh>
</div>
<div style="margin-top: 16px;height: 700px;" v-else>
<van-empty description="暂无数据" />
</div>
<votView :show =show :shows =shows @onchange="handlechange" @onchanges="handlechange" :ticket=tickets ></votView>
</div>
</template>
<script setup >
import first from '../assets/first.png'
import second from '../assets/second.png'
import third from '../assets/third.png'
import jiesao from '../assets/paiming1.png'
import toupiao from '../assets/toupiao1.png'
import tuwen from '../assets/tuwen.png'
import shipin from '../assets/shipin.png'
import search from '../assets/search.png'
import { goAuth } from '../utils/authorize.js'
import {votedata,browse,articlepage,videopage,rankarticle,rankvideo,votearticle,votevideo} from '../utils/api.js'
import { useRouter,useRoute } from 'vue-router';
import { debounce } from 'lodash';
import { WXSHARE } from '../utils/wxshare-1.6.0';
import {saveurl} from'../utils/authorize.js'
const inputValue=ref('');
const show = ref(false);
const shows = ref(false);
const voting = ref(true);
// const istuwen = ref(true);
const istuwen = ref(false);//
const num1 = ref(0);
const num2 = ref(0);
const router = useRouter();
const route = useRoute();
const needrequestdata = ref(true);
const Style11 = ref({
'background': 'linear-gradient( 180deg, #FE1B28 0%, #FD5C65 100%)'
});
const Style12 = ref({
'background': 'linear-gradient( 180deg, #FF6623 0%, #FE824D 100%)'
});
const Style13 = ref({
'background': 'linear-gradient( 180deg, #FEB903 0%, #FEC93D 100%)'
});
const Style14 = ref({
'background': '#F0AA99'
});
const Style1 = ref({
'backgroundImage': 'url(' + first + ')',
});
const Style2 = ref({
'backgroundImage': 'url(' + second + ')',
});
const Style3 = ref({
'backgroundImage': 'url(' + third + ')',
});
const dynamicStyle = ref({
'backgroundImage':'url('+toupiao+')',
'height': '48px',
'background-size': 'cover',
'background-repeat': 'no-repeat',
});
const style1=ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight':'bold',
'font-size': '20px',
'color': '#0E3564',
'line-height': '24px',
'flex': '1',
'text-align': 'center',
'margin-top': '11px'
})
const style2=ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight':'bold',
'font-size': '20px',
'color': '#FFFFFF',
'line-height': '24px',
'flex': '1',
'text-align': 'center',
'margin-top': '16px'
})
const dynamicStyle1 = ref({
'backgroundImage':'url('+tuwen+')',
'background-size': '100% 100%',
'height': '40px',
'width':'344px',
'background-size': 'contain',
'background-repeat': 'no-repeat',
});
const style3=ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight':'bold',
'font-size': '16px',
'color': '#FFFFFF',
'line-height': '40px',
'flex': '1',
'text-align': 'center',
})
const style4=ref({
'font-family': 'AlimamaShuHeiTi',
'font-weight':'bold',
'font-size': '16px',
'color': '#07ADEB',
'line-height': '40px',
'flex': '1',
'text-align': 'center',
})
function changeinfo(name){
if(name=='开始投票'){
dynamicStyle.value.backgroundImage = 'url('+toupiao+')'
style1.value.color='#0E3564'
style2.value.color='#FFFFFF'
style1.value.marginTop='11px'
style2.value.marginTop='16px'
voting.value=true
}else if(name=='线上排名'){
dynamicStyle.value.backgroundImage = 'url('+jiesao+')'
style1.value.color='#FFFFFF'
style2.value.color='#0E3564'
style1.value.marginTop='16px'
style2.value.marginTop='11px'
voting.value=false
}
else if(name=='图文类投稿'){
dynamicStyle1.value.backgroundImage = 'url('+tuwen+')'
style3.value.color='#FFFFFF'
style4.value.color='#07ADEB'
istuwen.value=true
}else if(name=='视频类投稿'){
dynamicStyle1.value.backgroundImage = 'url('+shipin+')'
style3.value.color='#07ADEB'
style4.value.color='#FFFFFF'
istuwen.value=false
}
refreshing.value=true;
onRefresh();
}
const debouncedInputHandler = debounce(() => {
//
console.log('Input value changed:', inputValue.value);
refreshing.value=true;
onRefresh();
}, 1500);
const list = ref([]);
const listvideo = ref([]);
const loading = ref(false);
const finished = ref(false);
const refreshing = ref(false);
const tickets = ref('');
const page = ref(1);
const onLoad = () => {
setTimeout(() => {
if (refreshing.value) {
list.value = [];
listvideo.value = [];
refreshing.value = false;
}
if(voting.value)
{
if(istuwen.value)
{
gotoarticlepage()
}
else
{
gotovideopage()
}
}
else{
if(istuwen.value)
{
gotorankarticle()
}
else
{
gotorankvideo()
}
}
}, 100);
};
const onRefresh = () => {
needrequestdata.value=true;
//
finished.value = false;
page.value=1;
// refreshing.value=true;
//
// loading true
loading.value = true;
onLoad();
};
const video_author_t=ref("")
function vote(id,index)
{
const token=localStorage.getItem('bearer-tokens');
if(typeof token === "undefined"||token ==null|| token == ""|| token == "undefined")
{
const ticket= localStorage.getItem('qr-tickets');
if(typeof ticket === "undefined"||ticket ==null|| ticket == ""|| ticket == "undefined")
{
goAuth()
}
else
{
tickets.value=ticket;
show.value=true;
localStorage.setItem('qr-tickets', "");
}
return;
}
if(istuwen.value)
{
votearticle(id).then((data) => {
console.log("votearticle",data)
if('200'==data.code)
{
shows.value=true;
list.value[index].vote_num=list.value[index].vote_num+1;
list.value[index].is_vote=true;
// refreshing.value=true;
// onRefresh();
}
else
{
showToast(data.message);
}
});
}
else
{
votevideo(id).then((data) => {
console.log("votevideo",data)
if('200'==data.code)
{
shows.value=true;
listvideo.value[index].vote_num=listvideo.value[index].vote_num+1;
listvideo.value[index].is_vote=true;
// refreshing.value=true;
// onRefresh();
}
else
{
// showToast(data.massage);
showToast(data.message+"");
}
});
}
}
function gotoDetails(id,name,video_authors)
{
if(istuwen.value)
{
router.push({ path: '/articleDetails' ,query:{id:id,name:name}})
}
else
{
// video_author_t.value=""
// if(video_authors!=null&&video_authors!='')
// {
// video_authors.forEach((auther)=>{
// video_author_t.value=video_author_t.value+ auther.author_name+""
// })
// video_author_t.value=video_author_t.value.slice(0, -1);
// }
router.push({ path: '/videoDetails' ,query:{id:id,name:name}})
}
}
function handlechange(){
show.value = false;
shows.value = false;
}
function initData()
{
votedata().then((data) => {
console.log("votedata",data)
num1.value = data.data.view_num
num2.value = data.data.vote_num
});
}
function updatBrowse()
{
browse().then((data) => {
console.log("browse",data)
});
}
function gotoarticlepage()
{
articlepage(page.value,10,inputValue.value).then((data) => {
needrequestdata.value=false;
console.log("articlepage",data)
loading.value = false;
list.value.push(...data.data.data);
if (data.data.data.length < 10) {
finished.value = true;
return;
}
page.value++
});
}
function gotovideopage()
{
videopage(page.value,10,inputValue.value).then((data) => {
needrequestdata.value=false;
console.log("videopage",data)
loading.value = false;
listvideo.value.push(...data.data.data);
if (data.data.data.length < 10) {
finished.value = true;
return;
}
page.value++
});
}
function gotorankarticle()
{
rankarticle().then((data) => {
needrequestdata.value=false;
console.log("rankarticle",data)
loading.value = false;
finished.value = true;
list.value.push(...data.data);
});
}
function gotorankvideo()
{
rankvideo(page.value,10,inputValue.value).then((data) => {
needrequestdata.value=false;
console.log("rankvideo",data)
loading.value = false;
finished.value = true;
listvideo.value.push(...data.data);
});
}
const Share_PATH = import.meta.env.VITE_SHARE_URL+'home';
onMounted(() => {
initData()
updatBrowse()
WXSHARE('2024第九届肝胆英雄榜最具影响力视频投票开始啦', '就差你一票~助力喜欢的专家或者视频上"肝胆英雄榜"', Share_PATH,"")
saveurl('/voteList','','')
})
</script>
<style scoped>
.text1{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0E3564;
line-height: 17px;
text-align: left;
font-style: normal;
}
input {
margin-left: 5px;
margin-right: 5px;
font-size: 12px;
background: transparent;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
outline: none;
flex: 1;
font-family: PingFangSC, PingFang SC;;
color: rgba(0,0,0,0.65);
}
input:focus {
margin-left: 5px;
margin-right: 5px;
font-size: 12px;
background: transparent;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
outline: none;
flex: 1;
font-family: PingFangSC, PingFang SC;;
color: rgba(0,0,0,0.65);
}
.divsearch {
display: flex;
flex: 1;
margin-left: 8px;
height: 32px;
background: #FFFFFF;
border-radius: 21px;
align-items: center;
justify-content: center;
}
.litme{
margin: 12px 16px;
min-height: 109px;
background: #FFFFFF;
border-radius: 12px;
}
.litmev{
margin: 12px 16px;
padding-top: 16px;
padding-bottom: 16px;
min-height: 93px;
background: #FFFFFF;
border-radius: 12px;
display: flex;
align-items: center;
}
.numbers{
width: 32px;
height: 36px;
margin-left: 12px;
font-family: AlibabaPuHuiTiB;
font-size: 14px;
color: rgba(0,0,0,0.65);
font-weight: bold;
line-height: 36px;
text-align: center;
font-style: normal;
background-size:cover;
background-repeat: no-repeat;
}
.numbers1{
width: 32px;
height: 32px;
margin-left: 12px;
font-family: AlibabaPuHuiTiB;
font-size: 14px;
color: rgba(0,0,0,0.65);
font-weight: bold;
line-height: 32px;
border-radius:32px;
background: #EFEFEF;
text-align: center;
font-style: normal;
background-size:cover;
background-repeat: no-repeat;
}
.numberss{
width: 70px;
height: 30px;
border-radius: 12px 0px 16px 0px;
font-family: AlibabaPuHuiTiB;
font-size: 16px;
color: #FFFFFF;
line-height: 30px;
text-align: center;
font-style: normal;
}
.title{
font-family: AlibabaPuHuiTiB;
font-size: 16px;
color: #0E3564;
line-height: 26px;
text-align: left;
font-style: normal;
font-weight: bold;
margin-bottom: 4px;
}
.name{
margin-top: 2px;
font-family: AlibabaPuHuiTiR;
font-size: 14px;
color: #0E3564;
line-height: 20px;
text-align: left;
font-style: normal;
white-space: pre-wrap;
}
.letfdiv{
margin-left: 16px;
flex: 1;
}
.rightdiv{
margin-right: 16px;
margin-left: 16px;
display: flex;
flex-direction: column;
align-items: center;
min-width: 50px;
}
.toubg1{
font-family: AlibabaPuHuiTiB;
font-size: 20px;
color: #0BBDFF;
line-height: 27px;
text-align: center;
font-style: normal;
}
.toubg{
margin-top: 5px;
width: 80px;
height: 40px;
/* background: linear-gradient( 180deg, #51EAFF 0%, #00B9FF 100%); */
box-shadow: inset 2px 2px 5px 0px rgba(255,255,255,0.5);
border-radius: 20px;
font-family: AlimamaShuHeiTi, AlimamaShuHeiTi;
font-weight: bold;
font-size: 16px;
color: #FFFFFF;
line-height: 40px;
/* text-shadow: 0px 2px 2px #00A9E6; */
text-align: center;
font-style: normal;
}
</style>

4838
stats.html Normal file

File diff suppressed because one or more lines are too long

104
vite.config.js Normal file
View File

@ -0,0 +1,104 @@
import {
join
} from 'path'
import {
defineConfig
} from 'vite';
import vue from '@vitejs/plugin-vue';
import {
VuetifyResolver
} from 'unplugin-vue-components/resolvers';
import Components from 'unplugin-vue-components/vite';
import AutoImport from 'unplugin-auto-import/vite';
import viteCompression from 'vite-plugin-compression'
import { visualizer } from 'rollup-plugin-visualizer' //查看项目的依赖
import { createHtmlPlugin } from 'vite-plugin-html'
import { VantResolver } from '@vant/auto-import-resolver';
export default defineConfig(({ command }) => {
return {
base: command === 'build' ? './' : '/web/v',
plugins: [
vue(),
AutoImport({
// 自动导入 Vue 相关函数ref, reactive, toRef 等
imports: ['vue'],
resolvers: [VantResolver()],
}),
visualizer({
open: false
}),
// 将下面的添加到plugin下
createHtmlPlugin({
minify: true,
inject: {
data: {
title: '肝胆英雄榜最具影响力视频投票',
}
}
}),
Components({
resolvers: [VuetifyResolver()],
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
dirs: ['src/components', 'src/views'],
resolvers: [VantResolver()],
}),
],
build: {
assetsInlineLimit: 4096, // 图片转 base64 编码的阈值
minify: 'terser',
plugins: [
viteCompression({
threshold: 1024000 // 对大于 1mb 的文件进行压缩
}),
],
// rollup 配置
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'static/js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
manualChunks(id) {
// 如果不同模块使用的插件基本相同那就尽可能打包在同一个文件中减少http请求如果不同模块使用不同插件明显那就分成不同模块打包。这是一个矛盾体。
// 这里使用的是最小化拆分包。如果是前者可以直接选择返回'vendor'。
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString(); //让打开那个页面加载那个页面的js ,让之间的关联足够小
// return 'vendor' 如果不同模块使用的插件基本相同那就尽可能打包在同一个文件中减少http请求;
}
}
}
},
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
},
resolve: {
alias: {
'@': join(__dirname, 'src'),
}
},
server: {
host: true,
port: 1798,
//secure: false,
proxy: {
// '/api': {
//   target: 'https://vue3.go-admin.dev',
//   changeOrigin: true,             //开启跨域
//   rewrite: (path) => path.replace(/^\/api/, '')
// },
'/api': {
target: 'https://prod-vote.igandan.com',
changeOrigin: true, //开启跨域
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
publicDir: '/public'
}
});