<!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/index.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> <style> [v-cloak] { display: none; } </style> </head> <body> <div id="app" class="main" v-cloak> <img class="index-icon" src="/img/index-icon.png" /> <div style="display: flex;" class="header-box flexacenter"> <img class="bj" src="/img/header-bj.svg" /> <div class="search flexacenter"> <div class="input flex1">搜索项目</div> <img class="search-icon" src="/img/search-icon.svg" /> </div> <div class="btn flexacenter"> <div class="item flexcenter"> <img class="icon" src="/img/contrast-icon.png" /> 项目对比 </div> <div class="item flexcenter"> <img class="icon" src="/img/contrast-icon.png" /> 项目对比 </div> </div> </div> <!-- 筛选 --> <div style="display: flex;" class="screen flexflex"> <div class="block school"> <div class="title flexacenter"> <div class="icon flexcenter"> <img class="img" src="/img/school-icon.png" /> </div> 按学校查看 </div> <div class="list"> <div class="item flexcenter" v-for="(item,index) in university" :key="index">{{ item.label }}</div> </div> </div> <div class="block subject flex1"> <div class="title flexacenter"> <div class="icon flexcenter"> <img class="img" src="/img/school-icon.png" /> </div> 按学科查看 </div> <div class="list flexflex"> <div class="item flexcenter" v-for="(item,index) in discipline">{{ item.label }}</div> </div> </div> </div> <!-- 缘分 --> <div class="fate"> <div class="title flexacenter"> <div>今日缘分项目</div> <div class="btn flexacenter" @click="getFate"> <img class="icon" src="/img/trade-icon.png" /> 换一批 </div> </div> <div class="list flexflex"> <div class="item flexacenter" v-for="(item,index) in fateProject"> <div class="left"> <div class="name one-line-display">{{ item.name_zh }}</div> <div class="message flexacenter"> <div class="project one-line-display">{{ item.name_en }}</div> <span class="virgule">|</span>{{ item.schoolname }} </div> </div> <div v-if="!item?.state" class="btn flexacenter" :class="'add' + item.random" @click="handleClick('fate',item,index)"> <div class="add flexcenter"> <img class="icon" src="/img/add-xiao.svg" /> </div> 加入对比单 </div> <div v-else class="already flexacenter"> <div class="tick-box flexcenter"> <img class="img-tick" src="/img/tick-icon.svg" /> </div> 已加入 </div> </div> </div> </div> <!-- 招生官 --> <div class="recruit"> <div class="title flexacenter"> <img class="img" src="/img/admission-icon.png" /> <div class="btn flexacenter"> 招生官频道 <img class="icon" src="/img/arrows-icon.png" /> </div> </div> <div class="list flexflex" ref="recruitListRef"> <div class="list-item" v-for="(item,index) in admissionList"> <div class="item flexflex" v-for="(item,i) in item"> <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" class="circle flexcenter" @click="openMoreSelect('admission',index,i)"> <img class="img-dot" src="/img/dot-dot-dot.png" /> </div> <div v-else class="circle flexcenter" @click="handleClick('admission',item,index,i)" :class="'add' + item.random"> <img class="img-add" src="/img/add-thick.svg" /> </div> <div v-if="item.moreState" class="select-mask" @click="closeMoreSelectAll('admission')"></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('admission',item,index,i)"><img class="img" src="/img/add-circle.svg" />加入{{ item.contraststatus?.status == 1 ? '项目管理' : '对比单' }}</div> </div> </div> <img class="avatar" :src="item.schoollogo" /> <div class="info"> <div class="school">{{ item.schoolname }}</div> <div class="name one-line-display">{{ item.name_zh }}</div> <div class="name-en one-line-display">{{ item.name_en }}</div> <div class="aq flexacenter"> <div class="text">招生官答疑时间</div> <div class="value flex1">长期答疑</div> <img class="icon" src="/img/arrows-long-icon.png" /> </div> </div> </div> </div> </div> <div class="indicate flexcenter"> <img class="icon" @click="cutAdmissionPage('left')" :src="reversedMessage('left')" /> <div class="text">{{ admissionPage }}/{{ admissionTotalPage }}</div> <img class="icon btn-right" @click="cutAdmissionPage('right')" :src="reversedMessage('right')" /> </div> </div> <!-- 列表 --> <div class="data" ref="dataListRef"> <img class="data-item fall" @load="imageFallLoaded" src="/img/25fall.svg" /> <div class="data-item item" v-for="(item,index) in projectList"> <div class="school flexacenter"><img class="img" :src="item.schoollogo" />{{ item.schoolname }}</div> <div class="name">{{ item.name_zh }}</div> <div class="name-en">{{ item.name_en }}</div> <div class="introduce flexacenter"> <div class="flexacenter" v-if="item.rank"> 专业排名 <div class="quantity">{{ item.rank }}</div> </div> <div class="flexacenter" v-if="item.tuition_fee_text"> <div class="line" v-if="item.rank">|</div> 学费HK$ <div class="quantity">{{ item.tuition_fee_text }}</div> </div> </div> <div class="word" v-if="item.distinctive">{{ item.distinctive }}</div> <div class="tag flexflex"> <!-- <div class="tag-item admissions">招生官项目</div> --> <div class="tag-item gray" :class="{'semester': item.semesterState}">{{ item.semester.text }}</div> <div class="tag-item" v-for="(item,index) in item.tags">{{ item }}</div> </div> <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" class="circle flexcenter" @click="openMoreSelect('list',index)"> <img class="img-dot" src="/img/dot-dot-dot.png" /> </div> <div v-else class="circle flexcenter" :class="'add' + item.random" @click="handleClick('list',item,index)"> <img class="img-add" src="/img/add-thick.svg" /> </div> <div v-if="item.moreState" class="select-mask" @click="closeMoreSelectAll('list')"></div> <div class="select flexflex" :class="{'show': item.moreState}"> <div class="top flex1 flexcenter"> <div class="title flexacenter"> <div class="dot"></div> {{ item.contraststatus?.status == 1 ? '该项目已加入对比单,未加入项目管理' : '该项目已加入项目管理,未加入对比单' }} </div> <div class="btn flexcenter" @click="handleClick('list',item,index)"><img class="img" src="/img/add-circle.svg" />加入{{ item.contraststatus?.status == 1 ? '项目管理' : '对比单' }}</div> </div> <div class="bottom"></div> </div> </div> <!-- <div class="type flexflex" wx:if="{{ item.admissionsproject }}"> --> <div class="type flexcenter" v-if="item.admissionsproject"> <img class="type-icon" src="/img/angle.svg" /> <img class="type-name" src="/img/admission-icon.png" /> </div> </div> </div> <!-- 底部 --> <base-bottom ref="baseRef"></base-bottom> <div class="my-project flexacenter"> <div class="my-box"> <div class="head flexacenter"> <div class="item flexcenter" :class="{'pitch': classify == 'vs'}" @click="cutClassify('vs')"> <img class="icon" src="/img/contrast-icon.png" /> <img class="bj bj-left" src="/img/left-icon.svg" /> 项目对比 </div> <div class="item flexcenter" :class="{'pitch': classify == 'manage'}" @click="cutClassify('manage')"> <img class="icon" src="/img/manage-icon.png" /> <img class="bj bj-right" src="/img/left-icon.svg" /> 项目管理 </div> </div> <div v-if="classify == 'vs'" class="contrast-box flexflex"> <div class="left" :class="{'left1': quickList.length == 0 }"> <div class="hint flexacenter"> <div class="text">选择2~3个项目开始对比</div> <div class="btn flexacenter"> <div class="delete flexcenter" @click="contrastDelete" :class="{'have': isPitchExceedOne}">删除</div> <div class="begin flexcenter" :class="{'have': isPitchExceedTwo}">开始对比</div> </div> </div> <div v-if="false" class="empty-box flexcenter"> <img class="icon" src="/img/empty-icon.png" /> <span class="text">把你感兴趣的项目加进来,</span> <span class="text">可以做项目对比哦!</span> </div> <div class="list"> <template v-for="(item, index) in contrastList" :key="item.projectid"> <div v-if="item.status == 1" class="item flexacenter"> <div class="left"> <div class="name">{{ item.name_zh }}</div> <div class="english">{{ item.name_en }}</div> <div class="message flexacenter"> <img class="icon" :src="item.schoollogo" /> {{ item.schoolalias }} <template v-if="item.ismanage == 1"> <div class="line">|</div> <div class="state-text">{{ stateObj[item.typeid] }}</div> </template> </div> </div> <div class="btn flexcenter" :class="{'btn-forbid': isPitchExceedThree, 'btn-normal': item.pitch }" @click="cutSelect(index)"> <img v-if="item.pitch" class="icon" src="/img/tick-circle-green.svg" /> <img v-else class="icon" src="/img/tick-circle-gray-hollow.svg" /> </div> </div> </template> </div> </div> <div v-if="quickList.length != 0" class="right"> <div class="hint">快速对比({{ quickList.length }})</div> <div class="list"> <div class="item flexacenter" v-for="(item, index) in quickList"> <div class="project-list"> <div class="project-item flexacenter" v-for="item in item.data"> <img class="icon" mode="widthFix" :src="item.schoollogo" /> {{ item.schoolalias }} <img class="arrows" src="/img/arrows-circle-yellow-green.svg" mode="widthFix" /> <view class="text one-line-display">{{ item.name_zh }}</view> </div> </div> <div class="btn flexcenter"> <img class="icon" src="/img/arrows-long-white.svg" /> </div> <img @click="quickShowHideDelete(index)" class="dot" src="/img/dot-dot-dot-gray.png" /> <div v-if="item.deleteState" @click="quickDelete(index)" class="delete flexcenter">删除</div> <div v-if="item.deleteState" @click="quickShowHideDelete(index)" class="delete-mask flexcenter"></div> </div> </div> </div> </div> <div v-else class="manage-box"> <div class="tab-list flexflex"> <div class="item" :class="{'pitch': index == typeIndex }" v-for="(item,index) in typeList" @click="cutTypeid(index)">{{ item.name }} {{ item.count }}</div> </div> <div v-if="manageEmpty" class="empty-box flexcenter"> <img class="icon" src="/img/empty-icon.png" /> <span class="text">暂无项目</span> </div> <div v-else class="list"> <div class="hint flexacenter" v-if="!manageHintState"> <div class="text">加入对比单的项目会同步进入项目管理当中;两者独立管理,删除操作互不影响。</div> <img @click="manageClose()" class="icon" src="/img/close-icon.png" /> </div> <div class="list-box flexflex" ref="manageListRef"> <template v-for="(item,index) in manageList"> <!-- <div class="item" v-if="item.ismanage == 1" :class="'item' + index" :data-index="index" :style="{'top':item.top,'left': item.left,}" @dragstart="dragStart(index)" @dragenter.prevent="dragEnter(index)" @dragend="dragEnd"> --> <div class="item" v-if="item.ismanage == 1" :class="{'load': item.load}" :data-index="index" :style="{'top':item.top + 'px','left': item.left + 'px' }" @mousemove="dragging(index)" @mouseup="endDrag"> <div class="top flexacenter"> <div class="info flex1"> <div class="name">{{ item.name_zh }}{{item.top}},{{ item.left}}</div> <div class="english">{{ item.name_en }}</div> <div class="school flexacenter"> <img class="icon" :src="item.schoollogo" /> {{ item.schoolalias }} </div> </div> <div class="state-box"> <div class="btn flexcenter" :class="{'undetermined': item.typeid == 0}" @click.stop="cutManageStateShow(index)">{{ stateObj[item.typeid] }}<img class="icon" src="/img/arrows-triangle-white.svg" /></div> <div v-if="item.state" class="state-list-box flexacenter"> <div class="state-list flexacenter"> <div class="state-item" :class="{'pitch': item.typeid == key}" v-for="(it,key) in stateObj" @click.stop="cutManageState(key, index)">{{ it }}</div> </div> <div class="delete flexcenter"> <img class="delete-icon" src="/img/delete-icon.svg" /> </div> </div> </div> </div> <div class="bottom flexflex"> <div class="edit flexcenter"> <img class="icon" src="/img/u1434.png" /> </div> <textarea class="manage-input flex1" :style="{height: item.inputHeight}" v-model="item.remarks" placeholder="添加备注…" maxlength="100" @blur="inputblur(index)" @input="inputInput(index)"></textarea> <img class="drag-icon" src="/img/drag-icon.png" @mousedown="startDrag(index)" /> </div> </div> </template> </div> </div> </div> </div> </div> </div> <script> const { createApp, ref, onMounted, nextTick, onUnmounted, computed, getCurrentInstance } = Vue const projectIndex = createApp({ setup() { const { proxy } = getCurrentInstance() let dataListRef = ref(null) onMounted(() => { 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("") // 初始化 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 getFate() getAdmission() getProjectData() getMyInit() }) } // 今日缘分项目 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) }) fateProject.value = data }) } let admissionList = ref([]) let admissionTotalPage = ref(0) // 总页数 // 获取 招生官项目 const getAdmission = () => { $ajaxget("/api/lists", { limit: 20, page: 1, admissionsproject: 1, }).then(res => { if (res.code != 200) return const data = res.data const list = data.data || [] const targetList = (list || []).map(element => ({ ...element, random: randomString(6), })) const chunkArray = (array, size) => { const result = [] for (let i = 0; i < array.length; i += size) { result.push(array.slice(i, i + size)) } return result } const groupedAdmissionList = chunkArray(targetList, 4) admissionList.value = groupedAdmissionList admissionTotalPage.value = groupedAdmissionList.length }) } let admissionPage = ref(1) let recruitListRef = ref(null) // 点击切换 招生官 轮播图 滚动 const cutAdmissionPage = type => { if (type == "left") { if (admissionPage.value > 1) admissionPage.value-- } else { if (admissionPage.value < admissionTotalPage.value) admissionPage.value++ } recruitListRef.value.scrollTo({ left: 1140 * (admissionPage.value - 1), behavior: "smooth", }) } // 计算 const reversedMessage = type => { if (type == "left") { 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" } } let projectList = ref([]) let projectPage = 1 // 获取项目数据 const getProjectData = () => { if (projectPage == 0) return $ajaxget("/api/lists", { limit: 20, page: projectPage, }).then(res => { if (res.code != 200) return const data = res.data const date = new Date() const month = date.getMonth() + 1 const year = date.getFullYear() let list = data.data || [] 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 nextTick(() => { listMasonryInstance.reloadItems() listMasonryInstance.layout() }) }) } //瀑布实例 let listMasonryInstance = null const imageFallLoaded = () => { listMasonryInstance.reloadItems() listMasonryInstance.layout() } const handleScroll = () => { const scrollHeight = document.documentElement.scrollHeight const clientHeight = document.documentElement.clientHeight const scrollTop = window.pageYOffset if (scrollTop + clientHeight >= scrollHeight) { getProjectData() } } const baseRef = ref(null) // 点击事件 const handleClick = (type, item, index, i) => { const random = item.random if (item.status == 1) return $ajax("/api/contrast/add", { projectid: item.id, }).then(res => { baseRef.value.calculate(random) 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 } if (type == "list") { projectList.value[index]["contraststatus"] = { status: 1, ismanage: 1, } projectList.value[index]["moreState"] = false } }) } const openMoreSelect = (type, index, i) => { if (type == "admission") { admissionList.value[index][i]["moreState"] = true } if (type == "list") { console.log(222) projectList.value[index]["moreState"] = true } } // 关闭所有 状态 选择 弹出框 const closeMoreSelectAll = type => { if (type == "admission") { admissionList.value.forEach(element => { element.forEach(ele => { ele["moreState"] = false }) }) } if (type == "list") { projectList.value.forEach(element => { element["moreState"] = false }) } } onUnmounted(() => { window.removeEventListener("scroll", handleScroll) }) let contrastList = ref([]) const stateObj = ref({ 0: "待定", 1: "主申", 2: "冲刺", 3: "保底", }) let manageHintState = ref(false) let classify = ref("vs") // 我的项目的初始化 const getMyInit = () => { manageHintState.value = localStorage.getItem("PMState") || false getList().then(res => { const data = res.data || {} data.nums = { contrast: 0, manage: 10, } const nums = data.nums || {} classify.value = "vs" if (nums["contrast"] == 0 && nums["manage"] != 0) { classify.value = "manage" handleUserProjectData(res) } else { 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 typeid = ref("") let typeIndex = ref(0) let typeList = ref([]) // 获取项目管理 const getUserProject = () => { getList({ page: 1, typeid: typeid.value, }).then(res => { handleUserProjectData(res) }) } const getProjectList = () => { getList({ page: 1, }).then(res => { handleProjectListData(res) }) } 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 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" } }) nextTick(() => { 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 calculateWaterfall = () => { let list = JSON.parse(JSON.stringify(manageList.value)) || [] list.sort((a, b) => a.sortKey - b.sortKey) let topLeft = 0 let topRigth = 0 for (let i = 0; i < list.length; 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 if (side == "left") { top = topLeft topLeft += height } else { top = topRigth topRigth += height left = 440 } if (!element.load) { element["top"] = top element["left"] = left } element["height"] = height } } manageList.value = list } const manageEmpty = computed(() => { return typeList.value[typeIndex.value]["count"] == 0 }) const isPitchExceedOne = computed(() => { return contrastList.value.filter(item => item.pitch).length >= 1 }) const isPitchExceedTwo = computed(() => { 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 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([]) // 获取快速列表 const getQuickList = () => { $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 quickDelete = index => { const data = quickList.value[index] $ajax("/api/contrast/deleteQuick", { id: data.id, }).then(res => { quickList.value.splice(index, 1) }) } // 点击 删除 我的对比 const contrastDelete = () => { contrastList.value.forEach((element, index) => { if (element["pitch"]) { $ajax("/api/contrast/delete", { projectid: element.projectid, }).then(res => { contrastList.value[index]["status"] = false }) } }) } // 公共的获取列表 方法 const getList = (obj = {}) => { return new Promise((resolve, reject) => { $ajax("/api/user", { limit: 2000, page: obj.page || 1, typeid: obj.typeid || "", }).then(res => resolve(res)) }) } // 切换查看类型 const cutClassify = type => { // const classify = e.currentTarget.dataset.type if (type == classify.value) return classify.value = type if (classify.value == "manage") { typeid.value = "" manageList.value = [] getUserProject() } if (classify.value == "vs") { quickList.value = [] contrastList.value = [] getProjectList() getQuickList() } } 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 inputblur = index => { const target = manageList.value[index] $ajax("/api/user/remarks", { token: target.token, remarks: target.remarks, }).then(res => { console.log("message", res.message) getAllHeight() }) } // 关闭 底部提示框 const manageClose = () => { manageHintState.value = true localStorage.setItem("PMState", 1) } // 点击头部 tab 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)) manageList.value[index]["state"] = !manageList.value[index]["state"] } const cutManageState = (typeid, index) => { const target = manageList.value[index] || {} $ajax("/api/user/changeType", { token: target.token, typeid, }).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++ }) manageList.value[index]["typeid"] = typeid manageList.value[index]["state"] = false if (typeIndex.value != 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] manageList.value[index]["load"] = true } let timer = null 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 target = list[index] for (let i = 0; i < list.length; 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 halfArea = (420 * element.height) / 2 if (overlapArea > halfArea && overlapArea > maxOverlapArea) { maxOverlapArea = overlapArea maxOverlapElement = i } } } if (maxOverlapElement != null) { 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 } } const endDrag = () => { if (isDragging.value == null) return isDragging.value = null manageList.value.forEach(element => { element["load"] = false }) calculateWaterfall() } return { user, university, discipline, contrastcount, encodekey, fateProject, getFate, admissionList, admissionPage, admissionTotalPage, cutAdmissionPage, recruitListRef, reversedMessage, projectList, dataListRef, imageFallLoaded, handleClick, openMoreSelect, closeMoreSelectAll, baseRef, stateObj, contrastList, projectCount, cutSelect, isPitchExceedOne, isPitchExceedTwo, isPitchExceedThree, quickList, quickShowHideDelete, quickDelete, contrastDelete, classify, manageList, manageEmpty, cutClassify, typeList, typeid, typeIndex, inputblur, inputInput, manageListRef, manageHintState, manageClose, cutTypeid, cutManageStateShow, cutManageState, startDrag, dragging, endDrag, isDragging, } }, }) projectIndex.component("base-bottom", base) projectIndex.mount("#app") </script> </body> </html>