├── .github └── workflows │ └── release.yml ├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── app-icon.png ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public ├── tauri.svg └── vite.svg ├── src-tauri ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── src │ ├── main.rs │ └── utils.rs └── tauri.conf.json ├── src ├── App.vue ├── apis │ ├── article.ts │ ├── common.ts │ ├── files.ts │ ├── mock.ts │ └── user.ts ├── assets │ ├── iconfont │ │ ├── demo.css │ │ ├── demo_index.html │ │ ├── iconfont.css │ │ ├── iconfont.js │ │ ├── iconfont.json │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ └── image │ │ ├── chat.png │ │ ├── document.png │ │ ├── error.png │ │ ├── fileHub.png │ │ ├── fileHubDark.png │ │ ├── folder.png │ │ ├── loadColor.gif │ │ ├── music2.png │ │ ├── musicBg.gif │ │ ├── other.png │ │ └── zip.png ├── components │ ├── document.vue │ ├── filedialog.vue │ ├── foler.vue │ ├── music.vue │ ├── other.vue │ ├── picture.vue │ ├── titleBar.vue │ ├── uploading.vue │ └── video.vue ├── hooks │ └── theme.ts ├── lang │ ├── en.ts │ ├── index.ts │ └── zh.ts ├── layout │ ├── components │ │ ├── AppMain.vue │ │ ├── Header.vue │ │ └── Sidebar.vue │ └── index.vue ├── main.ts ├── route │ └── index.ts ├── stores │ ├── files.ts │ └── user.ts ├── style │ ├── index.scss │ ├── login.css │ └── theme.css ├── utils │ ├── encode.ts │ ├── index.ts │ ├── request.ts │ ├── update.ts │ ├── useTypes.ts │ └── webtorrent.min.js ├── views │ ├── analysis │ │ └── index.vue │ ├── article │ │ ├── component │ │ │ └── note.vue │ │ └── index.vue │ ├── category │ │ └── index.vue │ ├── chatgpt │ │ └── index.vue │ ├── files │ │ └── index.vue │ ├── help │ │ └── index.vue │ ├── login │ │ └── index.vue │ ├── publish │ │ └── index.vue │ ├── setting │ │ ├── component │ │ │ ├── base.vue │ │ │ ├── chatset.vue │ │ │ ├── image.vue │ │ │ └── user.vue │ │ └── index.vue │ ├── share │ │ └── index.vue │ ├── theme │ │ └── index.vue │ ├── tools │ │ └── index.vue │ ├── web │ │ └── index.vue │ └── webSet │ │ └── index.vue └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release CI 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 8 | workflow_dispatch: 9 | 10 | jobs: 11 | release: 12 | permissions: 13 | contents: write 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | # 选择编译平台 18 | platform: [macos-latest, ubuntu-20.04, windows-latest] 19 | runs-on: ${{ matrix.platform }} 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v3 23 | 24 | - name: Install dependencies (ubuntu only) 25 | if: matrix.platform == 'ubuntu-20.04' 26 | # You can remove libayatana-appindicator3-dev if you don't use the system tray feature. 27 | run: | 28 | sudo apt-get update 29 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev 30 | 31 | - name: Rust setup 32 | uses: dtolnay/rust-toolchain@stable 33 | 34 | - name: Rust cache 35 | uses: swatinem/rust-cache@v2 36 | with: 37 | workspaces: './src-tauri -> target' 38 | 39 | - name: Sync node version and insatll nodejs 40 | uses: actions/setup-node@v3 41 | with: 42 | node-version: 16 43 | 44 | # 使用 pnpm 作为包管理器 45 | - name: Install pnpm 46 | uses: pnpm/action-setup@v2 47 | id: pnpm-install 48 | with: 49 | version: 8 50 | run_install: false 51 | 52 | - name: Get pnpm store directory 53 | id: pnpm-cache 54 | shell: bash 55 | run: | 56 | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT 57 | 58 | - uses: actions/cache@v3 59 | name: Setup pnpm cache 60 | with: 61 | path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} 62 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 63 | restore-keys: | 64 | ${{ runner.os }}-pnpm-store- 65 | 66 | - name: Install app dependencies and build it 67 | run: pnpm i && pnpm bundle 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} 71 | TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} 72 | 73 | - name: Tauri Action 74 | uses: tauri-apps/tauri-action@v0.3 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} 78 | TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} 79 | with: 80 | tagName: ${{ github.ref_name }} # This only works if your workflow triggers on new tags. 81 | releaseName: 'FileHub v__VERSION__' # 自定义release名称,__VERSION__将自动填写为软件版本信息 82 | releaseBody: 'See the assets to download and install this version.' 83 | releaseDraft: true 84 | prerelease: false 85 | -------------------------------------------------------------------------------- /.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 | dist 12 | /src/config/* 13 | src-tauri/target/* 14 | dist-ssr 15 | *.local 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "tauri-apps.tauri-vscode", 5 | "rust-lang.rust-analyzer" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FileHub 介绍 2 | 3 |
4 | 5 |
6 | 一个基于Github开发的文件存储软件,美其名曰:FileHub,可存万物,而且绝不和谐任何文件。类似于百度云盘的功能,但是功能上肯定达不到百度云盘的效果,但是基本功能还是有的:例如登录注册,文件上传查看下载,资源分享等等。当然,还在努力添加ChatGPT功能,gitpage网站一键部署,gitpage主题切换,视频解析和视频无水印下载等等功能。如果对你有帮助,请给个Star吧,有问题请提交Isue吧 7 | 本项目使用的技术栈:Tauri + Vue3 + TypeScript + Vite + Pinia + element-plus 8 | 9 | ##### Windows 安装包 10 | 11 | Github 下载链接: [下载地址一](https://1024huijia.github.io/FileHub/root/filehub/FileHub_0.0.2_x64_zh-CN.msi) 12 | 蓝奏云下载链接:[下载地址二](https://wwlu.lanzouq.com/iwatV1lp3rud) 13 | 14 | ##### Mac 电脑安装包 15 | 16 | Github 下载链接: [下载地址一](https://1024huijia.github.io/FileHub/root/filehub/FileHub_0.0.2_x64.dmg) 17 | 蓝奏云下载链接:[下载地址二](https://wwlu.lanzouq.com/iwatV1lp3rud) 18 | 19 | ##### Linux 安装包 20 | 21 | Github 下载链接: [下载地址一](https://1024huijia.github.io/FileHub/root/filehub/file-hub_0.0.2_amd64.deb) 22 | 蓝奏云下载链接:[下载地址二](https://wwlu.lanzouq.com/iwatV1lp3rud) 23 | 24 | ## 软件功能介绍 25 | 26 | ### 基本功能特性 27 | 28 | 跨平台支持:windows + mac + linux 都支持,多主题:暗黑主题和亮白主题,多语言切换:中英互换。 29 | 上传文件,在线预览图片,播放视频,音乐,分享资源等等,修改 Token,修改密码,修改用户名,修改图片链接 CDN,加快访问速度。 30 | 待开发功能: 31 | 1.AI 产品集成:ChatGPT,WormGPT(邪恶版 ChatGPT),Bard,AI 绘画,AI 写作等智能 AI 应用接口 32 | 2.依托 Github 进行文章笔记管理:文章分类,文章发布,文章加密,文章分享等 33 | 3.依托 Github Page 发布自己的网站:使用 Github Page 发布自己的网站,可以设置不同的网站主题等等 4.常用工具插件:各平台视频无水印下载,音频下载,图片下载等,视频/音频/图片等转存到我的文件 34 | 5.依托 Github Action 实现:定时打卡签到等,定时爬虫任务,爬虫任务资源存储到我的文件等 35 | 6.移动端支持:安卓 Android 和苹果 IOS 客户端支持,暂定使用 Flutter 开发 36 | 7.对上传的图片进行压缩处理,以节省 Github 仓库容量(一个仓库容量 1G,一个账号最大容量 100G) 8.对根目录新建的文件夹,用新创建的仓库代替 37 | 38 | ### 登录注册 39 | 40 | 使用用户名和密码注册账户,或者仅仅使用 git token 登陆。注册用户的时候,需要添加上 git token,这个是必须项。注册成功后,就可以使用用户名和密码登陆,而不再需要 token。(我会对你的 token 进行公私钥加密存储,所以可放心食用) 41 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.2uh6124tv4a0.webp) 42 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.3p83ldepb780.webp) 43 | 44 | ### 文件系统 45 | 46 | 文件(各类文件)上传、拖动上传,文件预览,视频播放,音乐播放,m3u8 视频导入,资源链接导入,文件分享,文件下载,github cdn 链接转换。多文件选择多文件上传,多文件下载等 47 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.4ikm9oo3l3m0.webp) 48 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.5nlodjb062c0.webp) 49 | 50 | ### 资源广场 51 | 52 | 用户可以分享自己的资源到资源广场,实现资源的共享,可以分享 m3u8 类型的视频资源,也可以分享图片等等 53 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.7lcpf67knyo0.webp) 54 | 55 | ### 图片视频音乐播放 56 | 57 | 图片预览\放大\缩小\旋转等,视频播放\倍速\全屏播放\循环播放等,支持大多数视频文件,可以将网上的视频文件链接导入到文件中,音乐播放\倍速\循环播放,音乐后台播放等 58 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.69xjc9jm1800.webp) 59 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.26skfpadn5og.webp) 60 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230720/image.2whu0rbw5la0.webp) 61 | 62 | ### ChatGPT 集成效果 63 | 64 | chatgpt 大语言模型聊天\问答等 65 | ![](https://cdn.staticaly.com/gh/1024huijia/QingChunMeizi@master/20230720/image.32nkp0ib2r20.webp) 66 | 67 | ### 插件工具 68 | 69 | 视频无水印下载等 70 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.61j93kheyy80.webp) 71 | 72 | ### 设置中心 73 | 74 | 常用设置+图床设置+ChatGPT 设置+用户设置等 75 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.7ifcl62dqew0.webp) 76 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.2myajqua1sy0.webp) 77 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.9e8nookw6o0.webp) 78 | 79 | ### 帮助反馈 80 | 81 | ![](https://jsd.cdn.zzko.cn/gh/1024huijia/QingChunMeizi@master/20230726/image.2umhfyy4khq0.webp) 82 | 83 | 84 | # 本地开发配置 85 | 86 | 1.需要安装tauri开发环境哦:https://tauri.app/zh-cn/ 87 | 88 | 2.克隆项目: 89 | 90 | ``` 91 | git clone https://github.com/Sjj1024/s-hub.git 92 | ``` 93 | 94 | 3.然后切换 node 环境为 19.0.0 以上,推荐使用 pnpm 来管理依赖包。 95 | 上述环境安装好后,开始安装依赖: 96 | 97 | ``` 98 | pnpm i 99 | 100 | 或者 101 | npm i 102 | 103 | 或者 104 | yarn 105 | ``` 106 | 107 | 4.基于安全原因,本地开发需要先在 src 目录下创建一个 config 文件夹,并添加 index.ts 文件,文件配置如下: 108 | 109 | ``` 110 | // Filehub根路径地址:用于存储文件和被Frok 111 | export const fileHubBoss = "" 112 | // DataHub根路径:用于用户注册,分享内容,评论等 113 | export const bossUrl = "" 114 | // token1:用于开发测试 115 | export const bossToken = "" 116 | // token2:用于开发测试 117 | export const guestToken = "" 118 | 119 | // 公私钥加解密秘钥 120 | export const publickKey = `` 121 | 122 | export const privateKey = `` 123 | ``` 124 | 125 | 5.启动项目: 126 | 127 | ``` 128 | pnpm tauri dev 129 | ``` 130 | 131 | 6.编译项目: 132 | 133 | ``` 134 | pnpm tauri build 135 | ``` 136 | 137 | # TODO: 138 | 139 | 1.多语言配置,等最后再集成吧 140 | 2.集成 ChatGPT 141 | 3.开发文章管理 142 | 4.开发网站管理 143 | 144 | # 20230717:Done 145 | 146 | 1.资源分享页面按钮控制, 147 | .搜索 Issue 内容:并进行分页 148 | 3.资源分享页面分页展示 149 | 4.下载文件 150 | 5.多文件下载 151 | 6.软件自动更新 152 | 7.其他页面的 demo 样式 153 | 8.暗黑亮白模式样式适配: chatgpt 模式 154 | 9.更改 token,登陆时更改,设置页面更改 155 | 10.用户名和密码记住功能 156 | -------------------------------------------------------------------------------- /app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/app-icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tauri + Vue + TS 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "s-hub", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vue-tsc --noEmit && vite build", 9 | "preview": "vite preview", 10 | "develop": "tauri dev", 11 | "bundle": "tauri build" 12 | }, 13 | "dependencies": { 14 | "@element-plus/icons-vue": "^2.1.0", 15 | "@tauri-apps/api": "^1.3.0", 16 | "dplayer": "^1.27.1", 17 | "element-plus": "^2.3.6", 18 | "flv.js": "^1.6.2", 19 | "hls.js": "^1.4.6", 20 | "jsencrypt": "^3.3.2", 21 | "pinia": "^2.1.3", 22 | "sass": "^1.62.1", 23 | "sass-loader": "^13.3.1", 24 | "vue": "^3.3.2", 25 | "vue-gtag": "^2.0.1", 26 | "vue-i18n": "9.3.0-beta.19", 27 | "vue-router": "^4.1.6" 28 | }, 29 | "devDependencies": { 30 | "@tauri-apps/cli": "^1.3.1", 31 | "@types/node": "^18.7.10", 32 | "@vitejs/plugin-vue": "^4.0.0", 33 | "typescript": "^4.9.5", 34 | "vite": "^4.2.1", 35 | "vue-tsc": "^1.0.11" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/tauri.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "s-hub" 3 | version = "0.0.0" 4 | description = "一个可以存储任何文件的应用" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | edition = "2021" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [build-dependencies] 13 | tauri-build = { version = "1.3", features = [] } 14 | 15 | [dependencies] 16 | tauri = { version = "1.3", features = ["api-all", "updater"] } 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | window-shadows = "0.2.1" 20 | 21 | [features] 22 | # this feature is used for production builds or when `devPath` points to the filesystem 23 | # DO NOT REMOVE!! 24 | custom-protocol = ["tauri/custom-protocol"] 25 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | use crate::{ 5 | utils::{set_window_shadow} 6 | }; 7 | 8 | mod utils; 9 | 10 | fn main() { 11 | tauri::Builder::default() 12 | .setup(|app| { 13 | set_window_shadow(app); 14 | Ok(()) 15 | }) 16 | .invoke_handler(tauri::generate_handler![]) 17 | .run(tauri::generate_context!()) 18 | .expect("error while running tauri application"); 19 | } -------------------------------------------------------------------------------- /src-tauri/src/utils.rs: -------------------------------------------------------------------------------- 1 | use tauri::{Manager, Runtime}; 2 | use window_shadows::set_shadow; 3 | 4 | pub fn set_window_shadow(app: &tauri::App) { 5 | let window = app.get_window("customization").unwrap(); 6 | set_shadow(&window, true).expect("Unsupported platform!"); 7 | } -------------------------------------------------------------------------------- /src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "beforeDevCommand": "pnpm dev", 4 | "beforeBuildCommand": "pnpm build", 5 | "devPath": "http://localhost:1420", 6 | "distDir": "../dist", 7 | "withGlobalTauri": false 8 | }, 9 | "package": { 10 | "productName": "FileHub", 11 | "version": "0.0.1" 12 | }, 13 | "tauri": { 14 | "allowlist": { 15 | "all": true, 16 | "http": { 17 | "scope": ["http://**", "https://**"] 18 | }, 19 | "shell": { 20 | "all": false, 21 | "open": true 22 | }, 23 | "fs": { 24 | "all": true, 25 | "scope": ["*", "$DOWNLOAD/*"] 26 | }, 27 | "window": { 28 | "all": true 29 | } 30 | }, 31 | "bundle": { 32 | "active": true, 33 | "targets": "all", 34 | "identifier": "com.filehub.dev", 35 | "icon": [ 36 | "icons/32x32.png", 37 | "icons/128x128.png", 38 | "icons/128x128@2x.png", 39 | "icons/icon.icns", 40 | "icons/icon.ico" 41 | ], 42 | "shortDescription": "万物可存储", 43 | "longDescription": "只要你想,没有不可以", 44 | "windows": { 45 | "webviewInstallMode": { 46 | "type": "embedBootstrapper" 47 | }, 48 | "wix": { 49 | "language": "zh-CN" 50 | } 51 | } 52 | }, 53 | "security": { 54 | "csp": null 55 | }, 56 | "updater": { 57 | "active": true, 58 | "endpoints": [ 59 | "https://sjj1024.github.io/DataHub/FileData/update/index.json" 60 | ], 61 | "dialog": false, 62 | "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEMxNDAyRUI1NjlDQThCRUYKUldUdmk4cHB0UzVBd2FFbk91T1FXSnVWdERRK09tY0dSM2tyV01Tb2pIUVM2ME5qRDJuZGMwalEK" 63 | }, 64 | "windows": [ 65 | { 66 | "label": "customization", 67 | "fullscreen": false, 68 | "resizable": true, 69 | "title": "FileHub", 70 | "fileDropEnabled": false, 71 | "width": 1031, 72 | "height": 580, 73 | "center": true, 74 | "decorations": false 75 | } 76 | ] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/apis/common.ts: -------------------------------------------------------------------------------- 1 | import http from '@/utils/request' 2 | import { ResponseType } from '@tauri-apps/api/http' 3 | 4 | export default { 5 | gitRatelimit() { 6 | return http('/rate_limit', { 7 | method: 'get', 8 | }) 9 | }, 10 | creatIssue(body: any) { 11 | return http('/repos/Sjj1024/DataHub/issues', { 12 | method: 'post', 13 | body, 14 | }) 15 | }, 16 | registUser(token: string, body: any) { 17 | return http(`/repos/Sjj1024/DataHub/issues`, { 18 | method: 'post', 19 | headers: { 20 | Authorization: `Bearer ${token}`, 21 | }, 22 | body, 23 | }) 24 | }, 25 | creatGitPage(user: string, repo: string, token: string, body: any) { 26 | return http(`/repos/${user}/${repo}/pages`, { 27 | method: 'post', 28 | headers: { 29 | Authorization: `Bearer ${token}`, 30 | }, 31 | body, 32 | }) 33 | }, 34 | getHubInfo() { 35 | return http( 36 | `https://sjj1024.github.io/DataHub/FileData/update/index.json`, 37 | { 38 | method: 'get', 39 | responseType: ResponseType.JSON, 40 | } 41 | ) 42 | }, 43 | // 获取支付二维码 44 | getPayQrCode(body: any) { 45 | return http('https://payjs.cn/api/native', { 46 | method: 'post', 47 | headers: { 48 | 'content-type': 'application/x-www-form-urlencoded', 49 | }, 50 | body, 51 | }) 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /src/apis/files.ts: -------------------------------------------------------------------------------- 1 | import http from '@/utils/request' 2 | import { useUserStore } from '@/stores/user' 3 | import { ResponseType } from '@tauri-apps/api/http' 4 | const userStore = useUserStore() 5 | // 先判断仓库FileHub是否存在,存在就获取文件,不存在就frok然后再获取 6 | 7 | export default { 8 | getFiles(path: string) { 9 | return http(userStore.gitPath + path, { 10 | method: 'get', 11 | }) 12 | }, 13 | downFile(path: string) { 14 | return http(path, { 15 | method: 'get', 16 | responseType: ResponseType.Binary, 17 | }) 18 | }, 19 | creatIssue(body: any) { 20 | return http('/repos/Sjj1024/DataHub/issues', { 21 | method: 'post', 22 | body: body, 23 | }) 24 | }, 25 | uploadFile(filePath: string, body: any) { 26 | return http( 27 | `/repos/${userStore.gitName}/${userStore.gitRepo}/contents${filePath}`, 28 | { 29 | method: 'put', 30 | body: body, 31 | } 32 | ) 33 | }, 34 | importSource(filePath: string, body: any) { 35 | return http( 36 | `/repos/${userStore.gitName}/${userStore.gitRepo}/contents${filePath}`, 37 | { 38 | method: 'put', 39 | body: body, 40 | } 41 | ) 42 | }, 43 | delFile(filePath: string, body: any) { 44 | return http( 45 | `/repos/${userStore.gitName}/${userStore.gitRepo}/contents/${filePath}`, 46 | { 47 | method: 'DELETE', 48 | body: body, 49 | } 50 | ) 51 | }, 52 | shareFile(body: any) { 53 | return http('/repos/Sjj1024/DataHub/issues', { 54 | method: 'post', 55 | body: body, 56 | }) 57 | }, 58 | registUser(token: string, body: any) { 59 | return http(`/repos/Sjj1024/DataHub/issues`, { 60 | method: 'post', 61 | headers: { 62 | Authorization: `Bearer ${token}`, 63 | }, 64 | body: body, 65 | }) 66 | }, 67 | getShareFiles(label?: string) { 68 | return http(`/repos/Sjj1024/DataHub/issues?${label}`, { 69 | method: 'get', 70 | }) 71 | }, 72 | searchShare( 73 | keyWord: string = 'FileHub', 74 | lable: string = '+label:share', 75 | state: string = '+state:closed', 76 | author: string = '', 77 | pageSize: number = 35, 78 | pageNum: number = 1 79 | ) { 80 | // 在Sjj1024/DataHub中搜索关闭的和分享的内容,并且是标题里面包含关键字的 81 | return http( 82 | `/search/issues?q=${ 83 | keyWord + lable + state + author 84 | }+in:title+repo:Sjj1024/DataHub&per_page=${pageSize}&page=${pageNum}`, 85 | { 86 | method: 'get', 87 | } 88 | ) 89 | }, 90 | } 91 | -------------------------------------------------------------------------------- /src/apis/user.ts: -------------------------------------------------------------------------------- 1 | import http from '@/utils/request' 2 | 3 | 4 | export default { 5 | getFiles() { 6 | return [] 7 | }, 8 | getUserInfo(token: String) { 9 | return http('/user', { 10 | method: 'get', 11 | headers: { 12 | Authorization: `Bearer ${token}`, 13 | }, 14 | }) 15 | }, 16 | getUserRepos(gitName: String) { 17 | return http(`/users/${gitName}/repos`, { 18 | method: 'get', 19 | }) 20 | }, 21 | loginUserName(userName: String) { 22 | return http( 23 | `repos/Sjj1024/DataHub/contents/FileData/users/${userName}.txt`, 24 | { 25 | method: 'get', 26 | } 27 | ) 28 | }, 29 | registUser(token: string, body: any) { 30 | return http(`/repos/Sjj1024/DataHub/issues`, { 31 | method: 'post', 32 | headers: { 33 | Authorization: `Bearer ${token}`, 34 | }, 35 | body, 36 | }) 37 | }, 38 | updateUser(token: string, body: any){ 39 | return http(`/repos/Sjj1024/DataHub/issues`, { 40 | method: 'put', 41 | headers: { 42 | Authorization: `Bearer ${token}`, 43 | }, 44 | body, 45 | }) 46 | }, 47 | frokFileHub(token: string, body: any) { 48 | return http(`/repos/Sjj1024/FileHub/forks`, { 49 | method: 'post', 50 | headers: { 51 | Authorization: `Bearer ${token}`, 52 | }, 53 | body, 54 | }) 55 | }, 56 | creatFileHub(token: string, body: any) { 57 | return http(`/repos/Sjj1024/FileHub/generate`, { 58 | method: 'post', 59 | headers: { 60 | Authorization: `Bearer ${token}`, 61 | }, 62 | body, 63 | }) 64 | }, 65 | checkReady(path: string) { 66 | return http(path, { 67 | method: 'get', 68 | }) 69 | }, 70 | } 71 | -------------------------------------------------------------------------------- /src/assets/iconfont/demo.css: -------------------------------------------------------------------------------- 1 | /* Logo 字体 */ 2 | @font-face { 3 | font-family: "iconfont logo"; 4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); 5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), 6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), 7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), 8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); 9 | } 10 | 11 | .logo { 12 | font-family: "iconfont logo"; 13 | font-size: 160px; 14 | font-style: normal; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | /* tabs */ 20 | .nav-tabs { 21 | position: relative; 22 | } 23 | 24 | .nav-tabs .nav-more { 25 | position: absolute; 26 | right: 0; 27 | bottom: 0; 28 | height: 42px; 29 | line-height: 42px; 30 | color: #666; 31 | } 32 | 33 | #tabs { 34 | border-bottom: 1px solid #eee; 35 | } 36 | 37 | #tabs li { 38 | cursor: pointer; 39 | width: 100px; 40 | height: 40px; 41 | line-height: 40px; 42 | text-align: center; 43 | font-size: 16px; 44 | border-bottom: 2px solid transparent; 45 | position: relative; 46 | z-index: 1; 47 | margin-bottom: -1px; 48 | color: #666; 49 | } 50 | 51 | 52 | #tabs .active { 53 | border-bottom-color: #f00; 54 | color: #222; 55 | } 56 | 57 | .tab-container .content { 58 | display: none; 59 | } 60 | 61 | /* 页面布局 */ 62 | .main { 63 | padding: 30px 100px; 64 | width: 960px; 65 | margin: 0 auto; 66 | } 67 | 68 | .main .logo { 69 | color: #333; 70 | text-align: left; 71 | margin-bottom: 30px; 72 | line-height: 1; 73 | height: 110px; 74 | margin-top: -50px; 75 | overflow: hidden; 76 | *zoom: 1; 77 | } 78 | 79 | .main .logo a { 80 | font-size: 160px; 81 | color: #333; 82 | } 83 | 84 | .helps { 85 | margin-top: 40px; 86 | } 87 | 88 | .helps pre { 89 | padding: 20px; 90 | margin: 10px 0; 91 | border: solid 1px #e7e1cd; 92 | background-color: #fffdef; 93 | overflow: auto; 94 | } 95 | 96 | .icon_lists { 97 | width: 100% !important; 98 | overflow: hidden; 99 | *zoom: 1; 100 | } 101 | 102 | .icon_lists li { 103 | width: 100px; 104 | margin-bottom: 10px; 105 | margin-right: 20px; 106 | text-align: center; 107 | list-style: none !important; 108 | cursor: default; 109 | } 110 | 111 | .icon_lists li .code-name { 112 | line-height: 1.2; 113 | } 114 | 115 | .icon_lists .icon { 116 | display: block; 117 | height: 100px; 118 | line-height: 100px; 119 | font-size: 42px; 120 | margin: 10px auto; 121 | color: #333; 122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear; 123 | -moz-transition: font-size 0.25s linear, width 0.25s linear; 124 | transition: font-size 0.25s linear, width 0.25s linear; 125 | } 126 | 127 | .icon_lists .icon:hover { 128 | font-size: 100px; 129 | } 130 | 131 | .icon_lists .svg-icon { 132 | /* 通过设置 font-size 来改变图标大小 */ 133 | width: 1em; 134 | /* 图标和文字相邻时,垂直对齐 */ 135 | vertical-align: -0.15em; 136 | /* 通过设置 color 来改变 SVG 的颜色/fill */ 137 | fill: currentColor; 138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 139 | normalize.css 中也包含这行 */ 140 | overflow: hidden; 141 | } 142 | 143 | .icon_lists li .name, 144 | .icon_lists li .code-name { 145 | color: #666; 146 | } 147 | 148 | /* markdown 样式 */ 149 | .markdown { 150 | color: #666; 151 | font-size: 14px; 152 | line-height: 1.8; 153 | } 154 | 155 | .highlight { 156 | line-height: 1.5; 157 | } 158 | 159 | .markdown img { 160 | vertical-align: middle; 161 | max-width: 100%; 162 | } 163 | 164 | .markdown h1 { 165 | color: #404040; 166 | font-weight: 500; 167 | line-height: 40px; 168 | margin-bottom: 24px; 169 | } 170 | 171 | .markdown h2, 172 | .markdown h3, 173 | .markdown h4, 174 | .markdown h5, 175 | .markdown h6 { 176 | color: #404040; 177 | margin: 1.6em 0 0.6em 0; 178 | font-weight: 500; 179 | clear: both; 180 | } 181 | 182 | .markdown h1 { 183 | font-size: 28px; 184 | } 185 | 186 | .markdown h2 { 187 | font-size: 22px; 188 | } 189 | 190 | .markdown h3 { 191 | font-size: 16px; 192 | } 193 | 194 | .markdown h4 { 195 | font-size: 14px; 196 | } 197 | 198 | .markdown h5 { 199 | font-size: 12px; 200 | } 201 | 202 | .markdown h6 { 203 | font-size: 12px; 204 | } 205 | 206 | .markdown hr { 207 | height: 1px; 208 | border: 0; 209 | background: #e9e9e9; 210 | margin: 16px 0; 211 | clear: both; 212 | } 213 | 214 | .markdown p { 215 | margin: 1em 0; 216 | } 217 | 218 | .markdown>p, 219 | .markdown>blockquote, 220 | .markdown>.highlight, 221 | .markdown>ol, 222 | .markdown>ul { 223 | width: 80%; 224 | } 225 | 226 | .markdown ul>li { 227 | list-style: circle; 228 | } 229 | 230 | .markdown>ul li, 231 | .markdown blockquote ul>li { 232 | margin-left: 20px; 233 | padding-left: 4px; 234 | } 235 | 236 | .markdown>ul li p, 237 | .markdown>ol li p { 238 | margin: 0.6em 0; 239 | } 240 | 241 | .markdown ol>li { 242 | list-style: decimal; 243 | } 244 | 245 | .markdown>ol li, 246 | .markdown blockquote ol>li { 247 | margin-left: 20px; 248 | padding-left: 4px; 249 | } 250 | 251 | .markdown code { 252 | margin: 0 3px; 253 | padding: 0 5px; 254 | background: #eee; 255 | border-radius: 3px; 256 | } 257 | 258 | .markdown strong, 259 | .markdown b { 260 | font-weight: 600; 261 | } 262 | 263 | .markdown>table { 264 | border-collapse: collapse; 265 | border-spacing: 0px; 266 | empty-cells: show; 267 | border: 1px solid #e9e9e9; 268 | width: 95%; 269 | margin-bottom: 24px; 270 | } 271 | 272 | .markdown>table th { 273 | white-space: nowrap; 274 | color: #333; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown>table th, 279 | .markdown>table td { 280 | border: 1px solid #e9e9e9; 281 | padding: 8px 16px; 282 | text-align: left; 283 | } 284 | 285 | .markdown>table th { 286 | background: #F7F7F7; 287 | } 288 | 289 | .markdown blockquote { 290 | font-size: 90%; 291 | color: #999; 292 | border-left: 4px solid #e9e9e9; 293 | padding-left: 0.8em; 294 | margin: 1em 0; 295 | } 296 | 297 | .markdown blockquote p { 298 | margin: 0; 299 | } 300 | 301 | .markdown .anchor { 302 | opacity: 0; 303 | transition: opacity 0.3s ease; 304 | margin-left: 8px; 305 | } 306 | 307 | .markdown .waiting { 308 | color: #ccc; 309 | } 310 | 311 | .markdown h1:hover .anchor, 312 | .markdown h2:hover .anchor, 313 | .markdown h3:hover .anchor, 314 | .markdown h4:hover .anchor, 315 | .markdown h5:hover .anchor, 316 | .markdown h6:hover .anchor { 317 | opacity: 1; 318 | display: inline-block; 319 | } 320 | 321 | .markdown>br, 322 | .markdown>p>br { 323 | clear: both; 324 | } 325 | 326 | 327 | .hljs { 328 | display: block; 329 | background: white; 330 | padding: 0.5em; 331 | color: #333333; 332 | overflow-x: auto; 333 | } 334 | 335 | .hljs-comment, 336 | .hljs-meta { 337 | color: #969896; 338 | } 339 | 340 | .hljs-string, 341 | .hljs-variable, 342 | .hljs-template-variable, 343 | .hljs-strong, 344 | .hljs-emphasis, 345 | .hljs-quote { 346 | color: #df5000; 347 | } 348 | 349 | .hljs-keyword, 350 | .hljs-selector-tag, 351 | .hljs-type { 352 | color: #a71d5d; 353 | } 354 | 355 | .hljs-literal, 356 | .hljs-symbol, 357 | .hljs-bullet, 358 | .hljs-attribute { 359 | color: #0086b3; 360 | } 361 | 362 | .hljs-section, 363 | .hljs-name { 364 | color: #63a35c; 365 | } 366 | 367 | .hljs-tag { 368 | color: #333333; 369 | } 370 | 371 | .hljs-title, 372 | .hljs-attr, 373 | .hljs-selector-id, 374 | .hljs-selector-class, 375 | .hljs-selector-attr, 376 | .hljs-selector-pseudo { 377 | color: #795da3; 378 | } 379 | 380 | .hljs-addition { 381 | color: #55a532; 382 | background-color: #eaffea; 383 | } 384 | 385 | .hljs-deletion { 386 | color: #bd2c00; 387 | background-color: #ffecec; 388 | } 389 | 390 | .hljs-link { 391 | text-decoration: underline; 392 | } 393 | 394 | /* 代码高亮 */ 395 | /* PrismJS 1.15.0 396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 397 | /** 398 | * prism.js default theme for JavaScript, CSS and HTML 399 | * Based on dabblet (http://dabblet.com) 400 | * @author Lea Verou 401 | */ 402 | code[class*="language-"], 403 | pre[class*="language-"] { 404 | color: black; 405 | background: none; 406 | text-shadow: 0 1px white; 407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 408 | text-align: left; 409 | white-space: pre; 410 | word-spacing: normal; 411 | word-break: normal; 412 | word-wrap: normal; 413 | line-height: 1.5; 414 | 415 | -moz-tab-size: 4; 416 | -o-tab-size: 4; 417 | tab-size: 4; 418 | 419 | -webkit-hyphens: none; 420 | -moz-hyphens: none; 421 | -ms-hyphens: none; 422 | hyphens: none; 423 | } 424 | 425 | pre[class*="language-"]::-moz-selection, 426 | pre[class*="language-"] ::-moz-selection, 427 | code[class*="language-"]::-moz-selection, 428 | code[class*="language-"] ::-moz-selection { 429 | text-shadow: none; 430 | background: #b3d4fc; 431 | } 432 | 433 | pre[class*="language-"]::selection, 434 | pre[class*="language-"] ::selection, 435 | code[class*="language-"]::selection, 436 | code[class*="language-"] ::selection { 437 | text-shadow: none; 438 | background: #b3d4fc; 439 | } 440 | 441 | @media print { 442 | 443 | code[class*="language-"], 444 | pre[class*="language-"] { 445 | text-shadow: none; 446 | } 447 | } 448 | 449 | /* Code blocks */ 450 | pre[class*="language-"] { 451 | padding: 1em; 452 | margin: .5em 0; 453 | overflow: auto; 454 | } 455 | 456 | :not(pre)>code[class*="language-"], 457 | pre[class*="language-"] { 458 | background: #f5f2f0; 459 | } 460 | 461 | /* Inline code */ 462 | :not(pre)>code[class*="language-"] { 463 | padding: .1em; 464 | border-radius: .3em; 465 | white-space: normal; 466 | } 467 | 468 | .token.comment, 469 | .token.prolog, 470 | .token.doctype, 471 | .token.cdata { 472 | color: slategray; 473 | } 474 | 475 | .token.punctuation { 476 | color: #999; 477 | } 478 | 479 | .namespace { 480 | opacity: .7; 481 | } 482 | 483 | .token.property, 484 | .token.tag, 485 | .token.boolean, 486 | .token.number, 487 | .token.constant, 488 | .token.symbol, 489 | .token.deleted { 490 | color: #905; 491 | } 492 | 493 | .token.selector, 494 | .token.attr-name, 495 | .token.string, 496 | .token.char, 497 | .token.builtin, 498 | .token.inserted { 499 | color: #690; 500 | } 501 | 502 | .token.operator, 503 | .token.entity, 504 | .token.url, 505 | .language-css .token.string, 506 | .style .token.string { 507 | color: #9a6e3a; 508 | background: hsla(0, 0%, 100%, .5); 509 | } 510 | 511 | .token.atrule, 512 | .token.attr-value, 513 | .token.keyword { 514 | color: #07a; 515 | } 516 | 517 | .token.function, 518 | .token.class-name { 519 | color: #DD4A68; 520 | } 521 | 522 | .token.regex, 523 | .token.important, 524 | .token.variable { 525 | color: #e90; 526 | } 527 | 528 | .token.important, 529 | .token.bold { 530 | font-weight: bold; 531 | } 532 | 533 | .token.italic { 534 | font-style: italic; 535 | } 536 | 537 | .token.entity { 538 | cursor: help; 539 | } 540 | -------------------------------------------------------------------------------- /src/assets/iconfont/demo_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iconfont Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | 38 |
39 |

