no message

This commit is contained in:
DESKTOP-RQ919RC\Pc 2025-03-17 14:36:03 +08:00
parent 911f31668f
commit c64f3c4430
6 changed files with 813 additions and 456 deletions

View File

@ -431,6 +431,82 @@
height: 16px;
margin-left: 8px;
}
.ranking {
width: 1200px;
height: 239px;
background-color: #ffffff;
border-radius: 12px;
padding-left: 30px;
}
.ranking .synthesize {
width: 256px;
margin-right: 65px;
}
.ranking .major {
width: 821px;
}
.ranking .major .head {
justify-content: space-between;
}
.ranking .major .head .more {
font-size: 16px;
color: #333333;
font-weight: 400;
}
.ranking .major .head .more .icon {
width: 16px;
height: 16px;
margin-left: 7px;
transform: rotate(270deg);
}
.ranking .major .list {
flex-wrap: wrap;
justify-content: space-between;
}
.ranking .major .list .item {
width: 371px;
}
.ranking .major .list .item .organ {
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
font-weight: 650;
font-size: 14px;
color: #000000;
}
.ranking .major .list .item .arrows {
width: 12px;
height: 12px;
margin: 0 6px;
}
.ranking .major .list .item .text {
max-width: 195px;
}
.ranking .head {
height: 52px;
line-height: 52px;
font-weight: 650;
font-size: 16px;
color: #000000;
border-bottom: 1px solid #ebebeb;
}
.ranking .list {
padding-top: 11px;
}
.ranking .list .item {
font-size: 14px;
color: #333;
line-height: 24px;
}
.ranking .list .item .dot {
width: 8px;
height: 8px;
background-color: #fddf6d;
border: 1px solid #cab157;
border-radius: 39px;
margin-right: 13px;
}
.ranking .list .item:not(:last-of-type) {
margin-bottom: 8px;
}
.recruit {
width: 100%;
border: 1px solid #ebebeb;

View File

@ -490,6 +490,88 @@
}
}
.ranking {
width: 1200px;
height: 239px;
background-color: rgba(255, 255, 255, 1);
border-radius: 12px;
padding-left: 30px;
.synthesize {
width: 256px;
margin-right: 65px;
}
.major {
width: 821px;
.head {
justify-content: space-between;
.more {
font-size: 16px;
color: #333333;
font-weight: 400;
.icon {
width: 16px;
height: 16px;
margin-left: 7px;
transform: rotate(270deg);
}
}
}
.list {
flex-wrap: wrap;
justify-content: space-between;
.item {
width: 371px;
.organ {
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
font-weight: 650;
font-size: 14px;
color: #000000;
}
.arrows {
width: 12px;
height: 12px;
margin: 0 6px;
}
.text {
max-width: 195px;
}
}
}
}
.head {
height: 52px;
line-height: 52px;
font-weight: 650;
font-size: 16px;
color: #000000;
border-bottom: 1px solid #ebebeb;
}
.list {
padding-top: 11px;
.item {
.dot {
width: 8px;
height: 8px;
background-color: rgba(253, 223, 109, 1);
border: 1px solid rgba(202, 177, 87, 1);
border-radius: 39px;
margin-right: 13px;
}
font-size: 14px;
color: #333;
line-height: 24px;
&:not(:last-of-type) {
margin-bottom: 8px;
}
}
}
}
.recruit {
width: 100%;
// height: 502px;
@ -624,7 +706,6 @@
font-size: 14px;
padding: 0 8px;
.img-add {
width: 12px;
height: 12px;

View File

@ -126,44 +126,38 @@
color: #000000;
width: 62px;
}
.boxbox .content .content-left .list .item .info .name {
.boxbox .content .content-left .list .item .info .head {
justify-content: space-between;
align-items: flex-start;
}
.boxbox .content .content-left .list .item .info .head .name {
font-weight: 650;
font-style: normal;
font-size: 16px;
color: #000000;
margin-bottom: 5px;
}
.boxbox .content .content-left .list .item .info .head .grade {
font-size: 14px;
color: #aaaaaa;
text-align: right;
width: max-content;
}
.boxbox .content .content-left .list .item .info .head .grade .sum {
font-weight: 650;
color: #333333;
}
.boxbox .content .content-left .list .item .info .name-en {
font-size: 13px;
line-height: 20px;
color: #333333;
margin-bottom: 6px;
}
.boxbox .content .content-left .list .item .info .city {
font-size: 14px;
color: #7f7f7f;
line-height: 20px;
.boxbox .content .content-left .list .item .info .bottom {
justify-content: space-between;
align-items: flex-start;
}
.boxbox .content .content-left .list .item .right {
align-items: flex-end;
position: relative;
}
.boxbox .content .content-left .list .item .grade {
font-size: 14px;
line-height: 28px;
color: #aaaaaa;
margin-bottom: 16px;
text-align: right;
position: absolute;
top: 0;
right: 0;
width: max-content;
}
.boxbox .content .content-left .list .item .grade .sum {
font-weight: 650;
color: #333333;
}
.boxbox .content .content-left .list .item .btn {
.boxbox .content .content-left .list .item .info .bottom .btn {
width: 108px;
height: 30px;
background-color: #f95d5d;
@ -171,11 +165,16 @@
font-size: 14px;
color: #ffffff;
}
.boxbox .content .content-left .list .item .btn .icon {
.boxbox .content .content-left .list .item .info .bottom .btn .icon {
width: 16px;
height: 16px;
margin-left: 7px;
}
.boxbox .content .content-left .list .item .info .bottom .city {
font-size: 14px;
color: #7f7f7f;
line-height: 20px;
}
.boxbox .content .screen-box {
width: 360px;
background-color: #fff;
@ -291,10 +290,30 @@
z-index: -1;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .major-list-list {
margin: 64px 11px 20px;
margin: 64px 0 20px 11px;
overflow: auto;
height: 400px;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .major-list-list::-webkit-scrollbar {
width: 0;
height: 0;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .initial {
flex-direction: column;
margin-top: 64px;
font-size: 12px;
text-align: center;
line-height: 17px;
color: #aaaaaa;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .initial .select {
font-weight: 650;
color: #000000;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .initial .item {
padding: 0 7px;
cursor: pointer;
}
.boxbox .content .screen-box .screen-item.major .major-box .major-list .major-item {
line-height: 26px;
font-size: 14px;

View File

@ -143,12 +143,34 @@
}
.info {
.name {
font-weight: 650;
font-style: normal;
font-size: 16px;
color: #000000;
margin-bottom: 5px;
.head {
justify-content: space-between;
align-items: flex-start;
.name {
font-weight: 650;
font-style: normal;
font-size: 16px;
color: #000000;
margin-bottom: 5px;
}
.grade {
font-size: 14px;
// line-height: 28px;
color: #aaaaaa;
// margin-bottom: 16px;
text-align: right;
// position: absolute;
// top: 0;
// right: 0;
width: max-content;
.sum {
font-weight: 650;
color: #333333;
}
}
}
.name-en {
font-size: 13px;
@ -156,49 +178,36 @@
color: #333333;
margin-bottom: 6px;
}
.city {
font-size: 14px;
color: #7f7f7f;
line-height: 20px;
.bottom {
justify-content: space-between;
align-items: flex-start;
.btn {
width: 108px;
height: 30px;
background-color: rgba(249, 93, 93, 1);
border-radius: 95px;
font-size: 14px;
color: #ffffff;
.icon {
width: 16px;
height: 16px;
margin-left: 7px;
}
}
.city {
font-size: 14px;
color: #7f7f7f;
line-height: 20px;
}
}
}
.right {
align-items: flex-end;
position: relative;
}
.grade {
font-size: 14px;
line-height: 28px;
color: #aaaaaa;
margin-bottom: 16px;
text-align: right;
position: absolute;
top: 0;
right: 0;
width: max-content;
.sum {
font-weight: 650;
color: #333333;
}
}
.btn {
width: 108px;
height: 30px;
background-color: rgba(249, 93, 93, 1);
border-radius: 95px;
font-size: 14px;
color: #ffffff;
.icon {
width: 16px;
height: 16px;
margin-left: 7px;
}
}
// .right {
// align-items: flex-end;
// position: relative;
// }
}
}
}
@ -325,9 +334,33 @@
z-index: -1;
}
.major-list-list {
margin: 64px 11px 20px;
margin: 64px 0 20px 11px;
overflow: auto;
height: 400px;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
.initial {
flex-direction: column;
margin-top: 64px;
font-size: 12px;
text-align: center;
line-height: 17px;
color: #aaaaaa;
.select {
font-weight: 650;
color: #000000;
}
.item {
padding: 0 7px;
cursor: pointer;
}
}
.major-item {
line-height: 26px;

View File

@ -20,7 +20,6 @@
<body>
<div id="app" class="main" v-cloak>
<img class="index-icon" src="/img/index-icon.png" />
<div class="aaa"></div>
@ -226,6 +225,37 @@
</div>
</div>
<!-- 排名 -->
<div class="ranking flexflex">
<div class="synthesize">
<div class="head">综合排名</div>
<div class="list">
<div class="item flexacenter" v-for="item in 5">
<div class="dot"></div>
QS世界综合排名(2025年)
</div>
</div>
</div>
<div class="major">
<div class="head flexacenter">
专业排名
<div class="more flexacenter">
more
<img class="icon" src="/img/arrows-icon.png" />
</div>
</div>
<div class="list flexflex">
<div class="item flexacenter" v-for="item in 10">
<div class="dot"></div>
<div class="organ">QS</div>
<img class="arrows" src="/img/arrows-circle-green.svg" />
<div class="text one-line-display">世界综合排名世界综合排名世界综合排名世界综合排名世界综合排名世界综合排名</div>
(2025年)
</div>
</div>
</div>
</div>
<!-- 招生官 -->
<div class="recruit">
<div class="title flexacenter">
@ -475,61 +505,61 @@
</div>
</div>
<script>
const { createApp, ref, onMounted, nextTick, onUnmounted, computed, getCurrentInstance } = Vue
const { createApp, ref, onMounted, nextTick, onUnmounted, computed, getCurrentInstance } = Vue;
const projectIndex = createApp({
setup() {
const { proxy } = getCurrentInstance()
const { proxy } = getCurrentInstance();
let dataListRef = ref(null)
let dataListRef = ref(null);
onMounted(() => {
window.addEventListener("scroll", handleScroll)
window.addEventListener("scroll", handleScroll);
listMasonryInstance = new Masonry(dataListRef.value, {
itemSelector: ".data-item",
gutter: 20,
})
init()
})
let user = ref({})
let university = ref([])
let discipline = ref([])
let contrastcount = ref({})
let encodekey = ref("")
});
init();
});
let user = ref({});
let university = ref([]);
let discipline = ref([]);
let contrastcount = ref({});
let encodekey = ref("");
// 初始化
const init = () => {
$ajaxget("/api/home/basicData").then(result => {
const data = result.data || {}
user.value = data.user
university.value = data.university
discipline.value = data.discipline
contrastcount.value = data.contrastcount
encodekey.value = data.encodekey
$ajaxget("/api/home/basicData").then((result) => {
const data = result.data || {};
user.value = data.user;
university.value = data.university;
discipline.value = data.discipline;
contrastcount.value = data.contrastcount;
encodekey.value = data.encodekey;
getFate()
getAdmission()
getProjectData()
getMyInit()
})
}
getFate();
getAdmission();
getProjectData();
getMyInit();
});
};
// 今日缘分项目
let fateProject = ref([])
let fateProject = ref([]);
const getFate = () => {
$ajaxget("/api/home/todayFateProject").then(res => {
if (res.code != 200) return
const data = res.data || []
data.forEach(element => {
element["random"] = randomString(6)
})
$ajaxget("/api/home/todayFateProject").then((res) => {
if (res.code != 200) return;
const data = res.data || [];
data.forEach((element) => {
element["random"] = randomString(6);
});
fateProject.value = data
})
}
fateProject.value = data;
});
};
let admissionList = ref([])
let admissionTotalPage = ref(0) // 总页数
let admissionList = ref([]);
let admissionTotalPage = ref(0); // 总页数
// 获取 招生官项目
const getAdmission = () => {
@ -537,355 +567,355 @@
limit: 20,
page: 1,
admissionsproject: 1,
}).then(res => {
if (res.code != 200) return
const data = res.data
const list = data.data || []
}).then((res) => {
if (res.code != 200) return;
const data = res.data;
const list = data.data || [];
const targetList = (list || []).map(element => ({
const targetList = (list || []).map((element) => ({
...element,
random: randomString(6),
}))
}));
const chunkArray = (array, size) => {
const result = []
const result = [];
for (let i = 0; i < array.length; i += size) {
result.push(array.slice(i, i + size))
result.push(array.slice(i, i + size));
}
return result
}
return result;
};
const groupedAdmissionList = chunkArray(targetList, 4)
const groupedAdmissionList = chunkArray(targetList, 4);
admissionList.value = groupedAdmissionList
admissionTotalPage.value = groupedAdmissionList.length
})
}
admissionList.value = groupedAdmissionList;
admissionTotalPage.value = groupedAdmissionList.length;
});
};
let admissionPage = ref(1)
let recruitListRef = ref(null)
let admissionPage = ref(1);
let recruitListRef = ref(null);
// 点击切换 招生官 轮播图 滚动
const cutAdmissionPage = type => {
const cutAdmissionPage = (type) => {
if (type == "left") {
if (admissionPage.value > 1) admissionPage.value--
if (admissionPage.value > 1) admissionPage.value--;
} else {
if (admissionPage.value < admissionTotalPage.value) admissionPage.value++
if (admissionPage.value < admissionTotalPage.value) admissionPage.value++;
}
recruitListRef.value.scrollTo({
left: 1140 * (admissionPage.value - 1),
behavior: "smooth",
})
}
});
};
// 计算
const reversedMessage = type => {
const reversedMessage = (type) => {
if (type == "left") {
if (admissionPage.value == 1) return "/img/arrows-triangle-gray.svg"
else return "/img/arrows-triangle-blue.png"
if (admissionPage.value == 1) return "/img/arrows-triangle-gray.svg";
else return "/img/arrows-triangle-blue.png";
} else {
if (admissionPage.value == admissionTotalPage.value) return "/img/arrows-triangle-gray.svg"
else return "/img/arrows-triangle-blue.png"
if (admissionPage.value == admissionTotalPage.value) return "/img/arrows-triangle-gray.svg";
else return "/img/arrows-triangle-blue.png";
}
}
};
let projectList = ref([])
let projectPage = 1
let projectList = ref([]);
let projectPage = 1;
// 获取项目数据
const getProjectData = () => {
if (projectPage == 0) return
if (projectPage == 0) return;
$ajaxget("/api/lists", {
limit: 20,
page: projectPage,
}).then(res => {
if (res.code != 200) return
const data = res.data
}).then((res) => {
if (res.code != 200) return;
const data = res.data;
const date = new Date()
const month = date.getMonth() + 1
const year = date.getFullYear()
const date = new Date();
const month = date.getMonth() + 1;
const year = date.getFullYear();
let list = data.data || []
let list = data.data || [];
list = list.map(element => ({
list = list.map((element) => ({
...element,
random: randomString(6),
semesterState: month > element.semester.month && year + 1 <= element.semester.year,
tuition_fee_text: formatNumberWithSpaces(element.tuition_fee),
}))
projectList.value = projectList.value.concat(list)
projectPage = data.count > data.limit * data.page ? projectPage + 1 : 0
}));
projectList.value = projectList.value.concat(list);
projectPage = data.count > data.limit * data.page ? projectPage + 1 : 0;
nextTick(() => {
listMasonryInstance.reloadItems()
listMasonryInstance.layout()
})
})
}
listMasonryInstance.reloadItems();
listMasonryInstance.layout();
});
});
};
//瀑布实例
let listMasonryInstance = null
let listMasonryInstance = null;
const imageFallLoaded = () => {
listMasonryInstance.reloadItems()
listMasonryInstance.layout()
}
listMasonryInstance.reloadItems();
listMasonryInstance.layout();
};
const handleScroll = () => {
const scrollHeight = document.documentElement.scrollHeight
const clientHeight = document.documentElement.clientHeight
const scrollTop = window.pageYOffset
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
const scrollTop = window.pageYOffset;
if (scrollTop + clientHeight >= scrollHeight) {
getProjectData()
getProjectData();
}
}
};
const baseRef = ref(null)
const baseRef = ref(null);
// 点击事件
const handleClick = (type, item, index, i) => {
const random = item.random
const random = item.random;
if (item.status == 1) return
if (item.status == 1) return;
$ajax("/api/contrast/add", {
projectid: item.id,
}).then(res => {
baseRef.value.calculate(random)
}).then((res) => {
baseRef.value.calculate(random);
if (type == "fate") fateProject.value[index]["state"] = 1
if (type == "fate") fateProject.value[index]["state"] = 1;
if (type == "admission") {
admissionList.value[index][i]["contraststatus"] = {
status: 1,
ismanage: 1,
}
admissionList.value[index][i]["moreState"] = false
};
admissionList.value[index][i]["moreState"] = false;
}
if (type == "list") {
projectList.value[index]["contraststatus"] = {
status: 1,
ismanage: 1,
}
projectList.value[index]["moreState"] = false
};
projectList.value[index]["moreState"] = false;
}
})
}
});
};
const openMoreSelect = (type, index, i) => {
if (type == "admission") {
admissionList.value[index][i]["moreState"] = true
admissionList.value[index][i]["moreState"] = true;
}
if (type == "list") {
console.log(222)
projectList.value[index]["moreState"] = true
console.log(222);
projectList.value[index]["moreState"] = true;
}
}
};
// 关闭所有 状态 选择 弹出框
const closeMoreSelectAll = type => {
const closeMoreSelectAll = (type) => {
if (type == "admission") {
admissionList.value.forEach(element => {
element.forEach(ele => {
ele["moreState"] = false
})
})
admissionList.value.forEach((element) => {
element.forEach((ele) => {
ele["moreState"] = false;
});
});
}
if (type == "list") {
projectList.value.forEach(element => {
element["moreState"] = false
})
projectList.value.forEach((element) => {
element["moreState"] = false;
});
}
}
};
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll)
})
window.removeEventListener("scroll", handleScroll);
});
let contrastList = ref([])
let contrastList = ref([]);
const stateObj = ref({
0: "待定",
1: "主申",
2: "冲刺",
3: "保底",
})
});
let manageHintState = ref(false)
let classify = ref("vs")
let manageHintState = ref(false);
let classify = ref("vs");
// 我的项目的初始化
const getMyInit = () => {
manageHintState.value = localStorage.getItem("PMState") || false
manageHintState.value = localStorage.getItem("PMState") || false;
getList().then(res => {
const data = res.data || {}
getList().then((res) => {
const data = res.data || {};
data.nums = {
contrast: 0,
manage: 10,
}
const nums = data.nums || {}
classify.value = "vs"
};
const nums = data.nums || {};
classify.value = "vs";
if (nums["contrast"] == 0 && nums["manage"] != 0) {
classify.value = "manage"
handleUserProjectData(res)
classify.value = "manage";
handleUserProjectData(res);
} else {
getQuickList()
handleProjectListData(res)
getQuickList();
handleProjectListData(res);
}
})
}
});
};
let projectCount = ref(0)
handleProjectListData = res => {
const data = res.data
let list = data.data || []
let count = 0
list.forEach(element => {
if (element.status == 1) count++
})
projectCount.value = count
contrastList.value = list
}
let projectCount = ref(0);
handleProjectListData = (res) => {
const data = res.data;
let list = data.data || [];
let count = 0;
list.forEach((element) => {
if (element.status == 1) count++;
});
projectCount.value = count;
contrastList.value = list;
};
let typeid = ref("")
let typeIndex = ref(0)
let typeList = ref([])
let typeid = ref("");
let typeIndex = ref(0);
let typeList = ref([]);
// 获取项目管理
const getUserProject = () => {
getList({
page: 1,
typeid: typeid.value,
}).then(res => {
handleUserProjectData(res)
})
}
}).then((res) => {
handleUserProjectData(res);
});
};
const getProjectList = () => {
getList({
page: 1,
}).then(res => {
handleProjectListData(res)
})
}
}).then((res) => {
handleProjectListData(res);
});
};
let manageList = ref([])
const handleUserProjectData = res => {
const data = res.data
let list = data.data || []
let manageList = ref([]);
const handleUserProjectData = (res) => {
const data = res.data;
let list = data.data || [];
list.forEach((element, index) => {
element["sortKey"] = index
})
typeList.value = data.typeList
manageList.value = list
element["sortKey"] = index;
});
typeList.value = data.typeList;
manageList.value = list;
nextTick(() => {
manageList.value.forEach((element, index) => {
if (element.ismanage == 1 && element.remarks) {
console.log("element", element)
const textarea = manageListRef.value.querySelector(`.item[data-index="${index}"] textarea`)
element["inputHeight"] = textarea.scrollHeight + "px"
console.log("element", element);
const textarea = manageListRef.value.querySelector(`.item[data-index="${index}"] textarea`);
element["inputHeight"] = textarea.scrollHeight + "px";
}
})
});
nextTick(() => {
if (manageList.value.length != 0) getAllHeight()
})
})
}
if (manageList.value.length != 0) getAllHeight();
});
});
};
const getAllHeight = () => {
const all = manageListRef.value.querySelectorAll(".item") || []
all.forEach(element => {
const index = element.getAttribute("data-index") * 1
manageList.value[index]["height"] = element.offsetHeight + 20
})
calculateWaterfall()
}
const all = manageListRef.value.querySelectorAll(".item") || [];
all.forEach((element) => {
const index = element.getAttribute("data-index") * 1;
manageList.value[index]["height"] = element.offsetHeight + 20;
});
calculateWaterfall();
};
const calculateWaterfall = () => {
let list = JSON.parse(JSON.stringify(manageList.value)) || []
list.sort((a, b) => a.sortKey - b.sortKey)
let list = JSON.parse(JSON.stringify(manageList.value)) || [];
list.sort((a, b) => a.sortKey - b.sortKey);
let topLeft = 0
let topRigth = 0
let topLeft = 0;
let topRigth = 0;
for (let i = 0; i < list.length; i++) {
const element = list[i]
const element = list[i];
if (element.ismanage == 1) {
const height = element.height
let top = 0
let side = topLeft <= topRigth ? "left" : "right"
let left = 0
const height = element.height;
let top = 0;
let side = topLeft <= topRigth ? "left" : "right";
let left = 0;
if (side == "left") {
top = topLeft
topLeft += height
top = topLeft;
topLeft += height;
} else {
top = topRigth
topRigth += height
left = 440
top = topRigth;
topRigth += height;
left = 440;
}
if (!element.load) {
element["top"] = top
element["left"] = left
element["top"] = top;
element["left"] = left;
}
element["height"] = height
element["height"] = height;
}
}
manageList.value = list
}
manageList.value = list;
};
const manageEmpty = computed(() => {
return typeList.value[typeIndex.value]["count"] == 0
})
return typeList.value[typeIndex.value]["count"] == 0;
});
const isPitchExceedOne = computed(() => {
return contrastList.value.filter(item => item.pitch).length >= 1
})
return contrastList.value.filter((item) => item.pitch).length >= 1;
});
const isPitchExceedTwo = computed(() => {
return contrastList.value.filter(item => item.pitch).length >= 2
})
return contrastList.value.filter((item) => item.pitch).length >= 2;
});
const isPitchExceedThree = computed(index => {
console.log("index", index)
return contrastList.value.filter(item => item.pitch).length >= 3
})
const isPitchExceedThree = computed((index) => {
console.log("index", index);
return contrastList.value.filter((item) => item.pitch).length >= 3;
});
// 点击选择项目
const cutSelect = index => {
const item = contrastList.value[index]
const state = item["pitch"] || false
if (!state && contrastList.value.filter(item => item["pitch"]).length >= 3) return
item["pitch"] = !item["pitch"]
}
const cutSelect = (index) => {
const item = contrastList.value[index];
const state = item["pitch"] || false;
if (!state && contrastList.value.filter((item) => item["pitch"]).length >= 3) return;
item["pitch"] = !item["pitch"];
};
let quickList = ref([])
let quickList = ref([]);
// 获取快速列表
const getQuickList = () => {
$ajaxget("/api/contrast/getQuickList", {}).then(res => {
if (res.code != 200) return
const data = res.data
quickList.value = data || []
})
}
$ajaxget("/api/contrast/getQuickList", {}).then((res) => {
if (res.code != 200) return;
const data = res.data;
quickList.value = data || [];
});
};
// 快速列表点击 显示删除 按钮
const quickShowHideDelete = index => {
quickList.value[index]["deleteState"] = !quickList.value[index]["deleteState"]
}
const quickShowHideDelete = (index) => {
quickList.value[index]["deleteState"] = !quickList.value[index]["deleteState"];
};
// 点击删除快速对比
const quickDelete = index => {
const data = quickList.value[index]
const quickDelete = (index) => {
const data = quickList.value[index];
$ajax("/api/contrast/deleteQuick", {
id: data.id,
}).then(res => {
quickList.value.splice(index, 1)
})
}
}).then((res) => {
quickList.value.splice(index, 1);
});
};
// 点击 删除 我的对比
const contrastDelete = () => {
@ -893,12 +923,12 @@
if (element["pitch"]) {
$ajax("/api/contrast/delete", {
projectid: element.projectid,
}).then(res => {
contrastList.value[index]["status"] = false
})
}).then((res) => {
contrastList.value[index]["status"] = false;
});
}
})
}
});
};
// 公共的获取列表 方法
const getList = (obj = {}) => {
@ -907,152 +937,152 @@
limit: 2000,
page: obj.page || 1,
typeid: obj.typeid || "",
}).then(res => resolve(res))
})
}
}).then((res) => resolve(res));
});
};
// 切换查看类型
const cutClassify = type => {
const cutClassify = (type) => {
// const classify = e.currentTarget.dataset.type
if (type == classify.value) return
classify.value = type
if (type == classify.value) return;
classify.value = type;
if (classify.value == "manage") {
typeid.value = ""
manageList.value = []
getUserProject()
typeid.value = "";
manageList.value = [];
getUserProject();
}
if (classify.value == "vs") {
quickList.value = []
contrastList.value = []
getProjectList()
getQuickList()
quickList.value = [];
contrastList.value = [];
getProjectList();
getQuickList();
}
}
};
const manageListRef = ref(null)
const manageListRef = ref(null);
const inputInput = index => {
const textarea = manageListRef.value.querySelector(`.item[data-index="${index}"] textarea`)
manageList.value[index]["inputHeight"] = textarea.scrollHeight + "px"
}
const inputInput = (index) => {
const textarea = manageListRef.value.querySelector(`.item[data-index="${index}"] textarea`);
manageList.value[index]["inputHeight"] = textarea.scrollHeight + "px";
};
const inputblur = index => {
const target = manageList.value[index]
const inputblur = (index) => {
const target = manageList.value[index];
$ajax("/api/user/remarks", {
token: target.token,
remarks: target.remarks,
}).then(res => {
console.log("message", res.message)
}).then((res) => {
console.log("message", res.message);
getAllHeight()
})
}
getAllHeight();
});
};
// 关闭 底部提示框
const manageClose = () => {
manageHintState.value = true
localStorage.setItem("PMState", 1)
}
manageHintState.value = true;
localStorage.setItem("PMState", 1);
};
// 点击头部 tab
const cutTypeid = index => {
typeIndex.value = index
typeid.value = typeList.value[index].value
manageList.value = []
getUserProject()
}
const cutTypeid = (index) => {
typeIndex.value = index;
typeid.value = typeList.value[index].value;
manageList.value = [];
getUserProject();
};
const cutManageStateShow = index => {
manageList.value.forEach(element => (element["state"] = false))
const cutManageStateShow = (index) => {
manageList.value.forEach((element) => (element["state"] = false));
manageList.value[index]["state"] = !manageList.value[index]["state"]
}
manageList.value[index]["state"] = !manageList.value[index]["state"];
};
const cutManageState = (typeid, index) => {
const target = manageList.value[index] || {}
const target = manageList.value[index] || {};
$ajax("/api/user/changeType", {
token: target.token,
typeid,
}).then(res => {
if (res.code != 200) return
}).then((res) => {
if (res.code != 200) return;
const stateNameFront = stateObj.value[target.typeid] // 修改前的状态
const stateNameAfter = stateObj.value[typeid] // 修改后的状态
typeList.value.forEach(element => {
if (element.name == stateNameFront) element.count--
if (element.name == stateNameAfter) element.count++
})
const stateNameFront = stateObj.value[target.typeid]; // 修改前的状态
const stateNameAfter = stateObj.value[typeid]; // 修改后的状态
typeList.value.forEach((element) => {
if (element.name == stateNameFront) element.count--;
if (element.name == stateNameAfter) element.count++;
});
manageList.value[index]["typeid"] = typeid
manageList.value[index]["state"] = false
manageList.value[index]["typeid"] = typeid;
manageList.value[index]["state"] = false;
if (typeIndex.value != 0) {
manageList.value[index]["ismanage"] = 0
manageList.value[index]["height"] = 0
manageList.value[index]["ismanage"] = 0;
manageList.value[index]["height"] = 0;
}
})
}
});
};
let isDragging = ref(null)
const startDrag = index => {
isDragging.value = index
const target = manageList.value[index]
let isDragging = ref(null);
const startDrag = (index) => {
isDragging.value = index;
const target = manageList.value[index];
manageList.value[index]["load"] = true
}
manageList.value[index]["load"] = true;
};
let timer = null
let timer = null;
const dragging = index => {
if (isDragging.value != index) return
manageList.value[index]["left"] += event.movementX
manageList.value[index]["top"] += event.movementY
const dragging = (index) => {
if (isDragging.value != index) return;
manageList.value[index]["left"] += event.movementX;
manageList.value[index]["top"] += event.movementY;
const list = JSON.parse(JSON.stringify(manageList.value))
let maxOverlapArea = 0
let maxOverlapElement = null
const list = JSON.parse(JSON.stringify(manageList.value));
let maxOverlapArea = 0;
let maxOverlapElement = null;
const target = list[index]
const target = list[index];
for (let i = 0; i < list.length; i++) {
const element = list[i]
const element = list[i];
if (index !== i) {
const overlapArea = Math.max(0, Math.min(target.left + 420, element.left + 420) - Math.max(target.left, element.left)) * Math.max(0, Math.min(target.top + target.height, element.top + element.height) - Math.max(target.top, element.top))
const overlapArea = Math.max(0, Math.min(target.left + 420, element.left + 420) - Math.max(target.left, element.left)) * Math.max(0, Math.min(target.top + target.height, element.top + element.height) - Math.max(target.top, element.top));
// 计算重叠面积是否超过另一个元素的一半面积
const halfArea = (420 * element.height) / 2
const halfArea = (420 * element.height) / 2;
if (overlapArea > halfArea && overlapArea > maxOverlapArea) {
maxOverlapArea = overlapArea
maxOverlapElement = i
maxOverlapArea = overlapArea;
maxOverlapElement = i;
}
}
}
if (maxOverlapElement != null) {
const over1 = JSON.parse(JSON.stringify(list[maxOverlapElement]))
const over2 = JSON.parse(JSON.stringify(list[isDragging.value]))
const over1 = JSON.parse(JSON.stringify(list[maxOverlapElement]));
const over2 = JSON.parse(JSON.stringify(list[isDragging.value]));
list[maxOverlapElement]["sortKey"] = over2.sortKey
list[isDragging.value]["sortKey"] = over1.sortKey
manageList.value = list
calculateWaterfall()
isDragging.value = maxOverlapElement
list[maxOverlapElement]["sortKey"] = over2.sortKey;
list[isDragging.value]["sortKey"] = over1.sortKey;
manageList.value = list;
calculateWaterfall();
isDragging.value = maxOverlapElement;
}
}
};
const endDrag = () => {
if (isDragging.value == null) return
if (isDragging.value == null) return;
isDragging.value = null
isDragging.value = null;
manageList.value.forEach(element => {
element["load"] = false
})
manageList.value.forEach((element) => {
element["load"] = false;
});
calculateWaterfall()
}
calculateWaterfall();
};
return {
user,
@ -1106,13 +1136,13 @@
dragging,
endDrag,
isDragging,
}
};
},
})
});
projectIndex.component("base-bottom", base)
projectIndex.component("base-bottom", base);
projectIndex.mount("#app")
projectIndex.mount("#app");
</script>
</body>
</html>

