1119 lines
55 KiB
HTML
1119 lines
55 KiB
HTML
<!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 class="aaa"></div>
|
||
|
||
<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 v-if="false" 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="content">
|
||
<div class="item top flexflex">
|
||
<div class="head flexacenter">项目</div>
|
||
<div class="thead flex1 flexacenter">
|
||
<div class="school flexcenter">
|
||
<img class="img" src="https://oss.x-php.com/school/J6BSwE-VfCFkCblSBaR7ec6NYmSVtMENOf5NHJQuwf83NTE2" />
|
||
香港大学
|
||
</div>
|
||
<div class="name">理学硕士(电脑科学)</div>
|
||
<img class="vs" src="/img/vs.png" />
|
||
</div>
|
||
<div class="thead flex1 flexacenter">
|
||
<div class="school flexcenter">
|
||
<img class="img" src="https://oss.x-php.com/school/J6BSwE-VfCFkCblSBaR7ec6NYmSVtMENOf5NHJQuwf83NTE2" />
|
||
香港大学
|
||
</div>
|
||
<div class="name">理学硕士(电脑科学)</div>
|
||
</div>
|
||
<div class="thead flex1 flexacenter">
|
||
<div class="school flexcenter">
|
||
<img class="img" src="https://oss.x-php.com/school/J6BSwE-VfCFkCblSBaR7ec6NYmSVtMENOf5NHJQuwf83NTE2" />
|
||
香港大学
|
||
</div>
|
||
<div class="name">理学硕士(电脑科学)</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">专业排名</div>
|
||
<div class="thead flex1">
|
||
<div class="mode1 flexcenter">151-200</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode1 flexcenter">151-200</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode1 flexcenter">151-200</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">学费</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">入学保证金</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode3 flexcenter">
|
||
141,00
|
||
<div class="unit">HK$</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">奖学金</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">均有</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">均有</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">均有</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">一般学习时长</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">1.5年</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">-</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">-</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flexflex">
|
||
<div class="head flexacenter">授课语言</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">英语</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">英语</div>
|
||
</div>
|
||
<div class="thead flex1">
|
||
<div class="mode2 flexcenter">英语</div>
|
||
</div>
|
||
</div>
|
||
|
||
<a class="btn flexcenter" target="_blank" disabled>
|
||
项目对比
|
||
<img class="icon" src="/img/arrows-circle.svg" />
|
||
</a>
|
||
</div>
|
||
|
||
<div v-if="false" 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" v-if="false">
|
||
<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>
|