├── public ├── favicon.png ├── logo │ ├── lol.png │ ├── 36kr.png │ ├── acfun.png │ ├── baidu.png │ ├── sspai.png │ ├── tieba.png │ ├── v2ex.png │ ├── weibo.png │ ├── zhihu.png │ ├── bilibili.png │ ├── douyin.png │ ├── genshin.png │ ├── github.png │ ├── honkai.png │ ├── ithome.png │ ├── jianshu.png │ ├── juejin.png │ ├── kuaishou.png │ ├── ngabbs.png │ ├── qq-news.png │ ├── starrail.png │ ├── thepaper.png │ ├── toutiao.png │ ├── weread.png │ ├── douban-group.png │ ├── douban-movie.png │ ├── hellogithub.png │ ├── netease-news.png │ ├── zhihu-daily.png │ ├── qq_music_toplist.png │ └── netease_music_toplist.png └── ico │ ├── error.png │ ├── favicon.png │ ├── icon_error.png │ └── powered-by-vercel.svg ├── screenshots └── main.jpg ├── vercel.json ├── .vscode └── extensions.json ├── .env ├── src ├── style │ └── global.scss ├── router │ ├── index.js │ └── routes.js ├── api │ ├── index.js │ └── request.js ├── main.js ├── views │ ├── 404.vue │ ├── 403.vue │ ├── 500.vue │ ├── Home.vue │ ├── Test.vue │ ├── Setting.vue │ └── List.vue ├── components │ ├── Footer.vue │ ├── Provider.vue │ ├── Header.vue │ └── HotList.vue ├── utils │ └── getTime.js ├── App.vue └── store │ └── index.js ├── index.html ├── .gitignore ├── README.md ├── package.json ├── LICENSE └── vite.config.js /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/favicon.png -------------------------------------------------------------------------------- /public/logo/lol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/lol.png -------------------------------------------------------------------------------- /public/ico/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/ico/error.png -------------------------------------------------------------------------------- /public/logo/36kr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/36kr.png -------------------------------------------------------------------------------- /public/logo/acfun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/acfun.png -------------------------------------------------------------------------------- /public/logo/baidu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/baidu.png -------------------------------------------------------------------------------- /public/logo/sspai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/sspai.png -------------------------------------------------------------------------------- /public/logo/tieba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/tieba.png -------------------------------------------------------------------------------- /public/logo/v2ex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/v2ex.png -------------------------------------------------------------------------------- /public/logo/weibo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/weibo.png -------------------------------------------------------------------------------- /public/logo/zhihu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/zhihu.png -------------------------------------------------------------------------------- /screenshots/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/screenshots/main.jpg -------------------------------------------------------------------------------- /public/ico/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/ico/favicon.png -------------------------------------------------------------------------------- /public/logo/bilibili.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/bilibili.png -------------------------------------------------------------------------------- /public/logo/douyin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/douyin.png -------------------------------------------------------------------------------- /public/logo/genshin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/genshin.png -------------------------------------------------------------------------------- /public/logo/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/github.png -------------------------------------------------------------------------------- /public/logo/honkai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/honkai.png -------------------------------------------------------------------------------- /public/logo/ithome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/ithome.png -------------------------------------------------------------------------------- /public/logo/jianshu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/jianshu.png -------------------------------------------------------------------------------- /public/logo/juejin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/juejin.png -------------------------------------------------------------------------------- /public/logo/kuaishou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/kuaishou.png -------------------------------------------------------------------------------- /public/logo/ngabbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/ngabbs.png -------------------------------------------------------------------------------- /public/logo/qq-news.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/qq-news.png -------------------------------------------------------------------------------- /public/logo/starrail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/starrail.png -------------------------------------------------------------------------------- /public/logo/thepaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/thepaper.png -------------------------------------------------------------------------------- /public/logo/toutiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/toutiao.png -------------------------------------------------------------------------------- /public/logo/weread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/weread.png -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [{ "source": "/:path*", "destination": "/index.html" }] 3 | } 4 | -------------------------------------------------------------------------------- /public/ico/icon_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/ico/icon_error.png -------------------------------------------------------------------------------- /public/logo/douban-group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/douban-group.png -------------------------------------------------------------------------------- /public/logo/douban-movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/douban-movie.png -------------------------------------------------------------------------------- /public/logo/hellogithub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/hellogithub.png -------------------------------------------------------------------------------- /public/logo/netease-news.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/netease-news.png -------------------------------------------------------------------------------- /public/logo/zhihu-daily.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/zhihu-daily.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /public/logo/qq_music_toplist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/qq_music_toplist.png -------------------------------------------------------------------------------- /public/logo/netease_music_toplist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imsyy/DailyHot/HEAD/public/logo/netease_music_toplist.png -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # 全局 API 地址 2 | # VITE_GLOBAL_API="http://localhost:6688" 3 | VITE_GLOBAL_API="https://api-hot.imsyy.top" 4 | 5 | # ICP 备案号 6 | VITE_ICP = "豫ICP备2022018134号-1" 7 | 8 | # 全局目录 9 | VITE_DIR = "/" -------------------------------------------------------------------------------- /src/style/global.scss: -------------------------------------------------------------------------------- 1 | // 全局样式 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | -webkit-user-select: none; 6 | user-select: none; 7 | } 8 | 9 | html, 10 | body, 11 | #app { 12 | height: 100%; 13 | } 14 | 15 | // 动画 16 | .fade-enter-active, 17 | .fade-leave-active { 18 | transition: opacity 0.3s ease-in-out; 19 | } 20 | 21 | .fade-enter-from, 22 | .fade-leave-to { 23 | opacity: 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from "vue-router"; 2 | import routes from "@/router/routes"; 3 | 4 | const router = createRouter({ 5 | history: createWebHashHistory(), 6 | routes, 7 | }); 8 | 9 | // 路由守卫 10 | router.beforeEach(() => { 11 | $loadingBar.start(); 12 | }); 13 | 14 | router.afterEach(() => { 15 | $loadingBar.finish(); 16 | }); 17 | 18 | export default router; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 今日热榜 - 汇聚全网热点,热门尽览无余 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from "@/api/request"; 2 | 3 | /** 4 | * 获取热榜分类数据 5 | * @param {string} type 热榜分类名称 6 | * @param {boolean} isNew 是否拉取最新数据 7 | * @param {object} params 请求参数 8 | * @returns 9 | */ 10 | export const getHotLists = (type, isNew = false, params) => { 11 | return axios({ 12 | method: "GET", 13 | url: `/${type}`, 14 | params: { 15 | cache: !isNew, 16 | ...params, 17 | }, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import { createPinia } from "pinia"; 3 | import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; 4 | 5 | import App from "./App.vue"; 6 | import router from "@/router"; 7 | 8 | // 全局样式 9 | import "@/style/global.scss"; 10 | 11 | const app = createApp(App); 12 | 13 | const pinia = createPinia(); 14 | pinia.use(piniaPluginPersistedstate); 15 | app.use(pinia); 16 | app.use(router); 17 | 18 | app.mount("#app"); 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | logo 3 |

