474 lines
24 KiB
HTML
474 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="divport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Document</title>
|
|
<link rel="stylesheet" href="./h5.css" />
|
|
|
|
<style>
|
|
[v-cloak] {
|
|
display: none;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script>
|
|
(function (window, document) {
|
|
var sizeUI = 750; // 定义设计图尺寸
|
|
var remBase = 75; // 定义基准值
|
|
var docEl = document.documentElement;
|
|
var bodyEl = document.querySelector("body");
|
|
|
|
setRemUnit();
|
|
|
|
window.addEventListener("resize", setRemUnit);
|
|
window.addEventListener("pageshow", function (e) {
|
|
if (e.persisted) setRemUnit();
|
|
});
|
|
|
|
function setRemUnit() {
|
|
var docFontSize = (docEl.clientWidth / sizeUI) * remBase;
|
|
docEl.style.fontSize = docFontSize + "px";
|
|
bodyEl.style.fontSize = 16 / docFontSize + "rem";
|
|
handleRemAdapt();
|
|
}
|
|
|
|
function handleRemAdapt() {
|
|
var currentFontSize = parseInt(docEl.style.fontSize);
|
|
var temp = currentFontSize;
|
|
for (var i = 0; i < 100; i++) {
|
|
var realFontSize = parseInt(window.getComputedStyle(docEl).fontSize);
|
|
var differ = realFontSize - currentFontSize;
|
|
if (Math.abs(differ) >= 1) {
|
|
if (differ > 0) temp--;
|
|
else temp++;
|
|
docEl.style.fontSize = temp + "px";
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
})(window, document);
|
|
</script>
|
|
|
|
<div id="admission-officer" class="admission-officer" v-cloak class="container">
|
|
<div class="header-box">
|
|
<img class="header-bj" src="https://app.gter.net/image/miniApp/offer/admission-bj-blue.svg" />
|
|
<img class="bj-green" src="https://app.gter.net/image/miniApp/offer/admission-bj-green.svg" />
|
|
<img class="header-img" src="https://app.gter.net/image/miniApp/offer/admission-text.png" />
|
|
</div>
|
|
|
|
<div class="interview-box" v-if="interviewData" @click="getVideoUrl(interviewData.token)">
|
|
<div class="head">
|
|
<img class="icon" src="https://app.gter.net/image/miniApp/offer/interview-icon.png" />
|
|
<img class="name" src="https://app.gter.net/image/miniApp/offer/interview-name.png" />
|
|
<img class="head-bj" src="https://app.gter.net/image/miniApp/offer/interview-other.svg" />
|
|
</div>
|
|
<img class="ok" src="https://app.gter.net/image/miniApp/offer/duck-ok.png" />
|
|
<img class="img" :src="interviewData.video_cover" />
|
|
<img class="play" src="https://app.gter.net/image/miniApp/offer/play-btn.svg" />
|
|
<div class="bottom">
|
|
<div class="title one-line-display">{{ interviewData.title }}</div>
|
|
<div class="subtitle one-line-display">{{ interviewData.subtitle }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="interview-list" scroll-x v-if="interviewList.length > 0">
|
|
<div class="item" v-for="(item,index) in interviewList" :key="index" @click="getVideoUrl(item.token)">
|
|
<img class="img" :src="item.video_cover" />
|
|
<div class="title one-line-display">{{ item.title }}</div>
|
|
<div class="subtitle one-line-display">{{ item.subtitle }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="preach-box" ref="swiperBox" v-if="preachList.length != 0" @touchstart="handleTouchStart" @touchend="handleTouchEnd">
|
|
<div class="head">
|
|
<img class="icon" src="https://app.gter.net/image/miniApp/offer/preach-icon.png" />
|
|
<img class="name" src="https://app.gter.net/image/miniApp/offer/preach-name.png" />
|
|
<img class="head-bj" src="https://app.gter.net/image/miniApp/offer/preach-other.svg" />
|
|
</div>
|
|
<div class="swiper flexflex" ref="swiperBoxSwiper" :style="{'height': preachList[0].length >= 3 ? '4.08rem' : preachList[0].length * 1.36 + 'rem'}">
|
|
<div class="swiper-item" v-for="(item,index) in preachList" :key="index">
|
|
<a class="item" v-for="(it,index) in item" :key="index" :href="it.link_url" target="_blank">
|
|
<div class="title flexacenter">
|
|
<div class="one-line-display text">{{ it.title }}</div>
|
|
<img class="arrow" src="https://app.gter.net/image/miniApp/offer/arrow-return.svg" />
|
|
</div>
|
|
<div class="time one-line-display">{{ it.lecture_time || '长期答疑' }}</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="indicator flexcenter" v-if="preachList.length > 1">
|
|
<div class="item" :class="{'pitch': swiperCurrent == index}" v-for="(item,index) in preachList" :key="index"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="list" v-if="admissionList.length != 0">
|
|
<div class="item" v-for="(item,index) in admissionList" :key="item.id">
|
|
<div class="header">
|
|
<div class="abbreviation">
|
|
<img class="school-other" src="https://app.gter.net/image/miniApp/offer/school-other.svg" />
|
|
<div class="text" :style="{backgroundColor: item.color }">{{ item.abbreviation }}</div>
|
|
</div>
|
|
<img class="img" :src="item.banner" />
|
|
<div class="header-content flexacenter">
|
|
<img class="school-img" :src="item.logo" />
|
|
<div class="flex1">
|
|
<div class="school-name">
|
|
{{ item.name }}
|
|
<img class="arrow" src="https://app.gter.net/image/miniApp/offer/arrow-return.svg" />
|
|
</div>
|
|
<div class="school-english">{{ item.enname }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="introduction">{{ item.introduction }}</div>
|
|
<div class="year flexacenter">
|
|
<div class="year-item flexcenter" v-for="(it,i) in item.yList" :key="i" :class="{'pitch': item.pitch == it}" :style="{backgroundColor: item.pitch == it ? item.color : '' }" @click.stop="cutSchoolYear(index,it)">{{ it }}季</div>
|
|
|
|
<div class="year-item more flexcenter" :class="[{'unfold': item.state,'pitch': item.isPitchMore}]" :style="{backgroundColor: item.state || item.isPitchMore ? item.color : '' }" @click="openSchoolYearState(index)" v-if="item.yListMore.length > 0">
|
|
<text>{{ item.isPitchMore ? item.pitch + '季' : '更多' }}</text>
|
|
<div class="triangle"></div>
|
|
<div class="more-mask" @click.stop="closeSchoolYearState(index)"></div>
|
|
<div class="more-box" :style="{backgroundColor: item.color }">
|
|
<div class="more-item" v-for="(it,i) in item.yListMore" :key="i" @click.stop="selectSchoolYearState(index,it)">{{ it }}季</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="title-box">
|
|
<div class="title-item flexcenter" v-for="(it,index) in item.list[item.pitch]" :key="index">
|
|
<div class="name flexflex">
|
|
<div class="icon flexcenter">
|
|
<img class="img" src="https://app.gter.net/image/miniApp/offer/course-icon.png" />
|
|
</div>
|
|
<div class="text flex1">
|
|
{{ it.title }}
|
|
<div class="label" v-if="it.tag">
|
|
<img class="arrows" src="https://app.gter.net/image/miniApp/offer/arrows-triangle-blue.svg" />
|
|
{{ it.tag }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bottom flexacenter">
|
|
<div class="time flexacenter">
|
|
<div class="icon flexcenter">
|
|
<img class="img" src="https://app.gter.net/image/miniApp/offer/time-icon.png" />
|
|
</div>
|
|
{{ it.date || '长期答疑' }}
|
|
</div>
|
|
<a class="btn flexcenter" :href="it.url" target="_blank" :style="{backgroundColor: item.color }">详情 <img class="arrows" src="https://app.gter.net/image/miniApp/offer/arrows-circle-white.svg" /></a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="end">- End -</div>
|
|
|
|
<div class="paly-box-mask flexcenter" v-if="palyState">
|
|
<div class="paly-box" @click.stop="">
|
|
<img class="close" src="../img/cross-white.svg" @click="closePalyState" />
|
|
<div class="paly-video"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 引入了 vue3 js 创建 vue3 实例 -->
|
|
<script src="../js/vue.global.min.js"></script>
|
|
<script src="../js/artplayer.js"></script>
|
|
|
|
<script>
|
|
// 创建Vue3实例
|
|
const { createApp, onMounted, ref, onUnmounted, reactive } = Vue;
|
|
const admissionApp = createApp({
|
|
setup() {
|
|
onMounted(() => {
|
|
init();
|
|
getBannerList();
|
|
getAdmissionLists();
|
|
});
|
|
|
|
let interviewData = ref({}); // 模式一 的第一个访谈
|
|
|
|
let interviewList = ref({}); // 访谈 列表
|
|
|
|
const init = () => {
|
|
fetchData("/v1/admissionsOfficer/interview").then((res) => {
|
|
if (res.code != 200) return;
|
|
let data = res.data || [];
|
|
for (let i = 0; i < 20; i++) {
|
|
data.push({
|
|
title: "岭南大学保险",
|
|
subtitle: "香港商学院硕士都去卖保险了",
|
|
video_cover: "https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-Z0kdXrqqsgFptxhcq_cQnrlIKYkXFcXBq_D-81qNDQyOQ~~",
|
|
sid: 350 + i,
|
|
name: "岭南大学",
|
|
enname: "Lingnan University",
|
|
admission_officer_name: "施林佟",
|
|
admission_officer_rank: "副教授",
|
|
admission_officer_position: "数据科学学院助理院长",
|
|
focus_of_this_issue: "寄托建立了具有公信力的品牌评价系统\n致力打造一个华人区最专业的留学交流平台\n成为一个寄托或关于梦想的垂直门户网站",
|
|
istop: 1,
|
|
token: "D6zdTJ2cMaKd0g6nFqsa1JR5scupqIIg5Wuab33kATaY-myKGtBtHiygo4F5z8iY_Le6VEcmblBwOvlbiqvh1pyXKaET8hp8OsXbY1fFQwRKjq42OWQ3" + i,
|
|
});
|
|
}
|
|
|
|
let target = null;
|
|
const topItems = data.filter((item) => item.istop === 1);
|
|
|
|
if (topItems.length > 0) target = topItems[Math.floor(Math.random() * topItems.length)];
|
|
|
|
data = data.filter((item) => item.token !== target.token);
|
|
|
|
interviewData.value = target;
|
|
interviewList.value = data || [];
|
|
});
|
|
};
|
|
|
|
let palyState = ref(false); // 播放弹窗状态
|
|
|
|
let art = null; // 播放器实例
|
|
|
|
const getVideoUrl = (token) => {
|
|
fetchData(`/v1/admissionsOfficer/videoUrl?token=${token}`).then((res) => {
|
|
palyState.value = true;
|
|
setTimeout(() => {
|
|
art = new Artplayer({
|
|
container: ".paly-box-mask .paly-box .paly-video",
|
|
url: res.data.url,
|
|
autoplay: true,
|
|
fullscreen: true,
|
|
});
|
|
}, 500);
|
|
});
|
|
};
|
|
|
|
const closePalyState = () => {
|
|
art?.pause();
|
|
art?.destroy();
|
|
palyState.value = false;
|
|
};
|
|
|
|
let admissionList = ref([]); // 学校 招生官 列表
|
|
|
|
// 获取 院校 招生官 列表
|
|
const getAdmissionLists = () => {
|
|
fetchData(`/v1/admissionsOfficer/lists`).then((res) => {
|
|
if (res.code != 200) return;
|
|
const data = res.data;
|
|
let target = data.data || [];
|
|
|
|
target.forEach((item) => {
|
|
let year = [];
|
|
let obj = {};
|
|
item.articles.forEach((e) => {
|
|
year.push(e.year);
|
|
obj[e.year] = e.data;
|
|
});
|
|
|
|
item["pitch"] = year[0];
|
|
item["yList"] = year.slice(0, 4);
|
|
item["yListMore"] = year.slice(4);
|
|
item["list"] = obj;
|
|
});
|
|
|
|
admissionList.value = target;
|
|
});
|
|
};
|
|
|
|
// 切换招生官 院校 的 年份
|
|
const cutSchoolYear = (index, year) => {
|
|
admissionList.value[index]["pitch"] = year;
|
|
};
|
|
|
|
// 点击 招生官 年份 更多弹窗
|
|
const openSchoolYearState = (index) => (admissionList.value[index]["state"] = true);
|
|
|
|
// 选择 招生官 年份 更多弹窗
|
|
const selectSchoolYearState = (index, year) => {
|
|
admissionList.value[index]["pitch"] = year;
|
|
admissionList.value[index]["isPitchMore"] = true;
|
|
admissionList.value[index]["state"] = false;
|
|
};
|
|
|
|
// 关闭 招生官 年份 更多弹窗
|
|
const closeSchoolYearState = (index) => (admissionList.value[index]["state"] = false);
|
|
|
|
let moreSchoolSid = ref(0); // 选中 学校 sid
|
|
let moreSchoolData = ref({}); // 学校信息
|
|
let moreSchoolList = ref([]); // 年份下 列表 数据
|
|
let moreSchoolPitch = ref(0); // 选中年份
|
|
let moreSchoolYList = ref([]); // 年份 列表
|
|
let moreSchoolYMList = ref([]); // 年份 更多
|
|
const openMoreSchool = (sid) => {
|
|
fetchData(`/v1/admissionsOfficer/articles?sid=${sid}`).then((res) => {
|
|
if (res.code != 200) return;
|
|
const data = res.data || {};
|
|
moreSchoolData.value = data.school;
|
|
let target = data.data || [];
|
|
console.log("target", target);
|
|
let obj = {};
|
|
let yearList = [];
|
|
target.forEach((element) => {
|
|
obj[element.year] = element.data;
|
|
yearList.push(element.year);
|
|
});
|
|
|
|
moreSchoolYList.value = yearList.slice(0, 4);
|
|
moreSchoolYMList.value = yearList.slice(4);
|
|
moreSchoolPitch.value = yearList[0];
|
|
moreSchoolList.value = obj;
|
|
moreSchoolSid.value = sid;
|
|
document.body.style.overflow = "hidden";
|
|
});
|
|
};
|
|
|
|
let moreYearState = ref(false);
|
|
|
|
const openMoreYearState = () => {
|
|
moreYearState.value = true;
|
|
};
|
|
|
|
const closeMoreSchool = () => {
|
|
moreSchoolSid.value = 0;
|
|
document.body.style.overflow = "auto";
|
|
};
|
|
|
|
onUnmounted(() => {});
|
|
|
|
let preachList = ref([]); // 宣讲会 列表
|
|
let preachIndex = ref(0); // 宣讲会 下标
|
|
let preachI = ref(0); // 宣讲会 下标
|
|
let preachTimer = null;
|
|
|
|
let preachInterval = 3; // 每页 4 条
|
|
|
|
const getBannerList = () => {
|
|
fetchData(`/v1/admissionsOfficer/banner`).then((res) => {
|
|
if (res.code != 200) return;
|
|
|
|
let data = res.data;
|
|
|
|
for (let i = 0; i < 20; i++) {
|
|
data.push({
|
|
id: i + 20,
|
|
title: "香港中文大学 | 美国西北大学双硕士学位课程",
|
|
lecture_time: "2025-07-12 00:00:00",
|
|
image_url: "https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-Z0rfHjqqsgFptxhT66SWgrlI64uMxcfWaHf9cJWpdxZDnzZ5RLrizQ0Mjk~",
|
|
image_id: 977797,
|
|
sort: 1,
|
|
link_url: "https://www.baidu.com",
|
|
status: 1,
|
|
created_at: "2025-07-11 16:59:10",
|
|
updated_at: "2025-07-11 17:09:33",
|
|
});
|
|
}
|
|
|
|
// data.forEach((element, index) => (element["id"] = index + 1));
|
|
data.forEach((element) => (element["lecture_time"] = timeformat(element["lecture_time"])));
|
|
|
|
let target = [];
|
|
for (let i = 0; i < data.length; i += preachInterval) {
|
|
target.push(data.slice(i, i + preachInterval));
|
|
}
|
|
|
|
preachList.value = target;
|
|
|
|
preachListTimeout();
|
|
});
|
|
};
|
|
|
|
const timeformat = (time) => {
|
|
time = time.replaceAll("-", "/"); // 修改格式
|
|
let result = "";
|
|
var datetime = new Date(time);
|
|
var Nyear = datetime.getFullYear();
|
|
var Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
|
|
var Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
|
|
var Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
|
|
var Nmin = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
|
|
result = `${Nyear}年${Nmonth}月${Ndate}日 ${Nhour}:${Nmin}`;
|
|
|
|
return result;
|
|
};
|
|
|
|
const swiperBox = ref(null);
|
|
const swiperBoxSwiper = ref(null);
|
|
let swiperCurrent = ref(0); // 宣讲会 下标
|
|
let preachListTimer = null; // 宣讲会 定时器
|
|
const preachListTimeout = () => {
|
|
preachListTimer = setTimeout(() => {
|
|
const width = swiperBox.value.scrollWidth;
|
|
swiperCurrent.value++;
|
|
|
|
if (swiperCurrent.value >= preachList.value.length) swiperCurrent.value = 0;
|
|
|
|
swiperBoxSwiper.value.scrollTo({
|
|
left: width * swiperCurrent.value,
|
|
behavior: "smooth",
|
|
});
|
|
|
|
preachListTimeout();
|
|
}, 3000);
|
|
};
|
|
|
|
// const touchStartX = ref(0);
|
|
// const touchStartY = ref(0);
|
|
|
|
const handleTouchStart = (e) => {
|
|
clearTimeout(preachListTimer);
|
|
// touchStartX.value = e.touches[0].clientX;
|
|
// touchStartY.value = e.touches[0].clientY;
|
|
};
|
|
|
|
const handleTouchEnd = (e) => {
|
|
preachListTimeout();
|
|
|
|
// const touchEndX = e.changedTouches[0].clientX;
|
|
// const touchEndY = e.changedTouches[0].clientY;
|
|
// const diffX = touchEndX - touchStartX.value;
|
|
// const diffY = touchEndY - touchStartY.value;
|
|
// console.log(`Touch moved X: ${diffX}, Y: ${diffY}`);
|
|
};
|
|
|
|
const fetchData = (url, data) => {
|
|
return new Promise((resolve, reject) => {
|
|
const baseUrl = "https://api.gter.net";
|
|
if (url.indexOf("http") == -1) url = baseUrl + url;
|
|
// 构建查询字符串
|
|
const queryString = Object.keys(data || {})
|
|
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
|
|
.join("&");
|
|
|
|
// 将查询字符串添加到URL
|
|
if (queryString) url += (url.indexOf("?") === -1 ? "?" : "&") + queryString;
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.responseType = "json";
|
|
xhr.withCredentials = true;
|
|
|
|
xhr.open("POST", url, true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onreadystatechange = function () {
|
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|
let response = xhr.response;
|
|
resolve(response);
|
|
}
|
|
};
|
|
|
|
xhr.send();
|
|
});
|
|
};
|
|
|
|
return { swiperBoxSwiper, swiperBox, swiperCurrent, closePalyState, getVideoUrl, palyState, interviewList, closeSchoolYearState, selectSchoolYearState, openSchoolYearState, cutSchoolYear, admissionList, moreSchoolYMList, openMoreYearState, moreYearState, moreSchoolPitch, moreSchoolYList, moreSchoolList, moreSchoolData, moreSchoolSid, closeMoreSchool, openMoreSchool, interviewData, preachList, preachIndex, preachI, handleTouchStart, handleTouchEnd };
|
|
},
|
|
});
|
|
// 挂载到页面中的#app元素
|
|
admissionApp.mount("#admission-officer");
|
|
</script>
|
|
</body>
|
|
</html>
|