40 | 41 | 42 |

43 | 53 |
54 |
55 |
    56 | 57 |
  • 58 | 59 |
    list
    60 |
    
    61 |
  • 62 | 63 |
  • 64 | 65 |
    default
    66 |
    
    67 |
  • 68 | 69 |
  • 70 | 71 |
    皮肤
    72 |
    
    73 |
  • 74 | 75 |
  • 76 | 77 |
    43_主题
    78 |
    
    79 |
  • 80 | 81 |
  • 82 | 83 |
    language
    84 |
    
    85 |
  • 86 | 87 |
  • 88 | 89 |
    language
    90 |
    
    91 |
  • 92 | 93 |
  • 94 | 95 |
    中英文切换-英文
    96 |
    
    97 |
  • 98 | 99 |
100 |
101 |

Unicode 引用

102 |
103 | 104 |

Unicode 是字体在网页端最原始的应用方式,特点是:

105 |
    106 |
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 107 |
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • 108 |
109 |
110 |

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

111 |
112 |

Unicode 使用步骤如下:

113 |

第一步:拷贝项目下面生成的 @font-face

114 |
@font-face {
116 |   font-family: 'iconfont';
117 |   src: url('iconfont.woff2?t=1686637562048') format('woff2'),
118 |        url('iconfont.woff?t=1686637562048') format('woff'),
119 |        url('iconfont.ttf?t=1686637562048') format('truetype');
120 | }
121 | 
122 |