View File

@ -18,46 +18,67 @@
<div class="boxbox">
<div class="tab flexacenter">
首页
<a target="_blank" href="/">首页</a>
<img class="img" src="/img/arrows.svg" />
全部榜单
<a target="_blank" href="/projectAllList">全部榜单</a>
<img class="img" src="/img/arrows.svg" />
<div class="current">QS世界综合排名2025</div>
<div class="current">
<template v-if="classify == 'school'">{{ rankingKeyObj[comText.jg] || comText.jg }}世界综合排名({{ comText.year }}年)</template>
<template v-else> {{ rankingKeyObj[majText.jg] || majText.jg }}-{{ majText.major }}{{ majText.year }} </template>
</div>
</div>
<div class="content flexflex">
<div class="content-left flex1">
<div v-if="classify == 'school'" class="pitch-title">{{ rankingKeyObj[comText.jg] || comText.jg }}世界综合排名({{ comText.year }}年)</div>
<div v-else class="major-pitch flexcenter">
<span class="organ">QS</span>
<img class="icon" src="/img/arrows-circle-green.svg" />
世界综合排名2025
</div>
<div class="message flexacenter">
<div class="total flexacenter">
<div class="sum">{{ comTotal }}</div>
个排名
<template v-if="classify == 'school'">
<div class="pitch-title">{{ rankingKeyObj[comText.jg] || comText.jg }}世界综合排名({{ comText.year }}年)</div>
<div class="message flexacenter">
<div class="total flexacenter">
<div class="sum">{{ comTotal }}</div>
个排名
</div>
<div class="only flexacenter" @click="cutOnlyXg">
<img v-if="comOnly" class="icon" src="/img/u376.svg" />
<img v-else class="icon" src="/img/frame-icon.svg" />
仅显示香港学校
</div>
</div>
<div class="only flexacenter" bind:tap="cutOnlyXg">
<img v-if="comOnly" class="icon" src="/img/u376.svg" />
<img v-else class="icon" src="/img/frame-icon.svg" />
仅显示香港学校
</template>
<template v-else>
<div class="major-pitch flexcenter">
<span class="organ">{{ rankingKeyObj[majText.jg] || majText.jg }}</span>
<img class="icon" src="/img/arrows-circle-green.svg" />
{{ majText.major }}{{ majText.year }}
</div>
</div>
<div class="message flexacenter">
<div class="total flexacenter">
<div class="sum">{{ majTotal }}</div>
个排名
</div>
<div class="only flexacenter" @click="majOnlyXg">
<img v-if="majOnly" class="icon" src="/img/u376.svg" />
<img v-else class="icon" src="/img/frame-icon.svg" />
仅显示香港学校
</div>
</div>
</template>
<div class="list">
<div class="item flexflex" v-for="(item,index) in classify == 'school' ? comList : majList">
<div class="num">{{ item.rank }}</div>
<div class="info flex1">
<div class="name">{{ item.name || item.subject }}</div>
<div class="head flexflex">
<div class="name">{{ item.name || item.subject }}</div>
<div class="grade" v-if="item.total_score"><span class="sum">{{ item.total_score }}</span></div>
</div>
<div class="name-en">{{ item.enname }} {{ item.simple ? `${ item.simple }` : ''}}</div>
<div class="city">{{ item.city || '' }}</div>
</div>
<div class="right flexflex">
<div class="grade" v-if="item.total_score"><span class="sum">{{ item.total_score }}</span></div>
<a class="btn flexcenter" v-if="item.sid" target="_blank" :href="'/college/' + item.sid">
学校主页
<img class="icon" src="/img/arrows-circle.svg" />
</a>
<div class="bottom flexflex">
<div class="city">{{ item.city || '' }}</div>
<a class="btn flexcenter" v-if="item.sid" target="_blank" :href="'/college/' + item.sid">
学校主页
<img class="icon" src="/img/arrows-circle.svg" />
</a>
</div>
</div>
</div>
</div>
@ -86,7 +107,7 @@
评榜机构
</div>
<div class="list flexflex">
<div class="item" :class="{'pitch': comChoose.jg == item}" v-for="(item,key) in comJgList" @click="selectComJg(item)">{{ item }}</div>
<div class="item" :class="{'pitch': comChoose.jg == item}" v-for="(item,key) in comJgList" @click="selectComJg(item)">{{ rankingKeyObj[item] || item }}</div>
</div>
</div>
<div class="screen-item">
@ -113,10 +134,13 @@
<div class="text one-line-display">{{ majChoose.major || '请选择' }}</div>
<img class="icon" src="/img/arrows-black.svg" />
</div>
<div class="major-list" v-if="majorState">
<div class="major-list flexflex" v-if="majorState">
<div class="major-list-mask" @click="cutMajorState"></div>
<div class="major-list-list">
<div class="major-item" :class="{'pitch': item == majChoose.major}" v-for="(item, key) in majMajorList" @click="selectMajMajor(item)">{{ item }}</div>
<div class="major-list-list" ref="majorList" @scroll="majorListScroll">
<div class="major-item" :class="{'pitch': item == majChoose.major, }" :data-value="item.charAt(0).toLocaleUpperCase()" v-for="(item, key) in majMajorList" @click="selectMajMajor(item)">{{ item }}</div>
</div>
<div class="initial">
<div class="item" :class="{'select': initialKey.includes(item)}" :data-value="item" v-for="item in initialList" @click="jumpToIndex(item)">{{ item }}</div>
</div>
</div>
</div>
@ -127,7 +151,7 @@
评榜机构
</div>
<div class="list flexflex">
<div class="item" :class="{'pitch': majChoose.jg == item}" v-for="(item,key) in majJgList" @click="selectMajJg(item)">{{ item }}</div>
<div class="item" :class="{'pitch': majChoose.jg == item}" v-for="(item,key) in majJgList" @click="selectMajJg(item)">{{ rankingKeyObj[item] || item }}</div>
</div>
</div>
<div class="screen-item">
@ -156,17 +180,46 @@
onMounted(() => {
window.addEventListener("scroll", handleScroll);
const params = parseQueryString(location.search) || {};
if (params.type == "school") {
comDefault.value = {
jg: params.mechanism,
year: params.year,
};
classifySelect.value = classify.value = params.type;
} else {
majDefault.value = {
major: params.subject,
jg: params.system,
year: params.year,
};
classifySelect.value = classify.value = params.type;
}
console.log(111, classifySelect.value);
getBaseData().then((data) => {
const university = JSON.parse(JSON.stringify(data.university || {}));
university.forEach((element) => {
universityArr.push(element.value);
});
getRankings();
});
});
const parseQueryString = (queryString) => {
const params = {};
const query = queryString.substring(1); // 去掉开头的问号
if (!query) return params;
const pairs = query.split("&");
for (let i = 0; i < pairs.length; i++) {
const pair = pairs[i].split("=");
const key = decodeURIComponent(pair[0]);
const value = pair[1] ? decodeURIComponent(pair[1]) : null;
params[key] = value;
}
return params;
};
let universityArr = [];
let comOption = ref({});
@ -186,6 +239,7 @@
let majOption = ref({});
let majDefault = ref({});
let majText = ref({});
let majChoose = ref({
major: "",
jg: "",
@ -203,10 +257,9 @@
$ajax("https://api.gter.net/v1/program/rankings", {}).then((res) => {
if (res.code != 200) return;
const data = res.data;
console.log(11111, data);
const comprehensive = data.comprehensive;
let com = JSON.parse(JSON.stringify(comChoose.value));
let com = JSON.parse(JSON.stringify(comDefault.value));
for (const key in comprehensive) {
let element = comprehensive[key];
@ -227,7 +280,7 @@
com["token"] = comprehensive[com.jg]?.[com.year] || "";
const discipline = data.discipline;
let maj = JSON.parse(JSON.stringify(majChoose.value));
let maj = JSON.parse(JSON.stringify(majDefault.value));
const [dOrganizationKey, dOrganizationValue] = Object.entries(discipline)[0];
if (!maj["jg"]) maj["jg"] = dOrganizationKey;
if (!maj["major"]) maj["major"] = Object.entries(dOrganizationValue)[0][0];
@ -253,6 +306,7 @@
let majMajorList = ref([]);
let majJgList = ref([]);
let majYearList = ref([]);
let initialList = ref([]);
const initMaj = () => {
const option = majOption.value;
const allMajor = Object.values(option).flatMap((institutionData) => Object.keys(institutionData));
@ -262,6 +316,14 @@
return 0;
});
// 用于记录每个首字母的数量
let initial = [];
// 为每个对象添加首字母标识并统计首字母数量
majorList.forEach((item) => {
initial.push(item.charAt(0).toLocaleUpperCase());
});
initialList.value = [...new Set(initial)];
const maj = majDefault.value;
// if (maj.jg) {
@ -338,7 +400,12 @@
// 获取 综合排名 数据
const getSynthesizeData = () => {
let comChooseObj = comChoose.value || {};
let comDefaultObj = comDefault.value || {};
console.log(comChooseObj["token"] || comDefaultObj["token"]);
// return
$ajaxget("https://api.gter.net/v1/program/comprehensiverankings", {
token: comChooseObj["token"] || comDefaultObj["token"],
ishongkong: comOnly.value || 0,
@ -361,9 +428,6 @@
if (comChooseObj["token"]) comText.value = JSON.parse(JSON.stringify(comChooseObj));
else comText.value = JSON.parse(JSON.stringify(comDefaultObj));
comDefault.value = {};
classify.value = "school";
});
};
@ -383,7 +447,10 @@
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
const scrollTop = window.pageYOffset;
if (scrollTop + clientHeight >= scrollHeight - 50) renderComprehensiveList();
if (scrollTop + clientHeight >= scrollHeight - 50) {
if (classify.value == "school") renderComprehensiveList();
else renderDisciplineList();
}
};
const sortedYears = computed(() => {
@ -411,7 +478,10 @@
let majorState = ref(false); // 专业选择状态
// 切换专业选择状态
const cutMajorState = () => (majorState.value = !majorState.value);
const cutMajorState = () => {
majorState.value = !majorState.value;
if (!majorState.value) initialKey.value = ["A"];
};
// 选择专业
const selectMajMajor = (value) => {
@ -467,9 +537,14 @@
let text = "";
if (!com.jg) text = "请选择机构";
else if (!com.year) text = "请选择年份";
console.log("text", text);
if (text) return;
if (text) {
creationAlertBox("error", text);
return;
}
comChoose.value["token"] = option[com.jg][com.year];
comDefault.value = {};
getSynthesizeData();
} else {
const option = majOption.value;
@ -478,10 +553,14 @@
if (!maj.major) text = "请选择专业";
else if (!maj.jg) text = "请选择机构";
else if (!maj.year) text = "请选择年份";
console.log("text", text);
if (text) return;
majChoose["token"] = option[maj.jg][maj.major][maj.year];
if (text) {
creationAlertBox("error", text);
return;
}
majChoose.value["token"] = option[maj.jg][maj.major][maj.year];
majDefault.value = {};
getMajorData();
}
};
@ -520,8 +599,8 @@
majPage.value = 1;
renderDisciplineList();
if (comChooseObj["token"]) comText.value = JSON.parse(JSON.stringify(comChooseObj));
else comText.value = JSON.parse(JSON.stringify(comDefaultObj));
if (majChooseObj["token"]) majText.value = JSON.parse(JSON.stringify(majChooseObj));
else majText.value = JSON.parse(JSON.stringify(majDefaultObj));
classify.value = "subject";
});
@ -538,7 +617,46 @@
majList.value = majList.value.concat(target);
};
return { majList, majOnly, comOnly, comYearList, comJgList, haveChosen, selectMajYear, selectMajJg, majYearList, majJgList, majMajorList, selectMajMajor, majOption, majChoose, cutMajorState, majorState, selectComJg, selectComYear, sortedYears, classify, classifySelect, cutClassify, rankingKeyObj, comText, comChoose, comList, comTotal, comOption };
const cutOnlyXg = () => {
comOnly.value = comOnly.value ? 0 : 1;
getSynthesizeData();
};
const majOnlyXg = () => {
majOnly.value = majOnly.value ? 0 : 1;
getMajorData();
};
const majorList = ref(null);
let initialKey = ref(["A"]);
const majorListScroll = () => {
const itemList = majorList.value.querySelectorAll(".major-item");
let keyList = [];
itemList.forEach((element) => {
const isVisible = isElementVisibleInScrollContainer(element, majorList.value);
if (isVisible) keyList.push(element.dataset.value);
});
initialKey.value = [...new Set(keyList)];
};
const isElementVisibleInScrollContainer = (element, container) => {
const elementRect = element.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
return elementRect.top >= containerRect.top && elementRect.bottom <= containerRect.bottom;
};
const jumpToIndex = (value) => {
const item = majorList.value.querySelector(`.major-item[data-value=${value}]`);
3;
const offsetTop = item.offsetTop - 64;
majorList.value.scrollTo({
top: offsetTop,
behavior: "smooth",
});
};
return { jumpToIndex, initialKey, majorList, majorListScroll, initialList, majOnlyXg, cutOnlyXg, majTotal, majText, majList, majOnly, comOnly, comYearList, comJgList, haveChosen, selectMajYear, selectMajJg, majYearList, majJgList, majMajorList, selectMajMajor, majOption, majChoose, cutMajorState, majorState, selectComJg, selectComYear, sortedYears, classify, classifySelect, cutClassify, rankingKeyObj, comText, comChoose, comList, comTotal, comOption };
},
});
projectIndex.mount("#app");