今日热榜

4 |

汇聚全网热点,热门尽览无余

5 |
6 | 7 |
8 | 9 | 10 | ## 示例 11 | 12 | > 这里是示例站点 13 | 14 | - [今日热榜 - https://hot.imsyy.top/](https://hot.imsyy.top/) 15 | 16 | 17 | ## 部署 18 | 19 | ```bash 20 | // 安装依赖 21 | pnpm install 22 | 23 | // 开发 24 | pnpm dev 25 | 26 | // 打包 27 | pnpm build 28 | ``` 29 | 30 | ## Vercel 部署 31 | 32 | 现已支持 Vercel 一键部署,无需服务器 33 | 34 | > 请注意,需要修改环境变量中的 API 地址 35 | 36 | ![Powered by Vercel](./public/ico/powered-by-vercel.svg) 37 | -------------------------------------------------------------------------------- /src/views/404.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /src/views/403.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /src/views/500.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dailyhot", 3 | "description": "今日热榜", 4 | "author": "imsyy", 5 | "github": "https://github.com/imsyy", 6 | "version": "1.2.0", 7 | "private": true, 8 | "scripts": { 9 | "dev": "vite", 10 | "build": "vite build", 11 | "preview": "vite preview" 12 | }, 13 | "dependencies": { 14 | "@icon-park/vue-next": "^1.4.2", 15 | "@jridgewell/sourcemap-codec": "^1.5.0", 16 | "axios": "^1.7.7", 17 | "lunar-calendar": "^0.1.4", 18 | "pinia": "^2.2.6", 19 | "pinia-plugin-persistedstate": "^3.2.3", 20 | "sass": "^1.80.6", 21 | "scrollreveal": "^4.0.9", 22 | "terser": "^5.36.0", 23 | "vue": "^3.5.12", 24 | "vue-router": "^4.4.5", 25 | "vuedraggable": "^4.1.0" 26 | }, 27 | "devDependencies": { 28 | "@vitejs/plugin-vue": "^4.6.2", 29 | "naive-ui": "^2.40.1", 30 | "unplugin-auto-import": "^0.12.2", 31 | "unplugin-vue-components": "^0.22.12", 32 | "vite": "^4.5.5", 33 | "vite-plugin-pwa": "^0.14.7" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 底层用户 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | const routes = [ 2 | // 首页 3 | { 4 | path: "/", 5 | name: "home", 6 | meta: { 7 | title: "首页", 8 | }, 9 | component: () => import("@/views/Home.vue"), 10 | }, 11 | // 新闻列表 12 | { 13 | path: "/list", 14 | name: "list", 15 | meta: { 16 | title: "新闻列表", 17 | }, 18 | component: () => import("@/views/List.vue"), 19 | }, 20 | // 设置页 21 | { 22 | path: "/setting", 23 | name: "setting", 24 | meta: { 25 | title: "全局设置", 26 | }, 27 | component: () => import("@/views/Setting.vue"), 28 | }, 29 | // 测试页面 30 | { 31 | path: "/test", 32 | name: "test", 33 | meta: { 34 | title: "test", 35 | }, 36 | component: () => import("@/views/Test.vue"), 37 | }, 38 | // 403 39 | { 40 | path: "/403", 41 | name: "403", 42 | meta: { 43 | title: "403", 44 | }, 45 | component: () => import("@/views/403.vue"), 46 | }, 47 | // 404 48 | { 49 | path: "/404", 50 | name: "404", 51 | meta: { 52 | title: "404", 53 | }, 54 | component: () => import("@/views/404.vue"), 55 | }, 56 | // 500 57 | { 58 | path: "/500", 59 | name: "500", 60 | meta: { 61 | title: "500", 62 | }, 63 | component: () => import("@/views/500.vue"), 64 | }, 65 | { 66 | path: "/:pathMatch(.*)", 67 | redirect: "/404", 68 | }, 69 | ]; 70 | 71 | export default routes; 72 | -------------------------------------------------------------------------------- /src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 32 | 33 | 69 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 54 | 55 | 80 | -------------------------------------------------------------------------------- /src/api/request.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | switch (process.env.NODE_ENV) { 4 | case "production": 5 | axios.defaults.baseURL = import.meta.env.VITE_GLOBAL_API; 6 | break; 7 | case "development": 8 | axios.defaults.baseURL = import.meta.env.VITE_GLOBAL_API; 9 | break; 10 | default: 11 | axios.defaults.baseURL = import.meta.env.VITE_GLOBAL_API; 12 | break; 13 | } 14 | 15 | axios.defaults.timeout = 30000; 16 | axios.defaults.headers = { "Content-Type": "application/json" }; 17 | 18 | // 请求拦截 19 | axios.interceptors.request.use( 20 | (request) => { 21 | // if (request.loadingBar != "Hidden") $loadingBar.start(); 22 | const token = localStorage.getItem("token"); 23 | if (token) { 24 | request.headers.Authorization = token; 25 | } 26 | return request; 27 | }, 28 | (error) => { 29 | // $loadingBar.error(); 30 | $message.error("请求失败,请稍后重试"); 31 | return Promise.reject(error); 32 | } 33 | ); 34 | 35 | // 响应拦截 36 | axios.interceptors.response.use( 37 | (response) => { 38 | // $loadingBar.finish(); 39 | return response.data; 40 | }, 41 | (error) => { 42 | $loadingBar.error(); 43 | if (error.response) { 44 | let data = error.response.data; 45 | switch (error.response.status) { 46 | case 401: 47 | $message.error(data.message ? data.message : "请登录后使用"); 48 | break; 49 | case 301: 50 | $message.error(data.message ? data.message : "请求路径发生跳转"); 51 | break; 52 | case 403: 53 | $message.error(data.message ? data.message : "暂无访问权限"); 54 | break; 55 | case 404: 56 | $message.error(data.message ? data.message : "请求资源不存在"); 57 | break; 58 | case 500: 59 | $message.error(data.message ? data.message : "内部服务器错误"); 60 | break; 61 | default: 62 | $message.error(data.message ? data.message : "请求失败,请稍后重试"); 63 | break; 64 | } 65 | } else { 66 | $message.error(data.message ? data.message : "请求失败,请稍后重试"); 67 | } 68 | return Promise.reject(error); 69 | } 70 | ); 71 | 72 | export default axios; 73 | -------------------------------------------------------------------------------- /src/utils/getTime.js: -------------------------------------------------------------------------------- 1 | import LunarCalendar from "lunar-calendar"; 2 | 3 | export const formatTime = (timestamp) => { 4 | const date = new Date(timestamp); 5 | const now = new Date(); 6 | const diffInSeconds = (now.getTime() - date.getTime()) / 1000; 7 | const diffInMinutes = diffInSeconds / 60; 8 | const diffInHours = diffInMinutes / 60; 9 | 10 | if (diffInSeconds < 60) { 11 | return "刚刚更新"; 12 | } else if (diffInMinutes < 60) { 13 | const minutes = Math.floor(diffInMinutes); 14 | return `${minutes}分钟前更新`; 15 | } else if (diffInHours < 24) { 16 | const hours = Math.floor(diffInHours); 17 | return `${hours}小时前更新`; 18 | } else { 19 | const month = date.getMonth() + 1; 20 | const day = date.getDate(); 21 | return `${month}月${day}日`; 22 | } 23 | }; 24 | 25 | export const getCurrentTime = () => { 26 | const time = new Date(); 27 | const year = time.getFullYear(); 28 | const month = 29 | time.getMonth() + 1 < 10 30 | ? "0" + (time.getMonth() + 1) 31 | : time.getMonth() + 1; 32 | const day = time.getDate() < 10 ? "0" + time.getDate() : time.getDate(); 33 | const hour = time.getHours() < 10 ? "0" + time.getHours() : time.getHours(); 34 | const minute = 35 | time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes(); 36 | const second = 37 | time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds(); 38 | const weekday = [ 39 | "星期日", 40 | "星期一", 41 | "星期二", 42 | "星期三", 43 | "星期四", 44 | "星期五", 45 | "星期六", 46 | ]; 47 | // 获取农历 48 | const lunar = LunarCalendar.solarToLunar( 49 | time.getFullYear(), 50 | time.getMonth() + 1, 51 | time.getDate() 52 | ); 53 | const currentTime = { 54 | time: { 55 | year, 56 | month, 57 | day, 58 | hour, 59 | minute, 60 | second, 61 | weekday: weekday[time.getDay()], 62 | text: 63 | year + 64 | "-" + 65 | month + 66 | "-" + 67 | day + 68 | " " + 69 | hour + 70 | ":" + 71 | minute + 72 | ":" + 73 | second, 74 | }, 75 | lunar: { 76 | data: lunar, 77 | year: lunar.lunarYear, 78 | month: lunar.lunarMonthName, 79 | day: lunar.lunarDayName, 80 | GanZhiYear: lunar.GanZhiYear, 81 | GanZhiMonth: lunar.GanZhiMonth, 82 | GanZhiDay: lunar.GanZhiDay, 83 | text: lunar.lunarMonthName + lunar.lunarDayName, 84 | }, 85 | }; 86 | return currentTime; 87 | }; 88 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from "node:url"; 2 | import { defineConfig, loadEnv } from "vite"; 3 | import { NaiveUiResolver } from "unplugin-vue-components/resolvers"; 4 | import { VitePWA } from "vite-plugin-pwa"; 5 | import vue from "@vitejs/plugin-vue"; 6 | import AutoImport from "unplugin-auto-import/vite"; 7 | import Components from "unplugin-vue-components/vite"; 8 | 9 | export default defineConfig(({ mode }) => { 10 | return { 11 | base: loadEnv(mode, process.cwd())["VITE_DIR"], 12 | plugins: [ 13 | vue(), 14 | AutoImport({ 15 | imports: [ 16 | "vue", 17 | { 18 | "naive-ui": [ 19 | "useDialog", 20 | "useMessage", 21 | "useNotification", 22 | "useLoadingBar", 23 | ], 24 | }, 25 | ], 26 | }), 27 | Components({ 28 | resolvers: [NaiveUiResolver()], 29 | }), 30 | // PWA 31 | VitePWA({ 32 | registerType: "autoUpdate", 33 | workbox: { 34 | cleanupOutdatedCaches: true, 35 | runtimeCaching: [ 36 | { 37 | urlPattern: /(.*?)\.(woff2|woff|ttf)/, 38 | handler: "CacheFirst", 39 | options: { 40 | cacheName: "file-cache", 41 | }, 42 | }, 43 | { 44 | urlPattern: 45 | /(.*?)\.(webp|png|jpe?g|svg|gif|bmp|psd|tiff|tga|eps)/, 46 | handler: "CacheFirst", 47 | options: { 48 | cacheName: "image-cache", 49 | }, 50 | }, 51 | ], 52 | }, 53 | manifest: { 54 | name: "今日热榜", 55 | short_name: "DailyHot", 56 | description: "汇聚全网热点,热门尽览无余", 57 | display: "standalone", 58 | start_url: "/", 59 | theme_color: "#fff", 60 | background_color: "#efefef", 61 | icons: [ 62 | { 63 | src: "/ico/favicon.png", 64 | sizes: "200x200", 65 | type: "image/png", 66 | }, 67 | ], 68 | }, 69 | }), 70 | ], 71 | resolve: { 72 | alias: { 73 | "@": fileURLToPath(new URL("./src", import.meta.url)), 74 | }, 75 | }, 76 | server: { 77 | port: 6699, 78 | }, 79 | build: { 80 | minify: "terser", 81 | terserOptions: { 82 | compress: { 83 | pure_funcs: ["console.log"], 84 | }, 85 | }, 86 | }, 87 | }; 88 | }); 89 | -------------------------------------------------------------------------------- /src/components/Provider.vue: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 109 | -------------------------------------------------------------------------------- /src/views/Test.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 90 | 91 | 121 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 50 | 51 | 114 | -------------------------------------------------------------------------------- /public/ico/powered-by-vercel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import { defineStore } from "pinia"; 2 | 3 | export const mainStore = defineStore("mainData", { 4 | state: () => { 5 | return { 6 | // 系统主题 7 | siteTheme: "light", 8 | siteThemeAuto: true, 9 | // 新闻类别 10 | defaultNewsArr: [ 11 | { 12 | label: "哔哩哔哩", 13 | name: "bilibili", 14 | order: 0, 15 | show: true, 16 | }, 17 | { 18 | label: "微博", 19 | name: "weibo", 20 | order: 1, 21 | show: true, 22 | }, 23 | { 24 | label: "抖音", 25 | name: "douyin", 26 | order: 2, 27 | show: true, 28 | }, 29 | { 30 | label: "知乎", 31 | name: "zhihu", 32 | order: 3, 33 | show: true, 34 | }, 35 | { 36 | label: "36氪", 37 | name: "36kr", 38 | order: 4, 39 | show: true, 40 | }, 41 | { 42 | label: "百度", 43 | name: "baidu", 44 | order: 5, 45 | show: true, 46 | }, 47 | { 48 | label: "少数派", 49 | name: "sspai", 50 | order: 6, 51 | show: true, 52 | }, 53 | { 54 | label: "IT之家", 55 | name: "ithome", 56 | order: 7, 57 | show: true, 58 | }, 59 | { 60 | label: "澎湃新闻", 61 | name: "thepaper", 62 | order: 8, 63 | show: true, 64 | }, 65 | { 66 | label: "今日头条", 67 | name: "toutiao", 68 | order: 9, 69 | show: true, 70 | }, 71 | { 72 | label: "百度贴吧", 73 | name: "tieba", 74 | order: 10, 75 | show: true, 76 | }, 77 | { 78 | label: "稀土掘金", 79 | name: "juejin", 80 | order: 11, 81 | show: true, 82 | }, 83 | { 84 | label: "腾讯新闻", 85 | name: "qq-news", 86 | order: 12, 87 | show: true, 88 | }, 89 | { 90 | label: "豆瓣电影", 91 | name: "douban-movie", 92 | order: 13, 93 | show: true, 94 | }, 95 | { 96 | label: "原神", 97 | name: "genshin", 98 | order: 14, 99 | show: true, 100 | }, 101 | { 102 | label: "崩坏:星穹铁道", 103 | name: "starrail", 104 | order: 16, 105 | show: true, 106 | }, 107 | { 108 | label: "LOL", 109 | name: "lol", 110 | order: 15, 111 | show: true, 112 | }, 113 | { 114 | label: "网易新闻", 115 | name: "netease-news", 116 | order: 17, 117 | show: true, 118 | }, 119 | { 120 | label: "微信读书", 121 | name: "weread", 122 | order: 18, 123 | show: true, 124 | }, 125 | { 126 | label: "豆瓣讨论小组", 127 | name: "douban-group", 128 | order: 19, 129 | show: true, 130 | }, 131 | { 132 | label: "NGA", 133 | name: "ngabbs", 134 | order: 20, 135 | show: true, 136 | }, 137 | { 138 | label: "HelloGitHub", 139 | name: "hellogithub", 140 | order: 21, 141 | show: true, 142 | }, 143 | { 144 | label: "简书", 145 | name: "jianshu", 146 | order: 22, 147 | show: true, 148 | }, 149 | { 150 | label: "知乎日报", 151 | name: "zhihu-daily", 152 | order: 23, 153 | show: true, 154 | }, 155 | ], 156 | newsArr: [], 157 | // 链接跳转方式 158 | linkOpenType: "open", 159 | // 页头固定 160 | headerFixed: true, 161 | // 时间数据 162 | timeData: null, 163 | // 字体大小 164 | listFontSize: 16, 165 | }; 166 | }, 167 | getters: {}, 168 | actions: { 169 | // 更改系统主题 170 | setSiteTheme(val) { 171 | $message.info(`已切换至${val === "dark" ? "深色模式" : "浅色模式"}`, { 172 | showIcon: false, 173 | }); 174 | this.siteTheme = val; 175 | this.siteThemeAuto = false; 176 | }, 177 | // 检查更新 178 | checkNewsUpdate() { 179 | const mainData = JSON.parse(localStorage.getItem("mainData")); 180 | let updatedNum = 0; 181 | if (!mainData) return false; 182 | console.log("列表尝试更新", this.defaultNewsArr, this.newsArr); 183 | // 执行比较并迁移 184 | if (this.newsArr.length > 0) { 185 | for (const newItem of this.defaultNewsArr) { 186 | const exists = this.newsArr.some( 187 | (news) => newItem.label === news.label && newItem.name === news.name 188 | ); 189 | if (!exists) { 190 | console.log("列表有更新:", newItem); 191 | updatedNum++; 192 | this.newsArr.push(newItem); 193 | } 194 | } 195 | if (updatedNum) $message.success(`成功更新 ${updatedNum} 个榜单数据`); 196 | } else { 197 | console.log("列表无内容,写入默认"); 198 | this.newsArr = this.defaultNewsArr; 199 | } 200 | }, 201 | }, 202 | persist: [ 203 | { 204 | storage: localStorage, 205 | paths: [ 206 | "siteTheme", 207 | "siteThemeAuto", 208 | "newsArr", 209 | "linkOpenType", 210 | "headerFixed", 211 | "listFontSize", 212 | ], 213 | }, 214 | ], 215 | }); 216 | -------------------------------------------------------------------------------- /src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 89 | 90 | 218 | 219 | 302 | -------------------------------------------------------------------------------- /src/views/Setting.vue: -------------------------------------------------------------------------------- 1 | 145 | 146 | 215 | 216 | 307 | -------------------------------------------------------------------------------- /src/views/List.vue: -------------------------------------------------------------------------------- 1 | 121 | 122 | 220 | 221 | 395 | -------------------------------------------------------------------------------- /src/components/HotList.vue: -------------------------------------------------------------------------------- 1 | 137 | 138 | 266 | 267 | 431 | --------------------------------------------------------------------------------