第二步:定义使用 iconfont 的样式

123 |
.iconfont {
125 |   font-family: "iconfont" !important;
126 |   font-size: 16px;
127 |   font-style: normal;
128 |   -webkit-font-smoothing: antialiased;
129 |   -moz-osx-font-smoothing: grayscale;
130 | }
131 | 
132 |

第三步:挑选相应图标并获取字体编码,应用于页面

133 |
134 | <span class="iconfont">&#x33;</span>
136 | 
137 |
138 |

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

139 |
140 |
141 |
142 |
143 |
    144 | 145 |
  • 146 | 147 |
    148 | list 149 |
    150 |
    .icon-list 151 |
    152 |
  • 153 | 154 |
  • 155 | 156 |
    157 | default 158 |
    159 |
    .icon-morentubiao 160 |
    161 |
  • 162 | 163 |
  • 164 | 165 |
    166 | 皮肤 167 |
    168 |
    .icon-pifu 169 |
    170 |
  • 171 | 172 |
  • 173 | 174 |
    175 | 43_主题 176 |
    177 |
    .icon-43_zhuti 178 |
    179 |
  • 180 | 181 |
  • 182 | 183 |
    184 | language 185 |
    186 |
    .icon-language 187 |
    188 |
  • 189 | 190 |
  • 191 | 192 |
    193 | language 194 |
    195 |
    .icon-language1 196 |
    197 |
  • 198 | 199 |
  • 200 | 201 |
    202 | 中英文切换-英文 203 |
    204 |
    .icon-zhongyingwenqiehuan-yingwen 205 |
    206 |
  • 207 | 208 |
