diff --git a/.env.development b/.env.development index 7dd8fec..b57434a 100644 --- a/.env.development +++ b/.env.development @@ -22,13 +22,5 @@ VITE_BASE_API_RETRY=5 # 失败重试时间 VITE_BASE_API_RETRY_DELAY=3000 -# 是否在打包时使用cdn替换本地库 替换 true 不替换 false -VITE_CDN=false - -# 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件) -# 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) -# 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) -VITE_COMPRESSION="none" - # 开发环境读取配置文件路径 VITE_PUBLIC_PATH=/ diff --git a/.env.production b/.env.production index d4bf382..5abfbd1 100644 --- a/.env.production +++ b/.env.production @@ -7,9 +7,6 @@ VITE_ROUTER_HISTORY="hash" # 基础请求路径 VITE_BASE_API=/admin -# 跨域代理地址 -VITE_APP_URL=http://localhost:8000 - # mock地址 VITE_MOCK_BASE_API=/mock diff --git a/ReadMe.md b/ReadMe.md index 344f007..a0f32e6 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -8,8 +8,6 @@ Pure-admin文档:https://pure-admin.github.io/pure-admin-doc # 项目预览 -不知道为什么,图床用的使自己的,Gitee就是不显示其它GitHub和Gitea都能显示就Gitee显示不出来,如果想用Gitee就把ReadMe文件下载下来也行;或者把项目clone下来看也可以 - **线上地址** - 正式线上预览地址:http://bunny-web.site/#/welcome @@ -19,6 +17,10 @@ Pure-admin文档:https://pure-admin.github.io/pure-admin-doc - 测试预览地址:http://106.15.251.123/#/welcome - 服务器到期时间:12月30日 +**打包视频** + +https://www.bilibili.com/video/BV1AYm8YSEKY/ + **Github地址** - [前端地址](https://github.com/BunnyMaster/bunny-admin-web.git) diff --git a/build/compress.ts b/build/compress.ts index 6178986..323a702 100644 --- a/build/compress.ts +++ b/build/compress.ts @@ -1,63 +1,57 @@ -import type { Plugin } from "vite"; -import { isArray } from "@pureadmin/utils"; -import compressPlugin from "vite-plugin-compression"; +import type { Plugin } from 'vite'; +import { isArray } from '@pureadmin/utils'; +import compressPlugin from 'vite-plugin-compression'; -export const configCompressPlugin = ( - compress: ViteCompression -): Plugin | Plugin[] => { - if (compress === "none") return null; +export const configCompressPlugin = (compress: ViteCompression): Plugin | Plugin[] => { + if (compress === 'none') return null; - const gz = { - // 生成的压缩包后缀 - ext: ".gz", - // 体积大于threshold才会被压缩 - threshold: 0, - // 默认压缩.js|mjs|json|css|html后缀文件,设置成true,压缩全部文件 - filter: () => true, - // 压缩后是否删除原始文件 - deleteOriginFile: false - }; - const br = { - ext: ".br", - algorithm: "brotliCompress", - threshold: 0, - filter: () => true, - deleteOriginFile: false - }; + const gz = { + // 生成的压缩包后缀 + ext: '.gz', + // 体积大于threshold才会被压缩 + threshold: 0, + // 默认压缩.js|mjs|json|css|html后缀文件,设置成true,压缩全部文件 + filter: () => true, + // 压缩后是否删除原始文件 + deleteOriginFile: false, + }; + const br = { + ext: '.br', + algorithm: 'brotliCompress', + threshold: 0, + filter: () => true, + deleteOriginFile: false, + }; - const codeList = [ - { k: "gzip", v: gz }, - { k: "brotli", v: br }, - { k: "both", v: [gz, br] } - ]; + const codeList = [ + { k: 'gzip', v: gz }, + { k: 'brotli', v: br }, + { k: 'both', v: [gz, br] }, + ]; - const plugins: Plugin[] = []; + const plugins: Plugin[] = []; - codeList.forEach(item => { - if (compress.includes(item.k)) { - if (compress.includes("clear")) { - if (isArray(item.v)) { - item.v.forEach(vItem => { - plugins.push( - compressPlugin(Object.assign(vItem, { deleteOriginFile: true })) - ); - }); - } else { - plugins.push( - compressPlugin(Object.assign(item.v, { deleteOriginFile: true })) - ); - } - } else { - if (isArray(item.v)) { - item.v.forEach(vItem => { - plugins.push(compressPlugin(vItem)); - }); - } else { - plugins.push(compressPlugin(item.v)); - } - } - } - }); + codeList.forEach(item => { + if (compress.includes(item.k)) { + if (compress.includes('clear')) { + if (isArray(item.v)) { + item.v.forEach(vItem => { + plugins.push(compressPlugin(Object.assign(vItem, { deleteOriginFile: true }))); + }); + } else { + plugins.push(compressPlugin(Object.assign(item.v, { deleteOriginFile: true }))); + } + } else { + if (isArray(item.v)) { + item.v.forEach(vItem => { + plugins.push(compressPlugin(vItem)); + }); + } else { + plugins.push(compressPlugin(item.v)); + } + } + } + }); - return plugins; + return plugins; }; diff --git a/build/info.ts b/build/info.ts index 3c0a235..a1cd3b2 100644 --- a/build/info.ts +++ b/build/info.ts @@ -1,62 +1,53 @@ -import type { Plugin } from "vite"; -import { getPackageSize } from "./utils"; -import dayjs, { type Dayjs } from "dayjs"; -import duration from "dayjs/plugin/duration"; -import gradientString from "gradient-string"; -import boxen, { type Options as BoxenOptions } from "boxen"; +import type { Plugin } from 'vite'; +import { getPackageSize } from './utils'; +import dayjs, { type Dayjs } from 'dayjs'; +import duration from 'dayjs/plugin/duration'; +import gradientString from 'gradient-string'; +import boxen, { type Options as BoxenOptions } from 'boxen'; dayjs.extend(duration); const welcomeMessage = (VITE_PORT: number) => { - return gradientString("cyan", "magenta").multiline( - `您好! 欢迎使用 bunny 系列开发模板 + return gradientString('cyan', 'magenta').multiline( + `您好! 欢迎使用 bunny 系列开发模板 项目访问地址如下: -http://localhost:${VITE_PORT}` - ); +http://localhost:${VITE_PORT}`, + ); }; const boxenOptions: BoxenOptions = { - padding: 0.5, - borderColor: "cyan", - borderStyle: "round" + padding: 0.5, + borderColor: 'cyan', + borderStyle: 'round', }; export function viteBuildInfo(VITE_PORT: number): Plugin { - let config: { command: string }; - let startTime: Dayjs; - let endTime: Dayjs; - let outDir: string; - return { - name: "vite:buildInfo", - configResolved(resolvedConfig) { - config = resolvedConfig; - outDir = resolvedConfig.build?.outDir ?? "dist"; - }, - buildStart() { - console.log(boxen(welcomeMessage(VITE_PORT), boxenOptions)); - if (config.command === "build") { - startTime = dayjs(new Date()); - } - }, - closeBundle() { - if (config.command === "build") { - endTime = dayjs(new Date()); - getPackageSize({ - folder: outDir, - callback: (size: string) => { - console.log( - boxen( - gradientString("cyan", "magenta").multiline( - `🎉 恭喜打包完成(总用时${dayjs - .duration(endTime.diff(startTime)) - .format("mm分ss秒")},打包后的大小为${size})` - ), - boxenOptions - ) - ); - } - }); - } - } - }; + let config: { command: string }; + let startTime: Dayjs; + let endTime: Dayjs; + let outDir: string; + return { + name: 'vite:buildInfo', + configResolved(resolvedConfig) { + config = resolvedConfig; + outDir = resolvedConfig.build?.outDir ?? 'dist'; + }, + buildStart() { + console.log(boxen(welcomeMessage(VITE_PORT), boxenOptions)); + if (config.command === 'build') { + startTime = dayjs(new Date()); + } + }, + closeBundle() { + if (config.command === 'build') { + endTime = dayjs(new Date()); + getPackageSize({ + folder: outDir, + callback: (size: string) => { + console.log(boxen(gradientString('cyan', 'magenta').multiline(`🎉 恭喜打包完成(总用时${dayjs.duration(endTime.diff(startTime)).format('mm分ss秒')},打包后的大小为${size})`), boxenOptions)); + }, + }); + } + }, + }; } diff --git a/build/optimize.ts b/build/optimize.ts index 5f59491..0cb1921 100644 --- a/build/optimize.ts +++ b/build/optimize.ts @@ -4,31 +4,12 @@ * 尤其当您禁用浏览器缓存时(这种情况只应该发生在调试阶段)必须将对应模块加入到 include里,否则会遇到开发环境切换页面卡顿的问题(vite 会认为它是一个新的依赖包会重新加载并强制刷新页面),因为它既无法使用浏览器缓存,又没有在本地 node_modules/.vite 里缓存 * 温馨提示:如果您使用的第三方库是全局引入,也就是引入到 src/main.ts 文件里,就不需要再添加到 include 里了,因为 vite 会自动将它们缓存到 node_modules/.vite */ -const include = [ - "qs", - "mitt", - "dayjs", - "axios", - "pinia", - "vue-i18n", - "vue-types", - "js-cookie", - "vue-tippy", - "pinyin-pro", - "sortablejs", - "@vueuse/core", - "@pureadmin/utils", - "responsive-storage" -]; +const include = ['qs', 'mitt', 'dayjs', 'axios', 'pinia', 'vue-i18n', 'vue-types', 'js-cookie', 'vue-tippy', 'pinyin-pro', 'sortablejs', '@vueuse/core', '@pureadmin/utils', 'responsive-storage']; /** * 在预构建中强制排除的依赖项 * 温馨提示:所有以 `@iconify-icons/` 开头引入的的本地图标模块,都应该加入到下面的 `exclude` 里,因为平台推荐的使用方式是哪里需要哪里引入而且都是单个的引入,不需要预构建,直接让浏览器加载就好 */ -const exclude = [ - "@iconify-icons/ep", - "@iconify-icons/ri", - "@pureadmin/theme/dist/browser-utils" -]; +const exclude = ['@iconify-icons/ep', '@iconify-icons/ri', '@pureadmin/theme/dist/browser-utils']; export { include, exclude }; diff --git a/docker/Dockerfile b/docker/Dockerfile index 349fcba..0461d86 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,10 +6,10 @@ RUN rm /etc/nginx/conf.d/default.conf # 将自定义的 Nginx 配置文件复制到容器中 COPY nginx.conf /etc/nginx/conf.d/default.conf -#COPY bunny-web.site.csr /etc/nginx/bunny-web.site.csr -#COPY bunny-web.site.key /etc/nginx/bunny-web.site.key -#COPY bunny-web.site_bundle.crt /etc/nginx/bunny-web.site_bundle.crt -#COPY bunny-web.site_bundle.pem /etc/nginx/bunny-web.site_bundle.pem +COPY bunny-web.site.csr /etc/nginx/bunny-web.site.csr +COPY bunny-web.site.key /etc/nginx/bunny-web.site.key +COPY bunny-web.site_bundle.crt /etc/nginx/bunny-web.site_bundle.crt +COPY bunny-web.site_bundle.pem /etc/nginx/bunny-web.site_bundle.pem # 设置时区,构建镜像时执行的命令 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime @@ -25,6 +25,7 @@ COPY dist/ /etc/nginx/html # 暴露 Nginx 的默认端口 EXPOSE 80 +EXPOSE 443 # 自动启动 Nginx CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/nginx.conf b/docker/nginx.conf index fca77a4..05490e0 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -3,10 +3,59 @@ map $http_upgrade $connection_upgrade { '' close; } +server { + #SSL 默认访问端口号为 443 + listen 443 ssl; + #请填写绑定证书的域名 + server_name localhost; + #请填写证书文件的相对路径或绝对路径 + ssl_certificate bunny-web.site_bundle.crt; + #请填写私钥文件的相对路径或绝对路径 + ssl_certificate_key bunny-web.site.key; + ssl_session_timeout 5m; + #请按照以下协议配置 + ssl_protocols TLSv1.2 TLSv1.3; + #请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。 + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; + ssl_prefer_server_ciphers on; + + location / { + root /etc/nginx/html; + index index.html index.htm; + try_files $uri /index.html; + } + + # 后端跨域请求 + location ~/admin/ { + proxy_pass http://172.17.0.1:8000; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # 后端跨域请求 + location ~/api/v1/ { + proxy_pass http://129.211.31.58:3000; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect http:// https://; + } + + error_page 404 404.html; + + location = /50x.html { + root html; + } + } + server { listen 80 ; listen [::]:80; server_name localhost; + return 301 https://$host$request_uri; location / { root /etc/nginx/html; diff --git a/index.html b/index.html index 8380b7a..b99c065 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ 如果遇到http和https混用问题,可以使将全部的htp都转成https 但是如果都不支持 如果对方服务器可以支持https可以试下这个方案 如果不支持需要修改代码,将请求修改成/api/xxx的形式之后使用NGINX做反向代理 - --> +--> bunny-admin diff --git a/public/logo.svg b/public/logo.svg deleted file mode 100644 index a63d2b1..0000000 --- a/public/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/layout/components/lay-footer/index.vue b/src/layout/components/lay-footer/index.vue index 1c748ac..70e0985 100644 --- a/src/layout/components/lay-footer/index.vue +++ b/src/layout/components/lay-footer/index.vue @@ -9,7 +9,6 @@ const Copyright = getConfig('Copyright'); diff --git a/src/style/login.css b/src/style/login.css index 3e0a8ab..da9fe82 100644 --- a/src/style/login.css +++ b/src/style/login.css @@ -1,96 +1,96 @@ .wave { - position: fixed; - height: 100%; - width: 80%; - left: 0; - bottom: 0; - z-index: -1; + position: fixed; + height: 100%; + width: 80%; + left: 0; + bottom: 0; + z-index: -1; } .login-container { - width: 100vw; - height: 100vh; - max-width: 100%; - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-gap: 18rem; - padding: 0 2rem; + width: 100vw; + height: 100vh; + max-width: 100%; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-gap: 18rem; + padding: 0 2rem; } .img { - display: flex; - justify-content: flex-end; - align-items: center; + display: flex; + justify-content: flex-end; + align-items: center; } .img img { - width: 500px; + width: 500px; } .login-box { - display: flex; - align-items: center; - text-align: center; - overflow: hidden; + display: flex; + align-items: center; + text-align: center; + overflow: hidden; } .login-form { - width: 360px; + width: 360px; } .avatar { - width: 350px; - height: 80px; + width: 80px; + height: 80px; } .login-form h2 { - text-transform: uppercase; - margin: 15px 0; - color: #999; - font: - bold 200% Consolas, - Monaco, - monospace; + text-transform: uppercase; + margin: 15px 0; + color: #999; + font: + bold 200% Consolas, + Monaco, + monospace; } @media screen and (max-width: 1180px) { - .login-container { - grid-gap: 9rem; - } + .login-container { + grid-gap: 9rem; + } - .login-form { - width: 290px; - } + .login-form { + width: 290px; + } - .login-form h2 { - font-size: 2.4rem; - margin: 8px 0; - } + .login-form h2 { + font-size: 2.4rem; + margin: 8px 0; + } - .img img { - width: 360px; - } + .img img { + width: 360px; + } - .avatar { - width: 280px; - height: 80px; - } + .avatar { + width: 280px; + height: 80px; + } } @media screen and (max-width: 968px) { - .wave { - display: none; - } + .wave { + display: none; + } - .img { - display: none; - } + .img { + display: none; + } - .login-container { - grid-template-columns: 1fr; - } + .login-container { + grid-template-columns: 1fr; + } - .login-box { - justify-content: center; - } + .login-box { + justify-content: center; + } } diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 19c4730..2b20afa 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -3,7 +3,6 @@ import Motion from './utils/motion'; import { useNav } from '@/layout/hooks/useNav'; import { useLayout } from '@/layout/hooks/useLayout'; import bg from '@/assets/login/bg.png'; -import avatar from '@/assets/login/avatar.svg?component'; import illustration from '@/assets/login/illustration.svg?component'; import { onMounted, toRaw } from 'vue'; import { useTranslationLang } from '@/layout/hooks/useTranslationLang'; @@ -65,7 +64,7 @@ onMounted(() => {
- + logo

{{ title }}

@@ -77,10 +76,6 @@ onMounted(() => {
- -