Object.assign(window, Vue) const forumApp = Vue.createApp({ setup() { const baseURL = "https://ask.gter.net" let type = ref('list') // list details onMounted(() => { getUserData() getList() getListClass() window.addEventListener('scroll', handleScroll); getHistoricalSearchList() }) onUnmounted(() => { window.removeEventListener('scroll', handleScroll); }); // 我的 数据 数量 let myCount = ref({}) // // 获取用户数据 const getUserData = () => { $ajax("/api/user").then(res => { console.log("res", res); if (res.code != 200) return let data = res.data console.log(data, "data"); myCount.value = data.count }) } // 是否是搜索模式 let isSearchMode = ref(false) // 获取历史记录方法 const getHistoricalSearchList = () => { const list = localStorage.getItem('historical-Search'); if (list) historicalSearchList.value = JSON.parse(list) || [] else historicalSearchList.value = [] } // 存入历史记录 随便去重 和 限制长度 方法 const setHistoricalSearchList = () => { historicalSearchList.value.unshift(keyword.value) historicalSearchList.value = [...new Set(historicalSearchList.value)] historicalSearchList.value = historicalSearchList.value.slice(0, 10) localStorage.setItem('historical-Search', JSON.stringify(historicalSearchList.value)); } // 搜索点击事件 const searchClick = () => { if (keyword.value == "") return setHistoricalSearchList() page = 1 list.value = [] type.value = 'list' pitchIndex.value = null getList() } // 搜索获取焦点 const searchFocus = () => { if (historicalSearchList.value.length == 0) return historicalSearchState.value = true } // 搜索失去焦点 const searchBlur = () => { setTimeout(() => historicalSearchState.value = false, 100) } // 点击历史记录 item const handleClickHistoricalItem = (value) => { keyword.value = value searchClick() } // 点击清除搜索 const handleClickClear = () => { keyword.value = "" page = 1 list.value = [] type.value = 'list' pitchIndex.value = null getList() } let historicalSearchState = ref(false) // 历史记录弹窗状态 let historicalSearchList = ref([]) // 历史记录数据 let tabListFixeState = ref(false) // 顶部 类型的 固定状态 const handleScroll = () => { const scrollTop = document.documentElement.scrollTop || document.body.scrollTop const scrollHeight = document.documentElement.scrollHeight; const clientHeight = document.documentElement.clientHeight; // 列表下 滑动到底部 获取新数据 if (scrollTop + clientHeight >= scrollHeight) getList() // 列表下 滚动到顶部 触发类型的固定状态 if (scrollTop > 115 && type.value == 'list') tabListFixeState.value = true else tabListFixeState.value = false } let keyword = ref('') // 搜索的值 let list = ref([]) // 列表数据 let page = 1 let total = ref(0) // 回答总数 let loading = false // 获取列表数据 const getList = () => { if (page == 0 || loading) return loading = true $ajax("/api/lists", { page, limit: 20, keyword: keyword.value, // type: 'all', } ).then(res => { if (res.code != 200) return let data = res.data list.value = list.value.concat(data.data || []) total.value = data.count || 0 if (list.value.length != data['count']) page++ else page = 0 if (keyword.value) isSearchMode.value = true else isSearchMode.value = false }).finally(() => loading = false) } let typeList = ref([]) let typePitch = ref('') // 获取分类数据 列表分类 const getListClass = () => { $ajax("/api/common/typeList").then(res => { if (res.code != 200) return let data = res.data console.log(data, "data"); data = [{ id: "all", name: "All", }, { id: "all2", name: "All", }, { id: "all3", name: "All", }, { id: "all4", name: "All", }, { id: "all5", name: "All", }, { id: "all6", name: "All", }] typeList.value = data typePitch.value = data[0].id getPageHeight() }) } let pageHeaderHeight = ref(0) // 头部的高度 let pageListHeight = ref(0) // 底部列表的高度 const getPageHeight = () => { let pageHeader = document.querySelector("#pageHeader") // let pageHeader = document.querySelector("#pageHeader") pageHeaderHeight.value = pageHeader.clientHeight + 10 pageListHeight.value = window.innerHeight - pageHeaderHeight.value } let detailsInfo = ref({}) // 详情信息 let detailsIsanswered = ref(0) // 详情信息 let detailsIscollection = ref(0) // 详情信息 let detailsIsmyself = ref(0) // 详情信息 let detailsToken = '' // 详情信息 let detailShare = ref({}) // 详情信息 // 获取详情 const getDetails = (uniqid, index) => { uniqid = "fubm5CnD05qj" // 标记一下 $ajax("/api/details", { uniqid }).then(res => { if (res.code != 200) return let data = res.data console.log("data", data); detailsInfo.value = data['info'] || {} detailsIsanswered.value = data['isanswered'] || 0 detailsIscollection.value = data['iscollection'] || 0 detailsIsmyself.value = data['ismyself'] || 0 detailsToken = data['token'] || '' detailShare.value = data['share'] || {} type.value = 'details' cut(index) getAnswerList() }) } let answerList = ref([]) // 回答列表数据 // 获取详情的回答数据 const getAnswerList = () => { $ajax("/api/details/answerList", { token: detailsToken }).then(res => { if (res.code != 200) return let data = res.data data.data.forEach(element => { element['commentList'] = [] }) // commentList answerList.value = data.data }) } // 操作 - 点赞 const operateLike = (token, index) => { $ajax("/api/operate/like", { token }).then(res => { if (res.code != 200) return let data = res.data answerList.value[index]['islike'] = data['status'] answerList.value[index]['likenum'] = data['count'] }) } let isNeedNewColletData = false // 是否需要获取新的收藏数据 ,顶部的我的弹窗需要 // 操作 - 收藏 const operateCollect = (token = detailsToken, index) => { $ajax("/api/operate/collect", { token }).then(res => { if (res.code != 200) return let data = res.data isNeedNewColletData = true myCollectionPage = 1 myCollectionList.value = [] if (data['type'] == 'askquestioncollection') detailsIscollection.value = data['status'] else { answerList.value[index]['iscollection'] = data['status'] answerList.value[index]['collectionnum'] = data['count'] } }) } // 操作 - 回答 const operateIAnswer = (token = detailsToken, index) => { $ajax("/api/publish/answerSubmit", { token }).then(res => { console.log("res", res); }) } let IAnswerState = ref(false) // 我来回答-弹窗的状态 let IAnswerEditState = ref(false) // 编辑回答-弹窗的状态 let IAnswerInfo = ref({}) // 我来回答-弹窗的信息 // 开启我来回答 const openIAnswer = (index, type) => { if (index == null) { IAnswerInfo.value = { title: detailsInfo.value['title'], content: detailsInfo.value['content'], anonymous: 0, } IAnswerState.value = true nextTick(() => { handleInput() }) } else { // IAnswerInfo.value = answerList.value[index] if (type == 'my') { IAnswerInfo.value = { title: detailsInfo.value['title'], ...myAnswerList.value[index], text: myAnswerList.value[index]['content'], content: detailsInfo.value['content'], } myType.value = "" } else { IAnswerInfo.value = { title: detailsInfo.value['title'], ...answerList.value[index], text: answerList.value[index]['content'], content: detailsInfo.value['content'], } } IAnswerEditState.value = true } } // 关闭我来回答 const closeIAnswer = () => { IAnswerState.value = false IAnswerEditState.value = false } // 修改我来回答的匿名状态 const amendIAnswer = () => { IAnswerInfo.value['anonymous'] = IAnswerInfo.value['anonymous'] == 0 ? 1 : 0 } let isNeedNewAnswersData = false // 是否需要获取新的我的回答数据 // 提交回答 const submitAnswer = () => { const questionTextarea = document.querySelector(".question-textarea") IAnswerInfo.value['text'] = questionTextarea.innerHTML $ajax("/api/publish/answerSubmit", { token: IAnswerInfo.value['token'] || detailsToken, anonymous: IAnswerInfo.value['anonymous'] || 0, content: IAnswerInfo.value['text'], }).then(res => { console.log(res); if (res.code == 200) { getAnswerList() closeIAnswer() isNeedNewAnswersData = true } else { } }) } // 打开回答的评论 const openCommentState = index => { if (answerList.value[index]['commentState']) answerList.value[index]['commentState'] = false else answerList.value[index]['commentState'] = true if (answerList.value[index]['commentList'].length == 0 && answerList.value[index]['commentnum'] != 0) getAnswerCommentList(index) // answerList.value[index]['commentState'] = true } let answerCommentLimit = 3 // 获取回答评论的数据 const getAnswerCommentList = (index) => { getAnswerCommentPublic(index).then(res => { let data = res.data answerList.value[index]['commentList'] = answerList.value[index]['commentList'].concat(data.data) answerList.value[index]['commentCount'] = data['count'] }) } // 获取全部评论 const handleAllComment = index => { answerCommentLimit = 1000 getAnswerCommentPublic(index).then(res => { if (res.code != 200) return let data = res.data answerList.value[index]['commentList'] = answerList.value[index]['commentList'].concat(data.data.slice(3)) }) } // 获取评论数据的公共接口 const getAnswerCommentPublic = (index) => { return new Promise((resolve, reject) => { $ajax("/api/comment/lists", { token: answerList.value[index]['token'], limit: answerCommentLimit, }).then(res => { if (res.code != 200) return resolve(res) }) }) } // 提交回答-评论 const submitAnswerComments = (index, ind, i) => { // answerList.value[index]['commentState'] = true const targetAnswerList = [...answerList.value] let content = "" let parentid = null let token = targetAnswerList[index]['token'] if (i != null) { content = targetAnswerList[index]['commentList'][ind]['child'][i]['commentInput'] parentid = targetAnswerList[index]['commentList'][ind]['child'][i]['id'] } else if (ind != null) { content = targetAnswerList[index]['commentList'][ind]['commentInput'] parentid = targetAnswerList[index]['commentList'][ind]['id'] } else content = targetAnswerList[index]['commentInput'] $ajax("/api/comment/submit", { content, token, parentid, }).then(res => { console.log("res", res); if (res.code != 200) return let data = res.data if (i != null) { let targetData = { content, isauthor: 1, islike: 0, likenum: 0, reply: { nickname: targetAnswerList[index]['commentList'][ind]['child'][i]['nickname'] }, ...data, } targetAnswerList[index]['commentList'][ind]['child'].unshift(targetData) } else if (ind != null) { let targetData = { content, isauthor: 1, islike: 0, likenum: 0, reply: [], ...data, } targetAnswerList[index]['commentList'][ind]['child'].unshift(targetData) } else { let targetData = { content, isauthor: 1, islike: 0, likenum: 0, ...data, child: [] } targetAnswerList[index]['commentList'].unshift(targetData) } closeAnswerCommentsChild() console.log("targetAnswerList", targetAnswerList); }) } // 回答-评论 点赞 operateIAnswer const operateAnswerCommentsLike = (token, index, ind, i) => { $ajax("/api/comment/like", { token, }).then(res => { console.log("res", res); if (res.code != 200) return let data = res.data console.log("data", data); const targetAnswerList = [...answerList.value] if (i == null) { targetAnswerList[index]['commentList'][ind]['islike'] = data['status'] targetAnswerList[index]['commentList'][ind]['likenum'] = data['likenum'] } else { targetAnswerList[index]['commentList'][ind]['child'][i]['islike'] = data['status'] targetAnswerList[index]['commentList'][ind]['child'][i]['likenum'] = data['likenum'] } answerList.value = targetAnswerList }) } // 打开 回答-评论 的子评论 const openAnswerCommentsChild = (index, ind, i) => { console.log(""); closeAnswerCommentsChild() if (i == null) { answerList.value[index].commentList[ind]['childState'] = true } else { answerList.value[index].commentList[ind]['child'][i]['childState'] = true } } // 关闭 回答-评论 的子评论 const closeAnswerCommentsChild = (index, ind, i) => { const targetAnswerList = [...answerList.value] targetAnswerList.forEach(element => { if (element['commentList'] && element['commentList'].length != 0) { element['commentList'].forEach(ele => { ele['childState'] = false if (ele['child'] && ele['child'].length != 0) { ele['child'].forEach(el => { el['childState'] = false }) } }) } }) answerList.value = targetAnswerList } // 获取剩下的子评论 const alsoCommentsData = (index, ind) => { const targetAnswerList = [...answerList.value] const parentid = targetAnswerList[index]['commentList'][ind]['id'] const token = targetAnswerList[index]['commentList'][ind]['token'] $ajax("/api/comment/childrenList", { token, parentid, limit: 20, page: 1, }).then(res => { console.log("res", res); if (res.code != 200) return let data = res.data targetAnswerList[index]['commentList'][ind]['child'] = targetAnswerList[index]['commentList'][ind]['child'].concat(data.data) answerList.value = targetAnswerList }) } let myType = ref('') // collect answers questions // 专门处理 我的 弹窗数据 const handleMy = (key) => { // if ((key == 'collect' && isNeedNewColletData) || (key == 'collect' && myCollectionList.value.length == 0)) { if (key == 'collect') { myCollectionList.value = [] myCollectionPage = 1 getMyCollection() return } else if (key == 'answers') { myAnswerList.value = [] myAnswerPage = 1 getMyAnswer() return } else if (key == 'questions') { getMyQuestions() return } myType.value = key } let myCollectionList = ref([]) // 我的收藏列表 let myCollectionCount = ref(0) // 我的收藏数量 let myCollectionPage = 1 // 我的收藏页数 // 获取我的收藏 const getMyCollection = () => { if (myCollectionPage == 0) return $ajax("/api/user/collect", { limit: 20, page: myCollectionPage, }).then(res => { if (res.code != 200) return let data = res.data myType.value = 'collect' isNeedNewColletData = false myCollectionList.value = myCollectionList.value.concat(data.data) myCollectionCount.value = data.count if (myCollectionList.value.length != data['count']) myCollectionPage++ else myCollectionPage = 0 }) } // 取消收藏 const cancelCollection = (token, index) => { $ajax("/api/user/deleteCollect", { token }).then(res => { if (res.code == 200) { myCollectionList.value.splice(index, 1) myCollectionCount.value-- } }) } // 监听 我的收藏滚动到底部 const handleCollectionScroll = (e) => { const el = e.target; // 判断滚动到底部 if (el.scrollHeight - el.scrollTop !== el.clientHeight) return getMyCollection() } let myAnswerList = ref([]) // 我的回答数据 let myAnswerCount = ref(0) // 我的回答数量 let myAnswerPage = 1 // 获取我的回答 const getMyAnswer = () => { if (myAnswerPage == 0) return $ajax("/api/user/answer", { limit: 20, page: myAnswerPage, }).then(res => { if (res.code != 200) return let data = res.data data.data.forEach(element => { element['popupState'] = false }) myAnswerList.value = myAnswerList.value.concat(data.data) myAnswerCount.value = data.count if (myAnswerList.value.length != data['count']) myAnswerPage++ else myAnswerPage = 0 console.log("myAnswerList", myAnswerList.value); myType.value = 'answers' isNeedNewAnswersData = false }) } const handleAnswersScroll = e => { const el = e.target; // 判断滚动到底部 if (el.scrollHeight - el.scrollTop !== el.clientHeight) return getMyAnswer() } let answerIndexOld = null // 切换 我的提问的公开匿名 弹窗状态 const cutAnswerPopupState = index => { myAnswerList.value[index]['popupState'] = true if (answerIndexOld == index) { myAnswerList.value[index]['popupState'] = false answerIndexOld = null } else { myAnswerList.value[index]['popupState'] = true if (answerIndexOld != null) myAnswerList.value[answerIndexOld]['popupState'] = false answerIndexOld = index } } // 更改匿名状态 const changeAnonymous = (token, anonymous, index) => { $ajax("/api/publish/changeAnonymous", { token, anonymous }).then(res => { if (res.code != 200) return let data = res.data myAnswerList.value[index]['anonymous'] = anonymous cutAnswerPopupState(index) }) } let myQuestionsList = ref([]) // 我的提问数据 let myQuestionsCount = ref(0) // 我的提问数量 // 获取我的提问 const getMyQuestions = () => { $ajax("/api/user/questions").then(res => { if (res.code != 200) return let data = res.data myQuestionsList.value = myQuestionsList.value.concat(data.data) myQuestionsCount.value = data.count myType.value = 'questions' }) } let questionsSetp = ref(0) // 提问的步骤 // 切换提问步骤 const cutQuestionsSetp = (value) => { questionsSetp.value = value } let questionsTypeList = ref([]) // 提问的类型主题 let questionsObj = ref({ // 提问的内容 token: "", title: "", content: "", tags: "", tid: "", anonymous: 0, }) // 报 提问的初始化 const questionsInit = () => { $ajax("/api/publish/questions").then(res => { if (res.code != 200) return let data = res.data questionsObj.value['token'] = data['token'] questionsTypeList.value = data['typeList'] || [] cutQuestionsSetp(1) }) } // 选择提问主题 const choosingTheme = (id) => { questionsObj.value.tid = id cutQuestionsSetp(2) } // 切换匿名状态 const cutAnonymous = () => { questionsObj.value.anonymous = questionsObj.value.anonymous == 0 ? 1 : 0 } // 发布问题 const postingIssue = () => { console.log("发布问题", questionsObj.value); $ajax("/api/publish/questionsSubmit", questionsObj.value).then(res => { console.log("res", res); }) } let pitchIndex = ref(null) // 选中的下标 const cut = index => { // if (pitchIndex.value == null) type.value = type.value == 'list' ? 'details' : 'list' pitchIndex.value = index setTimeout(() => { scrollLeftInMiddle() }, 350) } // 滚动左边在中间 const scrollLeftInMiddle = () => { // console.log(pitchIndex.value, "pitchIndex"); let list = document.querySelector(".list-box") // console.log("list", list); console.log(107 * pitchIndex.value, pageListHeight.value / 2); list.scrollTo({ top: 128 * pitchIndex.value + 64 - 385, behavior: 'smooth' }) } const listStyle = () => { const newtype = type.value let width = "" let margin = "" if (newtype == 'list') { width = '1200px' margin = '0 auto' } else { width = 'calc((100vw - 1200px) / 2 + 512px)' margin = 'initial' } return { width, margin } } const itemStyle = (index, content) => { const newtype = type.value // pitchIndex // let itemHeight = content == "" ? 106 : 128 let obj = {} if (newtype == 'list') { let top = Math.floor(index / 2) * 128 + 'px' obj['top'] = top if (index % 2 == 0) obj['left'] = 0 else obj['left'] = 649 + 'px' } else { obj['top'] = index * 128 + 'px' obj['left'] = 0 obj['width'] = '100%' // obj['backgroundColor'] = '#fbfbfb' obj['paddingLeft'] = 'calc((100vw - 1200px) / 2)' } return obj }; // list-box const listBoxStyle = () => { const newtype = type.value let obj = {} if (newtype == 'list') { obj['overflow'] = 'visible' } else { // obj['height'] = 'calc(100vh - ' + pageHeaderHeight.value + 'px)' obj['height'] = pageListHeight.value + 'px' } return obj } const $ajax = (url, data) => { url = url.indexOf('//') > -1 ? url : baseURL + url; return new Promise(function (resolve, reject) { axios.post(url, data, { emulateJSON: true, withCredentials: true, headers: { // authorization: "9l3vfdx6h5xhu2hbw4fv5ygbog1dhtly" authorization: "194cdc367ed40c938f2eaaf1c6dfa5ff" } }).then(function (res) { var data = null try { data = typeof res.data == 'string' ? JSON.parse(res.data) : res.data; } catch (error) { } resolve(data) }); }); } // 处理时间 const handleDate = (dateTimeStamp) => { dateTimeStamp = dateTimeStamp ? dateTimeStamp : null; var timestamp = new Date(dateTimeStamp) timestamp = timestamp.getTime() var minute = 1000 * 60; var hour = minute * 60; var day = hour * 24; var now = new Date().getTime(); var diffValue = now - timestamp; var result; if (diffValue < 0) return; var dayC = diffValue / day; var hourC = diffValue / (hour + 1); var minC = diffValue / minute; if (dayC >= 7) { let date = new Date(timestamp); let Y = date.getFullYear() + '-'; let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; let D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '; let h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'; let m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()); result = "" + Y + M + D + h + m; } else if (dayC >= 1) result = "" + Math.round(dayC) + "天前"; else if (hourC >= 1) result = "" + Math.round(hourC) + "小时前"; else if (minC >= 1) result = "" + Math.round(minC) + "分钟前"; else result = "刚刚"; return result; } // 问题的转发 弹窗状态 let questionsTransmitState = ref(false) // 关闭转发状态 const closeTransmitState = () => { answerList.value.forEach(element => { element['transmitState'] = false }) questionsTransmitState.value = !questionsTransmitState.value } // 开启和关闭回答的转发状态 type open close const handleAnswerTransmitList = (Iindex, type) => { // handleAnswerTransmitList questionsTransmitState.value = false answerList.value.forEach((element, index) => { if (index != Iindex) element['transmitState'] = false }) answerList.value[Iindex]['transmitState'] = !answerList.value[Iindex]['transmitState'] } // 关闭详情模式 const closeDetailMode = () => { type.value = 'list' pitchIndex.value = null } const handleListScroll = (e) => { const el = e.target; // 判断滚动到底部 if (el.scrollHeight - el.scrollTop !== el.clientHeight) return getList() } // 处理 回答弹窗的复制图片 const handlePaste = (event) => { const items = (event.clipboardData || event.originalEvent.clipboardData).items; for (const item of items) { if (item.type.indexOf('image') === 0) { const file = item.getAsFile(); const reader = new FileReader(); reader.onload = (e) => { const img = new Image(); img.src = e.target.result; const questionTextarea = document.querySelector(".question-textarea") questionTextarea.appendChild(img); handleInput() // IAnswerInfo.value['text'] = questionTextarea.innerHTML }; reader.readAsDataURL(file); } } } let questionPlaceholderState = ref(false) const handleInput = (event) => { // IAnswerInfo.value['text'] = event.target.innerHTML; const questionTextarea = document.querySelector(".question-textarea") const html = questionTextarea.innerHTML if (html) questionPlaceholderState.value = false else questionPlaceholderState.value = true console.log("questionPlaceholderState", questionPlaceholderState); } return { questionPlaceholderState, handleInput, handlePaste, itemStyle, listStyle, listBoxStyle, myType, type, pitchIndex, cut, list, keyword, getList, total, typeList, typePitch, getDetails, detailsInfo, detailsIsanswered, detailsIscollection, detailsIsmyself, detailShare, answerList, operateLike, operateCollect, IAnswerState, IAnswerEditState, IAnswerInfo, amendIAnswer, openIAnswer, closeIAnswer, operateIAnswer, submitAnswer, openCommentState, submitAnswerComments, operateAnswerCommentsLike, openAnswerCommentsChild, closeAnswerCommentsChild, alsoCommentsData, handleAllComment, myCollectionList, myCollectionCount, myQuestionsList, myQuestionsCount, myAnswerList, myAnswerCount, cutAnswerPopupState, handleDate, handleCollectionScroll, handleAnswersScroll, cancelCollection, getMyCollection, questionsSetp, questionsObj, cutAnonymous, cutQuestionsSetp, questionsTypeList, postingIssue, choosingTheme, handleMy, changeAnonymous, pageHeaderHeight, pageListHeight, questionsTransmitState, closeTransmitState, handleAnswerTransmitList, closeDetailMode, tabListFixeState, handleListScroll, historicalSearchState, historicalSearchList, searchFocus, searchBlur, searchClick, handleClickHistoricalItem, handleClickClear, isSearchMode, questionsInit, }; } }) forumApp.mount("#answer-app"); //初始化