209 |
210 |

font-class 引用

211 |
212 | 213 |

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

214 |

与 Unicode 使用方式相比,具有如下特点:

215 |
    216 |
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • 217 |
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • 218 |
219 |

使用步骤如下:

220 |

第一步:引入项目下面生成的 fontclass 代码:

221 |
<link rel="stylesheet" href="./iconfont.css">
222 | 
223 |

第二步:挑选相应图标并获取类名,应用于页面:

224 |
<span class="iconfont icon-xxx"></span>
225 | 
226 |
227 |

" 228 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

229 |
230 |
231 |
232 |
233 |
    234 | 235 |
  • 236 | 239 |
    list
    240 |
    #icon-list
    241 |
  • 242 | 243 |
  • 244 | 247 |
    default
    248 |
    #icon-morentubiao
    249 |
  • 250 | 251 |
  • 252 | 255 |
    皮肤
    256 |
    #icon-pifu
    257 |
  • 258 | 259 |
  • 260 | 263 |
    43_主题
    264 |
    #icon-43_zhuti
    265 |
  • 266 | 267 |
  • 268 | 271 |
    language
    272 |
    #icon-language
    273 |
  • 274 | 275 |
  • 276 | 279 |
    language
    280 |
    #icon-language1
    281 |
  • 282 | 283 |
  • 284 | 287 |
    中英文切换-英文
    288 |
    #icon-zhongyingwenqiehuan-yingwen
    289 |
  • 290 | 291 |
292 |
293 |

Symbol 引用

294 |
295 | 296 |

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 297 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

298 |
    299 |
  • 支持多色图标了,不再受单色限制。
  • 300 |
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • 301 |
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • 302 |
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • 303 |
304 |

使用步骤如下:

305 |

第一步:引入项目下面生成的 symbol 代码:

306 |
<script src="./iconfont.js"></script>
307 | 
308 |

第二步:加入通用 CSS 代码(引入一次就行):

309 |
<style>
310 | .icon {
311 |   width: 1em;
312 |   height: 1em;
313 |   vertical-align: -0.15em;
314 |   fill: currentColor;
315 |   overflow: hidden;
316 | }
317 | </style>
318 | 
319 |

第三步:挑选相应图标并获取类名,应用于页面:

