469 lines
13 KiB
Vue
469 lines
13 KiB
Vue
<template>
|
|
<div class="wrapper">
|
|
<!-- 广告轮播 -->
|
|
<SplashAdvSwiper
|
|
class="advSwiper"
|
|
:autoTime="2500"
|
|
:list="state.launchInfo"
|
|
:isShowIndicators="state.launchInfo && state.launchInfo.length >= 2"
|
|
v-if="state.launchInfo && state.launchInfo.length"
|
|
/>
|
|
<div class="countdown" v-if="state.countdown >= 0">
|
|
<span v-show="state.countdown > 0">{{ state.countdown }}</span>
|
|
<div class="jump_over" v-show="state.countdown <= 0" @click="goApp">跳过</div>
|
|
</div>
|
|
<EnterGroupPopup v-if="state.isCheckError" />
|
|
<!-- <UpgradePopup :show="state.isUpgrade" /> -->
|
|
<div class="selectLineBox" v-if="state.loading">
|
|
<van-loading color="#1989fa" size="30" />
|
|
<div class="selectLine">选线中...</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { AdType, SourceType } from '@/enums/app';
|
|
import AppApi from '@/service/app';
|
|
import { useAppStore } from '@/stores/app';
|
|
import { useConfigStore } from '@/stores/config';
|
|
import { useUserStore } from '@/stores/user';
|
|
import { getDevType } from '@/utils';
|
|
import { getAdItem } from '@/utils/getConfig';
|
|
import { showDialog } from 'vant';
|
|
import { reactive } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { jumpAdv } from '@/utils/index';
|
|
import { useGlobalStore } from '@/stores/global';
|
|
import setTheme from '@/assets/theme/index';
|
|
import { markHomeOldUserGuidePendingFromSplash } from '@/utils/paymentGuide';
|
|
import { detectLine } from '@/utils/detectLine';
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const appStore = useAppStore();
|
|
const userStore = useUserStore();
|
|
const configStore = useConfigStore();
|
|
const globalStore = useGlobalStore();
|
|
const state = reactive({
|
|
countdown: -1, //广告倒计时
|
|
launchInfo: <Array<Types.App.AdsInfoListItem>>[], //广告
|
|
timer: <any>null, //广告定时器
|
|
checkTimer: <any>null, //检测图片是否加载成功定时器
|
|
checkTime: 3, //图片加载成功检测时间
|
|
isCheckError: false, //是否选线失败
|
|
checkLineErrorNum: 0, //选线失败次数
|
|
isResLock: false, // 请求结果锁
|
|
loading: true, // 选线loading
|
|
isUpgrade: true, //是否升级
|
|
});
|
|
|
|
/**
|
|
* @description 检测广告图片是否加载成功
|
|
*/
|
|
const checkImgLoad = () => {
|
|
state.checkTimer = setInterval(() => {
|
|
if (state.checkTime <= 0) {
|
|
clearInterval(state.checkTimer);
|
|
state.checkTimer = null;
|
|
if (!state.timer) {
|
|
countdownStrat();
|
|
}
|
|
return;
|
|
}
|
|
state.checkTime--;
|
|
}, 1000);
|
|
};
|
|
|
|
/**
|
|
* @description 广告失败
|
|
*/
|
|
const imgError = () => {
|
|
if (!state.timer) {
|
|
countdownStrat();
|
|
if (state.checkTimer) {
|
|
clearInterval(state.checkTimer);
|
|
state.checkTimer = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @description 广告加载成功
|
|
*/
|
|
const imgLoad = () => {
|
|
if (!state.timer) {
|
|
countdownStrat();
|
|
if (state.checkTimer) {
|
|
clearInterval(state.checkTimer);
|
|
state.checkTimer = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @description 启动倒计时
|
|
*/
|
|
const countdownStrat = () => {
|
|
state.loading = false;
|
|
state.countdown = 3;
|
|
// 倒计时期间预取壳页,缩短跳过/倒计时结束后的等待(不改 3s 时长)
|
|
void import('@/views/MainView.vue');
|
|
const entry = String(configStore.appConfig?.defaultEntryPage || '').toLowerCase();
|
|
if (entry === 'drama') {
|
|
void import('@/views/shortVideo/index.vue');
|
|
} else {
|
|
void import('@/views/lldhome/index.vue');
|
|
}
|
|
userStore.updateWallet(); // 获取用户钱包
|
|
globalStore.setTabs(); // 获取tabs数据
|
|
globalStore.setAnnounce(); // 获取跑马灯数据
|
|
// 预售活动开启了,获取预售信息
|
|
if (configStore.appConfig.advanceStatus && configStore.appConfig.advanceStatus.activityStatus) {
|
|
globalStore.setPresaleActivityDetail();
|
|
}
|
|
globalStore.setVideoRoadLine(configStore.sourceInfo.VID[0]); // 默认选择第一个线路
|
|
state.timer = setInterval(() => {
|
|
if (state.countdown <= 0) {
|
|
clearInterval(state.timer);
|
|
} else {
|
|
state.countdown--;
|
|
}
|
|
}, 1000);
|
|
};
|
|
|
|
/**
|
|
* @description 开机广告
|
|
*/
|
|
function adControl() {
|
|
const launchList = getAdItem(AdType.START);
|
|
if (launchList.length > 0) {
|
|
state.launchInfo = launchList;
|
|
}
|
|
// checkImgLoad();
|
|
countdownStrat();
|
|
}
|
|
|
|
/**
|
|
* @description 进入APP
|
|
*/
|
|
const goApp = () => {
|
|
const entry = String(configStore.appConfig?.defaultEntryPage || '').toLowerCase();
|
|
if (entry === 'drama') {
|
|
// 默认进短剧:不走首页老用户吸底引导
|
|
router.replace({ path: '/shortVideo', query: { type: '4' } });
|
|
} else {
|
|
// 仅启动页进首页允许弹老用户吸底;首页消费该标记
|
|
markHomeOldUserGuidePendingFromSplash();
|
|
router.replace('/home');
|
|
}
|
|
let createAt = new Date(userStore.userInfo.createdAt).getTime();
|
|
let now = Date.now();
|
|
if (now - createAt > configStore.appConfig?.newbieSaleTime * 60 * 60 * 1000 && now - createAt > 3600000 * 24) {
|
|
getFirstLoginTime();
|
|
}
|
|
};
|
|
const getFirstLoginTime = () => {
|
|
const key = `first_login_time_${userStore.userInfo.uid}`; // userId 是登录用户的唯一标识
|
|
let firstLoginTime = localStorage.getItem(key);
|
|
firstLoginTime = Date.now().toString();
|
|
localStorage.setItem(key, firstLoginTime);
|
|
};
|
|
|
|
const toAdv = (item: any) => {
|
|
jumpAdv(item, 'ads');
|
|
};
|
|
|
|
/**
|
|
* @description 如果没有用户ID就生成一个
|
|
*/
|
|
const generateUid = () => {
|
|
if (!appStore.uid) {
|
|
// 配合商店包,如果链接中存在设备ID,就当作uuid,没有就使用自动生成的
|
|
if (route.query.uuid && JSON.stringify(route.query.uuid).indexOf('null') == -1) {
|
|
appStore.setUid(route.query.uuid.toString());
|
|
} else {
|
|
appStore.generateUid();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @description 登陆
|
|
* @returns 是否登陆成功
|
|
*/
|
|
const login = async (): Promise<boolean> => {
|
|
try {
|
|
const uid = appStore.uid;
|
|
const sysType = getDevType();
|
|
const isAppStore = route.query.isAppStore ? true : false;
|
|
let cutInfos: any = undefined;
|
|
// 判断是否来自商店包
|
|
if (isAppStore) {
|
|
// 判断是否有pc值,也就是粘贴板是否有内容
|
|
const pcStr: any = route.query.pc || route.query.dc;
|
|
if (pcStr) {
|
|
// 解析pc的JSON字符串
|
|
const pc = JSON.parse(pcStr);
|
|
// 如果JSON对象有以下值,则直接传pc值
|
|
if (pc.dc || pc.pc || pc.ch) {
|
|
cutInfos = route.query.pc || route.query.dc;
|
|
}
|
|
}
|
|
} else {
|
|
// 非商店包,原本的读取方式
|
|
cutInfos = Object.keys(route.query).length > 0 ? JSON.stringify(route.query) : undefined;
|
|
}
|
|
let userInfo = await AppApi.login(uid, sysType, cutInfos, isAppStore);
|
|
await userStore.saveLoginResult({ userInfo, token: userInfo.token });
|
|
return true;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const restoreUserFromStorage = () => {
|
|
if (userStore.userInfo && userStore.token) return;
|
|
const userInfo = localStorage.getItem('userInfo');
|
|
const token = localStorage.getItem('token');
|
|
if (userInfo && token) {
|
|
userStore.saveToken(JSON.parse(token));
|
|
userStore.saveUserInfo(JSON.parse(userInfo));
|
|
}
|
|
};
|
|
|
|
const ensureAuthAndConfig = async (): Promise<boolean> => {
|
|
restoreUserFromStorage();
|
|
if (!(userStore.userInfo && userStore.token)) {
|
|
const loginOk = await login();
|
|
if (!loginOk) {
|
|
showDialog({
|
|
title: '温馨提示',
|
|
message: '用户登陆失败',
|
|
confirmButtonText: '重试',
|
|
theme: 'round-button',
|
|
}).then(() => {
|
|
appStore.$reset();
|
|
userStore.$reset();
|
|
configStore.$reset();
|
|
state.isResLock = false;
|
|
init();
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
const configOk = await getConfig();
|
|
if (!configOk) {
|
|
showDialog({
|
|
title: '温馨提示',
|
|
message: '获取配置信息失败',
|
|
confirmButtonText: '重试',
|
|
theme: 'round-button',
|
|
}).then(() => {
|
|
appStore.$reset();
|
|
userStore.$reset();
|
|
configStore.$reset();
|
|
userStore.saveToken('');
|
|
localStorage.removeItem('userInfo');
|
|
localStorage.removeItem('token');
|
|
init();
|
|
});
|
|
return false;
|
|
}
|
|
adControl();
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* @description 初始化资源域名配置
|
|
* @param list 资源列表
|
|
*/
|
|
const initSourceInfo = (list: Array<Types.App.SourceListItem>): void => {
|
|
let sourceInfo: Types.App.SourceInfo = {
|
|
GROUP: '',
|
|
GUIDE: '',
|
|
AUDIO: '',
|
|
QRCODE: '',
|
|
IMAGE: '',
|
|
VID: [],
|
|
LAND: '',
|
|
PROXYRULE: '',
|
|
FAQ: '',
|
|
WELFARE: '',
|
|
ACT: '',
|
|
AppStore: '',
|
|
UP: '',
|
|
PRESALEBGIMG: '',
|
|
};
|
|
for (let item of list) {
|
|
switch (item.type) {
|
|
case SourceType.GROUP:
|
|
sourceInfo.GROUP = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.GUIDE:
|
|
sourceInfo.GUIDE = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.AUDIO:
|
|
sourceInfo.AUDIO = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.PRESALEBGIMG:
|
|
sourceInfo.PRESALEBGIMG = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.IMAGE:
|
|
sourceInfo.IMAGE = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.VID:
|
|
sourceInfo.VID = item.domain;
|
|
break;
|
|
case SourceType.LAND:
|
|
sourceInfo.LAND = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.PROXYRULE:
|
|
sourceInfo.PROXYRULE = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.FAQ:
|
|
sourceInfo.FAQ = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.QRCODE:
|
|
sourceInfo.QRCODE = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.WELFARE:
|
|
sourceInfo.WELFARE = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.AppStore:
|
|
sourceInfo.AppStore = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.ACT:
|
|
sourceInfo.ACT = item.domain[0]?.url;
|
|
break;
|
|
case SourceType.UP:
|
|
sourceInfo.UP = item.domain[0]?.url;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
configStore.saveSourceInfo(sourceInfo);
|
|
};
|
|
/**
|
|
* @description 获取配置信息
|
|
* @returns 获取配置信息是否成功
|
|
*/
|
|
const getConfig = async (): Promise<boolean> => {
|
|
try {
|
|
const configList = await AppApi.queryDomain();
|
|
configStore.saveAppConfig(configList);
|
|
globalStore.setAdvanceStatus(configList.advanceStatus);
|
|
initSourceInfo(configList.sourceList);
|
|
setTheme(configList.festivalUi);
|
|
return true;
|
|
} catch (error) {
|
|
state.isResLock = false;
|
|
return false;
|
|
}
|
|
};
|
|
/**
|
|
* @description 选线失败:首次弹「选线失败」可重试,重试仍失败则弹进群引导
|
|
*/
|
|
const onLineCheckFail = () => {
|
|
if (state.checkLineErrorNum == 1) {
|
|
state.isCheckError = true;
|
|
return;
|
|
}
|
|
showDialog({
|
|
title: '温馨提示',
|
|
message: '选线失败',
|
|
confirmButtonText: '重试',
|
|
theme: 'round-button',
|
|
}).then(() => {
|
|
state.checkLineErrorNum++;
|
|
appStore.$reset();
|
|
userStore.$reset();
|
|
configStore.$reset();
|
|
init();
|
|
});
|
|
};
|
|
/**
|
|
* 初始化
|
|
*/
|
|
const init = async () => {
|
|
generateUid();
|
|
route.query.isAppStore
|
|
? localStorage.setItem('isAppStore', route.query.isAppStore.toString())
|
|
: localStorage.setItem('isAppStore', ''); // 保存是否来自商店包,用于判断是否跳转外链
|
|
// 选线:本地线路 → 全挂则 DNS 解析兜底,同安卓 DetectLineManager
|
|
const line = await detectLine();
|
|
if (!line) {
|
|
onLineCheckFail();
|
|
return;
|
|
}
|
|
if (state.isResLock) return;
|
|
state.isResLock = true;
|
|
configStore.saveBaseUrl(line);
|
|
await ensureAuthAndConfig();
|
|
};
|
|
|
|
/**
|
|
* created
|
|
*/
|
|
init();
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.wrapper {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: url('../assets/images/webp/splash.webp') no-repeat;
|
|
background-size: 100% 100%;
|
|
position: relative;
|
|
.advSwiper {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
border-radius: 0px !important;
|
|
position: relative;
|
|
:deep(.adv-swiper-slide) {
|
|
height: 100% !important;
|
|
border-radius: 0px !important;
|
|
}
|
|
}
|
|
.countdown {
|
|
position: absolute;
|
|
top: 30px;
|
|
right: 25px;
|
|
z-index: 999;
|
|
width: 76px;
|
|
height: 36px;
|
|
border-radius: 18px;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
color: #fff;
|
|
font-size: 20px;
|
|
font-family: Inter;
|
|
font-weight: 800;
|
|
.jump_over {
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
}
|
|
}
|
|
.selectLineBox {
|
|
height: 120px;
|
|
width: 150px;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
border-radius: 10px;
|
|
position: fixed;
|
|
z-index: 1;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
.selectLine {
|
|
margin-top: 20px;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|