diff --git a/app.vue b/app.vue index 0f3fa14..bf6fd7f 100644 --- a/app.vue +++ b/app.vue @@ -1,4 +1,11 @@ +<!-- + 讨论测试一下 + 我发起的投票不能修改 匿名状态 + 我发起的投票不确定能下拉加载 + --> <template> + <div id="append_parent"></div> + <div id="ajaxwaitid"></div> <RouterView></RouterView> </template> <script setup> diff --git a/components/DetailsArea.vue b/components/DetailsArea.vue index 08864ae..26644f6 100644 --- a/components/DetailsArea.vue +++ b/components/DetailsArea.vue @@ -85,6 +85,7 @@ let islike = inject("islike") let iscollection = inject("iscollection") let qrcode = inject("qrcode") let token = inject("token") +const topHeadRef = inject("topHeadRef") // 获取完整 url const getFullUrl = () => { @@ -127,7 +128,7 @@ const handleCollect = () => { return } - // topHeadRef.value.count = {} + topHeadRef.value.count = {} operateCollectHttp({ token: token.value }).then(res => { if (res.code != 200) { @@ -149,6 +150,16 @@ const isBrowser = computed(() => { // 点赞 const handleLike = () => { + if (isNeedLogin.value) { + goLogin() + return + } + + if (islike.value) { + ElMessage.error("不可取消点赞") + return + } + operateLikeHttp({ token: token.value }).then(res => { if (res.code != 200) { ElMessage.error(res.message) diff --git a/components/DetailsComments.vue b/components/DetailsComments.vue index 15cbfae..34cc842 100644 --- a/components/DetailsComments.vue +++ b/components/DetailsComments.vue @@ -3,7 +3,7 @@ 讨论 <span class="comment-amount">{{ commentComments || "" }}</span> </div> - <div class="post-comment flexacenter"> + <div class="post-comment flexacenter" @click="loginJudgment()"> <textarea class="post-input flex1" placeholder="说说你的想法或疑问…" v-model="commentInputTop"></textarea> <div class="post-ok flexcenter" @click="submitAnswerComments()">发送</div> </div> @@ -36,7 +36,7 @@ <div class="comments-username" @click="openAvatarPopover(index)">{{ item["nickname"] }}</div> <div class="comments-time">{{ handleDate(item["timestamp"]) }}</div> <div class="comments-identity" v-if="item['isauthor']">作者</div> - <img class="comments-title" v-if="item['groupid'] == 14" src="@/assets/img/title.png" /> + <img class="comments-title" v-if="item['groupid'] === 14" src="@/assets/img/title.png" /> </div> <div class="comment-header-right flexacenter"> <div class="menu-box flexacenter"> @@ -132,11 +132,12 @@ <script setup> import { ElMessage } from "element-plus" +import { isEmpty } from "element-plus/es/utils" + let isNeedLogin = inject("isNeedLogin") const goLogin = inject("goLogin") -const props = defineProps({ - token: String, -}) + +const props = defineProps({ token: String }) watch( () => props.token, @@ -187,6 +188,11 @@ const getCommentList = () => { // 评论点赞 const commentLike = (index, i) => { + if (isNeedLogin.value) { + goLogin() + return + } + const targetCommentList = [...commentList.value] let token = "" @@ -211,15 +217,20 @@ const commentLike = (index, i) => { // 打开 回答-评论 的子评论 const openAnswerCommentsChild = (index, i) => { - closeAnswerCommentsChild() + if (isNeedLogin.value) { + goLogin() + return + } + closeAnswerCommentsChild(false) if (i == null) commentList.value[index]["childState"] = true else commentList.value[index]["child"][i]["childState"] = true - commentInput.value = "" + // commentInput.value = "" } -// 关闭 回答-评论 的子评论 -const closeAnswerCommentsChild = () => { - commentInput.value = "" +// 关闭 回答-评论 的子评论 isempty 是否需要清空输入框 默认需要清空 +const closeAnswerCommentsChild = (isempty = true) => { + console.log("isempty", isempty) + if (isempty) commentInput.value = "" commentList.value.forEach(ele => { ele["childState"] = false if (ele["child"] && ele["child"].length != 0) ele["child"].forEach(el => (el["childState"] = false)) @@ -308,6 +319,10 @@ const submitAnswerComments = (index, i) => { // 获取剩下的子评论 const alsoCommentsData = (index, ind) => { + if (isNeedLogin.value) { + goLogin() + return + } let targetCommentItem = { ...commentList.value[index] } const token = targetCommentItem["token"] const parentid = targetCommentItem["id"] @@ -357,6 +372,10 @@ const report = token => { // 打开评论的 信息框 const openAvatarPopover = (index, i) => { + if (isNeedLogin.value) { + goLogin() + return + } if (i != null) commentList.value[index]["child"][i]["popoverState"] = true else commentList.value[index]["popoverState"] = true } @@ -373,6 +392,35 @@ const handleScroll = () => { } provide("reportAlertShow", reportAlertShow) + +// 登录判断 +const loginJudgment = () => { + if (isNeedLogin.value) goLogin() +} + +// 修改投票的值 +const changeCommentVoteoption = voteoption => { + const uin = window["userInfoWin"]["uin"] + commentList.value.forEach(element => { + if (uin == element["uin"]) element["voteoption"] = voteoption + element.child.forEach(el => { + if (uin == element["uin"]) el["voteoption"] = voteoption + }) + }) +} + +// 修改投票的值 +const wipeCommentVoteoption = () => { + const uin = window["userInfoWin"]["uin"] + commentList.value.forEach(element => { + if (uin == element["uin"]) element["voteoption"] = null + element.child.forEach(el => { + if (uin == element["uin"]) el["voteoption"] = null + }) + }) +} + +defineExpose({ changeCommentVoteoption, wipeCommentVoteoption }) </script> <style scoped lang="less"> diff --git a/components/MyPopup.vue b/components/MyPopup.vue index 25ff53f..4b6a53c 100644 --- a/components/MyPopup.vue +++ b/components/MyPopup.vue @@ -9,11 +9,12 @@ </div> </div> - <!-- <div class="empty-box flexcenter" v-loading="true" v-if="(MyPopupState == 'collect' && collectLoading) || (MyPopupState == 'mj' && publisloading)"></div> --> + <div class="empty-box flexcenter" v-loading="true" v-if="(MyPopupState == 'collect' && collectLoading) || (MyPopupState == 'takevote' && takevoteloading) || (MyPopupState == 'publish' && publisloading)"></div> <div class="empty-box flexcenter" v-if="showList.length == 0"> <Empty></Empty> </div> <el-scrollbar v-else height="479px"> + <!-- <el-scrollbar v-else height="40px"> --> <div class="content" @scroll="handleListScroll"> <div class="item flexflex" v-for="(item, index) in showList" :key="item.uniqid" @click="goDetails(item['uniqid'] || item?.data?.uniqid)"> <div class="left flexflex"> @@ -115,7 +116,7 @@ const getPublish = () => { if (publisPage == 0 && !publisloading.value) return publisloading.value = true - MyUserPublishHttp({ page: publisPage }) + MyUserPublishHttp({ limit: 1, page: publisPage }) .then(res => { if (res.code != 200) return let data = res.data @@ -151,6 +152,12 @@ const cutMy = (key, isEmpty) => { collectList = [] collectPage = 1 collectCount.value = 0 + + takevoteList = [] + takevotePage = 1 + + publishList = [] + publisPage = 1 } if (key == "collect" && collectList.length == 0) getCollect() @@ -238,6 +245,7 @@ const closeDialog = () => { // const emit = defineEmits(["cutMy"]); const unbookmarkSamePage = inject("unbookmarkSamePage") +const unbookmark = inject("unbookmark") // 处理取消收藏 const cancelCollection = (token, index, uniqid) => { @@ -281,7 +289,7 @@ const deleteVote = () => { publishList.splice(deleteobj["index"], 1) showList.value = [...publishList] - if (id == deleteobj["uniqid"]) unbookmarkSamePage() + if (id == deleteobj["uniqid"]) unbookmark() ElMessage.success(res.message) deleteobj = {} diff --git a/components/top-head.vue b/components/top-head.vue index 96c939a..7043a95 100644 --- a/components/top-head.vue +++ b/components/top-head.vue @@ -141,8 +141,6 @@ const handleUser = async key => { return } - console.log("key", key) - if (Object.keys(count.value).length === 0) { await getUser() MyPopupRef.value.cutMy(key, true) diff --git a/composables/utils.js b/composables/utils.js index 6296f85..28f5574 100644 --- a/composables/utils.js +++ b/composables/utils.js @@ -33,6 +33,8 @@ export const handleDate = (dateTimeStamp = new Date()) => { // 处理 截止时间 export const handleDeadline = (dateTimeStamp = new Date()) => { if (typeof dateTimeStamp == "number") dateTimeStamp = dateTimeStamp ? dateTimeStamp * 1000 : null + if (typeof dateTimeStamp == "string" && dateTimeStamp.match(/^\d{4}-\d{2}-\d{2}$/)) dateTimeStamp += " 23:59:59"; + var timestamp = new Date(dateTimeStamp) timestamp = timestamp.getTime() diff --git a/nuxt.config.ts b/nuxt.config.ts index 4ab83df..6bc2257 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,6 +1,43 @@ // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ - devtools: { enabled: true }, - modules: ['@element-plus/nuxt'], - + ssr: true, + devtools: { enabled: true }, + modules: ["@element-plus/nuxt"], + app: { + head: { + link: [{ rel: "stylesheet", href: "//bbs.gter.net/data/cache/style_2_common.css?Z62" }], + script: [ + // { src: "https://app.gter.net/bottom?tpl=header&menukey=mj" }, + // { src: "https://app.gter.net/bottom?tpl=footer", body: true }, + { + src: "//bbs.gter.net/static/js/common.js", + body: true, + charset: "gb2312", + }, + { + innerHTML: ` + window.userInfoWin = {} + STYLEID = "2"; + STATICURL = "static/"; + IMGDIR = "https://bbs.gter.net/template/archy_plt8/image"; + VERHASH = "Z62"; + charset = "gbk"; + discuz_uid = "0"; + cookiepre = "4B5x_c0ae_"; + cookiedomain = "gter.net"; + cookiepath = "/"; + showusercard = "1"; + attackevasive = "0"; + disallowfloat = ""; + creditnotice = ","; + defaultstyle = ""; + REPORTURL = "aHR0cDovL2Jicy5ndGVyLm5ldC9mb3J1bS5waHA/dGlkPTI0MDYzNTYmZ290bz1sYXN0cG9zdA=="; + SITEURL = "https://ask.gter.net/"; + JSPATH = "static/js/";`, + type: "text/javascript", + charset: "utf-8", + }, + ], + }, + }, }) diff --git a/pages/details/[id].vue b/pages/details/[id].vue index 937e877..d220955 100644 --- a/pages/details/[id].vue +++ b/pages/details/[id].vue @@ -4,14 +4,16 @@ <Meta name="keyword" :content="seo['keyword']" /> <Meta name="description" :content="seo['description']" /> </Head> - <TopHead></TopHead> + <TopHead ref="topHeadRef"></TopHead> <div class="content flexflex" :style="{ '--main-color': colourValue[uniqidIndex]['main'], '--bg-color': colourValue[uniqidIndex]['bg'], '--bc-color': colourValue[uniqidIndex]['bc'] }"> <div class="header flexacenter"> <span>{{ info.title }}</span> - <span class="views flexcenter"> - <img class="eye-icon" src="@/assets/img/eye-icon.svg" /> - {{ info.views }} - </span> + <ClientOnly> + <span class="views flexcenter"> + <img class="eye-icon" src="@/assets/img/eye-icon.svg" /> + {{ info.views }} + </span> + </ClientOnly> </div> <div class="left"> <div class="info flexacenter"> @@ -19,7 +21,7 @@ <el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false"> <template #reference> <div class="flexcenter"> - <img class="avatar" v-if="info.avatar" :src="info.avatar" /> + <img class="avatar" :src="info.avatar" /> <div class="username">{{ info.nickname }}</div> </div> </template> @@ -49,7 +51,7 @@ </div> <div class="message">{{ info.message }}</div> - <div class="hint">{{ info.status == 1 && isvote == 0 ? `已有 ${info.votes || ""} 人参与,` : `共有 ${info.votes || 0} 人参与` }} {{ `${isvote == 1 ? "你已投票" : info.status == 1 ? "参与投票即可查看实时结果" : ""}` }}</div> + <div class="hint">{{ info.status == 1 && isvote == 0 ? `已有 ${info.votes || 0} 人参与,` : `共有 ${info.votes || 0} 人参与` }} {{ `${isvote == 1 ? "你已投票" : info.status == 1 ? "参与投票即可查看实时结果" : ""}` }}</div> <div class="option-list flexflex" v-if="info['status'] == 1 && isvote == 0"> <div class="option-item flexflex" v-for="(item, index) in option" :key="item.id" @click="handleVote(item.id, index)"> @@ -71,7 +73,7 @@ </div> </div> </div> - <div class="right"><DetailsComments :token="token"></DetailsComments></div> + <div class="right"><DetailsComments ref="commentsRef" :token="token"></DetailsComments></div> </div> <DetailsArea></DetailsArea> @@ -166,48 +168,82 @@ const redirectToExternalWebsite = url => { provide("sendMessage", sendMessage) provide("TAHomePage", TAHomePage) -// 处理点进投票 -const handleVote = (token, index) => { - operationCollectHttp({ token }).then(res => { - if (res.code != 200) { - ElMessage.error(res.message) - return - } - let data = res.data - let optionList = data["optionList"] || [] - optionList[index]["selected"] = 1 - option.value = optionList - isvote.value = 1 - info.value.votes = data["votes"] +const commentsRef = ref(null) +let voteLoading = false - ElMessage.success(res.message) - }) +// 处理点击投票 +const handleVote = (token, index) => { + if (isNeedLogin.value) { + goLogin() + return + } + + if (voteLoading) return + voteLoading = true + + topHeadRef.value.count = {} + operationCollectHttp({ token }) + .then(res => { + if (res.code != 200) { + ElMessage.error(res.message) + return + } + let data = res.data + let optionList = data["optionList"] || [] + optionList[index]["selected"] = 1 + option.value = optionList + isvote.value = 1 + info.value.votes = data["votes"] + + const value = optionList[index]["value"] + commentsRef.value.changeCommentVoteoption(value) + + ElMessage.success(res.message) + }) + .finally(() => (voteLoading = false)) } let unvoteVoteIndex = null // 选项下标 // 点击 取消投票 const handleUnvoteVote = (index, selected) => { + if (isNeedLogin.value) { + goLogin() + return + } if (selected == 0) return cancelPopoverState.value = true unvoteVoteIndex = index } const unvoteVote = () => { + if (isNeedLogin.value) { + goLogin() + return + } const token = option.value[unvoteVoteIndex].id - unvoteCollectHttp({ token }).then(res => { - if (res.code != 200) { - ElMessage.error(res.message) - return - } - let data = res.data - let optionList = data["optionList"] || [] - optionList[unvoteVoteIndex]["selected"] = 0 - option.value = optionList - isvote.value = 0 - info.value.votes = data["votes"] - cancelPopoverState.value = false - }) + if (voteLoading) return + voteLoading = true + + topHeadRef.value.count = {} + + unvoteCollectHttp({ token }) + .then(res => { + if (res.code != 200) { + ElMessage.error(res.message) + return + } + let data = res.data + let optionList = data["optionList"] || [] + optionList[unvoteVoteIndex]["selected"] = 0 + option.value = optionList + isvote.value = 0 + info.value.votes = data["votes"] + cancelPopoverState.value = false + + commentsRef.value.wipeCommentVoteoption() + }) + .finally(() => (voteLoading = false)) } const clearAllData = () => { @@ -227,6 +263,7 @@ const unbookmarkSamePage = () => { iscollection.value = 0 info.value.favs-- } + provide("unbookmarkSamePage", unbookmarkSamePage) // 删除同页面的投票需要跳转到 首页 @@ -250,6 +287,27 @@ const clearBottom = () => { indexFooter.style.display = "none" } + +let topHeadRef = ref(null) +provide("topHeadRef", topHeadRef) + +try { + if (process.server) { + await detailsHttp({ uniqid: id }).then(res => { + if (res.code != 200) { + ElMessage.error(res.message) + router.push("/index.html") + return + } + + let data = res.data + info.value = data["info"] + option.value = data["option"] + isvote.value = data["isvote"] + seo.value = data.seo + }) + } +} catch (error) {} </script> <style scoped lang="less"> @@ -288,7 +346,7 @@ const clearBottom = () => { .left { width: 658px; - // height: 500px; + min-height: calc(100vh - 165px); padding: 30px 42px 100px 30px; border-right: 16px solid #f6f6f6; .info { diff --git a/pages/index.html/index.vue b/pages/index.html/index.vue index b9e2467..edcc570 100644 --- a/pages/index.html/index.vue +++ b/pages/index.html/index.vue @@ -44,14 +44,15 @@ </div> </div> </a> - <div class="empty-box flexcenter" v-if="keyword && list.length == 0"> - <Empty :isNeedIssue="true"></Empty> - </div> + <div class="empty-box flexcenter" v-if="keyword && list.length == 0"><Empty :isNeedIssue="true"></Empty></div> </div> </template> <script setup> useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=vote" }, { src: "https://app.gter.net/bottom?tpl=footer", body: true }] }) +let isNeedLogin = inject("isNeedLogin") +const goLogin = inject("goLogin") + import { useRoute } from "vue-router" const route = useRoute() const router = useRouter() @@ -116,6 +117,10 @@ const handleScroll = () => { // 处理点赞 const handleLike = (token, index) => { + if (isNeedLogin.value) { + goLogin() + return + } operateLikeHttp({ token }).then(res => { if (res.code != 200) { ElMessage.error(res.message) @@ -202,7 +207,7 @@ try { margin: 0 auto; display: flex; flex-wrap: wrap; - + min-height: 100vh; .vote-item { width: 385px; background-color: rgba(255, 255, 255, 1); @@ -312,6 +317,7 @@ try { font-size: 14px; color: #333; line-height: 20px; + word-break: break-word; } .vote-option-progress { diff --git a/pages/publish/index.vue b/pages/publish/index.vue index 5e84b71..3e06c6e 100644 --- a/pages/publish/index.vue +++ b/pages/publish/index.vue @@ -37,9 +37,11 @@ <div class="time-box item-input-box flexacenter"> <el-config-provider :locale="zhCn"> - <el-date-picker v-model="info.deadline" type="date" placeholder="请选择" size="large" class="flex1 flexacenter" :clear-icon="{}" value-format="YYYY-MM-DD" :disabled-date="setDisabled" /> + <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> - <img class="calendar-icon" src="@/assets/img/calendar-icon.svg" /> + <div class="flexacenter"> + <img class="calendar-icon" @click="handlePicker" src="@/assets/img/calendar-icon.svg" /> + </div> </div> </div> </div> @@ -122,7 +124,15 @@ import Sortable from "sortablejs" const router = useRouter() const goLogin = inject("goLogin") const setDisabled = time => { - return time.getTime() < Date.now() // 可选历史天、可选当前天、不可选未来天 + // 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(() => {}) @@ -190,6 +200,16 @@ const submit = (status = 1) => { 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("不懂,围观学习") } @@ -239,11 +259,16 @@ const getinit = () => { 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 { + while (option.length < 2) { + option.push(null) + } + option.forEach((message, index) => { optionList.value.push({ id: index, message }) }) @@ -321,6 +346,11 @@ const deleteOption = index => { const clearMessage = index => { optionList.value[index]["message"] = "" } + +let pickerRef = ref(null) +const handlePicker = () => { + pickerRef.value.handleOpen() +} </script> <style scoped lang="less"> @@ -417,9 +447,9 @@ const clearMessage = index => { .time-box { .calendar-icon { - width: 15px; - height: 16px; - margin: 0 12px; + width: 17px; + // height: 16px; + margin: 0 9px; cursor: auto; } @@ -540,6 +570,7 @@ const clearMessage = index => { font-size: 14px; color: #333; cursor: pointer; + margin-bottom: 50px; // max-width: max-content; } } diff --git a/utils/http.js b/utils/http.js index d8153ea..c8b8f83 100644 --- a/utils/http.js +++ b/utils/http.js @@ -10,7 +10,7 @@ axios.defaults.withCredentials = true axios.interceptors.request.use( //响应拦截 async config => { // 开发时登录用的,可以直接替换小程序的 authorization - config['headers']['authorization'] = process.env.NODE_ENV !== "production" && "bee67e306e40b7d273d894657043eeb0" + config['headers']['authorization'] = process.env.NODE_ENV !== "production" && "be0e96a37a79c3ab16851b9a4318b03a" // config['headers']['authorization'] = "bee67e306e40b7d273d894657043eeb0" return config; },