From e01ac5326b3c2aea9f4ea752ae604442bc93a7e3 Mon Sep 17 00:00:00 2001
From: A1300399510 <A1300399510>
Date: Mon, 15 Jan 2024 19:02:10 +0800
Subject: [PATCH] no message

---
 app.vue                        |   5 +-
 components/DetailsArea.vue     |  14 ++-
 components/DetailsComments.vue |  40 +++++---
 components/Empty.vue           |  22 +++-
 components/MyPopup.vue         | 171 ++++++++++++++++++++++---------
 components/Report.vue          |   5 +-
 components/top-head.vue        |  19 +++-
 composables/api.js             |  52 +++++++++-
 composables/utils.js           |   3 +-
 pages/details/[id].vue         | 182 ++++++++++++++++++++++++++++++---
 pages/index.html/index.vue     |  54 ++++++++--
 pages/publish/index.vue        |  31 +++---
 12 files changed, 479 insertions(+), 119 deletions(-)

diff --git a/app.vue b/app.vue
index 6ac4428..0f3fa14 100644
--- a/app.vue
+++ b/app.vue
@@ -1,8 +1,5 @@
 <template>
-    <div>
-        <RouterView></RouterView>
-        <!-- <NuxtWelcome /> -->
-    </div>
+    <RouterView></RouterView>
 </template>
 <script setup>
 const route = useRoute()
diff --git a/components/DetailsArea.vue b/components/DetailsArea.vue
index b495751..08864ae 100644
--- a/components/DetailsArea.vue
+++ b/components/DetailsArea.vue
@@ -6,19 +6,17 @@
                     <img class="icon" src="@/assets/img/eye-icon-black.svg" />
                     {{ info["views"] }}
                 </div> -->
-                <div class="item flexacenter" @click="handleLike">
-                    <img class="icon" v-if="islike == 1" src="@/assets/img/like-icon-colours.png" />
-                    <img class="icon" v-else src="@/assets/img/like-icon.png" />
-                    {{ info["likes"] || "" }}
-                </div>
                 <ClientOnly>
+                    <div class="item flexacenter" @click="handleLike">
+                        <img class="icon" v-if="islike == 1" src="@/assets/img/like-icon-colours.png" />
+                        <img class="icon" v-else src="@/assets/img/like-icon.png" />
+                        {{ info["likes"] || "" }}
+                    </div>
                     <div class="item flexacenter" @click="handleCollect()">
                         <img class="icon" v-if="iscollection == 1" src="@/assets/img/collect-icon-colours.svg" />
                         <img class="icon" v-else src="@/assets/img/collect-icon.png" />
                         {{ info["favs"] || "收藏" }}
                     </div>
-                </ClientOnly>
-                <ClientOnly>
                     <el-popover placement="bottom" width="628px" trigger="click" popper-style="padding: 0;border-radius: 10px;" v-model:visible="transmitBoxState">
                         <template #reference>
                             <div class="item flexacenter" @click="handleShare"><img class="icon" src="@/assets/img/transmit-icon.png" />转发</div>
@@ -32,7 +30,7 @@
                                     <div class="transmit-headline">{{ info["title"] }}</div>
                                     <div class="transmit-url">{{ getFullUrl() }}</div>
                                 </div>
-                                <div class="transmit-web-btn flexcenter" @click="copyText(`${info['subject']} + ${getFullUrl()}`)">复制链接</div>
+                                <div class="transmit-web-btn flexcenter" @click="copyText(`${info['title']} + ${getFullUrl()}`)">复制链接</div>
                             </div>
                             <div class="transmit-right transmit-mini">
                                 <div class="transmit-title">转发小程序版</div>
diff --git a/components/DetailsComments.vue b/components/DetailsComments.vue
index 874b463..15cbfae 100644
--- a/components/DetailsComments.vue
+++ b/components/DetailsComments.vue
@@ -52,7 +52,7 @@
                         </div>
                     </div>
                     <div class="comment-text" @click="openAnswerCommentsChild(index)">{{ item["content"] }}</div>
-                    <!-- <div class="comments-input-box flexacenter" v-if="item['childState']"> -->
+                    <div class="alreadyVoted" v-if="item.voteoption">已投:{{ item.voteoption }}</div>
                     <div class="comments-input-box flexacenter" v-if="item['childState']">
                         <div class="comments-input flexflex">
                             <textarea class="flex1" placeholder="回复" v-model="commentInput"></textarea>
@@ -105,6 +105,7 @@
                                     <div class="comments-reply" v-if="ite?.reply?.nickname">@{{ ite?.reply?.nickname }}</div>
                                     {{ ite["content"] }}
                                 </div>
+                                <div class="alreadyVoted" v-if="ite.voteoption">已投:{{ ite.voteoption }}</div>
                                 <div class="comments-input-box flexacenter" v-if="ite['childState']">
                                     <div class="comments-input flexflex">
                                         <textarea class="flex1" placeholder="回复" v-model="commentInput"></textarea>
