This commit is contained in:
谢宇宁
2026-09-15 16:25:45 +07:00
parent da39ab9a2a
commit 2d63d37930
449 changed files with 25632 additions and 24085 deletions
+896
View File
@@ -0,0 +1,896 @@
<template>
<div class="mobile" id="mobile" v-if="showContent">
<div class="bg">
<picture>
<source type="image/webp" :srcset="bg1W" />
<img :src="bg1" alt="" />
</picture>
</div>
<!-- 顶部 -->
<div class="top1">
<div class="left">
<picture>
<source type="image/webp" :srcset="headW" />
<img :src="head" alt="" />
</picture>
</div>
<div class="right" @click.stop="downBtn(1)">
<picture>
<source type="image/webp" :srcset="icon2W" />
<img :src="icon2" alt="download" />
</picture>
</div>
</div>
<div class="content1">
<!-- tab -->
<div class="top3">
<div @click="activeItem = item" class="top3Item" :class="item.id == activeItem.id && 'activeClass'"
v-for="(item, index) in tabList" :key="index">
{{ item.name }}
</div>
</div>
<!-- 图片内容 -->
<div class="top4">
<picture>
<source type="image/webp" :srcset="activeItem.imgW" />
<img :src="activeItem.img" alt="" />
</picture>
</div>
</div>
<div class="top5">
<div class="top5-box">
<picture>
<source type="image/webp" :srcset="icon8W" />
<img :src="icon8" alt="" />
</picture>
<div class="btn-js" @click="downBtn(0)">
<picture>
<source type="image/webp" :srcset="btn2W" />
<img :src="btn2" alt="download" />
</picture>
</div>
<div class="btn-by" @click="downBtn(1)">
<picture>
<source type="image/webp" :srcset="btn5W" />
<img :src="btn5" alt="download" />
</picture>
</div>
</div>
</div>
<!-- <div class="fixdTitle" v-if="!isIos">
<div class="fixdTitleContent">
<div class="logo">
<picture>
<source type="image/webp" :srcset="logoW" />
<img :src="logo" alt="" />
</picture>
</div>
<div class="topFont">
<picture>
<source type="image/webp" :srcset="topFontW" />
<img :src="topFont" alt="" />
</picture>
</div>
</div>
<div class="btn2" @click="downBtn(1)">
<img src="../../assets/image/mebile-index/btn2.png" alt="" />
</div>
</div>
<div class="fixdTitle" v-else>
<div class="fixdTitleContent">
<div class="logo">
<picture>
<source type="image/webp" :srcset="logoW" />
<img :src="logo" alt="" />
</picture>
</div>
<div class="topFont">
<picture>
<source type="image/webp" :srcset="topFontW" />
<img :src="topFont" alt="" />
</picture>
</div>
</div>
<div class="btn2" @click="downBtn(1)">
<img src="../../assets/image/mebile-index/btn2.png" alt="" />
</div>
</div> -->
<div class="rightFixed" :class="{ hide: !isOpen }">
<div class="icon" @click="isOpenFn">
<picture v-if="!isOpen">
<source type="image/webp" :srcset="icon9W" />
<img :src="icon9" alt="" />
</picture>
<!-- ------------++++++ -->
<picture v-else>
<source type="image/webp" :srcset="icon3W" />
<img :src="icon3" alt="" />
</picture>
</div>
<div class="list">
<!-- 官方群组 -->
<div class="item">
<picture>
<source type="image/webp" :srcset="fj_iconW" />
<img :src="fj_icon" alt="" @click="links('https://t.me/bilitv12')" />
</picture>
<span>福利群组</span>
</div>
<!-- 商务渠道 -->
<div class="item">
<picture>
<source type="image/webp" :srcset="qz_iconW" />
<img :src="qz_icon" alt="" @click="links('https://t1t1.com/')" />
</picture>
<span>广告商务</span>
</div>
<!-- 在线客服 -->
<div class="item">
<picture>
<source type="image/webp" :srcset="kf_iconW" />
<img :src="kf_icon" alt="" @click="openCustomerService" />
</picture>
<span>在线客服</span>
</div>
</div>
</div>
<!-- <div class="content">
<div class="mobileTitle">
<picture>
<source type="image/webp" :srcset="mobileTitleW" />
<img :src="mobileTitle" alt="" />
</picture>
</div>
<div class="peopBg">
<div class="peopBgContent">
<picture>
<source type="image/webp" :srcset="peopLabelW" />
<img :src="peopLabel" alt="" />
</picture>
</div>
<picture>
<source type="image/webp" :srcset="peopBgW" />
<img :src="peopBg" alt="" />
</picture>
</div>
<div class="tipBtm">
<div class="tipBtmContent" @click="downBtn(0)">
立即下载
</div>
<div class="bottomText">
<picture>
<source type="image/webp" :srcset="bottomTextW" />
<img :src="bottomText" alt="" />
</picture>
</div>
</div>
</div> -->
<!-- <div
class="iosStore"
v-if="buttonList?.shopIosDownUrl && isIos"
@click="downBtn(0)"
>
<picture>
<source type="image/webp" :srcset="downloadBtnW" />
<img :src="downloadBtn" alt="" />
</picture>
</div> -->
</div>
</template>
<script lang="ts" setup>
import fj_icon from '~/assets/image/mebile-index/fj_icon.png'
import qz_icon from '~/assets/image/mebile-index/qz_icon.png'
import kf_icon from '~/assets/image/mebile-index/kf_icon.png'
import head from '~/assets/image/mebile-index2/head.png'
import headW from '~/assets/image/mebile-index2/head.webp'
import bg1 from '~/assets/image/mebile-index2/bg1.png'
import icon2 from '~/assets/image/mebile-index2/icon2.png'
import icon3 from '~/assets/image/mebile-index2/icon3.png'
import icon5 from '~/assets/image/mebile-index2/icon5.jpeg'
import icon6 from '~/assets/image/mebile-index2/icon6.jpeg'
import icon7 from '~/assets/image/mebile-index2/icon7.jpeg'
import icon8 from '~/assets/image/mebile-index2/icon8.png'
import icon9 from '~/assets/image/mebile-index2/icon9.png'
import btn2 from '~/assets/image/mebile-index/btn2.png'
import btn5 from '~/assets/image/mebile-index/btn5.png'
import btn2W from '~/assets/image/mebile-index/btn2.webp'
import btn5W from '~/assets/image/mebile-index/btn5.webp'
import fj_iconW from '~/assets/image/mebile-index/fj_icon.webp'
import qz_iconW from '~/assets/image/mebile-index/qz_icon.webp'
import kf_iconW from '~/assets/image/mebile-index/kf_icon.webp'
import bg1W from '~/assets/image/mebile-index2/bg1.webp'
import icon2W from '~/assets/image/mebile-index2/icon2.webp'
import icon3W from '~/assets/image/mebile-index2/icon3.webp'
import icon5W from '~/assets/image/mebile-index2/icon5.webp'
import icon6W from '~/assets/image/mebile-index2/icon6.webp'
import icon7W from '~/assets/image/mebile-index2/icon7.webp'
import icon8W from '~/assets/image/mebile-index2/icon8.webp'
import icon9W from '~/assets/image/mebile-index2/icon9.webp'
import { bottonclick, getButtonList, downloadH5, getCustomerServiceUrl } from '~/api/btn'
import type { donwloadParam, channel, H5param } from '~/api/interface'
import { onMounted, ref, reactive, version } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { getSessionTraceId, renewSessionTraceId } from '~/utils/useEventTracker'
import { copyToClipboard } from '~/utils/clipboard'
const props = defineProps({
version: {
type: String,
default() {
return ''
}
}
})
const showContent = ref(false)
const isOpen = ref(true)
const activeTab = ref('热门')
const route = useRoute()
const router = useRouter()
const uDonwloadParam = ref<donwloadParam>({})
function isIOS() {
const userAgent = navigator.userAgent.toLowerCase()
return /iphone|ipad|ipod/.test(userAgent)
}
const isIos = isIOS()
const ip = ref('')
const buttonList = ref()
const onlineServiceLoading = ref(false)
const isOpenFn = () => {
console.log(isOpen.value)
isOpen.value = !isOpen.value
}
const tabList = [
{ name: '热门', id: 0, img: icon5, imgW: icon5W },
{ name: '原创', id: 1, img: icon6, imgW: icon6W },
{ name: '动漫', id: 2, img: icon7, imgW: icon7W },
]
const activeItem = ref(tabList[0])
const getIP = async () => {
try {
const response = await fetch('https://api.ipify.org?format=json')
const data = await response.json()
ip.value = data.ip
} catch (err) {
console.log('获取外部IP失败' + err)
}
}
const getlist = async () => {
try {
const { data } = await getButtonList({
appId: 126,
domain: window.location.protocol + '//' + window.location.host,
channel: JSON.stringify(route.query),
version: props.version,
tid: getSessionTraceId(),
})
buttonList.value = data
} catch (err) {
console.log('获取按钮列表失败' + err)
}
}
onMounted(async () => {
try {
await getIP()
} catch (e) {
console.log(e)
}
await getlist()
showContent.value = true
})
function downBtn(index?: number) {
const trace_id = renewSessionTraceId()
copyToClipboard(JSON.stringify({ ...route.query, trace_id }))
const param = reactive<donwloadParam>({
appId: 126,
ip: ip.value,
channel: JSON.stringify(route.query),
domain: window.location.host || '',
terminal: isIos ? 'ios' : 'android',
version: props.version
})
if (isIos) {
let type = 'iosH5'
// 只有商店包跟轻量版
console.log(buttonList.value.iosDownUrl)
if (buttonList.value?.shopIosDownUrl && index === 0) {
type = 'iosStore'
} else {
type = 'iosH5'
}
downLoadIos(param, type)
} else {
// 下载android应用
downLoadAndroid(param, index)
}
}
//TODO:IOS下载
async function downLoadIos(param: donwloadParam, type: any) {
switch (type) {
case 'iosStore':
param.packageType = 2
try {
window.location.href = buttonList.value.shopIosDownUrl
} catch (error) {
console.log(error)
}
await bottonclick(param)
break
case 'iosH5':
param.packageType = 1
uDonwloadParam.value = param
if (buttonList.value?.iosDownUrl) {
const appVersion = navigator.appVersion
const IOSversion = appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/)
console.log(appVersion, IOSversion)
// if (IOSversion.length > 0 && parseInt(IOSversion[1]) >= 17) {
// alert(
// '当前设备系统版本过高,请手动打开 系统配置->通用->VPN与设备管理,手动安装描述文件'
// )
// router.push({
// path: '/h5-install',
// query: { url: buttonList.value.iosDownUrl }
// })
// setTimeout(() => {
// window.location.href = buttonList.value.iosDownUrl
// }, 300)
// } else {
// router.push({
// path: '/h5-install',
// query: { url: buttonList.value.iosDownUrl }
// })
// setTimeout(() => {
// window.location.href = buttonList.value.iosDownUrl
// }, 300)
// setTimeout(() => {
// window.location.href =
// 'https://df6.gepqjpb.cc/js/embedded.mobileprovision?v=1'
// }, 5000)
// }
alert(
'当前设备系统版本过高,请手动打开 系统配置->通用->VPN与设备管理,手动安装描述文件'
)
router.push({
path: '/h5-install',
query: { url: buttonList.value.iosDownUrl }
})
setTimeout(() => {
window.location.href = buttonList.value.iosDownUrl
}, 300)
} else if (buttonList.value.storeIosDownUrl) {
window.location.href = buttonList.value.storeIosDownUrl
} else {
const paramData: H5param = {
appId: 126,
dc: (uDonwloadParam.value.channel as channel).dc,
pc: (uDonwloadParam.value.channel as channel).pc
}
await downloadH5(paramData).then((res) => {
const file = new File(
[res.data.value as unknown as BlobPart],
'descriptionFile.mobileconfig',
{
type: 'application/x-apple-aspen-config'
}
)
// 方法3:
const objectUrl = URL.createObjectURL(file)
const eleLink = document.createElement('a')
eleLink.href = objectUrl
eleLink.download = 'descriptionFile.mobileconfig'
eleLink.click()
})
}
await bottonclick(param)
break
}
}
const isDcMatch = (value) => {
// ky01-ky100
const kyReg = /^ky(0?[1-9]|[1-9][0-9]|100)$/i;
// TLGG01-TLGG56
const tlggReg = /^TLGG(0?[1-9]|[1-4][0-9]|5[0-6])$/i;
// erra01-erra10
const erraReg = /^erra(0?[1-9]|10)$/i;
return kyReg.test(value) || tlggReg.test(value) || erraReg.test(value);
};
// 特殊渠道号 cctl01-cctl10
const isCctlDc = (dc: any) => {
return /^cctl(0[1-9]|10)$/i.test(dc);
};
//TODOandroid下载
async function downLoadAndroid(param: donwloadParam, index: number) {
try {
if(isCctlDc(route.query.dc)){
window.location.href = 'https://mdapkkk.zwk9.com/blxv_260202_2.0.1+19.apk';
return
}
// 特殊渠道号处理
if(isDcMatch(route.query.dc) && buttonList.value.hkAndroidDownUrl){
window.location.href = buttonList.value.hkAndroidDownUrl;
}else{
// 有渠道链接就走渠道链接
if(index === 0 && buttonList.value.channelApkAndDownUrl){
window.location.href = buttonList.value.channelApkAndDownUrl;
}else{
if (index === 0 && buttonList.value.androidDownUrl) {
window.location.href = buttonList.value.androidDownUrl;
} else {
window.location.href = buttonList.value.storeAndroidDownUrl;
}
}
}
await bottonclick(param);
} catch (error) {
console.log(error)
}
}
function links(url: string) {
window.location.href = url
}
function getDeviceType(userAgent: string) {
return /android/i.test(userAgent) ? 'Android' : 'iOS'
}
function getSystemType(userAgent: string) {
return /android/i.test(userAgent) ? 'Android' : 'iOS'
}
function getSystemVersion(userAgent: string) {
const androidVersion = userAgent.match(/Android\s([\d.]+)/i)
if (androidVersion?.[1]) {
return androidVersion[1]
}
const iosVersion = userAgent.match(/OS (\d+[_\d]*)/i)
if (iosVersion?.[1]) {
return iosVersion[1].replace(/_/g, '.')
}
return ''
}
async function openCustomerService() {
if (onlineServiceLoading.value) {
return
}
onlineServiceLoading.value = true
try {
const userAgent = navigator.userAgent || ''
const res = await getCustomerServiceUrl({
uid: String(route.query.uid || getSessionTraceId()),
appId: 126,
deviceType: getDeviceType(userAgent),
systemType: getSystemType(userAgent),
systemVersion: getSystemVersion(userAgent)
})
const serviceUrl = res && res.data
if (serviceUrl) {
window.location.href = serviceUrl as unknown as string
return
}
} catch (error) {
console.log('get customer service url error:', error)
} finally {
onlineServiceLoading.value = false
}
}
</script>
<style lang="scss" scoped>
.mobile {
width: 7.5rem;
height: 100%;
overflow: hidden;
position: relative;
.bg {
width: 7.5rem;
height: auto;
position: fixed;
top: 0;
left: 0;
z-index: -1;
img {
width: 100%;
height: auto;
}
}
.top1 {
width: 6.86rem;
position: fixed;
left: 0.32rem;
top: 0.2rem;
display: flex;
align-items: center;
justify-content: space-between;
.left {
width: 100%;
img {
width: 100%;
}
}
.right {
width: 1.7rem;
position: absolute;
right: 10px;
img {
width: 100%;
}
}
}
.content1 {
position: fixed;
left: 0.32rem;
top: 1.7rem;
width: 6.86rem;
.top2 {
height: 4.44rem;
width: 100%;
img {
width: 100%;
height: 100%;
}
}
.top3 {
width: 100%;
height: 0.6rem;
border-radius: 8px;
margin-top: 0.3rem;
background: #303030;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
.top3Item {
height: 0.6rem;
border-radius: 8px;
line-height: 0.6rem;
text-align: center;
font-size: 0.32rem;
}
.activeClass {
background: #FF3F7C;
}
}
.top4 {
margin-top: 0.3rem;
width: 100%;
// height: 400px;
height: calc(100dvh - 4.38rem);
overflow-y: auto;
img {
width: 100%;
}
}
}
.top5 {
width: 7.5rem;
height: 1.14rem;
position: fixed;
padding: 0 12px;
left: 0;
bottom: 10px;
z-index: 10;
img {
width: 100%;
height: 100%;
}
}
.bglog {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.9);
color: #fff;
text-align: center;
line-height: 5rem;
z-index: 10;
.copy {
width: 5rem;
height: 1rem;
margin: 0 auto;
line-height: 1rem;
}
}
.iosStore {
position: fixed;
bottom: 5rem;
left: 0;
right: 0;
z-index: 10;
img {
height: 0.66rem;
width: 5.5rem;
}
}
.fixdTitle {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 10;
padding: 0 0.32rem;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
height: 1.2rem;
background: url('~/assets/image/mebile-index/downloadBtn.png') no-repeat;
background-size: 100%;
.fixdTitleContent {
display: flex;
align-items: center;
justify-content: center;
gap: 0.2rem;
.logo {
img {
width: 0.6rem;
height: 0.6rem;
}
}
.topFont {
img {
width: 2.86rem;
height: 0.6rem;
}
}
}
.btn2 {
display: flex;
align-items: center;
img {
height: 0.72rem;
}
}
.btn1-txt {
width: 100%;
height: 100%;
background: linear-gradient(90.63deg, #003cc9 43.99%, #058be5 97.99%);
border-radius: 0.32rem;
padding: 0.04rem 0.16rem;
font-size: 0.28rem;
font-weight: 600;
span {
color: rgb(255, 221, 56);
}
}
}
.rightFixed {
position: fixed;
transition: transform 0.5s;
top: 4.2rem;
right: 0.22rem;
z-index: 100;
&.hide {
transform: translateX(1.38rem);
}
.icon {
position: absolute;
height: 0.56rem;
width: 0.32rem;
top: 50%;
transform: translateY(-50%);
right: 1.16rem;
img {
width: 100%;
}
}
.list {
width: 1.16rem;
height: 4.04rem;
border-radius: 1rem;
border: 0.01rem solid #fff;
background: rgba(45, 44, 47, 0.7);
display: flex;
flex-direction: column;
justify-content: space-around;
.item {
display: flex;
flex-wrap: wrap;
justify-content: center;
span {
font-size: 0.21rem;
}
img {
width: 0.5rem;
}
}
}
}
.content {
position: relative;
z-index: 9;
text-align: center;
height: 100%;
padding-bottom: 2.3rem;
overflow: auto;
padding-top: 1.6rem;
display: flex;
flex-direction: column;
align-items: center;
.mz {
width: 6.86rem;
}
.downloadBtn {
align-items: center;
display: flex;
justify-content: space-around;
width: 100%;
padding: 0 0.5rem;
img {
width: 2.8rem;
}
}
.mobileTitle {
img {
width: 6.86rem;
}
}
.tipBtm {
position: fixed;
bottom: 0rem;
left: 50%;
transform: translateX(-50%);
width: 6.54rem;
margin: 0.4rem auto;
border-radius: 0.16rem;
.tipBtmContent {
background: linear-gradient(90deg, #EA5B80 0%, #E60C49 100%);
width: 3.16rem;
height: 0.8rem;
margin: 0.4rem auto;
border-radius: 0.52rem;
padding-top: 6.17px;
padding-right: 9.25px;
padding-bottom: 6.17px;
padding-left: 9.25px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.32rem;
font-weight: 640;
color: #fff;
cursor: pointer;
}
}
.peopBg {
position: relative;
img {
width: 100%;
}
}
.bottomText {
img {
width: 6.54rem;
}
}
.peopBgContent {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0 auto;
img {
width: 6.54rem;
}
}
}
}
.fade-in-enter-active,
.fade-in-leave-active {
transition: opacity 0.2s ease-in-out;
}
.fade-in-enter-from,
.fade-in-leave-to {
opacity: 0;
}
@supports (-webkit-touch-callout: none) {
.page {
height: -webkit-fill-available;
}
}
.btn-js {
position: absolute;
right: 2rem;
top: 0.3rem;
width: 1.6rem;
height: 30px;
img {
width: 100%;
height: 100%;
}
}
.btn-by {
position: absolute;
right: 10px;
top: 0.3rem;
width: 1.6rem;
height: 30px;
img {
width: 100%;
height: 100%;
}
}
.top5-box {
position: relative;
width: 100%;
height: 100%;
}
</style>