320 |
<svg class="icon" aria-hidden="true">
321 |   <use xlink:href="#icon-xxx"></use>
322 | </svg>
323 | 
324 |
325 |
326 | 327 |
328 |
329 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 4113094 */ 3 | src: url('iconfont.woff2?t=1686637562048') format('woff2'), 4 | url('iconfont.woff?t=1686637562048') format('woff'), 5 | url('iconfont.ttf?t=1686637562048') format('truetype'); 6 | } 7 | 8 | .iconfont { 9 | font-family: "iconfont" !important; 10 | font-size: 16px; 11 | font-style: normal; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | .icon-list:before { 17 | content: "\e7f6"; 18 | } 19 | 20 | .icon-morentubiao:before { 21 | content: "\e7f7"; 22 | } 23 | 24 | .icon-pifu:before { 25 | content: "\e645"; 26 | } 27 | 28 | .icon-43_zhuti:before { 29 | content: "\e679"; 30 | } 31 | 32 | .icon-language:before { 33 | content: "\e602"; 34 | } 35 | 36 | .icon-language1:before { 37 | content: "\e600"; 38 | } 39 | 40 | .icon-zhongyingwenqiehuan-yingwen:before { 41 | content: "\e616"; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.js: -------------------------------------------------------------------------------- 1 | window._iconfont_svg_string_4113094='',function(l){var c=(c=document.getElementsByTagName("script"))[c.length-1],t=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var e,h,i,n,a,o=function(c,t){t.parentNode.insertBefore(c,t)};if(t&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}e=function(){var c,t=document.createElement("div");t.innerHTML=l._iconfont_svg_string_4113094,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(c=document.body).firstChild?o(t,c.firstChild):c.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(e,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),e()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=e,n=l.document,a=!1,d(),n.onreadystatechange=function(){"complete"==n.readyState&&(n.onreadystatechange=null,s())})}function s(){a||(a=!0,i())}function d(){try{n.documentElement.doScroll("left")}catch(c){return void setTimeout(d,50)}s()}}(window); -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "4113094", 3 | "name": "Filehub", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "29606771", 10 | "name": "list", 11 | "font_class": "list", 12 | "unicode": "e7f6", 13 | "unicode_decimal": 59382 14 | }, 15 | { 16 | "icon_id": "29749475", 17 | "name": "default", 18 | "font_class": "morentubiao", 19 | "unicode": "e7f7", 20 | "unicode_decimal": 59383 21 | }, 22 | { 23 | "icon_id": "3867965", 24 | "name": "皮肤", 25 | "font_class": "pifu", 26 | "unicode": "e645", 27 | "unicode_decimal": 58949 28 | }, 29 | { 30 | "icon_id": "14183069", 31 | "name": "43_主题", 32 | "font_class": "43_zhuti", 33 | "unicode": "e679", 34 | "unicode_decimal": 59001 35 | }, 36 | { 37 | "icon_id": "9940272", 38 | "name": "language", 39 | "font_class": "language", 40 | "unicode": "e602", 41 | "unicode_decimal": 58882 42 | }, 43 | { 44 | "icon_id": "11399049", 45 | "name": "language", 46 | "font_class": "language1", 47 | "unicode": "e600", 48 | "unicode_decimal": 58880 49 | }, 50 | { 51 | "icon_id": "31310820", 52 | "name": "中英文切换-英文", 53 | "font_class": "zhongyingwenqiehuan-yingwen", 54 | "unicode": "e616", 55 | "unicode_decimal": 58902 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/assets/image/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/chat.png -------------------------------------------------------------------------------- /src/assets/image/document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/document.png -------------------------------------------------------------------------------- /src/assets/image/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/error.png -------------------------------------------------------------------------------- /src/assets/image/fileHub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/fileHub.png -------------------------------------------------------------------------------- /src/assets/image/fileHubDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/fileHubDark.png -------------------------------------------------------------------------------- /src/assets/image/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/folder.png -------------------------------------------------------------------------------- /src/assets/image/loadColor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/loadColor.gif -------------------------------------------------------------------------------- /src/assets/image/music2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/music2.png -------------------------------------------------------------------------------- /src/assets/image/musicBg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/musicBg.gif -------------------------------------------------------------------------------- /src/assets/image/other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/other.png -------------------------------------------------------------------------------- /src/assets/image/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sjj1024/file-hub/2217b3172599f13efc48d2329d1abc40bea56cee/src/assets/image/zip.png -------------------------------------------------------------------------------- /src/components/document.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /src/components/filedialog.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 279 | 280 | 281 | -------------------------------------------------------------------------------- /src/components/foler.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /src/components/music.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 39 | -------------------------------------------------------------------------------- /src/components/other.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /src/components/picture.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 49 | 50 | 96 | -------------------------------------------------------------------------------- /src/components/titleBar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 99 | 100 | -------------------------------------------------------------------------------- /src/components/uploading.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | 22 | 42 | -------------------------------------------------------------------------------- /src/components/video.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 112 | 113 | 164 | -------------------------------------------------------------------------------- /src/hooks/theme.ts: -------------------------------------------------------------------------------- 1 | import { useUserStore } from '@/stores/user' 2 | 3 | const userStore = useUserStore() 4 | 5 | export default function (theme: string) { 6 | theme = theme || localStorage.getItem('theme') || 'dark' 7 | if (theme !== 'dark') { 8 | document.documentElement.setAttribute('theme', 'light') 9 | document.querySelector('html')?.classList.remove('dark') 10 | document.querySelector('html')?.classList.add('light') 11 | userStore.setTheme('light') 12 | } else { 13 | document.documentElement.setAttribute('theme', 'dark') 14 | document.querySelector('html')?.classList.remove('light') 15 | document.querySelector('html')?.classList.add('dark') 16 | userStore.setTheme('dark') 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/lang/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | login: { 3 | login: 'login', 4 | register: 'register', 5 | userName: 'userName', 6 | passWord: 'passWord', 7 | }, 8 | menu: { 9 | MyFiles: '我的文件', 10 | ArticleManagement: '文章管理', 11 | }, 12 | welcomeToFileHub: 'Welcome to FileHub', 13 | welcomeLoginFileHub: 'Welcome to FileHub', 14 | loginwithanaccount: 'Login with account', 15 | LoginusingToken: 'Login use Token', 16 | GetToken: 'Obtain a Token', 17 | Registeranewaccount: 'Register new account', 18 | captcha: 'Captcha', 19 | forgetPassword: 'Forget Password?', 20 | loginTip: 'The login result is random. Just fill in the captcha', 21 | editpassword: 'Edit Password', 22 | logout: 'Logout', 23 | errMsg: { 24 | inputRequired: 'Please Input {cont}', 25 | selectRequired: 'Please Select {cont}', 26 | }, 27 | setting: { 28 | baseSet: '常用设置', 29 | imgSet: '图床设置', 30 | chatSet: 'ChatGPT', 31 | accountSet: '账户设置', 32 | setTheme: 'Theme', 33 | setlang: 'Language', 34 | fileStyle: 'File Style', 35 | downPath: 'Down Path', 36 | copyTemp: 'Copy Link', 37 | shareTemp: '多文件分享格式', 38 | openStart: '开机自启动', 39 | autoUpdate: '软件自动更新', 40 | }, 41 | } 42 | -------------------------------------------------------------------------------- /src/lang/index.ts: -------------------------------------------------------------------------------- 1 | // index.ts 2 | import { createI18n } from 'vue-i18n' 3 | import zh from './zh' 4 | import en from './en' 5 | 6 | const messages = { 7 | en, 8 | zh, 9 | } 10 | const language = (navigator.language || 'en').toLocaleLowerCase() // 这是获取浏览器的语言 11 | const i18n = createI18n({ 12 | locale: localStorage.getItem('lang') || language.split('-')[0] || 'en', // 首先从缓存里拿,没有的话就用浏览器语言, 13 | fallbackLocale: 'zh', // 设置备用语言 14 | messages, 15 | legacy: false, 16 | globalInjection:true, 17 | }) 18 | 19 | export default i18n 20 | -------------------------------------------------------------------------------- /src/lang/zh.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | login: { 3 | login: '登      陆', 4 | register: '注      册', 5 | userName: '用户名', 6 | passWord: '密码', 7 | }, 8 | menu: { 9 | MyFiles: '我的文件', 10 | ArticleManagement: '文章管理', 11 | }, 12 | welcomeToFileHub: '欢迎使用FileHub', 13 | welcomeLoginFileHub: '欢迎登陆FileHub', 14 | loginwithanaccount: '使用账号登陆', 15 | LoginusingToken: '使用Token登陆', 16 | GetToken: '获取一个Token', 17 | Registeranewaccount: '注册新账户', 18 | captcha: '验证码', 19 | forgetPassword: '忘记密码了?', 20 | loginTip: '当前登录结果随机。验证码随便填', 21 | editpassword: '修改密码', 22 | logout: '退出登录', 23 | errMsg: { 24 | inputRequired: '请输入{cont}', 25 | selectRequired: '请选择{cont}', 26 | }, 27 | setting: { 28 | baseSet: '常用设置', 29 | imgSet: '图床设置', 30 | chatSet: 'ChatGPT', 31 | accountSet: '账户设置', 32 | setTheme: '设置主题', 33 | setlang: '语言设置', 34 | fileStyle: '文件展示样式', 35 | downPath: '文件下载路径', 36 | copyTemp: '复制链接格式', 37 | shareTemp: '多文件分享格式', 38 | openStart: '开机自启动', 39 | autoUpdate: '软件自动更新', 40 | }, 41 | } 42 | -------------------------------------------------------------------------------- /src/layout/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 30 | -------------------------------------------------------------------------------- /src/layout/components/Header.vue: -------------------------------------------------------------------------------- 1 | 124 | 125 | 172 | 173 | 272 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 45 | 46 | 94 | -------------------------------------------------------------------------------- /src/layout/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import App from './App.vue' 2 | import router from './route' 3 | import { createApp } from 'vue' 4 | import '@/assets/iconfont/iconfont.css' 5 | import '@/assets/iconfont/iconfont.js' 6 | import ElementPlus from 'element-plus' 7 | import 'element-plus/dist/index.css' 8 | import { createPinia } from 'pinia' 9 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 10 | import 'element-plus/theme-chalk/dark/css-vars.css' //这句是暗黑模式切换 11 | import '@/style/theme.css' 12 | import '@/style/index.scss' 13 | import zhCN from 'element-plus/dist/locale/zh-cn' 14 | import i18n from './lang/index' 15 | import VueGtag from 'vue-gtag' 16 | import './utils/update' 17 | 18 | const app = createApp(App) 19 | 20 | // 使用pinia 21 | app.use(createPinia()) 22 | 23 | // 使用elementUi 24 | app.use(ElementPlus, { 25 | locale: zhCN, 26 | }) 27 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 28 | app.component(key, component) 29 | } 30 | // 国际化 31 | app.use(i18n) 32 | 33 | // 使用路由 34 | app.use(router) 35 | // await router.isReady() 36 | 37 | // 使用google统计 38 | app.use( 39 | VueGtag, 40 | { 41 | config: { id: 'G-66KMVSDKH9' }, 42 | }, 43 | router 44 | ) 45 | 46 | app.mount('#app') 47 | -------------------------------------------------------------------------------- /src/route/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' 2 | 3 | const routes: Array = [ 4 | { 5 | path: '/', 6 | name: 'login', 7 | component: () => import('@/views/login/index.vue'), 8 | meta: { requiresAuth: false, show: false, title: '登陆页面' }, 9 | }, 10 | { 11 | path: '/index', 12 | name: 'index', 13 | redirect: '/index/files', 14 | component: () => import('@/layout/index.vue'), 15 | meta: { 16 | requiresAuth: false, 17 | show: true, 18 | title: '我的文件', 19 | icon: 'Files', 20 | }, 21 | // 所有的分类全都是layout的子路由 22 | children: [ 23 | // 上传文件嵌套进我的文件中,增加一个按钮 24 | { 25 | path: 'files', 26 | name: 'files', 27 | meta: { 28 | requiresAuth: false, 29 | show: true, 30 | title: '我的资源', 31 | icon: 'FolderOpened', 32 | }, 33 | component: () => import('@/views/files/index.vue'), 34 | }, 35 | { 36 | path: 'goods', 37 | name: 'goods', 38 | meta: { 39 | requiresAuth: false, 40 | show: true, 41 | title: '资源广场', 42 | icon: 'Goods', 43 | }, 44 | component: () => import('@/views/share/index.vue'), 45 | }, 46 | { 47 | path: 'chatgpt', 48 | name: 'chatgpt', 49 | component: () => import('@/views/chatgpt/index.vue'), 50 | meta: { 51 | requiresAuth: false, 52 | show: true, 53 | title: 'ChatGPT', 54 | icon: 'ChatLineRound', 55 | }, 56 | }, 57 | { 58 | path: 'article', 59 | name: 'article', 60 | meta: { 61 | requiresAuth: false, 62 | show: true, 63 | title: '文章管理', 64 | icon: 'Edit', 65 | }, 66 | children: [ 67 | { 68 | path: 'list', 69 | name: 'list', 70 | meta: { 71 | requiresAuth: false, 72 | show: true, 73 | title: '文章列表', 74 | icon: 'Document', 75 | }, 76 | component: () => import('@/views/article/index.vue'), 77 | }, 78 | { 79 | path: 'publish', 80 | name: 'publish', 81 | meta: { 82 | requiresAuth: false, 83 | show: true, 84 | title: '发布文章', 85 | icon: 'Document', 86 | }, 87 | component: () => import('@/views/publish/index.vue'), 88 | }, 89 | { 90 | path: 'category', 91 | name: 'category', 92 | meta: { 93 | requiresAuth: false, 94 | show: true, 95 | title: '分类管理', 96 | icon: 'MessageBox', 97 | }, 98 | component: () => import('@/views/category/index.vue'), 99 | }, 100 | ], 101 | }, 102 | { 103 | path: 'web', 104 | name: 'web', 105 | meta: { 106 | requiresAuth: false, 107 | show: true, 108 | title: '网站管理', 109 | icon: 'Monitor', 110 | }, 111 | children: [ 112 | { 113 | path: 'set', 114 | name: 'set', 115 | meta: { 116 | requiresAuth: false, 117 | show: true, 118 | title: '网站设置', 119 | icon: 'Document', 120 | }, 121 | component: () => import('@/views/webSet/index.vue'), 122 | }, 123 | { 124 | path: 'theme', 125 | name: 'theme', 126 | meta: { 127 | requiresAuth: false, 128 | show: true, 129 | title: '主题样式', 130 | icon: 'Document', 131 | }, 132 | component: () => import('@/views/theme/index.vue'), 133 | }, 134 | { 135 | path: 'analysis', 136 | name: 'analysis', 137 | meta: { 138 | requiresAuth: false, 139 | show: true, 140 | title: '统计管理', 141 | icon: 'MessageBox', 142 | }, 143 | component: () => import('@/views/analysis/index.vue'), 144 | }, 145 | ], 146 | }, 147 | { 148 | path: 'tools', 149 | name: 'tools', 150 | component: () => import('@/views/tools/index.vue'), 151 | meta: { 152 | requiresAuth: false, 153 | show: true, 154 | title: '插件工具', 155 | icon: 'SetUp', 156 | }, 157 | }, 158 | { 159 | path: 'setting', 160 | name: 'setting', 161 | component: () => import('@/views/setting/index.vue'), 162 | meta: { 163 | requiresAuth: false, 164 | show: true, 165 | title: '设置中心', 166 | icon: 'Setting', 167 | }, 168 | }, 169 | { 170 | path: 'help', 171 | name: 'help', 172 | component: () => import('@/views/help/index.vue'), 173 | meta: { 174 | requiresAuth: false, 175 | show: true, 176 | title: '帮助反馈', 177 | icon: 'Service', 178 | }, 179 | }, 180 | ], 181 | }, 182 | ] 183 | 184 | const router = createRouter({ 185 | history: createWebHistory(), 186 | routes, 187 | }) 188 | 189 | // 配置前置后置路由导航守卫 190 | router.beforeEach(async (to, from, next) => { 191 | // 判断是否已经登陆,是的话,就直接到主页,否则还是登陆页 192 | // console.log('to, from ,next', to, from, next) 193 | const gitToken = localStorage.getItem('gitToken') 194 | ? localStorage.getItem('gitToken') 195 | : '' 196 | if (to.path === '/') { 197 | if (gitToken) { 198 | // 存在token,就跳转到主页:记住上次的菜单和路由 199 | // localStorage.removeItem("menuIndex") 200 | localStorage.getItem("menuRoute") ? next(localStorage.getItem("menuRoute")!) : next('/index/files') 201 | } else { 202 | //否则就继续 203 | next() 204 | } 205 | } else { 206 | // 不存在token,就跳转到登陆页 207 | if (gitToken) { 208 | // 存在token,就跳转到主页 209 | next() 210 | } else { 211 | //否则就继续 212 | next('/') 213 | } 214 | } 215 | }) 216 | 217 | export default router 218 | export { routes } 219 | -------------------------------------------------------------------------------- /src/stores/files.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | export const useFileStore = defineStore('fileStore', { 4 | state: () => { 5 | return { 6 | downNum: 0, 7 | downDone: 0, 8 | } 9 | }, 10 | getters: { 11 | downRate: (state) => { 12 | if (state.downDone === state.downNum) { 13 | return 100 14 | } else { 15 | return (state.downDone / state.downNum) * 100 16 | } 17 | }, 18 | }, 19 | actions: { 20 | setDownNum(num: number) { 21 | this.downNum = num 22 | }, 23 | setDownDone(num: number) { 24 | this.downDone = num 25 | if (this.downDone === this.downNum) { 26 | this.downDone = 0 27 | this.downNum = 0 28 | } 29 | }, 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /src/stores/user.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | export const useUserStore = defineStore('userInfo', { 4 | // 定义state 5 | state: () => { 6 | return { 7 | name: '', 8 | userName: localStorage.getItem('userName') || '', 9 | passWord: localStorage.getItem('passWord') || '', 10 | email: localStorage.getItem('email') || '', 11 | weixin: localStorage.getItem('weixin') || '', 12 | qq: localStorage.getItem('qq') || '', 13 | douyin: localStorage.getItem('douyin') || '', 14 | gitToken: localStorage.getItem('gitToken') || '', 15 | serverKey: localStorage.getItem('serverKey') || '', 16 | gitAvatar: 'https://avatars.githubusercontent.com/u/48399687?v=4', 17 | theme: localStorage.getItem('theme') || 'light', 18 | gitName: localStorage.getItem('gitName') || 'sjj1024', 19 | gitRepo: localStorage.getItem('gitRepo') || 'FileHub', 20 | gitBranch: localStorage.getItem('gitBranch') || 'main', 21 | apiLimit: localStorage.getItem('apiLimit') 22 | ? JSON.parse(localStorage.getItem('apiLimit')!) 23 | : { 24 | limit: 5000, 25 | used: 0, 26 | remaining: 5000, 27 | reset: 1687853989 28 | }, 29 | gitPath: 30 | localStorage.getItem('gitPath') || 31 | 'https://api.github.com/repos/Sjj1024/HelloMyPic/contents', 32 | fileCdn: 33 | localStorage.getItem('fileCdn') || 34 | 'https://jsd.cdn.zzko.cn/gh/sjj1024/FileHub@main', 35 | cdnLink: localStorage.getItem('cdnLink') || 'ChinaJsDelivr', 36 | gitIoCdn: 37 | localStorage.getItem('gitIoCdn') || 'https://sjj1024.github.io/FileHub', 38 | gitInfo: JSON.parse( 39 | localStorage.getItem('gitInfo') 40 | ? localStorage.getItem('gitInfo')! 41 | : '{}' 42 | ) 43 | } 44 | }, 45 | // 定义getters 46 | getters: { 47 | apiRate: (state) => (state.apiLimit.remaining / state.apiLimit.limit) * 100, 48 | threeAge: () => 6 49 | }, 50 | // 定义action 51 | actions: { 52 | setTheme(the: string) { 53 | this.theme = the 54 | localStorage.setItem('theme', the) 55 | }, 56 | setFileHub(repo: string, branch: string) { 57 | const fileCdn = localStorage.getItem('fileCdn') 58 | this.gitRepo = repo 59 | this.gitBranch = branch 60 | this.gitPath = `https://api.github.com/repos/${this.gitName}/${this.gitRepo}/contents` 61 | // 根据本地缓存获取链接规则 62 | this.fileCdn = fileCdn 63 | ? fileCdn 64 | : `https://jsd.cdn.zzko.cn/gh/${this.gitName}/${this.gitRepo}@${this.gitBranch}/` 65 | this.gitIoCdn = `https://${this.gitName}.github.io/${this.gitRepo}` 66 | this.gitIoCdn = `https://${this.gitName}.github.io/${this.gitRepo}` 67 | localStorage.setItem('gitRepo', this.gitRepo) 68 | localStorage.setItem('gitBranch', this.gitBranch) 69 | localStorage.setItem('gitPath', this.gitPath) 70 | localStorage.setItem('fileCdn', this.fileCdn) 71 | localStorage.setItem('gitIoCdn', this.gitIoCdn) 72 | }, 73 | setFileCdn(cdnPath: string) { 74 | this.fileCdn = cdnPath 75 | console.log('setFileCdn', cdnPath) 76 | localStorage.setItem('fileCdn', cdnPath) 77 | localStorage.setItem('cdnLink', this.cdnLink) 78 | }, 79 | setGitInfo(gitToken: string, gitInfo: any) { 80 | const fileCdn = localStorage.getItem('fileCdn') 81 | this.gitToken = gitToken 82 | this.gitInfo = gitInfo 83 | this.name = gitInfo.name 84 | this.gitName = gitInfo.login 85 | this.gitAvatar = gitInfo.avatar_url 86 | this.gitPath = `https://api.github.com/repos/${this.gitName}/${this.gitRepo}/contents` 87 | // 根据本地缓存获取链接规则 88 | this.fileCdn = fileCdn 89 | ? fileCdn 90 | : `https://jsd.cdn.zzko.cn/gh/${this.gitName}/${this.gitRepo}@${this.gitBranch}/` 91 | this.gitIoCdn = `https://${this.gitName}.github.io/${this.gitRepo}` 92 | localStorage.setItem('gitToken', gitToken) 93 | localStorage.setItem('gitInfo', JSON.stringify(gitInfo)) 94 | localStorage.setItem('gitAvatar', this.gitAvatar) 95 | localStorage.setItem('name', this.name) 96 | localStorage.setItem('gitName', this.gitName) 97 | localStorage.setItem('gitPath', this.gitPath) 98 | localStorage.setItem('fileCdn', this.fileCdn) 99 | localStorage.setItem('gitIoCdn', this.gitIoCdn) 100 | }, 101 | setUserInfo(setInfo: any) { 102 | this.userName = setInfo.userName 103 | this.passWord = setInfo.passWord 104 | this.gitToken = setInfo.token 105 | this.serverKey = setInfo.serverKey 106 | this.email = setInfo.email 107 | this.weixin = setInfo.weixin 108 | this.qq = setInfo.qq 109 | this.douyin = setInfo.douyin 110 | localStorage.setItem('userName', this.userName) 111 | localStorage.setItem('passWord', this.passWord) 112 | localStorage.setItem('gitToken', this.gitToken) 113 | localStorage.setItem('serverKey', this.serverKey) 114 | localStorage.setItem('email', this.email) 115 | localStorage.setItem('weixin', this.weixin) 116 | localStorage.setItem('qq', this.qq) 117 | localStorage.setItem('douyin', this.douyin) 118 | console.log('setUserInfo------', setInfo) 119 | }, 120 | setApiRate(apiInfo: any) { 121 | this.apiLimit = apiInfo 122 | localStorage.setItem('apiLimit', JSON.stringify(apiInfo)) 123 | } 124 | } 125 | }) 126 | -------------------------------------------------------------------------------- /src/style/index.scss: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | a { 8 | color: var(--el-text-color-regular); 9 | text-decoration: none; 10 | } 11 | 12 | body { 13 | overflow: hidden; 14 | } 15 | 16 | #app { 17 | height: 100vh; 18 | background-color: var(--bg-color); 19 | overflow: hidden; 20 | } 21 | 22 | .dplayer-full-in-icon { 23 | display: none !important; 24 | } 25 | 26 | .dplayer-menu { 27 | display: none !important; 28 | } 29 | 30 | #dplayer { 31 | width: 100%; 32 | height: 100%; 33 | } 34 | 35 | // 关闭按钮 36 | .titlebar-button { 37 | margin-left: 15px !important; 38 | display: inline-flex; 39 | justify-content: center; 40 | align-items: center; 41 | width: 30px; 42 | height: 30px; 43 | color: var(--el-button-text-color); 44 | 45 | &:hover { 46 | background-color: var(--el-fill-color-light) !important; 47 | } 48 | } 49 | 50 | #titlebar-close { 51 | &:hover { 52 | color: white; 53 | background-color: rgb(235, 32, 19) !important; 54 | } 55 | } 56 | 57 | a:hover { 58 | color: #409eff; 59 | } 60 | 61 | .confirm-btn { 62 | background-color: #409eff !important; 63 | border-color: unset; 64 | } 65 | 66 | .confirm-btn:focus-visible { 67 | outline: unset; 68 | } 69 | 70 | .confirm-btn:active { 71 | background-color: #337ecc !important; 72 | } 73 | 74 | .confirm-btn:hover { 75 | background-color: #79bbff !important; 76 | } 77 | 78 | .el-dialog__body { 79 | padding-top: 0; 80 | padding-bottom: 10px !important; 81 | } 82 | 83 | // 文件列表中的文件高度 84 | $file-height: 80px; 85 | // 文件图标宽高 86 | $pre-width: 80%; 87 | $pre-height: 80%; 88 | -------------------------------------------------------------------------------- /src/style/login.css: -------------------------------------------------------------------------------- 1 | *, *::after, *::before { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | user-select: none; 6 | } 7 | 8 | 9 | .container { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | /* position: absolute; */ 14 | top: 0; 15 | width: 100%; 16 | height: 100%; 17 | padding: 25px; 18 | background-color: var(--bg-color); 19 | /* background-color: #ecf0f3; */ 20 | transition: 1.25s; 21 | } 22 | 23 | .form { 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | flex-direction: column; 28 | width: 100%; 29 | height: 100%; 30 | } 31 | .form__icon { 32 | object-fit: contain; 33 | width: 30px; 34 | margin: 0 5px; 35 | opacity: 0.5; 36 | transition: 0.15s; 37 | } 38 | .form__icon:hover { 39 | opacity: 1; 40 | transition: 0.15s; 41 | cursor: pointer; 42 | } 43 | .form__input { 44 | width: 350px; 45 | height: 40px; 46 | margin: 4px 0; 47 | padding-left: 16px; 48 | font-size: 13px; 49 | letter-spacing: 0.15px; 50 | border: none; 51 | outline: none; 52 | color: var(--input-color); 53 | font-family: "Montserrat", sans-serif; 54 | background-color: #ecf0f3; 55 | transition: 0.25s ease; 56 | border-radius: 8px; 57 | box-shadow: inset 2px 2px 4px #d1d9e6, inset -2px -2px 4px #f9f9f9; 58 | } 59 | .form__input:focus { 60 | box-shadow: inset 4px 4px 4px #d1d9e6, inset -4px -4px 4px #f9f9f9; 61 | } 62 | .form__span { 63 | margin-top: 30px; 64 | margin-bottom: 12px; 65 | } 66 | .form__link { 67 | /* color: #181818; */ 68 | font-size: 15px; 69 | margin-top: 25px; 70 | border-bottom: 1px solid #a0a5a8; 71 | line-height: 2; 72 | cursor: pointer; 73 | text-decoration: none; 74 | } 75 | 76 | .title { 77 | font-size: 34px; 78 | font-weight: 700; 79 | line-height: 3; 80 | color: var(--text-color); 81 | } 82 | 83 | .description { 84 | font-size: 14px; 85 | letter-spacing: 0.25px; 86 | text-align: center; 87 | line-height: 1.6; 88 | } 89 | 90 | .button { 91 | width: 180px; 92 | height: 50px; 93 | border-radius: 25px; 94 | margin-top: 30px; 95 | font-weight: 700; 96 | font-size: 14px; 97 | letter-spacing: 1.15px; 98 | background-color: #4B70E2; 99 | color: #f9f9f9; 100 | box-shadow: var(--box-shadow); 101 | border: none; 102 | outline: none; 103 | } 104 | 105 | /**/ 106 | .a-container { 107 | z-index: 100; 108 | } 109 | 110 | .b-container { 111 | z-index: 0; 112 | } 113 | 114 | .switch { 115 | display: flex; 116 | justify-content: center; 117 | align-items: center; 118 | position: absolute; 119 | top: 0; 120 | left: 0; 121 | height: 100%; 122 | width: 400px; 123 | padding: 56px; 124 | z-index: 200; 125 | transition: 1.25s; 126 | background-color: #ecf0f3; 127 | overflow: hidden; 128 | box-shadow: 4px 4px 10px #d1d9e6, -4px -4px 10px #f9f9f9; 129 | } 130 | .switch__circle { 131 | position: absolute; 132 | width: 500px; 133 | height: 500px; 134 | border-radius: 50%; 135 | background-color: #ecf0f3; 136 | box-shadow: inset 8px 8px 12px #d1d9e6, inset -8px -8px 12px #f9f9f9; 137 | bottom: -60%; 138 | left: -60%; 139 | transition: 1.25s; 140 | } 141 | .switch__circle--t { 142 | top: -30%; 143 | left: 60%; 144 | width: 300px; 145 | height: 300px; 146 | } 147 | .switch__container { 148 | display: flex; 149 | justify-content: center; 150 | align-items: center; 151 | flex-direction: column; 152 | position: absolute; 153 | width: 400px; 154 | padding: 56px 55px; 155 | transition: 1.25s; 156 | } 157 | .switch__button { 158 | cursor: pointer; 159 | } 160 | .switch__button:hover { 161 | box-shadow: 6px 6px 10px #d1d9e6, -6px -6px 10px #f9f9f9; 162 | transform: scale(0.985); 163 | transition: 0.25s; 164 | } 165 | .switch__button:active, .switch__button:focus { 166 | box-shadow: 2px 2px 6px #d1d9e6, -2px -2px 6px #f9f9f9; 167 | transform: scale(0.97); 168 | transition: 0.25s; 169 | } 170 | 171 | /**/ 172 | .is-txr { 173 | left: calc(100% - 400px ); 174 | transition: 1.25s; 175 | transform-origin: left; 176 | } 177 | 178 | .is-txl { 179 | left: 0; 180 | transition: 1.25s; 181 | transform-origin: right; 182 | } 183 | 184 | .is-z200 { 185 | z-index: 200; 186 | transition: 1.25s; 187 | } 188 | 189 | .is-hidden { 190 | visibility: hidden; 191 | opacity: 0; 192 | position: absolute; 193 | transition: 1.25s; 194 | } 195 | 196 | .is-gx { 197 | animation: is-gx 1.25s; 198 | } 199 | 200 | @keyframes is-gx { 201 | 0%, 10%, 100% { 202 | width: 400px; 203 | } 204 | 30%, 50% { 205 | width: 500px; 206 | } 207 | } -------------------------------------------------------------------------------- /src/style/theme.css: -------------------------------------------------------------------------------- 1 | /* 默认dark主题 */ 2 | :root[theme='dark'] { 3 | --bg-color: #0d1117; 4 | --text-color: #f0f6fc; 5 | --box-shadow: unset; 6 | --input-color: black; 7 | --menu-ative-bg: rgba(201, 211, 225, 0.08); 8 | --scroll-thumb: rgba(255, 255, 255, 0.2); 9 | --scroll-track: rgba(251, 249, 249, 0.1); 10 | --api-process: #363637; 11 | --filt-item: rgba(201, 211, 225, 0.08); 12 | --selected-item: rgba(218, 223, 231, 0.247); 13 | --file-menu-color: #181818; 14 | --file-menu-hover: rgb(145, 145, 145); 15 | --file-loading-mask: #0d1117ba; 16 | --file-loading-hover: rgba(201, 211, 225, 0); 17 | --img-pre-btn-bg: rgb(31 45 61 / 11%); 18 | --img-pre-btn-bg-hover: rgb(31 45 61 / 33%); 19 | --gpt-message-bg-hover: rgba(201, 211, 225, 0.2); 20 | --gpt-me-message-bg: rgb(123, 194, 87); 21 | --gpt-me-message-bg-hover: rgb(134, 212, 95); 22 | } 23 | 24 | /* light主题 */ 25 | :root[theme='light'] { 26 | --bg-color: #fff; 27 | --text-color: #181818; 28 | --box-shadow: 8px 8px 16px #d1d9e6, -8px -8px 16px #f9f9f9; 29 | --input-color: #181818; 30 | --menu-ative-bg: rgba(9, 30, 66, 0.08); 31 | --scroll-thumb: rgba(0, 0, 0, 0.2); 32 | --scroll-track: rgba(0, 0, 0, 0.1); 33 | --api-process: #cdcdcd; 34 | --filt-item: #ecf5ff; 35 | --selected-item: #d4e7fd; 36 | --file-menu-color: #181818; 37 | --file-menu-hover: rgb(200, 200, 200); 38 | --file-loading-mask: #ecf5ff6a; 39 | --file-loading-hover: #ecf5ff3a; 40 | --img-pre-btn-bg: rgba(31, 45, 61, 0.11); 41 | --img-pre-btn-bg-hover: rgba(31, 45, 61, 0.53); 42 | --gpt-message-bg-hover: rgba(9, 30, 66, 0.15); 43 | --gpt-me-message-bg: rgb(149, 236, 105); 44 | --gpt-me-message-bg-hover: rgb(137, 217, 97); 45 | } 46 | -------------------------------------------------------------------------------- /src/utils/encode.ts: -------------------------------------------------------------------------------- 1 | import { privateKey, publickKey } from '@/config' 2 | import JSEncrypt from 'jsencrypt' 3 | 4 | export const rsaEncode = (content: string) => { 5 | var encrypt = new JSEncrypt() 6 | encrypt.setPublicKey(publickKey) 7 | return encrypt.encrypt(content) as string 8 | } 9 | 10 | export const rsaDecode = (content: string) => { 11 | const decrypt = new JSEncrypt() 12 | decrypt.setPrivateKey(privateKey) 13 | return decrypt.decrypt(content) as string 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | function timestampToTime(timestamp: number) { 2 | // 时间戳为10位需*1000,时间戳为13位不需乘1000 3 | var date = new Date(timestamp * 1000) 4 | var Y = date.getFullYear() + '-' 5 | var M = 6 | (date.getMonth() + 1 < 10 7 | ? '0' + (date.getMonth() + 1) 8 | : date.getMonth() + 1) + '-' 9 | var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ' 10 | var h = date.getHours() + ':' 11 | var m = date.getMinutes() + ':' 12 | var s = date.getSeconds() 13 | return Y + M + D + h + m + s 14 | } 15 | 16 | export { 17 | timestampToTime, 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/request.ts: -------------------------------------------------------------------------------- 1 | import { HttpVerb, fetch } from '@tauri-apps/api/http' 2 | import { useUserStore } from '@/stores/user' 3 | import { Body } from '@tauri-apps/api/http' 4 | 5 | const server = 'https://api.github.com' 6 | const baseURL = `${server}` 7 | const userStore = useUserStore() 8 | 9 | const BODY_TYPE = { 10 | Form: 'Form', 11 | Json: 'Json', 12 | Text: 'Text', 13 | Bytes: 'Bytes', 14 | } 15 | 16 | const commonOptions = { 17 | timeout: 60, 18 | } 19 | 20 | const isAbsoluteURL = (url: string): boolean => { 21 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) 22 | } 23 | 24 | const combineURLs = (baseURL: string, relativeURL: string): string => { 25 | return relativeURL 26 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') 27 | : baseURL 28 | } 29 | 30 | const buildFullPath = (baseURL: string, requestedURL: string) => { 31 | if (baseURL && !isAbsoluteURL(requestedURL)) { 32 | return combineURLs(baseURL, requestedURL) 33 | } 34 | return requestedURL 35 | } 36 | 37 | // 重新获取API接口速率 38 | export const getApiLimit = () => { 39 | let payload = { 40 | method: 'GET' as HttpVerb, 41 | headers: { 42 | Authorization: userStore.gitToken!, 43 | }, 44 | } 45 | fetch('https://api.github.com/rate_limit', payload) 46 | .then(({ status, data }) => { 47 | if (status >= 200 && status < 500) { 48 | console.log('apilimit---', data) 49 | userStore.setApiRate((data as any).rate) 50 | } 51 | }) 52 | .catch((err) => { 53 | console.error('apilimiterr-------', err) 54 | }) 55 | } 56 | 57 | const http = async (url: string, options: any = {}) => { 58 | if (!options.headers) 59 | options.headers = { 60 | Authorization: userStore.gitToken, 61 | } 62 | if (options?.body) { 63 | options.body = Body.json(options.body) 64 | if (options.body.type === BODY_TYPE.Form) { 65 | options.headers['Content-Type'] = 'multipart/form-data' 66 | } 67 | } 68 | options = { ...commonOptions, ...options } 69 | console.log('request-------', buildFullPath(baseURL, url), options) 70 | return fetch(buildFullPath(baseURL, url), options) 71 | .then(({ status, data }) => { 72 | if (status >= 200 && status < 500) { 73 | return { status, data } 74 | } 75 | return Promise.reject({ status, data }) 76 | }) 77 | .catch((err) => { 78 | console.error(err) 79 | return Promise.reject(err) 80 | }) 81 | .finally(() => { 82 | // 发送接口速率 83 | getApiLimit() 84 | }) 85 | } 86 | 87 | export default http 88 | -------------------------------------------------------------------------------- /src/utils/update.ts: -------------------------------------------------------------------------------- 1 | import { 2 | checkUpdate, 3 | installUpdate, 4 | onUpdaterEvent, 5 | } from '@tauri-apps/api/updater' 6 | import { relaunch } from '@tauri-apps/api/process' 7 | import { confirm } from '@tauri-apps/api/dialog' 8 | 9 | onUpdaterEvent(({ error, status }) => { 10 | // This will log all updater events, including status updates and errors. 11 | console.log('Updater event', error, status) 12 | }).then((res) => { 13 | console.log('onUpdaterEvent-', res) 14 | }) 15 | 16 | try { 17 | checkUpdate() 18 | .then(async ({ shouldUpdate, manifest }) => { 19 | if (shouldUpdate) { 20 | // You could show a dialog asking the user if they want to install the update here. 21 | console.log( 22 | `Installing update ${manifest?.version}, ${manifest?.date}, ${manifest?.body}` 23 | ) 24 | const confirmed = await confirm( 25 | `FileHub有新版本V${manifest?.version}可用,\n${manifest?.body},\n立即更新?`, 26 | 'FileHub更新提醒' 27 | ) 28 | console.log('configrmed--', confirmed, manifest) 29 | if (confirmed) { 30 | // Install the update. This will also restart the app on Windows! 31 | await installUpdate() 32 | // On macOS and Linux you will need to restart the app manually. 33 | // You could use this step to display another confirmation dialog. 34 | await relaunch() 35 | } 36 | } 37 | }) 38 | .catch((err) => { 39 | console.log('检查升级错误:', err) 40 | }) 41 | } catch (error) { 42 | console.error(error) 43 | } 44 | 45 | // you need to call unlisten if your handler goes out of scope, for example if the component is unmounted. 46 | // unlisten() 47 | -------------------------------------------------------------------------------- /src/utils/useTypes.ts: -------------------------------------------------------------------------------- 1 | interface fileRes { 2 | name: string 3 | path: string 4 | type: string 5 | size: string 6 | sha: string 7 | openLink: string 8 | downLink: string 9 | htmlLink: string 10 | creatTime: string 11 | selected: boolean 12 | showTips: boolean 13 | uploading: boolean 14 | } 15 | 16 | 17 | export type { 18 | fileRes 19 | } -------------------------------------------------------------------------------- /src/views/analysis/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/views/article/component/note.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 45 | 46 | -------------------------------------------------------------------------------- /src/views/article/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/views/category/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/views/chatgpt/index.vue: -------------------------------------------------------------------------------- 1 | 234 | 235 | 264 | 265 | 292 | 293 | -------------------------------------------------------------------------------- /src/views/help/index.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 80 | 81 | -------------------------------------------------------------------------------- /src/views/login/index.vue: -------------------------------------------------------------------------------- 1 | 107 | 108 | 381 | 382 | 416 | -------------------------------------------------------------------------------- /src/views/publish/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/views/setting/component/base.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 170 | 171 | -------------------------------------------------------------------------------- /src/views/setting/component/chatset.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /src/views/setting/component/image.vue: -------------------------------------------------------------------------------- 1 | 94 | 95 | 180 | 181 | -------------------------------------------------------------------------------- /src/views/setting/component/user.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 101 | 102 | -------------------------------------------------------------------------------- /src/views/setting/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /src/views/theme/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/views/tools/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /src/views/web/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/views/webSet/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue' 5 | const component: DefineComponent<{}, {}, any> 6 | export default component 7 | } 8 | 9 | declare module 'dplayer' { 10 | import type { DefineComponent } from 'vue' 11 | const component: DefineComponent<{}, {}, any> 12 | export default component 13 | } 14 | 15 | declare module 'element-plus/dist/locale/zh-cn' { 16 | import type { Language } from 'vue' 17 | const component: Language<{}, {}, any> 18 | export default component 19 | } 20 | 21 | // declare module 'webtorrent' { 22 | // import type { DefineComponent } from "vue"; 23 | // const component: DefineComponent<{}, {}, any>; 24 | // export default component; 25 | // } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "types": ["element-plus/global"], 10 | "sourceMap": true, 11 | "noImplicitAny": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "esModuleInterop": true, 15 | "lib": ["ESNext", "DOM"], 16 | "skipLibCheck": true, 17 | "baseUrl": "./", 18 | "paths": { 19 | "@": ["src"], 20 | "@/*": ["src/*"] 21 | } 22 | }, 23 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import { fileURLToPath, URL } from 'node:url' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig(async () => ({ 7 | plugins: [vue()], 8 | resolve: { 9 | alias: { 10 | '@': fileURLToPath(new URL('./src', import.meta.url)) 11 | } 12 | }, 13 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 14 | // prevent vite from obscuring rust errors 15 | clearScreen: false, 16 | // tauri expects a fixed port, fail if that port is not available 17 | server: { 18 | port: 1420, 19 | strictPort: true, 20 | }, 21 | // to make use of `TAURI_DEBUG` and other env variables 22 | // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand 23 | envPrefix: ["VITE_", "TAURI_"], 24 | build: { 25 | // Tauri supports es2021 26 | target: "esnext", 27 | // don't minify for debug builds 28 | minify: !process.env.TAURI_DEBUG ? "esbuild" : false, 29 | // produce sourcemaps for debug builds 30 | sourcemap: !!process.env.TAURI_DEBUG, 31 | }, 32 | })); 33 | --------------------------------------------------------------------------------