@@ -139,17 +140,11 @@ const props = defineProps({
 
 watch(
     () => props.token,
-    newV => {
-        console.log(newV)
-        getCommentList()
-    },
-    {
-        immediate: false,
-    }
+    () => getCommentList(),
+    { immediate: false }
 )
-onMounted(() => {
-    window.addEventListener("scroll", handleScroll)
-})
+
+onMounted(() => window.addEventListener("scroll", handleScroll))
 
 const sendMessage = inject("sendMessage")
 const TAHomePage = inject("TAHomePage")
@@ -159,7 +154,6 @@ let commentComments = ref(0) // 所有的评论数
 let commentPage = ref(1)
 let commentList = ref([])
 let commentLoading = false
-let token = "4ZKbui89pS81jKgWpT41kLgcglLOJa8UQCmuucFl-cyzQKdjr0iEMTl4grDC04TSnq1vC90fZ2pVdeP6IUYPN2Y4Ng~~"
 let isEmptyState = ref(false) // 评论是否为空
 
 // 获取详情评论数据
@@ -255,7 +249,7 @@ const submitAnswerComments = (index, i) => {
 
     detailsSubmitommentListHttp({
         content,
-        token,
+        token: props.token,
         parentid,
     }).then(res => {
         if (res.code != 200) {
@@ -297,6 +291,7 @@ const submitAnswerComments = (index, i) => {
                 commentCount.value++
             }
         }
+
         commentComments.value++
         commentList.value = targetCommentList
 
@@ -323,7 +318,7 @@ const alsoCommentsData = (index, ind) => {
         limit: 10,
         page,
         parentid,
-        token,
+        token: props.token,
     }).then(res => {
         if (res.code != 200) return
         let data = res.data
@@ -398,6 +393,7 @@ provide("reportAlertShow", reportAlertShow)
     height: 60px;
     background-color: rgba(255, 255, 255, 1);
     border: 1px solid rgba(215, 215, 215, 1);
+    border-right: none;
     border-radius: 6px;
     margin-bottom: 30px;
     margin-right: 30px;
@@ -459,7 +455,7 @@ provide("reportAlertShow", reportAlertShow)
             .comment-header {
                 display: flex;
                 justify-content: space-between;
-                padding-right: 30px;
+                // padding-right: 30px;
                 margin-bottom: 10px;
 
                 .comment-header-left {
@@ -576,6 +572,16 @@ provide("reportAlertShow", reportAlertShow)
                 }
             }
 
+            .alreadyVoted {
+                font-size: 12px;
+                color: #aaaaaa;
+                background-color: rgba(246, 246, 246, 1);
+                line-height: 17px;
+                width: fit-content;
+                margin-bottom: 15px;
+                word-break: break-word;
+            }
+
             .comments-input-box {
                 margin-top: 13px;
                 margin-bottom: 10px;
@@ -585,6 +591,7 @@ provide("reportAlertShow", reportAlertShow)
                     flex: 1;
                     height: 60px;
                     border: 1px solid rgba(215, 215, 215, 1);
+                    border-right: none;
                     border-radius: 8px;
                     margin-right: 16px;
                     position: relative;
@@ -614,7 +621,8 @@ provide("reportAlertShow", reportAlertShow)
                     .comments-btn {
                         width: 58px;
                         height: 58px;
-                        background-color: #31d72e;
+                        // background-color: #31d72e;
+                        background-color: var(--main-color);
                         border-radius: 0 7px 7px 0;
                         font-size: 14px;
                         color: #ffffff;
diff --git a/components/Empty.vue b/components/Empty.vue
index 8e3a042..5993c23 100644
--- a/components/Empty.vue
+++ b/components/Empty.vue
@@ -9,14 +9,28 @@
             <img class="item" src="@/assets/img/dot-gray.svg" />
         </div>
         <img class="empty-icon" src="@/assets/img/empty-icon.svg" />
-        <div class="empty-hint">{{ hint || "暂无内容" }}</div>
+
+        <template v-if="isNeedIssue">
+            <div class="empty-hint" style="margin-bottom: 7px;">没有找到相关结果,请更换搜索关键词</div>
+            <div class="empty-hint flexacenter">
+                或者
+                <div class="sponsor" @click="goIssue">发起一个新投票</div>
+            </div>
+        </template>
+        <div v-else class="empty-hint">{{ hint || "暂无内容" }}</div>
     </div>
 </template>
 
 <script setup>
+import { useRouter } from "vue-router"
+const router = useRouter()
+
 let props = defineProps({
     hint: String,
+    isNeedIssue: Boolean,
 })
+
+const goIssue = () => router.push("/publish")
 </script>
 
 <style lang="less" scoped>
@@ -48,6 +62,12 @@ let props = defineProps({
         font-size: 13px;
         color: #7f7f7f;
         line-height: 22px;
+        .sponsor {
+            text-decoration: underline;
+            color: #72db86;
+            margin-left: 5px;
+            cursor: pointer;
+        }
     }
 }
 </style>
diff --git a/components/MyPopup.vue b/components/MyPopup.vue
index e3a9c31..25ff53f 100644
--- a/components/MyPopup.vue
+++ b/components/MyPopup.vue
@@ -9,67 +9,75 @@
                 </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-else-if="showList.length == 0">
+            <!-- <div class="empty-box flexcenter" v-loading="true" v-if="(MyPopupState == 'collect' && collectLoading) || (MyPopupState == 'mj' && publisloading)"></div> -->
+            <div class="empty-box flexcenter" v-if="showList.length == 0">
                 <Empty></Empty>
             </div>
             <el-scrollbar v-else height="479px">
                 <div class="content" @scroll="handleListScroll">
-                    <div class="item flexflex" v-for="(item, index) in showList" :key="index" @click="goDetails(item['uniqid'] || item?.data?.uniqid)">
+                    <div class="item flexflex" v-for="(item, index) in showList" :key="item.uniqid" @click="goDetails(item['uniqid'] || item?.data?.uniqid)">
                         <div class="left flexflex">
-                            <div class="name">{{ item.title }}</div>
-                            <div class="message">{{ item.message }}</div>
+                            <div class="name ellipsis">{{ item.title || item.data?.title }}</div>
+                            <div class="message ellipsis">{{ item.message || item.data?.message }}</div>
                             <div class="data">
-                                30人参与 <i>|</i> 投票已结束
-                                <span><i>|</i> 我已投:不懂,围观学习</span>
+                                {{ item.votes || item.data?.votes || 0 }}人参与 <i>|</i> {{ handleDeadline(item.deadline || item?.data?.deadline) }}结束
+                                <span v-if="item.optionvalue || item?.data?.optionvalue"><i>|</i> 我已投:{{ item.optionvalue || item?.data?.optionvalue }}</span>
                             </div>
                         </div>
                         <div class="operate-area flexacenter">
-                            <img class="delete-icon" v-if="MyPopupState == 'collect'" @click.stop="cancelCollection(item['token'], index)" src="@/assets/img/delete-icon.svg" />
-                            <div class="anonymous-box flexacenter" v-else @click.stop="openAnonymousState(index)">
-                                <div class="text">{{ item["anonymous"] == 1 ? "匿名" : "公开" }}</div>
-                                <img class="arrow-icon" src="@/assets/img/arrow-gray.svg" />
-                                <div class="state-popup flexflex" v-if="item['anonymousState']" @click.stop="">
-                                    <div class="state-popup-item flexacenter flex1" :class="{ 'pitch': item['anonymous'] == 0 }" @click="handleAnonymousState(item['token'], index, 0)">
-                                        <div class>公开发表</div>
-                                        <img class="state-popup-icon" src="@/assets/img/tick-green.svg" />
-                                    </div>
-                                    <div class="state-popup-item flexacenter flex1" :class="{ 'pitch': item['anonymous'] == 1 }" @click="handleAnonymousState(item['token'], index, 1)">
-                                        <div class>匿名发表</div>
-                                        <img class="state-popup-icon" src="@/assets/img/tick-green.svg" />
+                            <!-- <div class="anonymous-box flexacenter" v-if="MyPopupState == 'publish'" @click.stop="openAnonymousState(index)"> -->
+                            <template v-if="MyPopupState == 'publish'">
+                                <div class="anonymous-box flexacenter" @click.stop="openAnonymousState(index)">
+                                    <div class="text">{{ item["anonymous"] == 1 ? "匿名" : "公开" }}</div>
+                                    <img class="arrow-icon" src="@/assets/img/arrow-gray.svg" />
+                                    <div class="state-popup flexflex" v-if="item['anonymousState']" @click.stop="">
+                                        <div class="state-popup-item flexacenter flex1" :class="{ 'pitch': item['anonymous'] == 0 }" @click="handleAnonymousState(item['token'], index, 0)">
+                                            <div class>公开发表</div>
+                                            <img class="state-popup-icon" src="@/assets/img/tick-green.svg" />
+                                        </div>
+                                        <div class="state-popup-item flexacenter flex1" :class="{ 'pitch': item['anonymous'] == 1 }" @click="handleAnonymousState(item['token'], index, 1)">
+                                            <div class>匿名发表</div>
+                                            <img class="state-popup-icon" src="@/assets/img/tick-green.svg" />
+                                        </div>
                                     </div>
                                 </div>
-                            </div>
+                                <div class="halving-line"></div>
+                                <img class="delete-icon" @click.stop="openDeleteVote(item['token'], index, item.uniqid || item?.data?.uniqid)" src="@/assets/img/delete-icon.svg" />
+                            </template>
+
+                            <img class="delete-icon" v-if="MyPopupState == 'collect'" @click.stop="cancelCollection(item['token'], index, item.uniqid || item?.data?.uniqid)" src="@/assets/img/delete-icon.svg" />
                         </div>
                     </div>
                 </div>
             </el-scrollbar>
         </div>
     </el-dialog>
+
+    <el-dialog class="options-popup" v-model="deleteState" width="488px" align-center>
+        <div class="options-popup-text">您要删除投票吗?</div>
+        <div class="options-popup-btn flexflex">
+            <div class="options-popup-item options-no flexcenter" @click="deleteVote">删除投票</div>
+            <div class="options-popup-item options-yes flexcenter" @click="deleteState = false">不删除</div>
+        </div>
+    </el-dialog>
     <!-- </div> -->
 </template>
 <script setup>
 let props = defineProps({
-    // MyPopupState: String, // collect  mj
-    count: Object,
+    tabList: Array,
 })
 
+let deleteState = ref(false) // 确认删除弹窗
+
+let count = inject("count")
+
 let show = ref(false)
 const router = useRouter()
 const route = useRoute()
 
-let MyPopupState = ref("") // collect  participation  sponsor
+let MyPopupState = ref("") // collect  takevote  publish
 
-onMounted(() => {
-    // if (MyPopupState.value == "collect") getCollect();
-    // else if (MyPopupState.value == "mj") getPublish();
-})
-
-const tabList = [
-    { name: "我的收藏", type: "collect" },
-    { name: "我参与的投票", type: "participation" },
-    { name: "我发起的投票", type: "sponsor" },
-]
+onMounted(() => {})
 
 // 展示的 列表数据
 let showList = ref([])
@@ -82,20 +90,20 @@ let collectCount = ref(0)
 const getCollect = () => {
     if (collectPage == 0 || collectLoading.value) return
     collectLoading.value = true
+    // if (collectPage == 2) return
+
     MyUserCollectHttp({ page: collectPage })
         .then(res => {
             if (res.code != 200) return
             let data = res.data
             collectList = collectList.concat(data.data)
             showList.value = collectList
+            // showList.value = showList.value.concat(data.data)
 
             if (collectList.length < data["count"]) collectPage++
             else collectPage = 0
 
             collectCount.value = data["count"]
-
-            // MyPopupState.value = "collect"
-            // show.value = true
         })
         .finally(() => (collectLoading.value = false))
 }
@@ -104,11 +112,10 @@ let publishList = []
 let publisPage = 1
 let publisloading = ref(false)
 const getPublish = () => {
-    return
     if (publisPage == 0 && !publisloading.value) return
 
     publisloading.value = true
-    MyUserPublishHttp({ limit: 4, page: publisPage })
+    MyUserPublishHttp({ page: publisPage })
         .then(res => {
             if (res.code != 200) return
             let data = res.data
@@ -116,13 +123,28 @@ const getPublish = () => {
             if (publishList.length < data["count"]) publisPage++
             else publisPage = 0
             showList.value = publishList
-
-            // MyPopupState.value = "mj"
-            // show.value = true
         })
         .finally(() => (publisloading.value = false))
 }
 
+let takevoteList = []
+let takevotePage = 1
+let takevoteloading = ref(false)
+const getTakevote = () => {
+    if (takevotePage == 0 && !takevoteloading.value) return
+    takevoteloading.value = true
+    MyUserTakevoteHttp({ page: takevotePage })
+        .then(res => {
+            if (res.code != 200) return
+            let data = res.data
+            takevoteList = takevoteList.concat(data.data)
+            if (takevoteList.length < data["count"]) takevotePage++
+            else takevotePage = 0
+            showList.value = takevoteList
+        })
+        .finally(() => (takevoteloading.value = false))
+}
+
 // 切换  isEmpty 是否清空收藏数据, 因为不确定用户是否有新收藏
 const cutMy = (key, isEmpty) => {
     if (isEmpty) {
@@ -132,10 +154,12 @@ const cutMy = (key, isEmpty) => {
     }
 
     if (key == "collect" && collectList.length == 0) getCollect()
-    else if (key == "mj" && publishList.length == 0) getPublish()
+    else if (key == "takevote" && takevoteList.length == 0) getTakevote()
+    else if (key == "publish" && publishList.length == 0) getPublish()
 
     if (key == "collect") showList.value = collectList
-    else if (key == "mj") showList.value = publishList
+    else if (key == "takevote") showList.value = takevoteList
+    else if (key == "publish") showList.value = publishList
 
     MyPopupState.value = key
 
@@ -161,7 +185,10 @@ const closeAllAnonymousState = () => {
 // 修改匿名状态
 const handleAnonymousState = (token, index, anonymous) => {
     changeAnonymousHttp({ token, anonymous }).then(res => {
-        if (res.code != 200) return
+        if (res.code != 200) {
+            ElMessage.error(res.message)
+            return
+        }
 
         publishList[index]["anonymous"] = anonymous
         showList.value = [...publishList]
@@ -177,7 +204,8 @@ const handleListScroll = e => {
     // 判断滚动到底部
     if (el.scrollHeight - el.scrollTop !== el.clientHeight) return
     if (MyPopupState.value == "collect") getCollect()
-    if (MyPopupState.value == "mj") getPublish()
+    if (MyPopupState.value == "takevote") getTakevote()
+    if (MyPopupState.value == "publish") getPublish()
 }
 
 let clearAllData = inject("clearAllData") || null
@@ -185,7 +213,7 @@ let getDetails = inject("getDetails") || null
 
 // 打开详情页
 const goDetails = uniqid => {
-    return
+    // return
     let path = route["path"] || ""
     if (path.indexOf("/details/") != -1) {
         clearAllData()
@@ -209,9 +237,12 @@ const closeDialog = () => {
 }
 
 // const emit = defineEmits(["cutMy"]);
+const unbookmarkSamePage = inject("unbookmarkSamePage")
 
 // 处理取消收藏
-const cancelCollection = (token, index) => {
+const cancelCollection = (token, index, uniqid) => {
+    const id = route.params["id"]
+
     MyUserDeleteCollectHttp({ token }).then(res => {
         if (res.code != 200) {
             ElMessage.error(res.message)
@@ -219,8 +250,42 @@ const cancelCollection = (token, index) => {
         }
 
         collectList.splice(index, 1)
+        count.value.collect--
         collectCount.value--
         showList.value = [...collectList]
+
+        if (id == uniqid) unbookmarkSamePage()
+    })
+}
+
+let deleteobj = {}
+
+const openDeleteVote = (token, index, uniqid) => {
+    deleteobj["token"] = token
+    deleteobj["index"] = index
+    deleteobj["uniqid"] = uniqid
+    deleteState.value = true
+}
+
+// 点删除投票
+const deleteVote = () => {
+    const id = route.params["id"]
+
+    deleteHttp({ token: deleteobj["token"] }).then(res => {
+        if (res.code != 200) {
+            ElMessage.error(res.message)
+            return
+        }
+
+        count.value.publish--
+        publishList.splice(deleteobj["index"], 1)
+        showList.value = [...publishList]
+
+        if (id == deleteobj["uniqid"]) unbookmarkSamePage()
+
+        ElMessage.success(res.message)
+        deleteobj = {}
+        deleteState.value = false
     })
 }
 </script>
@@ -302,7 +367,8 @@ const cancelCollection = (token, index) => {
 
     .content {
         width: 100%;
-        height: 100%;
+        height: 479px;
+        // height: 100%;
         // background: #000000;
         overflow: auto;
         // padding-right: 13px;
@@ -337,12 +403,14 @@ const cancelCollection = (token, index) => {
                     line-height: 20px;
                     font-size: 14px;
                     margin-bottom: 10px;
+                    width: 550px;
                 }
                 .message {
                     color: #7f7f7f;
                     line-height: 22px;
                     font-size: 13px;
                     margin-bottom: 6px;
+                    width: 550px;
                 }
 
                 .data {
@@ -363,6 +431,13 @@ const cancelCollection = (token, index) => {
                     cursor: pointer;
                 }
 
+                .halving-line {
+                    margin: 0 20px;
+                    width: 1px;
+                    height: 13px;
+                    border-right: 1px solid #d7d7d7;
+                }
+
                 .anonymous-box {
                     .text {
                         font-size: 13px;
diff --git a/components/Report.vue b/components/Report.vue
index 51dcdad..2658f04 100644
--- a/components/Report.vue
+++ b/components/Report.vue
@@ -56,10 +56,7 @@ const alertSubmit = () => {
     }).then(res => {
         checkList.value = []
         reportAlertShow.value = false
-        ElMessage({
-            message: res.message || "举报成功",
-            type: "success",
-        })
+        ElMessage.success(res.message || "举报成功")
     })
 }
 
diff --git a/components/top-head.vue b/components/top-head.vue
index 4df5412..96c939a 100644
--- a/components/top-head.vue
+++ b/components/top-head.vue
@@ -17,20 +17,18 @@
                     <div class="my-btn-item flexcenter" @click="handleUser('collect')">我的收藏</div>
                 </div> -->
                 <div class="my-btn-list flexacenter">
-                    <div class="my-btn-item flexcenter" @click="handleUser('collect')">我的收藏</div>
-                    <div class="my-btn-item flexcenter" @click="handleUser('participation')">我参与的投票</div>
-                    <div class="my-btn-item flexcenter" @click="handleUser('sponsor')">我发起的投票</div>
+                    <div class="my-btn-item flexcenter" v-for="item in tabList" :key="item.type" @click="handleUser(item.type)">{{ item.name }}</div>
                 </div>
                 <div class="sponsor-btn flexcenter" @click="goPublish">
                     <img class="add-bj" src="@/assets/img/add-bj.svg" />
                     <img class="add-icon" src="@/assets/img/add-icon.svg" />
-                    发布面经
+                    发布投票
                 </div>
             </div>
         </div>
     </section>
 
-    <MyPopup ref="MyPopupRef" :count="count"></MyPopup>
+    <MyPopup ref="MyPopupRef" :tabList="tabList"></MyPopup>
 </template>
 
 <script setup>
@@ -42,14 +40,23 @@ const route = useRoute()
 let isNeedLogin = inject("isNeedLogin")
 const goLogin = inject("goLogin")
 
+const tabList = [
+    { name: "我的收藏", type: "collect" },
+    { name: "我参与的投票", type: "takevote" },
+    { name: "我发起的投票", type: "publish" },
+]
+
 let keyword = ref("")
 
 onMounted(() => {
     getHistoricalSearchList()
     keyword.value = route.query["keyword"]
 })
+
 let count = ref({})
 
+provide("count", count)
+
 const getUser = () => {
     return new Promise((resolve, reject) => {
         MyUserInfoHttp().then(res => {
@@ -134,6 +141,8 @@ 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/api.js b/composables/api.js
index e179c5a..b6c1a75 100644
--- a/composables/api.js
+++ b/composables/api.js
@@ -39,6 +39,15 @@ export const publishSubmitHttp = query => {
     return Http.post("/api/publish/submit", query)
 }
 
+// 发布相关 - 更改匿名状态
+export const changeAnonymousHttp = query => {
+    return Http.post("/api/publish/changeAnonymous", query)
+}
+
+// 发布相关 - 删除投票
+export const deleteHttp = query => {
+    return Http.post("/api/publish/delete", query)
+}
 
 // 操作-点赞
 export const operateLikeHttp = query => {
@@ -48,4 +57,45 @@ export const operateLikeHttp = query => {
 // 数据操作 - 收藏
 export const operateCollectHttp = query => {
     return Http.post("/api/operate/collect", query)
-}
\ No newline at end of file
+}
+
+// 数据操作 - 投票操作
+export const operationCollectHttp = query => {
+    return Http.post("/api/operate/operation", query)
+}
+
+// 数据操作 - 取消投票操作
+export const unvoteCollectHttp = query => {
+    return Http.post("/api/operate/unvote", query)
+}
+
+// 我的 - 用户信息
+export const MyUserInfoHttp = query => {
+    return Http.post("/api/user", query)
+}
+
+// 我的 - 我的发布的面经
+export const MyUserPublishHttp = query => {
+    return Http.post("/api/user/publish", query)
+}
+
+// 我的 - 用户相关 - 我参与
+export const MyUserTakevoteHttp = query => {
+    return Http.post("/api/user/takevote", query)
+}
+
+// 我的 - 删除收藏
+export const MyUserDeleteCollectHttp = query => {
+    return Http.post("/api/user/deleteCollect", query)
+}
+
+// 数据操作 - 收藏
+export const MyUserCollectHttp = query => {
+    return Http.post("/api/user/collect", query)
+}
+
+
+// 评论相关 - 举报 Comment related
+export const commentReportHttp = query => {
+    return Http.post("/api/operate/report", query)
+}
diff --git a/composables/utils.js b/composables/utils.js
index f5cdbc3..6296f85 100644
--- a/composables/utils.js
+++ b/composables/utils.js
@@ -32,7 +32,8 @@ export const handleDate = (dateTimeStamp = new Date()) => {
 
 // 处理 截止时间
 export const handleDeadline = (dateTimeStamp = new Date()) => {
-    // dateTimeStamp = dateTimeStamp ? dateTimeStamp * 1000 : null
+    if (typeof dateTimeStamp == "number") dateTimeStamp = dateTimeStamp ? dateTimeStamp * 1000 : null
+
     var timestamp = new Date(dateTimeStamp)
     timestamp = timestamp.getTime()
     var minute = 1000 * 60
diff --git a/pages/details/[id].vue b/pages/details/[id].vue
index 86e2ab3..937e877 100644
--- a/pages/details/[id].vue
+++ b/pages/details/[id].vue
@@ -1,4 +1,9 @@
 <template>
+    <Head>
+        <Title>{{ `${seo["title"] || "投票"} - 寄托天下出国留学网` }}</Title>
+        <Meta name="keyword" :content="seo['keyword']" />
+        <Meta name="description" :content="seo['description']" />
+    </Head>
     <TopHead></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">
@@ -43,18 +48,17 @@
                 </div>
             </div>
             <div class="message">{{ info.message }}</div>
-            <!-- 共有 58 人参与,你已投票 -->
 
-            <div class="hint">{{ info.status == 1 && isvote == 0 ? `已有 ${info.votes} 人参与,` : `共有 ${info.votes} 人参与` }} {{ `${isvote == 1 ? "你已投票" : info.status == 1 ? "参与投票即可查看实时结果" : ""}` }}</div>
+            <div class="hint">{{ info.status == 1 && isvote == 0 ? `已有 ${info.votes || ""} 人参与,` : `共有 ${info.votes || 0} 人参与` }} {{ `${isvote == 1 ? "你已投票" : info.status == 1 ? "参与投票即可查看实时结果" : ""}` }}</div>
 
-            <div class="option-list flexflex" v-if="info['status'] == 1">
-                <div class="option-item flexflex" v-for="(item, index) in option" :key="item.id">
+            <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)">
                     <div class="serial flexcenter">{{ index + 1 }}</div>
                     <span class="flex1">{{ item.value }} </span>
                 </div>
             </div>
             <div class="option-area" v-else>
-                <div class="option-item flexflex" :class="{ 'pitch': item.selected }" v-for="(item, index) in option" :key="item.id">
+                <div class="option-item flexflex" :class="{ 'pitch': item.selected }" v-for="(item, index) in option" :key="item.id" @click="handleUnvoteVote(index, item.selected)">
                     <div class="flexflex" style="padding: 2px 0px;">
                         <div class="option-number flexcenter">{{ index + 1 }}</div>
                         <img class="tick-icon" src="@/assets/img/tick-black.svg" />
@@ -70,13 +74,25 @@
         <div class="right"><DetailsComments :token="token"></DetailsComments></div>
     </div>
     <DetailsArea></DetailsArea>
+
+    <el-dialog class="options-popup" v-model="cancelPopoverState" width="488px" align-center>
+        <div class="options-popup-text">您要取消投票吗?</div>
+        <div class="options-popup-btn flexflex">
+            <div class="options-popup-item options-no flexcenter" @click="unvoteVote">取消投票</div>
+            <div class="options-popup-item options-yes flexcenter" @click="cancelPopoverState = false">不取消</div>
+        </div>
+    </el-dialog>
 </template>
 
 <script setup>
-import { useRoute } from "vue-router"
+useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=mj" }, { src: "https://app.gter.net/bottom?tpl=footer", body: true }] })
+
+import { useRoute, useRouter } from "vue-router"
 import { ElMessage } from "element-plus"
+
 const route = useRoute()
-// console.log(route, "route")
+const router = useRouter()
+
 let isNeedLogin = inject("isNeedLogin")
 const goLogin = inject("goLogin")
 
@@ -84,7 +100,10 @@ let id = route.params.id
 const uniqidEnd = id.charAt(id.length - 1)
 const uniqidIndex = base62ToDecimal(uniqidEnd) % 6
 
-onMounted(() => getinit())
+onMounted(() => {
+    getDetails()
+    clearBottom()
+})
 
 let info = ref({})
 let qrcode = ref("") // 分享二维码
@@ -95,17 +114,19 @@ let detailsLoading = ref(false) // 详情加载中
 let isvote = ref(0) // 是否已经投票
 let option = ref([])
 let token = ref("")
+let cancelPopoverState = ref(false) // 取消投票弹窗
+
 provide("info", info)
 provide("islike", islike)
 provide("iscollection", iscollection)
 provide("token", token)
 provide("qrcode", qrcode)
 
-const getinit = () => {
+const getDetails = () => {
     detailsHttp({ uniqid: id }).then(res => {
-        console.log(res)
         if (res.code != 200) {
             ElMessage.error(res.message)
+            router.push("/index.html")
             return
         }
 
@@ -118,11 +139,12 @@ const getinit = () => {
         option.value = data["option"]
         qrcode.value = data.share?.qrcode
         token.value = data["token"]
-
-        console.log(data.share?.qrcode, "data.share?.qrcode")
+        seo.value = data.seo
     })
 }
 
+provide("getDetails", getDetails)
+
 // 点击发送信息
 const sendMessage = uin => {
     redirectToExternalWebsite(`https://bbs.gter.net/home.php?mod=space&showmsg=1&uid=${uin}`)
@@ -143,6 +165,91 @@ 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"]
+
+        ElMessage.success(res.message)
+    })
+}
+
+let unvoteVoteIndex = null // 选项下标
+
+// 点击 取消投票
+const handleUnvoteVote = (index, selected) => {
+    if (selected == 0) return
+    cancelPopoverState.value = true
+    unvoteVoteIndex = index
+}
+
+const unvoteVote = () => {
+    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
+    })
+}
+
+const clearAllData = () => {
+    info.value = {}
+    qrcode.value = ""
+    iscollection.value = 0
+    islike.value = 0
+    ismyself.value = 0
+    isvote.value = 0
+    option.value = []
+}
+
+provide("clearAllData", clearAllData)
+
+// 取消了同页面的收藏
+const unbookmarkSamePage = () => {
+    iscollection.value = 0
+    info.value.favs--
+}
+provide("unbookmarkSamePage", unbookmarkSamePage)
+
+// 删除同页面的投票需要跳转到 首页
+const unbookmark = () => router.push("/index.html")
+provide("unbookmark", unbookmark)
+
+let seo = ref({})
+
+// 清除底部的次数
+let clearBottomCount = 0
+
+// 清除 底部
+const clearBottom = () => {
+    const indexFooter = document.querySelector("section.index-footer")
+    if (!indexFooter) {
+        clearBottomCount++
+        setTimeout(() => clearBottom(), 200)
+        return
+    }
+    if (clearBottomCount == 5) return
+
+    indexFooter.style.display = "none"
+}
 </script>
 
 <style scoped lang="less">
@@ -153,6 +260,7 @@ provide("TAHomePage", TAHomePage)
     border-radius: 16px;
     background: #fff;
     flex-wrap: wrap;
+    // min-height: 100vh;
 
     --main-color: rgba(44, 186, 230, 1);
     --bg-color: rgba(234, 245, 248, 1);
@@ -234,6 +342,7 @@ provide("TAHomePage", TAHomePage)
             line-height: 24px;
             color: #333;
             margin-bottom: 30px;
+            word-wrap: break-word;
         }
 
         .hint {
@@ -326,10 +435,12 @@ provide("TAHomePage", TAHomePage)
                 padding: 7px 15px 10px;
                 flex-direction: column;
                 word-break: break-all;
+                cursor: no-drop;
                 &:not(:last-of-type) {
                     border-bottom: 1px solid var(--bc-color);
                 }
                 &.pitch {
+                    cursor: pointer;
                     .option-number {
                         display: none;
                     }
@@ -395,3 +506,50 @@ provide("TAHomePage", TAHomePage)
     }
 }
 </style>
+
+<style lang="less">
+.options-popup {
+    border-radius: 10px;
+    .el-dialog__header {
+        padding: 0;
+        .el-dialog__headerbtn {
+            width: 36px;
+            height: 36px;
+        }
+    }
+    padding: 44px 74px;
+    .el-dialog__body {
+        padding: 0;
+    }
+
+    .options-popup-text {
+        font-size: 14px;
+        color: #333333;
+        text-align: center;
+        margin-bottom: 71px;
+    }
+
+    .options-popup-btn {
+        justify-content: space-between;
+        .options-popup-item {
+            font-size: 13px;
+            width: 160px;
+            height: 40px;
+            border-radius: 150px;
+            border: 1px solid;
+            cursor: pointer;
+
+            &.options-yes {
+                background-color: rgba(114, 219, 134, 1);
+                border-color: rgba(114, 219, 134, 1);
+                color: #fff;
+            }
+            &.options-no {
+                background-color: #fff;
+                border-color: rgba(170, 170, 170, 1);
+                color: #333;
+            }
+        }
+    }
+}
+</style>
diff --git a/pages/index.html/index.vue b/pages/index.html/index.vue
index e4ad6e7..b9e2467 100644
--- a/pages/index.html/index.vue
+++ b/pages/index.html/index.vue
@@ -8,6 +8,7 @@
         <div class="halving-line"></div>
         <div class="search-result">共 {{ count }} 条搜索数据</div>
     </div>
+
     <div class="vote-list-box" ref="gridContainer">
         <a class="vote-item" target="_blank" :href="`/details/${item['uniqid']}`" v-for="(item, index) in list" :key="index" :class="{ 'isvote': item['isvote'] == 1 || item['status'] == 0 }" :style="{ '--main-color': colourValue[item.uniqidIndex]['main'], '--bg-color': colourValue[item.uniqidIndex]['bg'], '--bc-color': colourValue[item.uniqidIndex]['bc'] }">
             <div class="vote-title">
@@ -17,7 +18,7 @@
             </div>
             <div class="vote-explain">{{ item["message"] }}</div>
             <div class="vote-option-list flexflex">
-                <div class="vote-option-item flexflex" :class="{ 'pitch': index == 1 }" v-for="(item, index) in item?.option" :key="index">
+                <div class="vote-option-item flexflex" :class="{ 'pitch': item.selected == 1 }" v-for="(item, index) in item?.option" :key="index">
                     <div class="flexflex" style="padding: 2px 0;">
                         <div class="vote-option-number flexcenter">{{ index + 1 }}</div>
                         <img class="tick-icon" src="@/assets/img/tick-black.svg" />
@@ -31,11 +32,11 @@
             </div>
             <div class="vote-data flexacenter">
                 <div class="vote-data-left flexacenter">
-                    18人参与 <template v-if="item['deadline']">| {{ handleDeadline(item["deadline"]) }}结束</template>
+                    {{ item.votes }}人参与 <template v-if="item['deadline']">| {{ handleDeadline(item["deadline"]) }}结束</template>
                 </div>
                 <div class="vote-data-right flexacenter">
-                    <div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/eye-icon.svg" />&nbsp; {{ 96 }}</div>
-                    <div class="vote-data-item flexacenter" @click="handleLike(item['token'])">
+                    <div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/eye-icon.svg" />&nbsp; {{ item.views }}</div>
+                    <div class="vote-data-item flexacenter" @click.stop.prevent="handleLike(item['token'], index)">
                         <img v-if="item['islike'] == 0" class="vote-data-icon" src="@/assets/img/like-no.svg" />
                         <img v-else class="vote-data-icon" src="@/assets/img/like-yes.png" />&nbsp; {{ item["likes"] }}
                     </div>
@@ -43,9 +44,14 @@
                 </div>
             </div>
         </a>
+        <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 }] })
+
 import { useRoute } from "vue-router"
 const route = useRoute()
 const router = useRouter()
@@ -109,8 +115,18 @@ const handleScroll = () => {
 }
 
 // 处理点赞
-const handleLike = token => {
-    console.log("handleLike", token)
+const handleLike = (token, index) => {
+    operateLikeHttp({ token }).then(res => {
+        if (res.code != 200) {
+            ElMessage.error(res.message)
+            return
+        }
+        let data = res.data
+
+        list.value[index].likes = data["count"]
+        list.value[index].islike = data["status"]
+        ElMessage.success(res.message)
+    })
 }
 
 // 点击关闭搜索
@@ -129,6 +145,24 @@ watch(
         getList()
     }
 )
+
+try {
+    if (process.server) {
+        await getListHttp({ page, keyword: keyword.value }).then(res => {
+            let data = res.data
+            data.data.forEach(element => {
+                let uniqidEnd = element["uniqid"].charAt(element["uniqid"].length - 1)
+                element["uniqidIndex"] = base62ToDecimal(uniqidEnd) % 6
+            })
+            list.value = list.value.concat(data.data)
+            count.value = data.count
+            if (data.count > list.value.length) page++
+            else page = 0
+
+            console.log("keyword", keyword.value)
+        })
+    }
+} catch (error) {}
 </script>
 <style lang="less" scoped>
 .vote-item {
@@ -323,4 +357,12 @@ watch(
         }
     }
 }
+
+.empty-box {
+    width: 1200px;
+    height: 540px;
+    background-color: rgba(255, 255, 255, 1);
+    border-radius: 16px;
+    margin: 0 auto;
+}
 </style>
diff --git a/pages/publish/index.vue b/pages/publish/index.vue
index af42e95..5e84b71 100644
--- a/pages/publish/index.vue
+++ b/pages/publish/index.vue
@@ -21,7 +21,7 @@
                             标题
                             <div class="asterisk">*</div>
                         </div>
-                        <el-input class="item-input headline-textarea" type="textarea" placeholder="请输入" maxlength="24" show-word-limit v-model="info.title" autosize></el-input>
+                        <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">
@@ -55,7 +55,7 @@
                                     <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>
-                                            <input class="option-input flex1" placeholder="请输入" />
+                                            <el-input class="option-input flex1" placeholder="请输入" />
                                         </div>
                                         <div class="option-drag flexcenter">
                                             <img class="option-icon" src="@/assets/img/option-icon.svg" />
@@ -66,7 +66,8 @@
                                     <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']" />
+                                            <!-- <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">
@@ -111,6 +112,7 @@
 </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"
@@ -184,6 +186,7 @@ const submit = (status = 1) => {
     if (status == 1) {
         if (option.length < 2) {
             ElMessage.error("请设置至少2个选项~")
+            loading = false
             return
         }
 
@@ -326,15 +329,14 @@ const clearMessage = index => {
     justify-content: center;
     padding: 0 122px;
 }
+
 @media (max-width: 920px) {
     .content-box {
         display: block;
         padding: 0 10px;
-        // padding: 0 122px;
     }
 }
 .contentcontent {
-    // width: 1200px;
     max-width: 1200px;
     min-width: 900px;
     min-height: calc(100vh - 120px);
@@ -364,11 +366,8 @@ const clearMessage = index => {
         .box-left {
             border-right: 16px solid #f6f6f6;
             width: 48.176%;
-
-            // .area-box {
             padding: 30px;
             padding-right: 50px;
-            border-bottom: 1px solid #ebebeb;
 
             .item {
                 &:not(:last-of-type) {
@@ -378,9 +377,7 @@ const clearMessage = index => {
                 .item-input {
                     border-radius: 5px;
                     outline: none;
-                    // width: 482px;
                     width: 100%;
-                    // padding: 13px 14px;
                     font-size: 14px;
 
                     /deep/ .el-textarea__inner {
@@ -500,12 +497,19 @@ const clearMessage = index => {
                             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: 0 10px;
+                            margin-right: 10px;
                         }
                     }
 
@@ -555,7 +559,7 @@ const clearMessage = index => {
 
 .floor-box {
     width: 100vw;
-    min-width: 1200px;
+    min-width: 900px;
     height: 90px;
     background-color: rgba(255, 255, 255, 1);
     -moz-box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
@@ -564,7 +568,8 @@ const clearMessage = index => {
     position: fixed;
     bottom: 0;
     .box {
-        width: 1200px;
+        max-width: 1200px;
+        min-width: 900px;
         height: 100%;
         margin: 0 auto;
         justify-content: space-between;