This commit is contained in:
谢宇宁
2026-10-08 23:37:39 +07:00
parent 3d9f1a7914
commit e3db013668
20 changed files with 174 additions and 896 deletions
+34
View File
@@ -0,0 +1,34 @@
import request from "@/utils/request";
// 下载相关接口对齐 huangguo_landpage,域名写死(接口已开 CORS: *)
const STAT_API = "https://blsp01.com/api/stat/version";
// 黄果短剧 App 在下载接口的 appId
export const APP_ID = 5;
// 按钮开关:iosDown / iosStore / iosTF / iosH5 / androidButton,不含下载地址
export const getButtonList = data =>
request({
method: "post",
url: `${STAT_API}/bottonlist`,
data: { ...data, appId: APP_ID }
});
// 点击下载:返回 data.link(下载地址数组),同时后端记录点击
export const bottonclick = data =>
request({
method: "post",
url: `${STAT_API}/bottonclick`,
data: { ...data, appId: APP_ID }
});
// iOS H5 描述文件:返回 .mobileconfig 原文(非 JSON)
export const downloadH5 = async data => {
const res = await fetch(`${STAT_API}/h5/config`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ...data, appId: APP_ID })
});
if (!res.ok) throw new Error("获取描述文件失败 " + res.status);
return res.text();
};
-14
View File
@@ -1,14 +0,0 @@
/*
* @Author: 王枫叶
* @Date: 2020-07-20 20:48:00
* @LastEditors: 王枫叶
* @LastEditTime: 2020-10-05 17:23:15
*/
import request from "@/utils/request";
export default data =>
request({
method: "post",
url: "/plm/okn/ijb/vl0gpuBNWklJwcv1",
data
});
-8
View File
@@ -1,8 +0,0 @@
import request from "@/utils/request";
export default data =>
request({
method: "post",
url: "/plm/okn/ijb/fsdfrererdfdf",
data,
});
-14
View File
@@ -1,14 +0,0 @@
/*
* @Author: 王枫叶
* @Date: 2020-08-10 22:55:30
* @LastEditors: 王枫叶
* @LastEditTime: 2020-10-28 22:55:14
*/
import request from "@/utils/request";
export default data =>
request({
method: "post",
url: "/plm/okn/ijb/nuS0EDXSczKgf3Xh",
data
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 MiB

After

Width:  |  Height:  |  Size: 4.9 MiB

-190
View File
@@ -1,190 +0,0 @@
const APPID = "JHA-214";
const APP_VERSION = "1.0.0";
export function getTraceId() {
let str = sessionStorage.getItem(`${APPID}_traceId`);
if (str) return str;
str =
Math.random()
.toString()
.substr(2, 36) + Date.now().toString(36);
sessionStorage.setItem(`${APPID}_traceId`, str);
return str;
}
function getAndroidBrand(model = "") {
const m = model.toLowerCase();
if (!m) return "";
if (/^(sm-|gt-|sch-|sgh-|shv-)/.test(m)) return "Samsung";
if (/^(mix|mi |mi-|mi\d|redmi|m\d{1,2}[a-z]|poco|2\d{3}[a-z0-9]{4,})/.test(m)) return "Xiaomi";
if (/^(pixel)/.test(m)) return "Google";
if (/^(huawei|huawe|ana-|bla-|ele-|lya-|noh-|tas-|vog-|aln-|bra-|clt-|dub-|eml-|frl-|hma-|ine-|jef-|jkm-|jny-|lio-|mar-|mrd-|nam-|oce-|pct-|pot-|sea-|snk-|stk-|tet-|wlz-|yal-)/.test(m)) return "HUAWEI";
if (/^(honor|ali-|bkl-|yal-|nth-|peg-|any-|are-|bkk-|cdy-|cph-|dnn-|fne-|hry-|jsn-|lld-|mov-|rne-|rea-|tfy-|tnr-|crr-|ksa-)/.test(m)) return "HONOR";
if (/^(vivo|v\d|pd\d)/.test(m)) return "vivo";
if (/^(oppo|cph|peh|pht|pgc|pgd|pgf|a\d{3})/.test(m)) return "OPPO";
if (/^(oneplus|hd19|kb20|le21|gm19|cph2\d|de2\d|ne2\d|in2\d|kb2\d|le2\d)/.test(m)) return "OnePlus";
if (/^(realme|rmx)/.test(m)) return "realme";
if (/^(moto|motorola|xt\d)/.test(m)) return "Motorola";
if (/^(iqoo|i2\d|v\d{4}[a-z])/.test(m)) return "iQOO";
if (/^(nokia|ta-\d+)/.test(m)) return "Nokia";
if (/^(sony|xq-|g8\d|xperia)/.test(m)) return "Sony";
if (/^(asus|zs\d|ai\d|rog)/.test(m)) return "ASUS";
if (/^(meizu|m\d+ note)/.test(m)) return "Meizu";
if (/^(nubia|nx\d)/.test(m)) return "nubia";
if (/^(zte|zte-)/.test(m)) return "ZTE";
if (/^(lenovo|tb-|l3\d)/.test(m)) return "Lenovo";
return "";
}
function extractMobileModel(ua = "") {
const sectionMatch = ua.match(
/\(([^)]*(Android|HarmonyOS|OpenHarmony)[^)]*)\)/i
);
if (!sectionMatch || !sectionMatch[1]) return "";
const candidates = sectionMatch[1]
.split(";")
.map(item => item.trim())
.map(item => item.replace(/\s+Build\/.*$/i, "").trim())
.filter(
item =>
item &&
!/^linux$/i.test(item) &&
!/^u$/i.test(item) &&
!/^wv$/i.test(item) &&
!/^android[\d.\s]*$/i.test(item) &&
!/^[a-z]{2}([-_][a-z]{2})?$/i.test(item)
);
return candidates.length ? candidates[candidates.length - 1] : "";
}
function getBrandFromUA(model = "", ua = "") {
const brand = getAndroidBrand(model);
if (brand) return brand;
if (/honor/i.test(ua)) return "HONOR";
if (/(huawei|huaweibrowser)/i.test(ua)) return "HUAWEI";
if (/\bxiaomi\b|miuibrowser/i.test(ua)) return "Xiaomi";
if (/\boppo\b|oppobrowser|heytap/i.test(ua)) return "OPPO";
if (/\bvivo\b|vivobrowser/i.test(ua)) return "vivo";
if (/\bsamsungbrowser\b/i.test(ua)) return "Samsung";
if (/\boneplus\b/i.test(ua)) return "OnePlus";
if (/\brealme\b/i.test(ua)) return "realme";
if (/\bmeizu\b/i.test(ua)) return "Meizu";
if (/\blenovo\b/i.test(ua)) return "Lenovo";
return "";
}
function parseDeviceInfo(ua = "") {
if (!ua) return { device_brand: "", device_model: "" };
if (/iPhone/i.test(ua)) return { device_brand: "Apple", device_model: "iPhone" };
if (/iPad/i.test(ua)) return { device_brand: "Apple", device_model: "iPad" };
if (/iPod/i.test(ua)) return { device_brand: "Apple", device_model: "iPod" };
if (/Android/i.test(ua) || /(harmonyos|openharmony|hongmeng|hmos)/i.test(ua)) {
const model = extractMobileModel(ua);
return { device_brand: getBrandFromUA(model, ua), device_model: model };
}
if (/Macintosh|Mac OS X/i.test(ua)) return { device_brand: "Apple", device_model: "Mac" };
if (/Windows/i.test(ua)) return { device_brand: "Microsoft", device_model: "Windows PC" };
if (/Linux/i.test(ua)) return { device_brand: "Linux", device_model: "Linux PC" };
return { device_brand: "", device_model: "" };
}
export function getSystemType(ua = navigator.userAgent || "") {
if (
/Android/i.test(ua) ||
/(harmonyos|openharmony|hongmeng|hmos)/i.test(ua)
) {
return "android";
}
if (/iPhone|iPad|iPod/i.test(ua)) {
return "ios";
}
return "pc";
}
export function getSystemVersion(ua = navigator.userAgent || "") {
const iosMatch = ua.match(/OS (\d+(?:[_\d]+)?)/i);
if (iosMatch && iosMatch[1]) {
return iosMatch[1].replace(/_/g, ".");
}
const androidMatch = ua.match(/Android\s+([\d.]+)/i);
if (androidMatch && androidMatch[1]) {
return androidMatch[1];
}
return "";
}
export function getDeviceType(ua = navigator.userAgent || "") {
if (/iPhone/i.test(ua)) return "iPhone";
if (/iPad/i.test(ua)) return "iPad";
if (/iPod/i.test(ua)) return "iPod";
if (
/Android/i.test(ua) ||
/(harmonyos|openharmony|hongmeng|hmos)/i.test(ua)
) {
return extractMobileModel(ua);
}
const { device_model } = parseDeviceInfo(ua);
return device_model;
}
let _cachedDeviceInfo = null;
function getDeviceInfo() {
if (!_cachedDeviceInfo) {
_cachedDeviceInfo = parseDeviceInfo(navigator.userAgent || "");
}
return _cachedDeviceInfo;
}
/**
* 上报落地页展示
* vm: 组件 this,必须传(读取 vm.version)
* opts: { landing_page_id }
*/
export function landingPageView(vm, opts = {}) {
const { device_brand, device_model } = getDeviceInfo();
const data = {
event: "landing_page_view",
landing_page_id: opts.landing_page_id || `${APPID}_${vm.version}`,
device_brand,
device_model,
app_version: APP_VERSION
};
return window.tracker(data);
}
/**
* 上报落地页点击
* vm: 组件 this
* opts: { landing_page_id, tab_key, tab_name, click_coordinates_x, click_coordinates_y,
* click_x_percent, click_y_percent, screen_width, screen_height, trace_id }
*/
export function landingPageClick(vm, opts = {}) {
const { device_brand, device_model } = getDeviceInfo();
const screenW = window.screen ? window.screen.width : opts.screen_width || 0;
const screenH = window.screen
? window.screen.height
: opts.screen_height || 0;
const data = {
event: "landing_page_click",
landing_page_id: opts.landing_page_id || `${APPID}_${vm.version}`,
tab_key: opts.tab_key || "",
tab_name: opts.tab_name || "",
click_coordinates_x: opts.click_coordinates_x || 0,
click_coordinates_y: opts.click_coordinates_y || 0,
click_x_percent:
typeof opts.click_x_percent === "number"
? opts.click_x_percent
: Math.round(((opts.click_coordinates_x || 0) / (screenW || 1)) * 100),
click_y_percent:
typeof opts.click_y_percent === "number"
? opts.click_y_percent
: Math.round(((opts.click_coordinates_y || 0) / (screenH || 1)) * 100),
screen_width: screenW,
screen_height: screenH,
trace_id: opts.trace_id || getTraceId(),
device_brand,
device_model,
app_version: APP_VERSION
};
return window.tracker(data);
}
+13
View File
@@ -0,0 +1,13 @@
// 会话 trace id:剪贴板里的 tid 供 App 首启做安装归因
const KEY = "hgmj_traceId";
export function getTraceId() {
let str = sessionStorage.getItem(KEY);
if (str) return str;
str =
Math.random()
.toString()
.substr(2, 36) + Date.now().toString(36);
sessionStorage.setItem(KEY, str);
return str;
}
+6 -131
View File
@@ -1,35 +1,13 @@
<template>
<div class="mobilePage" @click="pageClick">
<div class="mobilePage">
<div class="headerBox" :class="{ isIos: isIos }">
<div class="navBrand">
<img class="logoBox" :src="logoHeader" alt="91短剧" />
<img class="logoBox" :src="logoHeader" alt="黄果漫剧" />
<div class="brandCopy">
<p class="brandTitle">91短剧 原创基地</p>
<p class="brandTitle">黄果漫剧 原创基地</p>
<p class="brandDesc">沉浸体验 极速观影</p>
</div>
</div>
<div class="rightBox" v-if="configs && configs.length">
<div class="navItem" v-if="cTg" @click.stop="jumpUrl(cTg, $event)">
<div class="telegram"></div>
<span>群聊</span>
</div>
<div
class="navItem"
v-if="cBusiness"
@click.stop="jumpUrl(cBusiness, $event)"
>
<div class="business"></div>
<span>商务</span>
</div>
<div
class="navItem"
v-if="cChannel"
@click.stop="jumpUrl(cChannel, $event)"
>
<div class="channel"></div>
<span>客服</span>
</div>
</div>
<div
class="iosBanner"
@click.stop="getApkInfo(hasShopIos ? 'shopIos' : true, $event)"
@@ -122,13 +100,11 @@
</template>
<script>
import { landingPageClick } from "@/utils/eventTracker";
import tabContents from "./mobile1Contents";
export default {
props: {
os: {},
configs: {},
switchData: {},
version: {
type: String,
@@ -151,11 +127,8 @@ export default {
{ label: "刚满18", value: "adult" }
],
tabContents,
cTg: "",
cBusiness: "",
cChannel: "",
showIosTip: true,
logoHeader: require("@/assets/images/mobile1/logoHeader.webp")
logoHeader: require("@/assets/images/common/hgmj_logo.png")
};
},
computed: {
@@ -163,30 +136,7 @@ export default {
return !!(this.os && this.os.isPhone);
},
hasShopIos() {
return !!(
this.isIos &&
this.switchData &&
this.switchData.shopIosDownUrl
);
}
},
watch: {
configs: {
immediate: true,
handler(configs) {
if (!configs || !configs.length) {
return;
}
configs.forEach(item => {
if (item.configType === "tg_group") {
this.cTg = item.link;
} else if (item.configType === "sw_cooperate") {
this.cBusiness = item.link;
} else if (item.configType === "qd_cooperate") {
this.cChannel = item.link;
}
});
}
return !!(this.isIos && this.switchData && this.switchData.iosStore);
}
},
mounted() {
@@ -204,18 +154,6 @@ export default {
this.clearTabAutoPlay();
},
methods: {
pageClick(event) {
let click_coordinates_x = event.clientX;
let click_coordinates_y = event.clientY;
landingPageClick(this, {
tab_key: this.tabActive,
tab_name: this.getTabName(),
click_coordinates_x,
click_coordinates_y
}).then(res => {
console.log(res);
});
},
getTabName() {
const tab = this.tabs.find(item => item.value === this.tabActive);
return tab ? tab.label : "推荐";
@@ -256,7 +194,7 @@ export default {
this.androidPromptShow = true;
}
},
async getApkInfo(flag, event) {
async getApkInfo(flag) {
let type = this.os.isPhone ? "ios" : "android";
if (flag === "shopIos") {
type = "shopIos";
@@ -267,25 +205,9 @@ export default {
if (flag && flag !== "shopIos") {
await this.showInstallTutorial(type);
}
this.$emit("recordClick", type);
setTimeout(() => {
this.$emit("getApkInfo", type);
}, 500);
landingPageClick(this, {
tab_name: "下载按钮",
tab_key: "download",
click_coordinates_x: event ? event.clientX : 0,
click_coordinates_y: event ? event.clientY : 0
});
},
jumpUrl(url, event) {
landingPageClick(this, {
tab_key: this.tabActive,
tab_name: this.getTabName(),
click_coordinates_x: event ? event.clientX : 0,
click_coordinates_y: event ? event.clientY : 0
});
window.open(url);
}
}
};
@@ -389,53 +311,6 @@ export default {
}
}
}
.rightBox {
position: absolute;
right: 16px;
top: 13px;
z-index: 2;
display: flex;
align-items: center;
gap: 14px;
.navItem {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
width: 28px;
.telegram,
.business,
.channel {
width: 24px;
height: 24px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.telegram {
background-image: url("./../../../assets/images/mobile1/telegram.svg");
}
.business {
background-image: url("./../../../assets/images/mobile1/business.svg");
}
.channel {
background-image: url("./../../../assets/images/mobile1/channel.svg");
}
span {
color: #fff;
font-size: 10px;
line-height: 1;
letter-spacing: 0.8px;
white-space: nowrap;
}
}
}
}
.pageBody {
+11 -118
View File
@@ -1,12 +1,9 @@
<template>
<div class="mobilePage" @click="pageClick">
<div class="mobilePage">
<div
class="headerBox"
@click.stop="
getApkInfo(
os.isPhone && switchData.shopIosDownUrl ? 'shopIos' : true,
$event
)
getApkInfo(os.isPhone && switchData.iosStore ? 'shopIos' : true, $event)
"
>
<div class="header-bg">
@@ -21,30 +18,12 @@
></div>
<div class="navBox">
<div class="navBrand">
<img class="logoBox" :src="logoHeader" alt="海角社区" />
<img class="logoBox" :src="logoHeader" alt="黄果漫剧" />
<div class="brandCopy">
<div class="brandName">海角社区</div>
<div class="brandName">黄果漫剧</div>
<div class="brandDesc">全球最大乱伦平台</div>
</div>
</div>
<div class="rightBox" v-if="configs && configs.length">
<div class="navItem" v-if="cTg" @click.stop="jumpUrl(cTg)">
<div class="telegram"></div>
<span>群聊</span>
</div>
<div
class="navItem"
v-if="cBusiness"
@click.stop="jumpUrl(cBusiness)"
>
<div class="business"></div>
<span>商务</span>
</div>
<div class="navItem" v-if="cChannel" @click.stop="jumpUrl(cChannel)">
<div class="channel"></div>
<span>流量</span>
</div>
</div>
</div>
</div>
<van-tabs
@@ -68,7 +47,7 @@
class="main"
@click.stop="
getApkInfo(
os.isPhone && switchData.shopIosDownUrl ? 'shopIos' : true,
os.isPhone && switchData.iosStore ? 'shopIos' : true,
$event
)
"
@@ -105,10 +84,7 @@
class="bottomBox ios"
@click.stop="getApkInfo('shopIos', $event)"
>
<div
class="shopBtn"
@click.stop="getApkInfo('shopIos', $event)"
></div>
<div class="shopBtn" @click.stop="getApkInfo('shopIos', $event)"></div>
</div>
</div>
<van-overlay :show="androidPromptShow" z-index="999" class="androidOverlay">
@@ -135,10 +111,8 @@
</template>
<script>
import { landingPageClick } from "@/utils/eventTracker";
export default {
props: ["os", "configs", "switchData"],
props: ["os", "switchData"],
data() {
return {
androidPromptShow: false,
@@ -221,30 +195,13 @@ export default {
"【妹妹不睡我不睡,我玩游戏操亲妹!】爸妈外出后,我带妹妹玩真心话大冒险,没想到妹妹居然还穿着透明蕾丝内裤!看的我鸡巴一柱擎天!脱下裤子狂操妹妹,要不是怕妹妹怀孕,我高低要试试内射亲妹的滋味!!"
}
],
cTg: "",
cBusiness: "",
cChannel: "",
version: "B",
logoHeader: require("@/assets/images/mobile2/figma-logo.png")
logoHeader: require("@/assets/images/common/hgmj_logo.png")
};
},
computed: {
hasShopIos() {
return this.os && this.os.isPhone && this.switchData.shopIosDownUrl;
}
},
watch: {
configs(configs) {
configs.forEach(item => {
if (item.configType === "tg_group") {
this.cTg = item.link;
} else if (item.configType === "sw_cooperate") {
this.cBusiness = item.link;
} else if (item.configType === "qd_cooperate") {
this.cChannel = item.link;
}
});
return configs;
return this.os && this.os.isPhone && this.switchData.iosStore;
}
},
mounted() {
@@ -258,14 +215,6 @@ export default {
}
},
methods: {
pageClick(event) {
landingPageClick(this, {
tab_key: this.tabActive,
tab_name: this.getTabName(),
click_coordinates_x: event.clientX,
click_coordinates_y: event.clientY
});
},
getTabName() {
const tab = this.tabs.find(item => item.value === this.tabActive);
return tab ? tab.label : "精选";
@@ -280,7 +229,7 @@ export default {
},
onTabBeforeChange() {
this.getApkInfo(
this.os.isPhone && this.switchData.shopIosDownUrl ? "shopIos" : true
this.os.isPhone && this.switchData.iosStore ? "shopIos" : true
);
return false;
},
@@ -291,7 +240,7 @@ export default {
this.androidPromptShow = true;
}
},
async getApkInfo(flag, event) {
async getApkInfo(flag) {
let type = this.os.isPhone ? "ios" : "android";
if (flag === "shopIos") {
type = "shopIos";
@@ -302,19 +251,9 @@ export default {
if (flag && flag !== "shopIos") {
await this.showInstallTutorial(type);
}
this.$emit("recordClick", type);
setTimeout(() => {
this.$emit("getApkInfo", type);
}, 500);
landingPageClick(this, {
tab_name: "下载按钮",
tab_key: "download",
click_coordinates_x: event ? event.clientX : 0,
click_coordinates_y: event ? event.clientY : 0
});
},
jumpUrl(url) {
window.open(url);
}
}
};
@@ -390,52 +329,6 @@ export default {
font-weight: 500;
}
}
.rightBox {
position: absolute;
right: 13px;
top: 12px;
display: flex;
align-items: flex-start;
gap: 14px;
.navItem {
display: flex;
flex-direction: column;
align-items: center;
width: 24px;
span {
margin-top: 2px;
font-size: 10px;
color: #fff;
line-height: 1;
white-space: nowrap;
letter-spacing: 0.8px;
}
.telegram,
.business,
.channel {
width: 24px;
height: 24px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.telegram {
background-image: url("./../../../assets/images/mobile2/figma-group.svg");
}
.business {
background-image: url("./../../../assets/images/mobile2/figma-business.svg");
}
.channel {
background-image: url("./../../../assets/images/mobile2/figma-channel.svg");
}
}
}
}
.header-bg {
+4 -91
View File
@@ -3,43 +3,13 @@
<div class="page-bg"></div>
<div class="pcm-brand">
<img class="pcm-logo" :src="logoImg" alt="91短剧" />
<img class="pcm-logo" :src="logoImg" alt="黄果漫剧" />
<div class="pcm-brand-copy">
<div class="pcm-brand-title">91短剧 原创基地</div>
<div class="pcm-brand-title">黄果漫剧 原创基地</div>
<div class="pcm-brand-desc">沉浸体验 极速观影</div>
</div>
</div>
<div class="pcm-actions" v-if="configs && configs.length">
<button
class="pcm-action"
v-if="cTg"
type="button"
aria-label="群聊"
@click.stop="jumpUrl(cTg)"
>
<img :src="tgIcon" alt="" />
</button>
<button
class="pcm-action"
v-if="cBusiness"
type="button"
aria-label="商务合作"
@click.stop="jumpUrl(cBusiness)"
>
<img :src="businessIcon" alt="" />
</button>
<button
class="pcm-action"
v-if="cChannel"
type="button"
aria-label="客服"
@click.stop="jumpUrl(cChannel)"
>
<img :src="channelIcon" alt="" />
</button>
</div>
<div class="pcm-download">
<div class="pcm-qrcode">
<div class="pcm-qrcode-inner">
@@ -74,38 +44,13 @@ import autofit from "autofit.js";
autofit.init();
export default {
props: ["qrImg", "os", "configs"],
props: ["qrImg", "os"],
data() {
return {
cTg: "",
cBusiness: "",
cChannel: "",
logoImg: require("@/assets/images/pc/logo.webp"),
tgIcon: require("@/assets/images/pc/telegram.svg"),
businessIcon: require("@/assets/images/pc/business.svg"),
channelIcon: require("@/assets/images/pc/channel.svg"),
logoImg: require("@/assets/images/common/hgmj_logo.png"),
scanIcon: require("@/assets/images/pc/scanIcon.svg")
};
},
watch: {
configs: {
immediate: true,
handler(configs) {
if (!configs || !configs.length) {
return;
}
configs.forEach(item => {
if (item.configType === "tg_group") {
this.cTg = item.link;
} else if (item.configType === "sw_cooperate") {
this.cBusiness = item.link;
} else if (item.configType === "qd_cooperate") {
this.cChannel = item.link;
}
});
}
}
},
mounted() {
autofit.init(
{
@@ -123,12 +68,6 @@ export default {
methods: {
getApkInfo() {
this.$emit("getApkInfo", "android");
},
jumpUrl(url) {
if (!url) {
return;
}
window.open(url);
}
}
};
@@ -204,32 +143,6 @@ export default {
text-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.pcm-actions {
position: fixed;
top: 56px;
right: 96px;
z-index: 4;
display: flex;
align-items: center;
gap: 61px;
}
.pcm-action {
width: 69px;
height: 69px;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
cursor: pointer;
img {
width: 69px;
height: 69px;
object-fit: contain;
}
}
.pcm-download {
position: absolute;
left: 170px;
+4 -88
View File
@@ -4,43 +4,13 @@
<img class="pcm-top-mask" :src="pcTopMask" alt="" />
<div class="pcm-brand">
<img class="pcm-logo" :src="logoImg" alt="海角社区" />
<img class="pcm-logo" :src="logoImg" alt="黄果漫剧" />
<div class="pcm-brand-copy">
<div class="pcm-brand-title">海角社区</div>
<div class="pcm-brand-title">黄果漫剧</div>
<div class="pcm-brand-desc">全球最大乱伦平台</div>
</div>
</div>
<div class="pcm-actions" v-if="configs && configs.length">
<button
class="pcm-action"
v-if="cTg"
type="button"
aria-label="群组"
@click.stop="jumpUrl(cTg)"
>
<img :src="tgIcon" alt="" />
</button>
<button
class="pcm-action"
v-if="cBusiness"
type="button"
aria-label="商务合作"
@click.stop="jumpUrl(cBusiness)"
>
<img :src="businessIcon" alt="" />
</button>
<button
class="pcm-action"
v-if="cChannel"
type="button"
aria-label="渠道合作"
@click.stop="jumpUrl(cChannel)"
>
<img :src="channelIcon" alt="" />
</button>
</div>
<div class="pcm-download">
<div class="pcm-qrcode">
<img class="pcm-qrcode-img" :src="qrImg" alt="扫码下载" />
@@ -71,40 +41,15 @@
import autofit from "autofit.js";
export default {
props: ["qrImg", "os", "configs"],
props: ["qrImg", "os"],
data() {
return {
cTg: "",
cBusiness: "",
cChannel: "",
pcBg: require("@/assets/images/pc2/figma-pc-bg.webp"),
pcTopMask: require("@/assets/images/pc2/figma-pc-top-mask.png"),
logoImg: require("@/assets/images/pc2/figma-pc-logo.png"),
tgIcon: require("@/assets/images/pc2/figma-pc-tg.svg"),
businessIcon: require("@/assets/images/pc2/figma-pc-business.svg"),
channelIcon: require("@/assets/images/pc2/figma-pc-channel.svg"),
logoImg: require("@/assets/images/common/hgmj_logo.png"),
scanIcon: require("@/assets/images/pc2/figma-pc-scan.svg")
};
},
watch: {
configs: {
immediate: true,
handler(configs) {
if (!configs || !configs.length) {
return;
}
configs.forEach(item => {
if (item.configType === "tg_group") {
this.cTg = item.link;
} else if (item.configType === "sw_cooperate") {
this.cBusiness = item.link;
} else if (item.configType === "qd_cooperate") {
this.cChannel = item.link;
}
});
}
}
},
mounted() {
autofit.init(
{
@@ -122,9 +67,6 @@ export default {
methods: {
getApkInfo() {
this.$emit("getApkInfo", "android");
},
jumpUrl(url) {
window.open(url);
}
}
};
@@ -216,32 +158,6 @@ export default {
text-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
}
.pcm-actions {
position: absolute;
top: 86px;
right: 32px;
z-index: 4;
display: flex;
align-items: center;
gap: 29px;
}
.pcm-action {
width: 69px;
height: 69px;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
cursor: pointer;
img {
width: 69px;
height: 69px;
object-fit: contain;
}
}
.pcm-download {
position: absolute;
left: 112px;
+83 -157
View File
@@ -6,9 +6,7 @@
class="mobile"
:os="os"
@getApkInfo="handleGetApkInfo"
@recordClick="recordClick"
:ip="ip"
:configs="configs"
:switchData="switchData"
:version="version"
style="height:100%"
@@ -22,7 +20,6 @@
class="pc"
:qr-img="QRImg"
:os="os"
:configs="configs"
@getApkInfo="handleGetApkInfo"
></pc>
</template>
@@ -32,9 +29,7 @@
class="mobile"
:os="os"
@getApkInfo="handleGetApkInfo"
@recordClick="recordClick"
:ip="ip"
:configs="configs"
:switchData="switchData"
style="height:100%"
ref="mobileRef"
@@ -47,7 +42,6 @@
class="pc"
:qr-img="QRImg"
:os="os"
:configs="configs"
@getApkInfo="handleGetApkInfo"
></pc2>
</template>
@@ -74,8 +68,7 @@
</div>
</template>
<script>
import getApkInfo from "@/api/getApkInfo";
import getButtonlist from "@/api/getTemplate";
import { getButtonList, bottonclick, downloadH5 } from "@/api/btn";
import userAgent from "@/utils/userAgent";
import QRCode from "qrcode";
import axios from "@/utils/request.js";
@@ -85,8 +78,7 @@ import pc from "./components/pc";
import pc2 from "./components/pc2";
import tips from "./components/tips";
import selectLinePopup from "./components/selectLinePopup";
import { getTraceId, landingPageView } from "@/utils/eventTracker";
const APPID = 214;
import { getTraceId } from "@/utils/traceId";
export default {
components: {
mobile1,
@@ -98,29 +90,15 @@ export default {
},
data() {
return {
type: "",
QRImg: "",
os: "",
param: "",
cutInfo: {}, //替换url参数对象内<key> dc内容;
ip: "",
switchData: {},
page_pc_url: "",
iosDownUrl: "",
androidDownUrl: "",
shopIosDownUrl: "", // 商店包链接
storeAndroidDownUrl: "",
channelApkAndDownUrl: "",
// iosJumpSetUpUrl: "", // 执行完下载链接后需要执行的跳转
loading: true,
currUrl: window.location.href,
apiUrls: JSON.parse(process.env.VUE_APP_BASE_HOSTS), // api数组
showOverlay: false, // 显示选线弹窗
configs: [],
// tgUrl: "",
// potatoUrl: "",
// swUrl: "",
// qdUrl: "",
version: "A",
trace_id: getTraceId()
};
@@ -132,67 +110,47 @@ export default {
}
},
created() {
// const queryVersion = (this.$route.query.version || "").toUpperCase();
// this.version =
// queryVersion === "A" || queryVersion === "B"
// ? queryVersion
// : Math.random() < 0.5
// ? "A"
// : "B";
this.version = "A";
this.getPcUrl();
this.os = userAgent();
this.functionParam();
this.getButtonlist();
landingPageView(this);
this.init();
const referrer = document.referrer;
// console.log(referrer, "-----------referrer");
if (referrer) {
sessionStorage.setItem("referrer", referrer);
}
if (this.$route.query.dc) {
sessionStorage.setItem("dc", this.$route.query.dc);
}
// this.getIp();
},
mounted() {
this.getQRImg();
},
methods: {
isDcMatch(value) {
const reg = /^(?:ky(?:(?:0[1-9]|[1-9][0-9]|100))|TLGG(?:(?:0[1-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-6]))|erra(?:(?:0[1-9]|10))|cctl(?:(?:0[1-9]|10))|mijieer[1-5][a-d])$/;
return reg.test(value);
},
getPcUrl() {
this.page_pc_url = window.location.href;
},
//1.判断进来的url地址 替换到需要手动设置的参数 如cd
functionParam() {
this.param =
JSON.stringify(this.$route.query) === "{}"
? "{}"
: JSON.stringify(this.$route.query);
async init() {
await this.getIp();
await this.getButtonlist();
},
//2.获取按钮状态信息
// 去掉空值后序列化渠道参数
filterChannel() {
const result = {};
Object.entries(this.$route.query).forEach(([key, value]) => {
if (value) result[key] = value;
});
return JSON.stringify(result);
},
//1.获取按钮开关(iosDown / iosStore / iosTF / iosH5 / androidButton)
async getButtonlist() {
try {
let param_btn_list = {
appId: APPID,
channel: this.param,
domain: window.location.protocol + "//" + window.location.host,
version: this.version
};
const res = await getButtonlist(param_btn_list);
const res = await getButtonList({
ip: this.ip,
channel: JSON.stringify(this.$route.query)
});
this.loading = false;
if (res.data.code === 200) {
this.switchData = res.data.data;
this.configs = res.data.data.configs || [];
this.androidDownUrl = res.data.data.androidDownUrl;
this.storeAndroidDownUrl = res.data.data.storeAndroidDownUrl;
this.channelApkAndDownUrl = res.data.data.channelApkAndDownUrl;
this.iosDownUrl = res.data.data.iosDownUrl;
this.shopIosDownUrl = res.data.data.shopIosDownUrl;
// this.iosJumpSetUpUrl = res.data.data.iosJumpSetUpUrl;
this.switchData = res.data.data || {};
}
} catch (err) {
this.loading = false;
@@ -200,105 +158,73 @@ export default {
console.log(err);
}
},
//3. 获取外网IP地址
getIp() {
axios.get("https://api.ipify.org/?format=json").then(res => {
this.ip = res.data.ip;
});
//2. 获取外网IP地址
async getIp() {
try {
const res = await fetch("https://api.ipify.org?format=json");
const data = await res.json();
this.ip = data.ip || "";
} catch (err) {
console.log("获取外部IP失败" + err);
}
},
//4. 点击下载按钮获取apk信息并下载
jumpToLink(link) {
// 微信内加时间戳,避免命中缓存
window.location.href = this.os.isWx ? link + "?time=" + Date.now() : link;
},
// bottonclick 返回的下载地址数组
async fetchLinks(terminal, extra = {}) {
const res = await bottonclick({
ip: this.ip,
channel: this.filterChannel(),
domain: window.location.host || "",
type: "iosH5",
terminal,
...extra
});
const link = res && res.data && res.data.data && res.data.data.link;
return Array.isArray(link) ? link.filter(Boolean) : [];
},
// iOS 轻量版:直接调 h5/config 下载描述文件
async downloadMobileConfig() {
const paramData = {};
if (this.$route.query.dc) paramData.dc = String(this.$route.query.dc);
if (this.$route.query.pc) paramData.pc = String(this.$route.query.pc);
const content = await downloadH5(paramData);
const file = new File([content], "descriptionFile.mobileconfig", {
type: "application/x-apple-aspen-config"
});
const objectUrl = URL.createObjectURL(file);
const link = document.createElement("a");
link.href = objectUrl;
link.download = "descriptionFile.mobileconfig";
link.click();
setTimeout(() => URL.revokeObjectURL(objectUrl), 10000);
},
//3. 点击下载按钮获取下载地址并下载
async handleGetApkInfo(type) {
await this.doCopy();
let terminal;
let packageType;
if (type === "ios") {
terminal = "ios";
packageType = 1;
} else if (type == "shopIos") {
terminal = "ios";
packageType = 2;
} else if (type == "androidSpare") {
terminal = "androidSpare";
} else {
terminal = "android";
try {
if (type === "ios") {
await this.downloadMobileConfig();
} else if (type === "shopIos") {
if (!this.switchData.iosStore) return;
const links = await this.fetchLinks("ios", {
type: "iosStore",
packageType: 2
});
if (links.length) this.jumpToLink(links[0]);
} else {
const links = await this.fetchLinks("android");
const target = (type === "androidSpare" && links[1]) || links[0];
if (target) this.jumpToLink(target);
}
} catch (err) {
console.log("下载失败" + err);
}
if (terminal === "android" || terminal === "androidSpare") {
let dc = this.$route.query.dc;
if (this.storeAndroidDownUrl && this.isDcMatch(dc)) {
let url = this.storeAndroidDownUrl || this.channelApkAndDownUrl;
window.location.href = url;
} else if (terminal === "androidSpare") {
window.location.href = this.androidDownUrl;
} else {
let jumpUrl = this.channelApkAndDownUrl || this.androidDownUrl;
window.location.href = jumpUrl;
}
} else {
let dc = this.$route.query.dc;
let ch = this.$route.query.ch;
let pc = this.$route.query.pc;
let linkUrl = "";
if (dc) {
linkUrl = `${this.iosDownUrl}?dc=${dc}&tid=${this.trace_id}`;
} else if (ch) {
linkUrl = `${this.iosDownUrl}?ch=${ch}&tid=${this.trace_id}`;
} else if (pc) {
linkUrl = `${this.iosDownUrl}?pc=${pc}&tid=${this.trace_id}`;
} else {
linkUrl = `${this.iosDownUrl}?tid=${this.trace_id}`;
}
if (type == "shopIos" && this.shopIosDownUrl) {
window.open(this.shopIosDownUrl);
} else {
window.location.href = linkUrl;
}
// if (this.iosJumpSetUpUrl) {
// setTimeout(() => {
// window.location.href = this.iosJumpSetUpUrl;
// }, 1500);
// }
}
// getApkInfo(param);
},
recordClick(type) {
let terminal;
let packageType;
if (type === "ios") {
terminal = "ios";
packageType = 1;
} else if (type == "shopIos") {
terminal = "ios";
packageType = 2;
} else {
terminal = "android";
}
const param = {
appId: APPID,
ip: this.ip ? this.ip : "", //获取ip地址
channel: JSON.stringify({
...JSON.parse(this.param),
...this.cutInfo
}),
domain: window.location.protocol + "//" + window.location.host,
terminal,
packageType,
version: this.version
};
getApkInfo(param);
},
//5.生成二维码
//4.生成二维码
getQRImg() {
// const referrer = sessionStorage.getItem("referrer");
// const dc = sessionStorage.getItem("dc");
// if (referrer && dc) {
// this.currUrl = referrer + "user.html?dc=" + dc;
// } else {
// if (referrer) {
// this.currUrl = referrer + "user.html";
// } else {
// this.currUrl = window.location.href;
// }
// }
QRCode.toDataURL(this.currUrl, {
width: 170,
margin: 1,
@@ -317,13 +243,13 @@ export default {
}
});
},
// 6.剪贴板
// 5.剪贴板
doCopy() {
let req = JSON.stringify({
...this.$route.query,
tid: this.trace_id
});
this.$copyText(req).then(
return this.$copyText(req).then(
() => {
console.log("复制成功");
},