{"version":3,"file":"index-55fe60c2.js","sources":["../../../vite/modulepreload-polyfill","../../../src/components/AppLink.vue","../../../src/core/PageInfo.js","../../../src/core/pages.js","../../../src/assets/images/404.png","../../../src/assets/images/bg-side.png","../../../src/assets/images/feed-comment-bg.jpg","../../../src/assets/images/hand.png","../../../src/assets/images/ico-face.png","../../../src/assets/images/ico-link.png","../../../src/assets/images/loading.gif","../../../src/assets/images/logo.png","../../../src/assets/img/img-260x360.jpg","../../../src/assets/img/img-260x360a.jpg","../../../src/assets/img/img-50x50.jpg","../../../src/assets/img/img-603x1069.jpg","../../../src/core/util.js","../../../src/api/instance.js","../../../src/api/APIResponse.js","../../../src/api/index.js","../../../src/store/defineStore.js","../../../src/store/defineListStore.js","../../../src/core/dataGenerator.js","../../../src/models/richContent.js","../../../src/models/thread.js","../../../src/store/stores.js","../../../src/components/AppMenu.vue","../../../src/App.vue","../../../src/components/toast/index.js","../../../src/core/passport.js","../../../plugin-vue:export-helper","../../../src/components/ListLoader.vue","../../../src/components/UserFollowBtn.vue","../../../src/hooks/useBumpUp.js","../../../src/constants/constants.js","../../../src/directives/bi.js","../../../src/components/swiper-feed/user/SFUser.vue","../../../src/plugins/editor.js","../../../src/components/Editor.vue","../../../src/components/swiper-feed/comment/CommentForm.vue","../../../src/components/ParagraphText.vue","../../../src/components/swiper-feed/comment/CommentItem.vue","../../../src/store/comment.js","../../../src/components/swiper-feed/comment/CommentList.vue","../../../src/hooks/useCommentChanged.js","../../../src/components/swiper-feed/comment/SFComment.vue","../../../src/components/swiper-feed/SFPlayer.vue","../../../src/hooks/useThreadRecommends.js","../../../src/components/swiper-feed/user/useUserThreadList.js","../../../src/components/swiper-feed/SwiperFeed.vue","../../../src/components/ThreadItem.vue","../../../src/hooks/useTidLand.js","../../../src/pages/home/Home.vue","../../../src/pages/404.vue","../../../src/pages/Channel.vue","../../../src/pages/index.js","../../../src/routes.js","../../../src/main.js"],"sourcesContent":["const p = function polyfill() {\n const relList = document.createElement('link').relList;\n if (relList && relList.supports && relList.supports('modulepreload')) {\n return;\n }\n for (const link of document.querySelectorAll('link[rel=\"modulepreload\"]')) {\n processPreload(link);\n }\n new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type !== 'childList') {\n continue;\n }\n for (const node of mutation.addedNodes) {\n if (node.tagName === 'LINK' && node.rel === 'modulepreload')\n processPreload(node);\n }\n }\n }).observe(document, { childList: true, subtree: true });\n function getFetchOpts(script) {\n const fetchOpts = {};\n if (script.integrity)\n fetchOpts.integrity = script.integrity;\n if (script.referrerpolicy)\n fetchOpts.referrerPolicy = script.referrerpolicy;\n if (script.crossorigin === 'use-credentials')\n fetchOpts.credentials = 'include';\n else if (script.crossorigin === 'anonymous')\n fetchOpts.credentials = 'omit';\n else\n fetchOpts.credentials = 'same-origin';\n return fetchOpts;\n }\n function processPreload(link) {\n if (link.ep)\n // ep marker = processed\n return;\n link.ep = true;\n // prepopulate the load record\n const fetchOpts = getFetchOpts(link);\n fetch(link.href, fetchOpts);\n }\n};__VITE_IS_MODERN__&&p();","\n\n\n","import qs from 'qs'\n\nexport default class PageInfo {\n constructor(config) {\n // 页面标题\n this.title = config.title\n // 页面地址\n this.path = config.path\n\n this.name = config.name\n // // 页面组件实例\n // this.component = config.component\n // 父页面\n this.parent = config.parent\n this.needAuth = config.needAuth === true\n this.meta = config.meta\n }\n\n // 路由配置信息\n get routeInfo() {\n return { path: this.path }\n }\n\n // 返回指定参数后的完整跳转链接\n toLink(params, query) {\n let href = this.path\n href = href.replace(/\\?/g, '')\n if (params) {\n Object.keys(params).forEach((key) => {\n href = href.replace(`:${key}`, params[key])\n })\n }\n\n // 移除未传值的参数\n href = href.replace(/\\/:[a-z]*/g, '')\n if (query) {\n if (typeof query === 'string' && query.indexOf('#') > -1) {\n href += query\n } else {\n href += `?${qs.stringify(query)}`\n }\n }\n return href\n }\n\n // 跳转\n to(params) {\n const href = this.toLink(params)\n window.location.href = href\n }\n}\n","import PageInfo from './PageInfo'\n/*\n社区主页\nhttp://dev.club.17173.com/group/index\n圈子主页\nhttp://dev.club.17173.com/group/info\n圈子列表\nhttp://dev.club.17173.com/group/list\n\n贴子详情\nhttp://dev.club.17173.com/thread/info\n发布贴子\nhttp://dev.club.17173.com/thread/issue\n\n用户主页\nhttp://dev.club.17173.com/user/space\n*/\n\n/*\nexport的变量名称要与pages/index.js下保持一致.\n没有直接饮用pages/index.js是为了防止循环import\n */\n\nconst keywords =\n '搞视,囧图集,AI小姐姐,绅士社,造物煮,歪果人少系列,动物撕界,整活大师,变态任务'\nconst description =\n '欢迎来到搞视频道,这里放送各种来自国内外的欢乐、搞笑和猎奇的精彩趣味视频,为您提供一站式的解压放松体验!在这里,您将欣赏到最新AI技术创造处的AI小姐姐,涵盖海量沙雕时刻的囧图集,挑战人类极限的变态任务,聚集各种奇葩恶搞操作的整活大师,记录萌宠爆笑瞬间的动物撕届,汇聚老外硬核作死行为的歪果仁少系列。。。关注搞视,尽情畅享精彩视频,享受无限的轻松与快乐!'\n\nexport const home = new PageInfo({\n title: '搞视',\n path: '/',\n name: 'home',\n meta: {\n keywords,\n description,\n },\n})\nexport const channel = new PageInfo({\n title: '搞视',\n path: '/channel/:id',\n name: 'channel',\n meta: {\n keywords,\n description,\n },\n})\n\nexport const error = new PageInfo({\n title: '404',\n path: '/404',\n meta: {\n keywords,\n description,\n },\n})\n\n// export const sample = new PageInfo({\n// title: '功能示例',\n// path: '/sample/:id/:cc',\n// needAuth: true,\n// })\n","export default \"__VITE_ASSET__d14b9540__\"","export default \"__VITE_ASSET__8ed5fd50__\"","export default \"__VITE_ASSET__a9a69519__\"","export default \"__VITE_ASSET__53e87a11__\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkI4NTZBQ0UxQkM4RTExRURCMjhEQzlDNjUzNzNDQjUxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkI4NTZBQ0UyQkM4RTExRURCMjhEQzlDNjUzNzNDQjUxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Qjg1NkFDREZCQzhFMTFFREIyOERDOUM2NTM3M0NCNTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Qjg1NkFDRTBCQzhFMTFFREIyOERDOUM2NTM3M0NCNTEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz40gp2/AAACP0lEQVR42qyWTUhUURTH37xiTEh3hVEowUBZ0qbQtatWRil9L1qFiyANmibaR42k4seyZTX5RR/QNluXQYGCCzEdFMFalVJZqf8jvyevx52XY3Pgx5u559z/8V3PPWcSucFXXoxVi0uiURwRe8QvMSdmxRsxID4VEtgZI3xfnBM7Ir4ycRhOirskuS3yUSHfIX5KjIuL4o8Y5C0OIl4halkbEr+JneAZ+wZtoovEz8QtMRWJWRGTkBMpkRXN4rGoEt2uNziPY01k2DDl/dsspoU9q6ITrb8S2Jk/FAlxR3R4xVsHexNoVYcT3BO7xfA2xcNJhtHKBglqxAXO9ob3/9aOllVgjY+4T0XMRYKtBL/x9Lbom6fyNrR9LpHZc4fITV73epG+QKvREtTx5Z0j8IFYFr1F+sZ41iXUKn5wgXaJn15pLInWih9ZLLlZgi983ldC3UDrs08PMTtWwgQneI5bgtd8Oe0ILKeMKx2+SnzlDl+gNerTaq2HnBUHIoFXaGhv6U0V0Mxajpiw7UfLNAcswQwXI0knDdsL8UEcEiPiK4yw9pGYsHVTlaY5E1SRdcIlMqdDwQuiges/Rt0v89nW6okJLI3GEpqb88Am0VXxhMb3XfSH+n8PxNk19q6hlY/Og6c0O2u3fXTF1BYqJkUf60cvjZZzovUwwB8xRJrYbNPtPY0s+EceF2c4kiTH0sopxA79l/SnLC33MhSyVf7ijGvoF/pVkWeAZ0I/W46KvfgXuaCjVMt0oezrAgwAexWOcBFHBpgAAAAASUVORK5CYII=\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA25pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoyMTc2YTRkOC02NzdkLWJkNDItYjRhYy0wNWUxYmVlMTNjNTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTZEN0IzNzlBNjgwMTFFQzkyRjc5RDVFRjAwRkIyMUMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTZEN0IzNzhBNjgwMTFFQzkyRjc5RDVFRjAwRkIyMUMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkY5QUEwQ0FBNjdFMTFFQ0JBMTQ5MDEyNjA3RkIyQzQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkY5QUEwQ0JBNjdFMTFFQ0JBMTQ5MDEyNjA3RkIyQzQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz496QsQAAAD7klEQVR42qyYeUhVURDG9bmVtmiLbZpBFEFEK23YYhqVWRRhGLT+oUWBf1RmUVFkC4ZBYVRUtmJGRVGSEUUhQgW22F4mEWlZFiYuSfnMvoHvxnS59y3qwA89x/Pemzdn5pu5+uZduO7TDhYAuoOxYBjoCerAF/AYvAS1Vi9MSoz38fdpH5sJ5oEhoBcIAb9APfgMHoGToNTqxW11Qj50D5gCwmzODAXTwSJwCuwGv/UBRxscmAVuMALaAYnAT9AImtR+FNgKzoEe7RGJueAoQ2/YW5APboNPIIiRmg1iQTi/9ALQESwEDa11IgEcUQ40cb0dVJvOSi7kgjFgH5jM/XiwA6xrzXVMZAT6cO0EG0CqhQPaHvKb31J7KSD6/MUCX2+ckLPzlQPNYC3Y7+Hrv/KDK7nuBFaC/t440QKK1Fq+fbaXkfwAToA/XI8CM7x1QpRtEBgMDrkp3d42fzvLChLrJ1fizolg4KfWcgVl4J0L5cwEJWS4xZlSiphYZxDhyolpFJedINRD6d7FRA1i9UTbRLRO5VmYXYlKCR1XSVgMLrtJ2gyQpvbegJs2Z0OVQ/UOGx04phwQHahyEwWR4nS1fgWW8uqsZDyYv9fI1fpbNKIcqpuRA+vBfRcO7DVFQDrmMgqVlaXwuoxquaMjIRl/WDngpAPZdMbKMnnGsBdguQsHpNUnAl+uH4iAOdQ9SUgHqAhsBAd4b2bzowNp6g0lAiuojlYWSWEz5L6S7b3KwTeMAzEqWQ5S61tsqiCDVWA48NoDB86ACWpP+k0xhpoWByci6Wzd+McyRsXHJgLbwCZTEi5hBVmZtPDTYKraO8Ny/tfKRzJjjSjku6gG6ZSbTUm4mMJkZSG8ghi1J/PEap1nEokRKhmlHAtt3lAisEWtn7lxQKwLGK/WuWxaDVbC0UElZKXFm4WbdOApy7DEjX5849WJw1lglZLs/yYrp+pqvsohbSKz5WCgKsMSD6TcSem/xmnbaTfolqtx3J96UWQ618iZchK4Cz66CH84Z4c6tV/tblAp5kxoOJFgc/Y9s9zOgQiQxw6bo6TZo2lJBtR76kriTNnsiUWw7OK5TnTxCGDpRCOVq1yNXVlKPd1ZJLM+xiRE1d44IdpQQZVsUWOXhHa0B4PvFTVFG2WYzi/nsROGSaO6pNZS3wXsH+NAIKsnkPIr88ZVk6OGDtR6c5f+picno83O4QeGc6BN5qNbA1UwyFTKzbzSVG8iYPcYKENGEjtkudqXJ6auoC9/agcqqKbJrXHA7gmskSonObGG4Y7ihwdQ2n9wIClmOT5py1O1q8fA52xYsRSpSDpSQwcKKVzf2/p/hb8CDAC9uO20ew7vbgAAAABJRU5ErkJggg==\"","export default \"__VITE_ASSET__5149d0b6__\"","export default \"__VITE_ASSET__daf70e48__\"","export default \"__VITE_ASSET__fed1dbab__\"","export default \"__VITE_ASSET__248de873__\"","export default \"data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABZAAD/4QMvaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzE0MiA3OS4xNjA5MjQsIDIwMTcvMDcvMTMtMDE6MDY6MzkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEMzY4NjZERkUxQjkxMUVEQUI5RkRGMkZGMTk2RDkwNiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEMzY4NjZFMEUxQjkxMUVEQUI5RkRGMkZGMTk2RDkwNiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQzNjg2NkRERTFCOTExRURBQjlGREYyRkYxOTZEOTA2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkQzNjg2NkRFRTFCOTExRURBQjlGREYyRkYxOTZEOTA2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQIBAQEC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\"","export default \"__VITE_ASSET__0dd37de2__\"","/*\n * 引入assets下的静态资源\n * @param {name} 静态资源地址(assets下路径+文件名, 如: 'images/logo.png')\n * @example\n * getAssets('images/logo.png')\n */\nimport debounce from 'lodash.debounce'\n\nexport const getAssets = (name) => {\n const path = `../assets/${name}`\n const modules = import.meta.globEager('../assets/*/*')\n return modules[path].default\n}\n\nexport const getType = (o) => {\n const s = Object.prototype.toString.call(o)\n return s.match(/\\[object (.*?)\\]/)[1].toLowerCase()\n}\n\nexport const emptyFn = () => {}\n\nexport const durationFormat = (val) => {\n const h = Math.floor(val / 3600) > 0 ? Math.floor(val / 3600) : ''\n const m =\n Math.floor((val / 60) % 60) > 0\n ? `${Math.floor((val / 60) % 60)\n .toString()\n .padStart(2, '0')}:`\n : '00:'\n\n const s = Math.floor(val % 60)\n .toString()\n .padStart(2, '0')\n\n return h + m + s\n}\n\nexport const dateFormatNormal = (val, isYearOnly = false) => {\n const date = new Date(val.length > 10 ? val : val * 1000)\n const y = date.getFullYear()\n const m =\n date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1\n const d = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()\n const hh = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours()\n const mm =\n date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes()\n\n return isYearOnly ? `${y}-${m}-${d}` : `${y}-${m}-${d} ${hh}:${mm}`\n}\n\nexport const dateFormat = (val) => {\n const time = val.length > 10 ? val : val * 1000\n\n const diff = new Date().getTime() - time\n let text = ''\n\n if (diff < 0) {\n return dateFormatNormal(time)\n }\n\n const m = 60 * 1000\n const h = m * 60\n const d = h * 24\n\n const diffM = Math.floor(diff / m)\n const diffH = Math.floor(diff / h)\n const diffD = Math.floor(diff / d)\n\n if (diffD >= 7) {\n text = '7天前'\n } else if (diffH >= 24) {\n text = `${diffD}天前`\n } else if (diffH >= 1) {\n text = `${diffH}小时前`\n } else if (diffM > 5) {\n text = `${diffM}分钟前`\n } else {\n text = '刚刚'\n }\n\n return `${text}`\n}\n\nexport const numberFormat = (val) => {\n if (val >= 10000) {\n return `${Math.round(val / 1000) / 10}万`\n }\n\n return val\n}\n\nexport const sticky = (parent, el, time = 200) => {\n window.addEventListener(\n 'scroll',\n debounce(() => {\n const top = document.documentElement.scrollTop || document.body.scrollTop\n\n const $parent = document.querySelector(parent)\n const $el = document.querySelector(el)\n if (top >= $parent.offsetTop) {\n if (!$el.classList.contains('fixed')) {\n $el.style.width = `${$parent.clientWidth}px`\n $el.classList.add('fixed')\n $el.style.top = document.querySelector('body').style.paddingTop || 0\n }\n } else if ($el.classList.contains('fixed')) {\n $el.classList.remove('fixed')\n $el.style.top = 'auto'\n }\n }, time)\n )\n}\n\nexport const emoList = [\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/01.png',\n title: 'GD01',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/02.png',\n title: 'GD02',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/03.png',\n title: 'GD03',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/04.png',\n title: 'GD04',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/05.png',\n title: 'GD05',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/06.png',\n title: 'GD06',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/07.png',\n title: 'GD07',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/08.png',\n title: 'GD08',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/09.png',\n title: 'GD09',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/10.png',\n title: 'GD10',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/11.png',\n title: 'GD11',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/12.png',\n title: 'GD12',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/13.png',\n title: 'GD13',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/14.png',\n title: 'GD14',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/15.png',\n title: 'GD15',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/51.png',\n title: 'GD51',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/52.png',\n title: 'GD52',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/90.png',\n title: 'GD90',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/91.png',\n title: 'GD91',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/92.png',\n title: 'GD92',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/93.png',\n title: 'GD93',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/94.png',\n title: 'GD94',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/95.png',\n title: 'GD95',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/96.png',\n title: 'GD96',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/97.png',\n title: 'GD97',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/98.png',\n title: 'GD98',\n },\n {\n url: 'https://ue.17173cdn.com/a/lib/v4/1.3.24/comment/assets/img/attitude/99.png',\n title: 'GD99',\n },\n]\n\nfunction findEmoByCode(t) {\n return emoList.find((it) => it.title === t)\n}\nexport const formatParagraph = (t) => {\n return t.replace(/\\[(GD[0-9]{2})\\]/g, (_, code) => {\n const found = findEmoByCode(code)\n return found ? `` : ''\n })\n}\n","import axios from 'axios'\nimport qs from 'qs'\nimport md5 from 'md5'\n\nconst getToken = (url) => {\n const appkey = '50d85cf01cf70d6ec430105437d28568'\n const uri = url.replace('https', 'http')\n const timestamp = Math.floor(Date.now() / 1000)\n const accessToken = md5(appkey + uri + timestamp)\n return { timestamp, access_token: accessToken }\n}\n\nlet gtvBaseUrl = import.meta.env.VITE_GTV_API_HOST\nlet clubBaseUrl = import.meta.env.VITE_CLUB_API_HOST\n\n// 兼容内网地址\nif (gtvBaseUrl.indexOf('internal') !== -1) {\n gtvBaseUrl = 'https://club.internal.17173.com/'\n}\nif (clubBaseUrl.indexOf('internal') !== -1) {\n clubBaseUrl = 'https://club.internal.17173.com/'\n}\n\nexport const instance = axios.create({\n // baseURL: '/api',\n baseURL: gtvBaseUrl,\n timeout: 60000,\n paramsSerializer(params) {\n return qs.stringify(params)\n },\n data: {\n a: 1,\n },\n})\nexport const instance2 = axios.create({\n // baseURL: '/api',\n baseURL: clubBaseUrl,\n timeout: 60000,\n paramsSerializer(params) {\n return qs.stringify(params)\n },\n data: {\n a: 1,\n },\n})\nfunction instanceInit(myInstance) {\n myInstance.interceptors.request.use(\n (config) => {\n const tokens = getToken(config.baseURL + config.url)\n const cfg = {\n ...config,\n\n params: { ...config.params, platform: 'web', ...tokens },\n }\n\n return { ...cfg, withCredentials: true }\n },\n (error) => {\n console.error(error)\n return null\n }\n )\n myInstance.interceptors.response.use(\n (response) => response,\n (error) => {\n console.error(error)\n return null\n }\n )\n}\n\ninstanceInit(instance)\ninstanceInit(instance2)\n","class APIResponse {\n constructor(axiosResPromise, config) {\n this.config = config\n this.axiosResPromise = axiosResPromise\n this.res = null\n }\n\n async check() {\n const res = await this.getRes()\n return {\n success: res?.status === 200 && res.data?.code === 200,\n status: res?.status,\n code: res?.data && res.data.code,\n msg: res?.data && res.data.messages ? res.data.messages[0] : '',\n }\n }\n\n async getRes() {\n this.res = this.res || (await this.axiosResPromise)\n return this.res\n }\n\n async data() {\n const res = await this.getRes()\n let data = null\n if (\n res !== null &&\n res.status === 200 &&\n res.data.code === 200 &&\n res.data.data\n ) {\n data = res.data.data\n }\n return data\n }\n}\n\nexport default APIResponse\n","import { instance, instance2 } from './instance'\nimport APIResponse from './APIResponse'\n\n// gtv 接口\nexport const gtvAPI = {\n getList(params) {\n const axiosRes = instance.get('/thread/list', { params })\n return new APIResponse(axiosRes)\n },\n getSubList() {\n const axiosRes = instance.get('/thread/sub')\n return new APIResponse(axiosRes)\n },\n // 评论列表\n getCommentList(params) {\n const axiosRes = instance.get('/thread/post-list', { params })\n return new APIResponse(axiosRes)\n },\n // 评论的回复列表\n getReplyList(params) {\n const axiosRes = instance.get('/thread/reply-list', { params })\n return new APIResponse(axiosRes)\n },\n // 发表回帖/回复\n postComment(params) {\n const data = new FormData()\n data.append('tid', params.tid)\n data.append('message', params.message)\n if (params.pid) data.append('pid', params.pid)\n if (params.aid) data.append('attachQuote', params.aid)\n const axiosRes = instance.post('/thread/reply', data)\n return new APIResponse(axiosRes)\n },\n}\n\n// 帖子相关接口\nexport const threadAPI = {\n submitSupportThread(id) {\n const axiosRes = instance2.get('/thread/support', { params: { tid: id } })\n return new APIResponse(axiosRes)\n },\n\n getUserReplyList(params) {\n const axiosRes = instance.get('/home/post', { params })\n return new APIResponse(axiosRes)\n },\n\n getThreadInfo(params) {\n const axiosRes = instance.get('/thread/info', { params })\n return new APIResponse(axiosRes)\n },\n\n // 发帖&编辑帖子\n postThread(params) {\n const data = new FormData()\n data.append('gid', params.gid)\n data.append('subId', params.sid)\n data.append('subject', params.title)\n data.append('message', params.content)\n if (params.id) data.append('tid', params.id)\n const axiosRes = instance.post('/thread/issue', data)\n return new APIResponse(axiosRes)\n },\n supportComment(id) {\n const axiosRes = instance2.get('/thread/post-support', {\n params: { pid: id },\n })\n return new APIResponse(axiosRes)\n },\n}\n\n// 使用club接口,编辑器相关\nexport const editorAPI = {\n getLinkInfo(href) {\n const axiosRes = instance2.get('/app/get-title-by-url', {\n params: { url: href },\n })\n return new APIResponse(axiosRes)\n },\n get17173VideoInfo(href) {\n const axiosRes = instance2.get('/app/get-video-info-by-url', {\n params: { vurl: href },\n })\n return new APIResponse(axiosRes)\n },\n async upLoadImage(file, name) {\n const data = new FormData()\n data.append('pic[0]', file, name)\n\n const axiosRes = instance2.post('/upload/image', data, {\n headers: { 'Content-Type': 'multipart/form-data' },\n })\n return new APIResponse(axiosRes)\n },\n getQiniuToken() {\n const axiosRes = instance2.get('/upload/get-video-token')\n return new APIResponse(axiosRes)\n },\n qiniuUploadReceipt(params) {\n const axiosRes = instance2.get('/upload/confirm-video-info', {\n params,\n })\n return new APIResponse(axiosRes)\n },\n}\n\n// 使用club接口,登录、登出、用户状态、关注/取关\nexport const userAPI = {\n login() {\n const axiosRes = instance2.get('/my/login')\n return new APIResponse(axiosRes)\n },\n logout() {\n const axiosRes = instance2.get('/my/logout')\n return new APIResponse(axiosRes)\n },\n getAccountStatus() {\n const axiosRes = instance2.get('/my/get-status')\n return new APIResponse(axiosRes)\n },\n submitFollowUser(id) {\n const axiosRes = instance2.get('/follow/user', { params: { uid: id } })\n return new APIResponse(axiosRes)\n },\n cancelFollowUser(id) {\n const axiosRes = instance2.get('/follow/user-cancel', {\n params: { uid: id },\n })\n return new APIResponse(axiosRes)\n },\n getMyInfo() {\n const axiosRes = instance.get('/my/info')\n return new APIResponse(axiosRes)\n },\n getMyThreadList(params) {\n const axiosRes = instance.get('/my/thread', {\n params,\n })\n return new APIResponse(axiosRes)\n },\n getUserInfo(id) {\n const axiosRes = instance.get('/home/info', {\n params: { uuid: id },\n })\n return new APIResponse(axiosRes)\n },\n getUserThreadList(params) {\n const axiosRes = instance.get('/home/thread', {\n params,\n })\n return new APIResponse(axiosRes)\n },\n}\n","const storeCache = {}\n\n// debug\nwindow.storeCache = storeCache\n\n/*\n * 定义一个store函数,如果调用该函数时传入id字符串,则会以该id缓存store, 下次执行该函数会返回上一次缓存的结果.\n */\nfunction defineStore(creater) {\n return (config) => {\n let storeInstance\n if (config !== undefined && config.id !== undefined) {\n if (!storeCache[config.id]) {\n storeCache[config.id] = creater(config)\n }\n storeInstance = storeCache[config.id]\n } else {\n storeInstance = creater(config)\n }\n return storeInstance\n }\n}\nexport { defineStore }\n","import { isArray } from '@vue/shared'\nimport { defineStore } from './defineStore'\n/*\n *定义列表store\n * @param {config.pageSize} 分页大小\n * @param {config.getMethod} /src/api/index.js 下定义的接口方法, 如: threadAPI.plazaList\n */\nexport default function defineListStore(config) {\n return defineStore(() => {\n const items = ref([])\n\n const pageIndex = ref(0)\n\n const pageSize = ref(config.pageSize || 10)\n const empty = ref(false)\n const loading = ref(false)\n const finished = ref(false)\n const totalCount = ref(-1)\n const isLoaded = ref(false)\n\n async function load(params, option = {}) {\n const targetOption = {\n ...option,\n ...{\n limitTime: 1000,\n },\n }\n\n // 如果已经加载完毕,则不再加载\n // if (\n // totalCount.value > 0 &&\n // totalCount.value <= pageSize.value * pageIndex.value\n // )\n // return\n if (finished.value) return\n if (loading.value) return\n\n loading.value = true\n pageIndex.value += 1 // 因为服务端接口页数是从 1开始的,所以这里即使首次加载也+1\n\n const beginTime = Date.now() * 1\n const data = await config\n .getMethod({\n pageSize: pageSize.value,\n page: pageIndex.value,\n ...params,\n })\n .data()\n\n if (data !== null) {\n if (isArray(data)) {\n const dataSet =\n typeof config.dataParser === 'function'\n ? config.dataParser(data || [])\n : data || []\n pageIndex.value = 1\n totalCount.value = dataSet.length\n items.value = dataSet\n empty.value = !items.value.length\n finished.value = true\n isLoaded.value = true\n } else {\n if (!data.dataSet) {\n finished.value = true\n isLoaded.value = true\n return\n }\n const dataSet =\n typeof config.dataParser === 'function'\n ? config.dataParser(data.dataSet || [])\n : data.dataSet || []\n pageIndex.value = data.page\n totalCount.value = data.totalCount\n items.value = [...items.value, ...dataSet]\n empty.value = !items.value.length\n // totalCount 数据不准,无法用做判断\n // finished.value = items.value.length >= totalCount.value\n isLoaded.value = true\n }\n }\n const duration = Date.now() * 1 - beginTime\n const delay =\n duration > targetOption.limitTime\n ? 0\n : targetOption.limitTime - duration\n\n if (delay > 0) {\n setTimeout(() => {\n loading.value = false\n }, delay)\n } else {\n loading.value = false\n }\n }\n\n function reset() {\n pageIndex.value = 0\n items.value = []\n loading.value = false\n finished.value = false\n empty.value = false\n totalCount.value = -1\n isLoaded.value = false\n }\n\n function resume(_items, index, size) {\n pageIndex.value = index\n pageSize.value = size\n items.value = [..._items]\n totalCount.value = items.length\n empty.value = !items.length\n finished.value = false\n isLoaded.value = true\n }\n\n return {\n items,\n pageIndex,\n pageSize,\n totalCount,\n states: reactive({\n loading,\n finished,\n empty,\n isLoaded,\n }),\n actions: {\n load,\n reset,\n resume,\n },\n }\n })\n}\n","export function gString(value) {\n return value ? value.toString() : ''\n}\n\nexport function gNum(value) {\n return value || 0\n}\n\n// 服务端接口 1= true, 0=false\nexport function gBool(value) {\n if (typeof value === 'boolean') {\n return value\n }\n if (value * 1 === 1) {\n return true\n }\n return false\n}\n\nexport function gList(value) {\n return value || []\n}\n","import * as d from '@/core/dataGenerator'\n\nexport default class RichContentModel {\n static fromJson(data) {\n const model = new RichContentModel()\n model.type = d.gString(data.type)\n model.value = model.isImage\n ? `${data.value}!a-3-640x${data.value.substr(\n data.value.lastIndexOf('.')\n )}`\n : data.value\n\n if (data.childs) model.childs = data.childs\n\n model.attr = data.attr ? JSON.parse(data.attr) : {}\n\n if (model.attr.needComment === 'true') {\n model.needCommentClass =\n model.value.length > 0\n ? 'show-need-comment-con'\n : 'hide-need-comment-con'\n }\n\n if (data.aid) {\n model.aid = d.gString(data.aid)\n }\n return model\n }\n\n get isImage() {\n return this.type === 'image'\n }\n\n get isText() {\n return this.type === 'text'\n }\n\n get isLink() {\n return this.type === 'link'\n }\n\n get isVideo() {\n return this.type === 'video'\n }\n\n get isIframe() {\n return this.type === 'iframe'\n }\n\n get isBlockText() {\n return this.attr.h || this.value === '\\n'\n }\n}\n","import * as d from '@/core/dataGenerator'\nimport RichContentModel from './richContent'\n\nexport default class ThreadModel {\n static fromJson(data) {\n const model = new ThreadModel()\n // 如果是回帖&回复则id取的是pid, 如果是帖子则取得是tid\n model.id = d.gString(data.pid || data.tid)\n\n // 圈子id\n model.gid = d.gString(data.gid)\n\n // 子板块id\n model.subId = d.gString(data.subId)\n\n // 标题\n model.title = d.gString(data.subject)\n\n // 作者昵称\n model.author = d.gString(data.author)\n\n // 用户认证组名称\n model.authorTitle = d.gString(data.authorTitle)\n\n // 作者uid\n model.authorUid = d.gString(data.authorid)\n\n // 内容\n model.content = JSON.parse(d.gString(data.message))\n\n // 点赞数\n model.supports = d.gNum(data.support)\n\n // 当前用户是否已点赞\n model.hasSupported = d.gBool(data.supportState)\n\n // 回复数量(如果是帖子,则是所有评论)\n model.replies = d.gNum(data.replies)\n\n // 浏览数量\n model.views = d.gNum(data.views)\n\n // 回复的帖子用户uid\n model.puid = d.gString(data.puid)\n\n // 回复的帖子用户昵称\n model.pname = d.gString(data.pname)\n\n // 创建时间\n model.createDate = d.gNum(data.threadDate || data.postDate)\n // model.updateDate = d.gNum(data.threadEditDate || data.postEditDate)\n\n // 关联游戏\n model.newGameCode = d.gString(data.newGameCode)\n model.gameName = d.gString(data.gameName)\n model.gameCode = d.gString(data.gameCode)\n\n // 圈子名称\n model.groupName = d.gString(data.groupName)\n\n // 精华帖\n model.digest = d.gBool(data.digest)\n\n // 回复关联的回复id(对回复的回复)\n model.rpid = d.gString(data.rpid)\n\n // 回复关联的回帖id(对回帖的回复)\n model.ppid = d.gString(data.ppid)\n\n // 回帖/回复关联的帖子id\n model.tid = d.gString(data.tid)\n\n // 是否隐藏\n model.isHide = d.gNum(data.displayState) === 3\n\n // 是否广告\n // \n model.isAd = model.subId === '57'\n\n // 发布平台platform(1: app 2: web)\n model.platform = d.gNum(data.platform || 0)\n\n // 回复列表\n model.replys = []\n if (data.reply) {\n data.reply.forEach((t) => {\n model.replys.push(ThreadModel.fromJson(t))\n })\n }\n\n // 【回帖】数,含子评论\n model.posts = d.gNum(data.totalPostTotal)\n\n // 回帖列表新增字段\n // 主贴的字段\n model.orginThreadTitle = d.gString(data.threadSubject)\n model.orginThreadContent = d.gString(data.threadMessage)\n // 回帖的评论的字段\n model.orginReplyAuthor = d.gString(data.atAuthor)\n model.orginReplyAuthorUid = d.gString(data.atAuthorid)\n model.orginReplyContent = d.gString(data.postMessage)\n model.orginExist = model.orginThreadContent || model.orginReplyContent\n\n // 表情引用\n model.attachQuote = data.attachQuote ? data.attachQuote : null\n\n // 内容:文本\n // model.text = model.getText\n\n // 内容:图片\n // model.images = model.getImages\n\n // 内容:视频\n // model.videos = model.getVideos\n\n // ui state\n // 列表里面删帖\n model.$visible = true\n return model\n }\n\n // 内容:文本\n get text() {\n return this.richContents.filter((t) => t.isText)\n }\n\n // 内容:图片\n get images() {\n return this.richContents.filter((t) => t.isImage)\n }\n\n // 内容:视频\n get videos() {\n return this.richContents.filter((t) => t.isVideo)\n }\n\n // 内容:视频\n get iframe() {\n return this.richContents.filter((t) => t.isIframe)\n }\n\n // 内容:鏈接\n get link() {\n return this.richContents.filter((t) => t.isLink)\n }\n\n // content转成RichContentModel列表\n get richContents() {\n const list = []\n // const c = JSON.parse(\n // '[{\"type\":\"video\",\"value\":\"40026153\",\"attr\":\"{\\\\\"videoid\\\\\":\\\\\"40026153\\\\\"}\",\"aid\":\"0\"},{\"type\":\"text\",\"value\":\"了个文件管理\\\\n\",\"attr\":\"{}\"},{\"type\":\"image\",\"value\":\"https://i.17173cdn.com/2fhnvk/YWxqaGBf/cms3/xydDJRbpqqxtDrt.jpg!a-3-480x.jpg\",\"attr\":\"{\\\\\"height\\\\\":\\\\\"300\\\\\",\\\\\"width\\\\\":\\\\\"400\\\\\"}\",\"aid\":0},{\"type\":\"text\",\"value\":\"\\\\n\",\"attr\":\"{}\"},{\"type\":\"link\",\"value\":\"https://www.17173.com\",\"attr\":\"{\\\\\"title\\\\\":\\\\\"17173网络游戏门户站\\\\\"}\"},{\"type\":\"text\",\"value\":\"\\\\n\",\"attr\":\"{}\"},{\"type\":\"iframe\",\"value\":\"https://player.bilibili.com/player.html?aid=717833773&bvid=BV12Q4y1C7wh&cid=402195847&page=1\",\"attr\":\"{}\"},{\"type\":\"text\",\"value\":\"\\\\n\",\"attr\":\"{}\"}]'\n // )\n // this.content = [\n // { type: 'text', value: '11111', attr: '{}', aid: 0 },\n // { type: 'text', value: '2222', attr: '{\"bold\":true}', aid: 0 },\n // { type: 'text', value: '3333\\n', attr: '{}', aid: 0 },\n // { type: 'text', value: '4444', attr: '{\"h\":2}', aid: 0 },\n // { type: 'text', value: '\\n5555\\n6666\\n', attr: '{}', aid: 0 },\n // ]\n let textPara = []\n // 拆分换行\n const splitContents = []\n this.content.forEach((t) => {\n if (t.type === 'text') {\n const values = t.value.split(/(\\n)/g).filter((value) => value !== '')\n values.forEach((value) => {\n splitContents.push({ ...t, value })\n })\n } else {\n splitContents.push(t)\n }\n })\n for (let i = 0; i < splitContents.length; i += 1) {\n const t = splitContents[i]\n const richModel = RichContentModel.fromJson(t)\n if (richModel.type === 'text' && !richModel.isBlockText) {\n textPara.push(richModel)\n }\n // 最后一行,或者当前行不是文本,并且已经有暂存的文本组,则将文本组加入内容列表\n if (\n textPara.length &&\n (richModel.type !== 'text' ||\n i === splitContents.length - 1 ||\n richModel.isBlockText)\n ) {\n let text = ''\n textPara.forEach((tt) => {\n text += tt.value\n })\n const textParaContent = RichContentModel.fromJson({\n type: 'text',\n value: text,\n childs: [...textPara],\n })\n textPara = []\n list.push(textParaContent)\n // console.log(textParaContent, 1)\n }\n\n if (\n (richModel.type !== 'text' || richModel.isBlockText) &&\n (typeof richModel.value !== 'string' ||\n richModel.attr.needComment ||\n richModel.value)\n ) {\n list.push(richModel)\n }\n }\n // console.log(list, 11)\n return list\n }\n}\n","import { threadAPI, gtvAPI } from '@/api'\nimport defineListStore from './defineListStore'\nimport defineDetailStore from './defineDetailStore'\nimport ThreadModel from '@/models/thread'\nimport { defineStore } from './defineStore'\n\nexport const filterInvalidateVideo = (item) => !!item.videos?.[0]?.value?.url\n\nexport const threadInfoStore = defineDetailStore({\n getMethod: threadAPI.getThreadInfo,\n dataParser: (data) => {\n const json = { ...data.threadInfo, ...data.groupInfo }\n const threadModel = ThreadModel.fromJson(json)\n return threadModel\n },\n})\n\n// 推荐列表\nexport const threadListStore = defineListStore({\n getMethod: gtvAPI.getList,\n dataParser: (items) => {\n return (\n items\n .map((item) => {\n const threadModel = ThreadModel.fromJson(item)\n try {\n return threadModel\n } catch (e) {\n console.error(e)\n }\n return item\n })\n // 过滤掉没有视频的帖子\n .filter(filterInvalidateVideo)\n )\n },\n})\n\nexport const channelStore = defineStore(() => {\n const loading = ref(false)\n const items = ref([])\n\n async function init() {\n items.value = await gtvAPI.getSubList().data()\n\n loading.value = false\n }\n\n return {\n loading,\n items,\n init,\n }\n})({ id: 'channel' })\n\nexport const recommendListStore = defineStore(() => {\n const loading = ref(false)\n const loaded = ref(false)\n const items = ref([])\n\n async function init() {\n // \n const data = await gtvAPI.getList({ subId: 57 }).data()\n\n if (data.dataSet) {\n const d = data.dataSet.map((g) => {\n const m = ThreadModel.fromJson(g)\n // m.isAd = true\n\n return m\n })\n\n // 过滤没有链接或图片的帖子\n items.value = d.filter((el) => {\n return el.link.length > 0 && el.images.length > 0\n })\n\n loaded.value = true\n }\n\n loading.value = false\n }\n\n return {\n loading,\n loaded,\n init,\n items,\n }\n})({ id: 'recommendList' })\n","\n\n\n","\n\n\n","import { createVNode, render } from 'vue'\nimport ToastTemplate from './ToastTemplate.vue'\n\nconst defaultOption = {\n duration: 3000,\n parent: document.querySelector('body'),\n}\n\nexport function toast(msg, option) {\n const container = document.createElement('div')\n const opt = { ...defaultOption, ...option, msg }\n const vm = createVNode(ToastTemplate, opt)\n render(vm, container)\n opt.parent.appendChild(container)\n // document.body.appendChild(container)\n // 销毁弹窗, 如果duration设置为0,需要调用者手动销毁\n const dispose = () => {\n if (vm.el.querySelector('.toast-msg')) {\n // 淡入淡出效果\n vm.el.querySelector('.toast-msg').classList.add('reomve') // 销毁时添加淡入淡出效果\n const t = setTimeout(() => {\n render(null, container)\n clearTimeout(t)\n opt.parent.removeChild(container)\n }, 400)\n }\n }\n if (opt.duration) {\n const timer = setTimeout(() => {\n dispose()\n clearTimeout(timer)\n }, opt.duration)\n }\n return {\n dispose,\n }\n}\n","import md5 from 'md5'\nimport { toast } from '@/components/toast'\nimport { userAPI } from '@/api/index'\n\n// 当前用户uid\nexport const getUid = () => {\n return Passport.data('uid')\n}\n\nexport const getUname = () => {\n return Passport.data('nickname')\n}\n\nexport const getName = () => {\n return Passport.data('username')\n}\n\nexport const isBindPhone = async () => {\n return new Promise((resolve) => {\n Passport.getMobileStatus((o) => {\n resolve(o)\n })\n })\n}\n\nexport const isSockpuppet = async () => {\n const data = await userAPI.getAccountStatus().data()\n return data.identity ? data.identity === 2 : false\n}\n\n// 通过Uid获取用户头像, 不传uid则返回当前用户头像\nexport const getAvatar = (uid) => {\n const userId = (uid || getUid()).toString()\n let avator = 'https://ue.17173cdn.com/a/hao/app/images/avatar.png'\n if (userId) {\n const md5Str = md5(userId)\n avator = `https://i.17173cdn.com/avatar/YWxqaGBf/${md5Str.slice(\n 0,\n 2\n )}/${md5Str.slice(2, 4)}/${md5Str.slice(\n 4,\n 6\n )}/${userId}/hd.jpg?t=${Math.floor(Math.random() * 10000)}`\n }\n\n return avator\n}\n// 当前用户是否已登录\nexport const isLoggedIn = () => {\n return Passport.isLoggedIn()\n}\n\n// 当前用户是否禁言\nexport const isMuted = () => {\n return false\n}\n\n// 传入的uid是否当前用户\nexport const isCurrent = (uid) => {\n return uid === getUid()\n}\n\n// 当前用户是否被ban\nexport const isBaned = () => {\n return false\n}\n\n// 当前用户是否可以发言\nexport const canComment = () => {\n return !isBaned() && !isMuted()\n}\n\nconst isMobile = /android|iphone|ipad|ipod|Windows Phone|SymbianOS/gi.test(\n navigator.userAgent\n)\n\nexport const login = () => {\n if (!isLoggedIn()) {\n if (isMobile) {\n window.location.href = `https://passport.17173.com/wap?return_url=${encodeURIComponent(\n window.location.href\n )}`\n } else {\n Passport.Dialog.show()\n }\n }\n}\n\nexport const postAuthCheck = (fn) => {\n if (!isLoggedIn()) {\n if (isMobile) {\n login()\n } else {\n // eslint-disable-next-line no-restricted-globals\n const result = confirm('您尚未登录,是否跳转到登录页?')\n if (result) login()\n }\n return\n }\n\n if (canComment()) {\n fn()\n } else {\n toast('被禁言')\n }\n}\n","\nexport default (sfc, props) => {\n for (const [key, val] of props) {\n sfc[key] = val\n }\n return sfc\n}\n","\n\n\n\n","\n\n\n","import { inject, ref } from 'vue'\nimport { threadAPI } from '@/api'\nimport { toast } from '@/components/toast'\n\nexport function useBumpUp(namespace) {\n const eventBus = inject('event-bus')\n\n const saving = ref(false)\n\n async function request(data) {\n if (saving.value) return\n saving.value = true\n\n const res = threadAPI.submitSupportThread(data.id)\n const status = await res.check()\n\n if (status.success) {\n const d = await res.data()\n // eslint-disable-next-line no-param-reassign\n data.supports = d.totalCount\n\n // eslint-disable-next-line no-param-reassign\n data.hasSupported = d.supportState === 1\n\n const e = {\n __from: namespace,\n __target: data,\n uid: data.authorUid,\n tid: data.id,\n supports: data.supports,\n hasSupported: data.hasSupported,\n }\n\n eventBus.emit('bump:change', e)\n } else {\n toast(status.msg)\n }\n\n saving.value = false\n }\n\n let threadItemsGetter = null\n function registerThreadItemsForBumpUpChangeHandler(_threadItemsGetter) {\n threadItemsGetter = _threadItemsGetter\n }\n\n function onBumpChangeBoradcast(e) {\n if (!threadItemsGetter) return\n\n const targets = threadItemsGetter()\n\n targets.forEach((t) => {\n // eslint-disable-next-line no-underscore-dangle\n if (e.__target === t) return\n\n if (t.id === e.tid) {\n // eslint-disable-next-line no-param-reassign\n t.supports = e.supports\n // eslint-disable-next-line no-param-reassign\n t.hasSupported = e.hasSupported\n }\n })\n }\n\n eventBus.on('bump:change', onBumpChangeBoradcast)\n\n onUnmounted(() => {\n eventBus.off('bump:change', onBumpChangeBoradcast)\n })\n\n return {\n triggerBumpUp: request,\n registerThreadItemsForBumpUpChangeHandler,\n }\n}\n","export const T = {\n 视频详情: {\n name: '视频详情',\n types: {\n 地址栏直接打开: '地址栏直接打开',\n 点击打开: '点击打开',\n 滚动切换: '滚动切换',\n 个人页滚动切换: '个人页滚动切换',\n 点击个人中心列表: '点击个人中心列表',\n },\n },\n}\n","import { T } from '@/constants/constants'\nimport { getUid, isLoggedIn } from '@/core/passport'\n\n/**\n * 绑定模块统计\n * 在html元素上配置属性: v-track-module=\"'模块统计代码'\"\n */\nexport const trackModule = {\n mounted: (el, binding) => {\n if (binding.value) {\n _jc_ping.push(['_trackModule', el, binding.value])\n }\n },\n}\n\n/**\n * 绑定点击统计\n * 在html元素上配置属性: v-track-click=\"'点击统计代码'\"\n */\nexport const trackClick = {\n mounted: (el, binding) => {\n if (binding.value) {\n el.addEventListener('click', () => {\n // console.log(el, binding.value)\n _jc_ping.push(['_trackBlockClick', binding.value])\n })\n }\n },\n}\n\nconst getPlayerTimes = () => {\n const key = 'video_page_open_times'\n let times = localStorage.getItem(key) || 0\n times = parseInt(times, 10) + 1\n localStorage.setItem(key, times)\n return times\n}\n\nexport const trackClick2 = (params, adkey) => {\n const config = {\n ...params,\n duration: 0,\n uid: isLoggedIn() ? getUid() : ued.pingjs.get('ssid'),\n }\n // 5秒后再次上报\n config.playtimes = getPlayerTimes()\n if (params && params.name === T.视频详情.name) {\n setTimeout(() => {\n config.duration = 3\n window.dsm.call('track', window.dsm.E.custom, config)\n }, 3000)\n }\n window.dsm.call('track', window.dsm.E.custom, config)\n\n _jc_ping.push(['_trackBlockClick', adkey, JSON.stringify(params)])\n}\n","\n\n\n","import { editorAPI } from '@/api'\nimport { getAssets } from '@/core/util'\n\nconst linkIcon = getAssets('images/ico-link.png')\n\nconst defaultOptions = {\n theme: 'snow',\n modules: { toolbar: false },\n formats: [\n 'EmbedLink',\n 'EmbedIframe',\n 'EmbedImage',\n 'EmbedVideo',\n 'EmbedText',\n 'needComment',\n 'commentwrapper',\n ],\n imageDesc: false,\n}\n\nclass Editor {\n constructor(options) {\n const opt = { ...defaultOptions, ...options }\n this.ueditor = new UEditor(options.container, opt)\n if (opt.onChange) {\n this.ueditor.quill.on('text-change', () => {\n opt.onChange()\n })\n }\n }\n\n // 插入空行\n insertEmptyParagraph() {\n this.ueditor.insertText('\\n', '')\n }\n\n // 插入表情\n insertEmo(val) {\n this.ueditor.focus()\n this.ueditor.insertText(val, '')\n }\n\n /**\n * @returns 插入图片\n */\n insertImage(src, aid, width, height) {\n this.ueditor.focus()\n this.insertEmptyParagraph()\n this.ueditor.insertImage(src, aid, width, height)\n this.insertEmptyParagraph()\n }\n\n async insertVideo(videoid, aid) {\n if (videoid && aid) {\n this.ueditor.focus()\n this.ueditor.insertVideo(videoid, aid)\n } else {\n const src = prompt('请输入173视频页面地址或者B站视频嵌入代码')\n this.ueditor.focus()\n // https://v.17173.com/v_1_1/NDAwMjYxNTM.html\n // ueditor.insertIframe('https://player.bilibili.com/player.html?aid=717833773&bvid=BV12Q4y1C7wh&cid=402195847&page=1')\n if (!src) return\n if (src.indexOf('v.17173.com') !== -1) {\n const videoInfo = await editorAPI.get17173VideoInfo(src).data()\n this.ueditor.insertVideo(videoInfo.id, videoInfo.aid || 0)\n } else if (src.indexOf('player.bilibili.com') !== -1) {\n this.ueditor.insertIframe(src)\n } else {\n alert('视频格式错误,B站视频请填入视频地址,不要填页面地址')\n }\n }\n this.insertEmptyParagraph()\n }\n\n /**\n * @returns 弹出插入链接窗口\n */\n async insertLink() {\n const href = window.prompt('请输入链接')\n if (href) {\n const linkInfo = await editorAPI.getLinkInfo(href).data()\n const title = linkInfo ? linkInfo.title : href\n this.ueditor.focus()\n this.ueditor.insertLink(href, title, linkIcon)\n this.insertEmptyParagraph()\n }\n }\n\n toggleNeedComment() {\n this.ueditor.toggleNeedComment()\n }\n\n onToggleHeading() {\n this.ueditor.heading()\n }\n\n onToggleBold() {\n this.ueditor.bold()\n }\n\n clearFormat() {\n this.ueditor.clearFormat()\n }\n\n loadContents(contents) {\n this.ueditor.loadContents(contents)\n }\n\n get contents() {\n return JSON.stringify(this.ueditor.contents)\n }\n\n get length() {\n return this.ueditor.quill.getText().length\n }\n\n focus() {\n this.ueditor.quill.focus()\n }\n}\nexport default Editor\n","\n\n\n","\n\n\n","\n\n","\n\n","import { gtvAPI } from '@/api'\nimport defineListStore from './defineListStore'\nimport ThreadModel from '@/models/thread'\n\n// 评论列表\nexport const commentListStore = defineListStore({\n getMethod: gtvAPI.getCommentList,\n dataParser: (items) => {\n return items.map((item) => {\n const threadModel = ThreadModel.fromJson(item)\n try {\n return threadModel\n } catch (e) {\n console.error(e)\n }\n return item\n })\n },\n})\n","\n\n\n\n","export function useCommentChanged(namespace) {\n const eventBus = inject('event-bus')\n\n function emit(data) {\n const e = {\n __from: namespace,\n __target: data,\n uid: data.authorUid,\n tid: data.id,\n replies: data.replies,\n }\n\n eventBus.emit('comment:change', e)\n }\n\n let threadItemsGetter = null\n function registerThreadItemsForCommentChangeHandler(_threadItemsGetter) {\n threadItemsGetter = _threadItemsGetter\n }\n\n function handler(e) {\n if (!threadItemsGetter) return\n\n const targets = threadItemsGetter()\n\n targets.forEach((t) => {\n // eslint-disable-next-line no-underscore-dangle\n if (e.__target === t) return\n\n if (t.id === e.tid) {\n // eslint-disable-next-line no-param-reassign\n t.replies = e.replies\n // eslint-disable-next-line no-param-reassign\n t.hasSupported = e.hasSupported\n }\n })\n }\n\n eventBus.on('comment:change', handler)\n\n onUnmounted(() => {\n eventBus.off('comment:change', handler)\n })\n\n return {\n emit,\n registerThreadItemsForCommentChangeHandler,\n }\n}\n","\n\n\n","