<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <link rel="stylesheet" href="/css/common.css" /> <link rel="stylesheet" href="/css/subject.css" /> <script src="/js/axios.min.js"></script> <script src="/js/vue.global.js"></script> <script src="/js/common.js"></script> <script src="/js/base.js"></script> <script src="/js/masonry.pkgd.min.js"></script> </head> <body> <div class="main" id="app"> <img class="index-icon" src="/img/index-icon.png" /> <div class="boxbox"> <div class="tab flexacenter"> 首页 <img class="img" src="/img/arrows.svg" /> 按学科查看 <img class="img" src="/img/arrows.svg" /> <div class="current">{{ title }}</div> </div> <div class="info flexacenter"> <img class="img" src="/img/subject.png" /> <div class="flex1"> <div class="title">学科领域</div> <div class="list flexflex"> <div class="item flexacenter" :class="{'pitch': item.value == id}" v-for="(item,index) in discipline" @click="cutDiscipline(item.value)">{{ item.label }}</div> </div> </div> </div> <div class="body flexflex"> <div class="left"> <div class="item flexacenter" :class="{'pitch': !sid}" @click="cutSid('')"> <img v-if="!sid" class="img" src="/img/side-all-pitch.png" /> <img v-else class="img" src="/img/side-all.png" /> 全部项目 </div> <div class="item flexacenter" :class="{'pitch': item.value == sid}" @click="cutSid(item.value)" v-for="(item,index) in university"><img class="img" :src="item.logo" />{{ item.name }}</div> </div> <div class="right flex1"> <div class="h flexacenter"> <div class="total">共 {{ count }} 个项目</div> <div class="item flexacenter sort"> 学费由低到高 <img class="img-sort" src="/img/sort-icon.png" /> <template v-if="!sortState"> <div class="sort-mask"></div> <div class="sort-list"> <div class="sort-item pitch">排名由高到低</div> <div class="sort-item">学费由低到高</div> <div class="sort-item">学费由高到低</div> </div> </template> </div> <div class="item flexacenter" v-if="sid"> 学校主页 <img class="img-school" src="/img/arrows-circle-black.svg" /> </div> </div> <div class="list flexflex" ref="dataListRef"> <div class="item" v-for="(item,index) in showList"> <div class="operate flexcenter"> <div v-if="item.contraststatus?.status === 1 && item.contraststatus?.ismanage === 1" class="already flexacenter"> <div class="tick-box flexcenter"> <img class="img-tick" src="/img/tick-icon.svg" /> </div> 已加入 </div> <div v-else-if="item.contraststatus?.status === 0 || item.contraststatus?.ismanage === 0" @click="openMoreSelect(index)" class="circle flexcenter"> <img class="img-dot" src="/img/dot-dot-dot.png" /> </div> <div v-else class="circle flexcenter" :class="'add' + item.random" @click="handleClick(item,index)"> <img class="img-add" src="/img/add-thick.svg" /> </div> <div v-if="item.moreState" class="select-mask" @click="closeMoreSelectAll()"></div> <div class="select flexflex" :class="{'show': item.moreState}"> <div class="title flexacenter"> <div class="dot"></div> {{ item.contraststatus?.status == 1 ? '该项目已加入对比单,未加入项目管理' : '该项目已加入项目管理,未加入对比单' }} </div> <div class="btn flexcenter" @click="handleClick(item,index)"><img class="img" src="/img/add-circle.svg" />加入{{ item.contraststatus?.status == 1 ? '项目管理' : '对比单' }}</div> </div> </div> <div class="name flexflex">{{ item.name_zh }}</div> <div class="english">{{ item.name_en }}</div> <div class="introduce flexacenter"> {{ item.department }} <div class="flexacenter" v-if="item.rank"> <div class="line">|</div> 专业排名 <div class="quantity">{{ item.rank }}</div> </div> <div class="flexacenter" v-if="item.tuition_fee_text"> <div class="line">|</div> 学费HK$ <vie class="quantity">{{ item.tuition_fee_text }}</vie> </div> </div> <div class="word" v-if="item.distinctive">{{ item.distinctive }}</div> <div class="tag flexflex"> <div class="tag-item admissions" v-if="item.admissionsproject">招生官项目</div> <div class="tag-item gray" :class="{'semester': item.semesterState}">{{ item.semester.text }}</div> <div class="tag-item" v-for="item in item.tags">{{ item }}</div> </div> </div> </div> <div v-if="page == 0 && showList.length == 0" class="empty-box flexcenter"> <img class="icon" src="/img/empty-icon.png" /> <span class="text">暂无项目</span> </div> </div> </div> </div> <!-- 底部 --> <base-bottom ref="baseRef"></base-bottom> </div> <script> const { createApp, ref, onMounted, nextTick, onUnmounted, computed } = Vue const subject = createApp({ setup() { const dataListRef = ref(null) onMounted(() => { window.addEventListener("scroll", handleScroll) getBaseData().then(data => { let list = JSON.parse(JSON.stringify(data.university)) || [] let obj = {} data.discipline.forEach(element => { obj[element.value] = element }) title.value = obj[id.value].label console.log("obj", obj) discipline.value = obj university.value = list }) listMasonryInstance = new Masonry(dataListRef.value, { itemSelector: ".item", gutter: 10, }) getData() }) const handleScroll = () => { const scrollHeight = document.documentElement.scrollHeight const clientHeight = document.documentElement.clientHeight const scrollTop = window.pageYOffset if (scrollTop + clientHeight >= scrollHeight) { calculateShowList() } } let discipline = ref({}) let university = ref([]) let id = ref("3") let title = ref("") let sid = ref("") const getData = () => { $ajaxget("/api/project.lists", { limit: 2000, disciplineid: id.value, sid: sid.value, }).then(res => { if (res.code != 200) return const data = res.data let list = data.data || [] const date = new Date() const month = date.getMonth() + 1 const year = date.getFullYear() list = list.map(element => ({ tuition_fee_text: formatNumberWithSpaces(element.tuition_fee), ...element, rankk: convertRankToRankText(element.rank), random: randomString(6), semesterState: month > element.semester.month && year + 1 <= element.semester.year, })) function convertRankToRankText(rank) { if (!rank) return 0 if (rank.indexOf("-")) { const range = rank.split("-") const start = parseInt(range[0]) * 1 const end = parseInt(range[1]) * 1 return start || end || 0 } else return rank || 0 } listAll = list screenList = list count.value = data.count page.value = 1 screenData() }) } let count = ref(0) let listAll = [] let sortIndex = ref(1) let screenList = [] let showList = ref([]) let page = ref(1) // 筛选数据 const screenData = () => { const sort = sortIndex.value screenList = listAll // 按排名由低到高排序 if (sort == 0) { screenList.sort((a, b) => { // a 排在后面 if (a.rankk == 0) return 1 // b 排在后面 if (b.rankk == 0) return -1 // 普通情况下的排序逻辑 return a.rankk - b.rankk }) } else if (sort == 1) { // 按学费由低到高排序 screenList.sort((a, b) => { if (a.tuition_fee == null) return 1 if (b.tuition_fee == null) return -1 return a.tuition_fee - b.tuition_fee }) } else if (sort == 2) { // 按学费由高到低排序 screenList.sort((a, b) => { if (a.tuition_fee == null) return 1 if (b.tuition_fee == null) return -1 return b.tuition_fee - a.tuition_fee }) } showList.value = [] count.value = screenList.length calculateShowList() } let listMasonryInstance = null // 在 screenList 数据截取要显示的数据 const calculateShowList = () => { const limit = 20 if (page.value == 0) return const startIndex = (page.value - 1) * limit const endIndex = startIndex + limit let list = screenList.slice(startIndex, endIndex) showList.value = showList.value.concat(list) page.value = endIndex >= screenList.length ? 0 : page.value + 1 nextTick(() => { listMasonryInstance.reloadItems() listMasonryInstance.layout() }) } const cutSid = value => { sid.value = value getData() } const cutDiscipline = value => { id.value = value getData() } const baseRef = ref(null) // 点击事件 const handleClick = (item, index, i) => { const random = item.random if (item.status == 1) return $ajax("/api/project.contrast/add", { projectid: item.id, }).then(res => { console.log(baseRef.value) baseRef.value.calculate(random, res.data.count) const uniqid = item["uniqid"] listAll.forEach(element => { if (element.uniqid == uniqid) { element["contraststatus"] = { status: 1, ismanage: 1, } } }) showList.value[index]["contraststatus"] = { status: 1, ismanage: 1, } showList.value[index]["moreState"] = false }) } const openMoreSelect = index => { closeMoreSelectAll() showList.value[index]["moreState"] = true } // 关闭所有 状态 选择 弹出框 const closeMoreSelectAll = type => { showList.value.forEach(element => { element["moreState"] = false }) } return { title, discipline, university, id, sid, count, sortIndex, cutSid, cutDiscipline, showList, dataListRef, page, handleClick, openMoreSelect, baseRef, closeMoreSelectAll, } }, }) subject.component("base-bottom", base) subject.mount("#app") </script> </body> </html>