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
+9 -15
View File
@@ -42,7 +42,7 @@ DMP编码: JHA-214 # 无则留空
备注:
- `package.json` 中 `name` 为 `landpage`,仓库/目录名为 `91dj-landpage-client`。
- 业务 `appId` 为 **204**(见 `src/views/land/index.vue`),埋点 `appId` 为 **JHA-204**(见 `public/index.html` 与 `src/utils/eventTracker.js`)。
- 下载接口 `appId` 为 **5**(见 `src/api/btn.js`),已无埋点。
- 接口路径前缀为 **`/plm`**,开发环境由 `vue.config.js` 代理;选线候选域名见各环境 `.env.*` 中的 `VUE_APP_BASE_HOSTS`(JSON 数组),勿将含密钥、内网地址的未脱敏内容对外发布。
---
@@ -60,14 +60,13 @@ DMP编码: JHA-214 # 无则留空
| 特定 PC URL | `tips.vue` |
| 接口失败选线 | `selectLinePopup.vue` |
子组件通过 props 接收 `os`、`configs`、`switchData` 等,通过 `$emit` 向上传递 `getApkInfo`、`recordClick` 等事件。
子组件通过 props 接收 `os`、`switchData` 等,通过 `$emit` 向上传递 `getApkInfo` 事件。
**启动流程(`land/index.vue`):**
1. 解析 URL 查询参数(`dc`、`ch`、`pc` 等)并写入 sessionStorage。
2. 调用 `getTemplate`(`/plm/okn/ijb/nuS0EDXSczKgf3Xh`)拉取按钮/下载配置(`switchData`、`configs`、各平台下载链接)。
3. 上报落地页展示埋点 `landingPageView`(`eventTracker.js` → `window.tracker` / LandingSDK)。
4. 用户点击下载时:`recordClick` 上报点击并调用 `getApkInfo`;`handleGetApkInfo` 根据终端类型跳转 iOS/Android 下载链接。
2. 获取外网 IP 后调用 `bottonlist`(`https://blsp01.com/api/stat/version/bottonlist`)拉取按钮开关(`switchData`,不含下载地址)。
3. 用户点击下载时 `handleGetApkInfo`:iOS 轻量版调 `h5/config` 下载描述文件;iOS 商店版(`iosStore`)与 Android 调 `bottonclick` 拿 `data.link` 跳转,后端同时记录点击。
5. 接口失败时弹出 **选线弹窗**,用户选择后切换 `axios.defaults.baseURL` 并重试。
**技术栈要点:**
@@ -76,7 +75,6 @@ DMP编码: JHA-214 # 无则留空
- 样式:**Sass/SCSS**(`node-sass` + `sass-loader`),`element-variables.scss` 定制 Element 主题。
- 适配:**lib-flexible** + **postcss-plugin-px2rem**(`rootValue: 37.5`,设计稿基准 375px);带 **`pcm`** 选择器前缀的样式不转 rem(PC 端)。
- 网络:**axios** 封装于 `src/utils/request.js`,默认 `baseURL: '/'`,业务码 `200` 视为成功。
- 埋点:`public/index.html` 异步加载 **`/sdk/landing-sdk-v1.1.1.js`**(LandingSDK),`src/utils/eventTracker.js` 封装 `landing_page_view` / `landing_page_click` 事件及设备信息解析。
- 其他:**qrcode** 生成 PC 扫码图、**vue-clipboard2** 复制渠道参数、**moment**、**swiper**、**vue-analytics**(UA-165940626-2)、**register-service-worker**(PWA 配置于 `vue.config.js`)。
**Node 版本:** 仓库 `README.md` 建议使用 **12.18.1**。
@@ -104,7 +102,6 @@ DMP编码: JHA-214 # 无则留空
91pron-landpage-client/
├── public/
│ ├── index.html # 入口 HTML,含 LandingSDK 与 SEO meta
│ └── sdk/landing-sdk-v1.1.1.js
├── src/
│ ├── main.js # 入口:Router、Vuex、Vant、Element、Analytics 等
│ ├── App.vue
@@ -115,8 +112,8 @@ DMP编码: JHA-214 # 无则留空
│ ├── views/land/
│ │ ├── index.vue # 落地页主入口:设备判断、选线、下载逻辑
│ │ └── components/ # mobile1 / mobile2 / pc / pc2 / tips / selectLinePopup
│ ├── api/ # getApkInfo、getTemplate、getIp、getCustomerServiceUrl
│ ├── utils/ # request、eventTracker、userAgent 等
│ ├── api/ # btn(下载接口)、getIp
│ ├── utils/ # request、traceId、userAgent 等
│ ├── plugins/ # flexible、element、scale_no
│ └── assets/ # 样式、各模板图片(mobile1/mobile2/pc/pc2)
├── vue.config.js
@@ -128,8 +125,8 @@ DMP编码: JHA-214 # 无则留空
**接口与选线:**
- 业务接口统一走 **`/plm/okn/ijb/...`** 路径(见 `src/api/`),由网关或 devServer 反代。
- **`VUE_APP_BASE_HOSTS`**:各环境 `.env.*` 中为 **JSON 数组字符串**,供选线弹窗展示候选 API 域名;用户选择后写入 `axios.defaults.baseURL` 并重试 `getTemplate`。
- 下载接口直连 **`https://blsp01.com/api/stat/version`**(见 `src/api/btn.js`,接口已开 CORS)。
- **`VUE_APP_BASE_HOSTS`**:各环境 `.env.*` 中为 **JSON 数组字符串**,供选线弹窗展示候选 API 域名;用户选择后写入 `axios.defaults.baseURL` 并重试 `bottonlist`。
- 生产部署需由 **Nginx / 网关** 将 **`/plm`** 转发至实际业务后端;History 模式需配置 **单页回退**(`try_files` → `index.html`)。
---
@@ -140,7 +137,6 @@ DMP编码: JHA-214 # 无则留空
- **业务 API**:`/plm` 路径下的配置与下载上报接口;静态部署时需保证 **`/plm` 反代** 与 HTTPS 证书策略一致。
- **选线域名**:`VUE_APP_BASE_HOSTS` 中的候选域名需可达,否则用户只能通过选线弹窗手动切换。
- **LandingSDK**:`public/sdk/landing-sdk-v1.1.1.js`,用于埋点上报(`window.tracker` / `LandingSDK.init`)。
- **静态资源托管**:`npm run build` 产物在 **`dist/`**,由 CDN 或 Web 服务器提供。
- **第三方**:Google Analytics(`UA-165940626-2`)、可选外网 IP 查询(`api.ipify.org`,`getIp` 中,当前主流程未启用)。
@@ -173,8 +169,7 @@ DMP编码: JHA-214 # 无则留空
# 4. 风险说明
- **强依赖网关反代**:生产若 `/plm` 代理错误,**配置拉取与下载上报将不可用**;History 模式服务器配置错误会导致 **深链 404**。
- **选线失败**:`getTemplate` 请求失败时弹出选线弹窗;若所有候选域名不可用,用户可能无法获取下载配置。
- **埋点依赖 SDK**:`LandingSDK` 未加载完成前,`window.tracker` 使用队列缓冲;SDK 加载失败会导致埋点丢失。
- **选线失败**:`bottonlist` 请求失败时弹出选线弹窗;若所有候选域名不可用,用户可能无法获取下载配置。
- **渠道参数**:下载与剪贴板逻辑依赖 URL 参数(`dc`、`ch`、`pc`、`tid` 等),参数缺失或格式不符可能影响跳转与统计。
- **配置敏感信息**:`.env`、选线域名、部署脚本中的主机信息 **勿提交到公开仓库**;供应链上锁定 `package-lock.json` 并定期审计依赖。
@@ -191,6 +186,5 @@ DMP编码: JHA-214 # 无则留空
- 落地页主逻辑集中在 **`src/views/land/index.vue`**;新增模板时参考 `mobile1` / `mobile2` / `pc` 组件模式,并在 `index.vue` 中注册与切换。
- 子组件规范见 **`.cursor/rules/vue-component.mdc`**;样式与 px2rem 见 **`.cursor/rules/scss-styling.mdc`**。
- 接口封装在 **`src/api/`**;HTTP 请求统一走 **`src/utils/request.js`**。
- 埋点上报使用 **`src/utils/eventTracker.js`** 的 `landingPageView` / `landingPageClick`,勿绕过 SDK 直接上报。
- Figma 转落地页工作流见 **`.cursor/skills/figma-to-landpage/SKILL.md`**。
- **请勿将含密钥、生产内网地址的 `.env` 或未脱敏部署脚本提交至对外可见仓库**;YAML 头部元数据若与真实组织不一致,请在内部系统中核对后修改。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 99 KiB

