PC-vote/pages/publish/index.vue
2024-01-23 19:10:57 +08:00

690 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<Head>
<Title>寄托天下 - 面经发布</Title>
<Meta name="keyword" content="留学资讯,留学交流论坛,留学面经,面试经验,寄托天下" />
</Head>
<div class="content-box">
<div class="flexacenter save-box save-left" @click="submit(0)">
<img class="save-icon" src="@/assets/img/arrow-gray.png" />
保存并退出
</div>
<div class="flexacenter save-box save-right" @click="abandonSaving">
放弃保存
<img class="save-icon" src="@/assets/img/cross-icon.png" />
</div>
<div class="contentcontent flex1">
<div class="header flexacenter">发起投票</div>
<div class="box flex1 flexflex">
<div class="box-left">
<div class="item">
<div class="titletitle flexacenter">
标题
<div class="asterisk">*</div>
</div>
<el-input class="item-input headline-textarea" type="textarea" placeholder="请输入" maxlength="60" show-word-limit v-model="info.title" autosize></el-input>
</div>
<div class="item">
<div class="titletitle flexacenter">详细说明</div>
<el-input class="item-input explain-textarea" type="textarea" placeholder="请输入" maxlength="1000" show-word-limit v-model="info.message" autosize></el-input>
</div>
<div class="item">
<div class="titletitle flexacenter">
截止投票日期
<div class="asterisk">*</div>
</div>
<div class="time-box item-input-box flexacenter">
<el-config-provider :locale="zhCn">
<el-date-picker ref="pickerRef" v-model="info.deadline" type="date" placeholder="请选择" size="large" class="flex1 flexacenter" :clear-icon="{}" value-format="YYYY-MM-DD" :disabled-date="setDisabled" />
</el-config-provider>
<div class="flexacenter">
<img class="calendar-icon" @click="handlePicker" src="@/assets/img/calendar-icon.svg" />
</div>
</div>
</div>
</div>
<div class="box-right flex1">
<div class="item">
<div class="titletitle flexacenter">
选项
<div class="asterisk">*</div>
</div>
<div class="option-list flexflex">
<div class="" ref="draggableContainer">
<template v-if="optionList.length == 0">
<div class="option-item flexacenter" v-for="(item, index) in 2" :key="index">
<div class="option-content flexacenter">
<div class="option-text flexcenter">{{ index + 1 }}</div>
<el-input class="option-input flex1" placeholder="请输入" />
</div>
<div class="option-drag flexcenter">
<img class="option-icon" src="@/assets/img/option-icon.svg" />
</div>
</div>
</template>
<template v-else>
<div class="option-item flexacenter" v-for="(item, index) in optionList" :key="item.id">
<div class="option-content flexacenter">
<div class="option-text flexcenter">{{ index + 1 }}</div>
<!-- <input class="option-input flex1" placeholder="请输入" v-model="optionList[index]['message']" /> -->
<el-input class="option-input flex1" placeholder="请输入" maxlength="100" show-word-limit v-model="optionList[index]['message']" />
<img class="option-cross" v-if="optionList[index]['message']" @click="clearMessage(index)" src="@/assets/img/cross-undertint-icon.svg" />
</div>
<div class="option-drag flexcenter">
<img class="option-icon" src="@/assets/img/option-icon.svg" />
</div>
<img class="rubbish-icon" v-if="optionList.length > 2" @click="deleteOption(index)" src="@/assets/img/rubbish-icon.svg" />
</div>
</template>
</div>
<div class="option-item option-circusee flexacenter" :class="{ 'hascontent': optionList.length > 2 }">
<div class="option-content flexacenter">
<div class="option-text flexcenter">{{ optionList.length + 1 }}</div>
<input class="option-input flex1" disabled value="不懂,围观学习" />
</div>
</div>
</div>
<div class="flexcenter" style="padding-right: 26px;">
<div class="add-box flexcenter" @click="addOption()" v-if="optionList.length < 15">
<img class="add-icon" src="@/assets/img/add-green-icon.svg" />
添加选项
</div>
</div>
</div>
</div>
</div>
<div class="hint-box flexcenter">请确保以上内容已正确填写发布后将不能修改</div>
</div>
</div>
<div class="floor-box">
<div class="box flexacenter">
<div class="anonymous-box flexacenter" @click="cutAnonymous()">
<img class="anonymous-icon" v-if="info.anonymous == 0" src="@/assets/img/frame-no.svg" />
<img class="anonymous-icon" v-else src="@/assets/img/frame-pitch.svg" />
匿名发表
<div class="text">发布后可修改</div>
</div>
<div class="issue-btn flexcenter" @click="submit()">发布</div>
</div>
</div>
</template>
<script setup>
useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=footer", body: true }] })
import { useRouter } from "vue-router"
import { ElMessage } from "element-plus"
import zhCn from "element-plus/dist/locale/zh-cn.mjs"
import Sortable from "sortablejs"
const router = useRouter()
const goLogin = inject("goLogin")
const setDisabled = time => {
// return time.getTime() < Date.now() // 可选历史天、可选当前天、不可选未来天
const today = new Date()
const tomorrow = new Date(today)
tomorrow.setDate(today.getDate())
const thirtyDaysLater = new Date(today)
thirtyDaysLater.setDate(today.getDate() + 29)
return time < tomorrow || time > thirtyDaysLater
}
onMounted(() => {})
onBeforeMount(() => {
clearBottom()
// clearTop()
})
// 清除底部的次数
let clearBottomCount = 0
// 清除 底部
const clearBottom = () => {
const indexFooter = document.querySelector("section.index-footer")
if (!indexFooter) {
clearBottomCount++
setTimeout(() => clearBottom(), 50)
return
}
if (clearBottomCount == 15) return
indexFooter.style.display = "none"
}
// 清除顶部的次数
let clearTopCount = 0
// 清除 顶部
const clearTop = () => {
const indexHeader = document.querySelector("header.page-header")
if (!indexHeader) {
clearTopCount++
setTimeout(() => clearTop(), 50)
return
}
if (clearTopCount == 5) return
indexHeader.style.display = "none"
}
let info = ref({})
let token = ""
// 切换匿名状态
const cutAnonymous = () => {
info.value["anonymous"] = info.value["anonymous"] == 0 ? 1 : 0
}
let loading = false // 加载中
// 提交发布
const submit = (status = 1) => {
// status = 0
if (loading) return
loading = true
let option = []
optionList.value.forEach(element => {
if (element["message"].trim() !== "") option.push(element["message"])
})
if (status == 1) {
if (option.length < 2) {
ElMessage.error("请设置至少2个选项~")
loading = false
return
}
const hash = {}
for (let i = 0; i < option.length; i++) {
if (hash[option[i]]) {
ElMessage.error("选项名称不能重复")
loading = false
return // 有重复值
}
hash[option[i]] = true
}
option.push("不懂,围观学习")
}
info.value["option"] = option
// return
publishSubmitHttp({ info: info.value, token, status })
.then(res => {
if (res.code != 200) {
ElMessage.error(res.message)
return
}
const data = res.data
ElMessage.success(res.message)
// router.push(`/details/${data["uniqid"]}`)
if (status == 0) goToURL(`/index.html`, false)
else goToURL(`/details/${data["uniqid"]}`, false)
})
.finally(() => (loading = false))
}
// 放弃保存 跳跃上一页或者首页
const abandonSaving = () => {
if (router.currentRoute.value.meta.previousPage) router.go(-1)
else goToURL("./index.html", false) // 跳转到首页
// else router.push("./index.html") // 跳转到首页
}
let draggableContainer = ref(null)
const sortable = ref(null)
onMounted(() => {
getinit()
initDraggable()
})
const getinit = () => {
publishInitHttp().then(res => {
if (res.code != 200) {
ElMessage.error(res.message || "报错了,刷新一下")
if (res.code == 401) goLogin()
return
}
const data = res.data
// data.info.option = []
const option = data.info?.option || []
if (option.length == 0) {
for (let index = 0; index < 2; index++) {
optionList.value.push({ id: index, message: "" })
}
} else {
option.forEach((message, index) => {
if (message !== "不懂,围观学习") {
optionList.value.push({ id: index, message })
}
})
while (optionList.value.length < 2) {
optionList.value.push({ id: optionList.value.length, message: "" })
}
}
let deadline = data["info"]["deadline"] || 0
console.log("deadline", deadline)
if (deadline > 100000) data["info"]["deadline"] = handleDate(deadline)
else data["info"]["deadline"] = null
info.value = data.info
token = data.token
})
}
// 处理初始化 面试时间的 时间戳格式
const handleDate = timestamp => {
// 使用Date对象将时间戳转换为日期对象
var date = new Date(timestamp * 1000)
// 获取年份、月份和日期
var year = date.getFullYear()
var month = ("0" + (date.getMonth() + 1)).slice(-2) // 月份从0开始需要加1并补0
var day = ("0" + date.getDate()).slice(-2) // 获取日期并补0
// 拼接为yyyy-mm-dd格式的日期字符串
var formattedDate = year + "-" + month + "-" + day
return formattedDate
}
// 初始化拖拽
const initDraggable = () => {
if (!draggableContainer.value) {
console.warn("容器不能为空")
return
}
sortable.value = Sortable.create(draggableContainer.value, {
handle: ".option-drag",
draggable: ".option-item", // 允许拖拽的项目类名
direction: "horizontal",
forceFallback: true,
animation: 300,
onUpdate(e) {
if (e.oldIndex !== undefined && e.newIndex !== undefined) {
// 删除拖拽的元素
const list = [...optionList.value]
const item = list.splice(e.oldIndex, 1)[0]
// 把删除的元素放到新的位置
list.splice(e.newIndex, 0, item)
optionList.value = list
}
},
})
}
let optionList = ref([]) // 特殊的 选项 列表
// 点击添加选项
const addOption = () => {
optionList.value.push({
id: optionList.value.length,
message: "",
})
}
// 点击删除选项
const deleteOption = index => {
optionList.value.splice(index, 1)
optionList.value.forEach((element, index) => {
element["id"] = index
})
}
// 点进清除选项
const clearMessage = index => {
optionList.value[index]["message"] = ""
}
let pickerRef = ref(null)
const handlePicker = () => {
pickerRef.value.handleOpen()
}
</script>
<style scoped lang="less">
.content-box {
display: flex;
justify-content: center;
padding: 0 122px;
}
@media (max-width: 920px) {
.content-box {
display: block;
padding: 0 10px;
}
}
.contentcontent {
max-width: 1200px;
min-width: 900px;
min-height: calc(100vh - 120px);
background: #fff;
margin: 30px auto 90px;
border-radius: 16px;
display: flex;
flex-direction: column;
position: relative;
.header {
font-weight: 650;
font-size: 20px;
color: #000000;
border-bottom: 1px solid #ebebeb;
height: 88px;
padding-left: 30px;
}
.box {
.titletitle {
color: #666666;
font-size: 14px;
margin-bottom: 10px;
}
.box-left {
border-right: 16px solid #f6f6f6;
width: 48.176%;
padding: 30px;
padding-right: 50px;
.item {
&:not(:last-of-type) {
margin-bottom: 30px;
}
.item-input {
border-radius: 5px;
outline: none;
width: 100%;
font-size: 14px;
/deep/ .el-textarea__inner {
padding: 13px 14px;
border-radius: 5px;
box-shadow: none;
border: 1px solid rgba(215, 215, 215, 1);
}
}
.headline-textarea {
/deep/ .el-textarea__inner {
min-height: 70px !important;
}
}
.explain-textarea {
/deep/ .el-textarea__inner {
min-height: 300px !important;
}
}
}
.item-input-box {
// width: 482px;S
height: 46px;
border: 1px solid rgba(215, 215, 215, 1);
border-radius: 5px;
cursor: pointer;
/deep/ .el-input {
height: 100%;
.el-input__wrapper {
height: 100%;
box-shadow: none;
}
}
}
.time-box {
.calendar-icon {
width: 17px;
// height: 16px;
margin: 0 9px;
cursor: auto;
}
/deep/ .el-input {
.el-input__prefix {
display: none;
}
}
}
// }
.visible-box {
margin: 30px;
font-size: 14px;
color: #555555;
cursor: pointer;
user-select: none;
.visible-icon {
width: 18px;
height: 18px;
margin-right: 5px;
}
}
}
.box-right {
padding-top: 30px;
padding-left: 56px;
padding-right: 30px;
.option-list {
flex-direction: column;
margin-bottom: 53px;
.option-item {
// transition: all linear 0.3s;
&:not(:first-of-type) {
margin-top: 20px;
}
&.option-circusee {
// margin-bottom: 53px;
transition: all 0.3s;
padding-right: 33px;
&.hascontent {
padding-right: 66px;
}
.option-content {
background: rgba(246, 246, 246, 1);
.option-input {
background: transparent;
}
}
}
.option-content {
// width: 470px;
// width: 87.69%;
flex: 1;
height: 46px;
border: 1px solid rgba(215, 215, 215, 1);
border-radius: 5px;
.option-text {
width: 14px;
height: 14px;
color: #333;
font-size: 11px;
position: relative;
margin: 0 10px;
border-radius: 50%;
border: 1px solid #797979;
}
.option-input {
height: 100%;
border: none;
outline: none;
border-radius: 5px;
color: #333;
/deep/ .el-input__wrapper {
outline: none;
border: none;
box-shadow: none;
padding-right: 10px;
}
}
.option-cross {
width: 12px;
height: 12px;
cursor: pointer;
margin-right: 10px;
}
}
.option-drag {
padding-left: 15px;
.option-icon {
width: 18px;
height: 16px;
}
// cursor: move;
}
.rubbish-icon {
width: 13px;
height: 14px;
margin-left: 20px;
cursor: pointer;
}
}
}
.add-box {
.add-icon {
width: 14px;
height: 14px;
margin-right: 6px;
}
font-size: 14px;
color: #333;
cursor: pointer;
margin-bottom: 50px;
// max-width: max-content;
}
}
}
.hint-box {
height: 58px;
background-color: rgba(246, 246, 246, 1);
color: #555555;
font-size: 13px;
}
}
.asterisk {
color: #fa9183;
margin-left: 5px;
}
.floor-box {
width: 100vw;
min-width: 900px;
height: 90px;
background-color: rgba(255, 255, 255, 1);
-moz-box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
-webkit-box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
position: fixed;
bottom: 0;
.box {
max-width: 1200px;
min-width: 900px;
height: 100%;
margin: 0 auto;
justify-content: space-between;
padding: 0 30px;
.anonymous-box {
cursor: pointer;
color: #333333;
font-size: 14px;
user-select: none;
.text {
color: rgb(170, 170, 170);
font-size: 13px;
}
.anonymous-icon {
width: 18px;
height: 18px;
}
}
.issue-btn {
width: 200px;
height: 46px;
background-color: rgba(114, 219, 134, 1);
border-radius: 190px;
font-size: 16px;
color: #fff;
cursor: pointer;
}
}
}
// @media (max-width: 1300px) {
// .save-box.save-left {
// left: 0 !important;
// }
// .save-box.save-right {
// right: 0 !important;
// }
// }
.save-box {
font-size: 14px;
color: #666666;
position: absolute;
// position: fixed;
top: 30px;
cursor: pointer;
transition: all 0.3s;
z-index: 1;
&.save-left {
left: 0px;
// left: calc((1200px - 100vw) / 2 + 25px);
}
&.save-right {
right: 0px;
// right: calc((1200px - 100vw) / 2 + 25px);
.save-icon {
width: 16px;
height: 16px;
margin-left: 10px;
}
}
.save-icon {
width: 22px;
height: 22px;
margin-right: 10px;
transform: rotate(180deg);
}
}
</style>
<style scoped>
/* .list-transition-enter-active,
.list-transition-leave-active {
transition: all 0.3s;
}
.list-transition-enter,
.list-transition-leave-to {
opacity: 0;
transform: translateY(20px);
} */
</style>