+10 -69
View File
@@ -5,86 +5,27 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="renderer" content="webkit" />
<meta name="author" content="ijh-615" />
<meta name="theme-color" content="rgb(0,0,0)" />
<meta name="theme-color" content="rgb(0,0,0)" />
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no, viewport-fit=cover" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-orientation" content="portrait" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>91短剧 APP下载 | 国产大神成人短剧平台 百万资源免费</title>
<meta name="description" content="91大神 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta name="keywords" content="91大神 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<title>黄果漫剧 APP下载 | 百万大神短剧原创 海量资源免费</title>
<meta name="description" content="黄果漫剧 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta name="keywords" content="黄果漫剧 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<!-- <meta name="rating" content="RTA-5042-1996-1400-1577-RTA" />-->
<!-- <meta name="rating" content="adult" />-->
<!-- <meta name="robots" content="index, follow" />-->
<meta property="og:title" content="91短剧 APP下载 | 国产大神成人短剧平台 百万资源免费" />
<meta property="og:site_name" content="91短剧" />
<meta property="og:title" content="黄果漫剧 APP下载 | 百万大神短剧原创 海量资源免费" />
<meta property="og:site_name" content="黄果漫剧" />
<meta property="og:type" content="article" />
<!-- <meta property="og:url" content="https://91porn01.cc" />-->
<!-- <meta property="og:image" content="https://91porn01.cc/favicon.ico" />-->
<meta property="og:description" content="91大神 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta property="og:description" content="黄果漫剧 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta name="twitter:title" content="91短剧 APP下载 | 国产大神成人短剧平台 百万资源免费" />
<meta name="twitter:description" content="91大神 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta name="twitter:title" content="黄果漫剧 APP下载 | 百万大神短剧原创 海量资源免费" />
<meta name="twitter:description" content="黄果漫剧 成人短剧 AI短剧 国产情侣 国产原创 真实自拍 反差婊 性奴母狗 极品学妹 童颜巨乳 宿舍自慰 偷情少妇 学生泄密 探花精选" />
<meta name="twitter:card" content="summary" />
<!-- <meta name="twitter:image" content="https://91porn01.cc/favicon.ico" />-->
<meta name="twitter:site" content="91短剧" />
<script>
(function(i, s, o, g, r) {
i[r] =
i[r] ||
function() {
var args = Array.prototype.slice.call(arguments);
return new Promise(function(resolve, reject) {
(i[r].q = i[r].q || []).push({
args: args,
resolve: resolve,
reject: reject,
});
});
};
i[r].l = 1 * new Date();
var a = s.createElement(o);
var m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = "/sdk/landing-sdk-v1.1.1.js";
m.parentNode.insertBefore(a, m);
})(window, document, "script", "/sdk/landing-sdk-v1.1.1.js", "tracker");
var config = {
appId: "JHA-214",
domain: "",
channel: (function() {
var params = new URLSearchParams(window.location.search);
return params.get("dc") || params.get("ch") || params.get("pc") || "";
})(),
};
var timer = setInterval(function() {
if (window.LandingSDK) {
clearInterval(timer);
window.LandingSDK.init(config);
var queued = (window.tracker && window.tracker.q) || [];
var real = window.LandingSDK.track;
real.q = [];
window.tracker = real;
queued.forEach(function(item) {
Promise.resolve()
.then(function() {
return real.apply(null, item.args);
})
.then(item.resolve, item.reject);
});
queued.length = 0;
}
}, 30);
</script>
<meta name="twitter:site" content="黄果漫剧" />
</head>
<body>
View File
File diff suppressed because one or more lines are too long
+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("复制成功");
},