fixbug: 🐛 用户页面显示ip内容,登录页面修改,NGINX配置修改

This commit is contained in:
bunny 2024-10-15 15:24:52 +08:00
parent 24e2990da9
commit f1e88d4e6b
13 changed files with 203 additions and 217 deletions

View File

@ -5,7 +5,7 @@ VITE_PORT=7000
VITE_ROUTER_HISTORY="hash"
# 基础请求路径
VITE_BASE_API=/api
VITE_BASE_API=/admin
# 跨域代理地址
VITE_APP_URL=http://localhost:7070

3
ReadMe.md Normal file
View File

@ -0,0 +1,3 @@
# Docker配置详情
![img.png](images/img.png)

View File

@ -1,52 +1,52 @@
import { pathResolve } from "./utils";
import type { BuildOptions } from "vite";
import { pathResolve } from './utils';
import type { BuildOptions } from 'vite';
export const buildEnvironment = () => {
const environment: BuildOptions = {
target: "es2015",
assetsInlineLimit: 20000,
// 构建输出的目录,默认值为"dist"
outDir: "dist",
// 用于指定使用的代码压缩工具。在这里minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser
// esbuild 打包更快,但是不能去除 console.logterser打包慢但能去除 console.log
minify: "terser",
// 用于配置 Terser 的选项
terserOptions: {
// 用于配置压缩选项
compress: {
drop_console: true, // 是否删除代码中的 console 语句, 默认值false
drop_debugger: true // 是否删除代码中的 debugger 语句, 默认值false
}
},
// 禁用 gzip 压缩大小报告,可略微减少打包时间
reportCompressedSize: false,
// 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时构建过程不会生成源映射文件
sourcemap: false,
// 用于配置 CommonJS 模块的选项
commonjsOptions: {
// 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时构建过程会保留 CommonJS 模块中的 try-catch 语句
ignoreTryCatch: false
},
// 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时Vite 会发出警告
chunkSizeWarningLimit: 2000,
rollupOptions: {
input: {
index: pathResolve("../index.html", import.meta.url)
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]",
manualChunks: id => {
// 如果是包含在包中则打包成 vendor
if (id.includes("node_modules")) {
return "vendor";
}
}
}
}
};
const environment: BuildOptions = {
target: 'es2015',
assetsInlineLimit: 20000,
// 构建输出的目录,默认值为"dist"
outDir: 'docker/dist',
// 用于指定使用的代码压缩工具。在这里minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser
// esbuild 打包更快,但是不能去除 console.logterser打包慢但能去除 console.log
minify: 'terser',
// 用于配置 Terser 的选项
terserOptions: {
// 用于配置压缩选项
compress: {
drop_console: true, // 是否删除代码中的 console 语句, 默认值false
drop_debugger: true, // 是否删除代码中的 debugger 语句, 默认值false
},
},
// 禁用 gzip 压缩大小报告,可略微减少打包时间
reportCompressedSize: false,
// 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时构建过程不会生成源映射文件
sourcemap: false,
// 用于配置 CommonJS 模块的选项
commonjsOptions: {
// 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时构建过程会保留 CommonJS 模块中的 try-catch 语句
ignoreTryCatch: false,
},
// 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时Vite 会发出警告
chunkSizeWarningLimit: 2000,
rollupOptions: {
input: {
index: pathResolve('../index.html', import.meta.url),
},
// 静态资源分类打包
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks: id => {
// 如果是包含在包中则打包成 vendor
if (id.includes('node_modules')) {
return 'vendor';
}
},
},
},
};
return environment;
return environment;
};

View File

@ -1,66 +1,60 @@
import { cdn } from "./cdn";
import vue from "@vitejs/plugin-vue";
import { pathResolve } from "./utils";
import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader";
import type { PluginOption } from "vite";
import vueJsx from "@vitejs/plugin-vue-jsx";
import Inspector from "vite-plugin-vue-inspector";
import { configCompressPlugin } from "./compress";
import removeNoMatch from "vite-plugin-router-warn";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import { themePreprocessorPlugin } from "@pureadmin/theme";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme";
import { vitePluginFakeServer } from "vite-plugin-fake-server";
import { cdn } from './cdn';
import vue from '@vitejs/plugin-vue';
import { pathResolve } from './utils';
import { viteBuildInfo } from './info';
import svgLoader from 'vite-svg-loader';
import type { PluginOption } from 'vite';
import vueJsx from '@vitejs/plugin-vue-jsx';
import Inspector from 'vite-plugin-vue-inspector';
import { configCompressPlugin } from './compress';
import removeNoMatch from 'vite-plugin-router-warn';
import { visualizer } from 'rollup-plugin-visualizer';
import removeConsole from 'vite-plugin-remove-console';
import { themePreprocessorPlugin } from '@pureadmin/theme';
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
import { genScssMultipleScopeVars } from '../src/layout/theme';
import { vitePluginFakeServer } from 'vite-plugin-fake-server';
export function getPluginsList(
VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression,
VITE_PORT: number
): PluginOption[] {
const lifecycle = process.env.npm_lifecycle_event;
return [
vue(),
// jsx、tsx语法支持
vueJsx(),
VueI18nPlugin({
jitCompilation: false,
include: [pathResolve("../locales/**")]
}),
// 按下Command(⌘)+Shift(⇧)然后点击页面元素会自动打开本地IDE并跳转到对应的代码位置
Inspector(),
viteBuildInfo(VITE_PORT),
/**
* vue-router动态路由警告No match found for location with path
* https://github.com/vuejs/router/issues/521 和 https://github.com/vuejs/router/issues/359
* vite-plugin-router-warn只在开发环境下启用vue-router文件并且只在服务启动或重启时运行一次
*/
removeNoMatch(),
// mock支持
vitePluginFakeServer({
logger: false,
include: "mock",
infixName: false,
enableProd: true
}),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: genScssMultipleScopeVars(),
extract: true
}
}),
// svg组件化支持
svgLoader(),
VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION),
// 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })
: (null as any)
];
export function getPluginsList(VITE_CDN: boolean, VITE_COMPRESSION: ViteCompression, VITE_PORT: number): PluginOption[] {
const lifecycle = process.env.npm_lifecycle_event;
return [
vue(),
// jsx、tsx语法支持
vueJsx(),
VueI18nPlugin({
jitCompilation: false,
include: [pathResolve('../locales/**')],
}),
// 按下Command(⌘)+Shift(⇧)然后点击页面元素会自动打开本地IDE并跳转到对应的代码位置
Inspector(),
viteBuildInfo(VITE_PORT),
/**
* vue-router动态路由警告No match found for location with path
* https://github.com/vuejs/router/issues/521 和 https://github.com/vuejs/router/issues/359
* vite-plugin-router-warn只在开发环境下启用vue-router文件并且只在服务启动或重启时运行一次
*/
removeNoMatch(),
// mock支持
vitePluginFakeServer({
logger: false,
include: 'mock',
infixName: false,
enableProd: true,
}),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: genScssMultipleScopeVars(),
extract: true,
},
}),
// svg组件化支持
svgLoader(),
VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION),
// 线上环境删除console
removeConsole({ external: ['src/assets/iconfont/iconfont.js'] }),
// 打包分析
lifecycle === 'report' ? visualizer({ open: true, brotliSize: true, filename: 'report.html' }) : (null as any),
];
}

View File

@ -1,15 +1,9 @@
import dayjs from "dayjs";
import { readdir, stat } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import { formatBytes, sum } from "@pureadmin/utils";
import {
dependencies,
devDependencies,
engines,
name,
version
} from "../package.json";
import dayjs from 'dayjs';
import { readdir, stat } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
import { formatBytes, sum } from '@pureadmin/utils';
import { dependencies, devDependencies, engines, name, version } from '../package.json';
/** 启动`node`进程时所在工作目录的绝对路径 */
const root: string = process.cwd();
@ -19,93 +13,91 @@ const root: string = process.cwd();
* @param dir `build`
* @param metaUrl `url``build``import.meta.url`
*/
const pathResolve = (dir = ".", metaUrl = import.meta.url) => {
// 当前文件目录的绝对路径
const currentFileDir = dirname(fileURLToPath(metaUrl));
// build 目录的绝对路径
const buildDir = resolve(currentFileDir, "build");
// 解析的绝对路径
const resolvedPath = resolve(currentFileDir, dir);
// 检查解析的绝对路径是否在 build 目录内
if (resolvedPath.startsWith(buildDir)) {
// 在 build 目录内,返回当前文件路径
return fileURLToPath(metaUrl);
}
// 不在 build 目录内,返回解析后的绝对路径
return resolvedPath;
const pathResolve = (dir = '.', metaUrl = import.meta.url) => {
// 当前文件目录的绝对路径
const currentFileDir = dirname(fileURLToPath(metaUrl));
// build 目录的绝对路径
const buildDir = resolve(currentFileDir, 'build');
// 解析的绝对路径
const resolvedPath = resolve(currentFileDir, dir);
// 检查解析的绝对路径是否在 build 目录内
if (resolvedPath.startsWith(buildDir)) {
// 在 build 目录内,返回当前文件路径
return fileURLToPath(metaUrl);
}
// 不在 build 目录内,返回解析后的绝对路径
return resolvedPath;
};
/** 设置别名 */
const alias: Record<string, string> = {
"@": pathResolve("../src"),
"@build": pathResolve()
'@': pathResolve('../src'),
'@build': pathResolve(),
};
/** 平台的名称、版本、运行所需的`node`和`pnpm`版本、依赖、最后构建时间的类型提示 */
const __APP_INFO__ = {
pkg: { name, version, engines, dependencies, devDependencies },
lastBuildTime: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss")
pkg: { name, version, engines, dependencies, devDependencies },
lastBuildTime: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'),
};
/** 处理环境变量 */
const wrapperEnv = (envConf: Recordable): ViteEnv => {
// 默认值
const ret: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_ROUTER_HISTORY: "",
VITE_APP_URL: "",
VITE_CDN: false,
VITE_HIDE_HOME: "false",
VITE_COMPRESSION: "none"
};
// 默认值
const ret: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: '',
VITE_ROUTER_HISTORY: '',
VITE_APP_URL: '',
VITE_CDN: false,
VITE_HIDE_HOME: 'false',
VITE_COMPRESSION: 'none',
};
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, "\n");
realName =
realName === "true" ? true : realName === "false" ? false : realName;
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, '\n');
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
if (envName === "VITE_PORT") {
realName = Number(realName);
}
ret[envName] = realName;
if (typeof realName === "string") {
process.env[envName] = realName;
} else if (typeof realName === "object") {
process.env[envName] = JSON.stringify(realName);
}
}
return ret;
if (envName === 'VITE_PORT') {
realName = Number(realName);
}
ret[envName] = realName;
if (typeof realName === 'string') {
process.env[envName] = realName;
} else if (typeof realName === 'object') {
process.env[envName] = JSON.stringify(realName);
}
}
return ret;
};
const fileListTotal: number[] = [];
/** 获取指定文件夹中所有文件的总大小 */
const getPackageSize = options => {
const { folder = "dist", callback, format = true } = options;
readdir(folder, (err, files: string[]) => {
if (err) throw err;
let count = 0;
const checkEnd = () => {
++count == files.length &&
callback(format ? formatBytes(sum(fileListTotal)) : sum(fileListTotal));
};
files.forEach((item: string) => {
stat(`${folder}/${item}`, async (err, stats) => {
if (err) throw err;
if (stats.isFile()) {
fileListTotal.push(stats.size);
checkEnd();
} else if (stats.isDirectory()) {
getPackageSize({
folder: `${folder}/${item}/`,
callback: checkEnd
});
}
});
});
files.length === 0 && callback(0);
});
const { folder = 'dist', callback, format = true } = options;
readdir(folder, (err, files: string[]) => {
if (err) throw err;
let count = 0;
const checkEnd = () => {
++count == files.length && callback(format ? formatBytes(sum(fileListTotal)) : sum(fileListTotal));
};
files.forEach((item: string) => {
stat(`${folder}/${item}`, async (err, stats) => {
if (err) throw err;
if (stats.isFile()) {
fileListTotal.push(stats.size);
checkEnd();
} else if (stats.isDirectory()) {
getPackageSize({
folder: `${folder}/${item}/`,
callback: checkEnd,
});
}
});
});
files.length === 0 && callback(0);
});
};
export { root, pathResolve, alias, __APP_INFO__, wrapperEnv, getPackageSize };

View File

@ -5,7 +5,7 @@ FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
# 将自定义的 Nginx 配置文件复制到容器中
COPY nginx.conf /etc/nginx/conf.d/
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 设置时区,构建镜像时执行的命令
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

View File

@ -15,24 +15,13 @@ server {
}
# 后端跨域请求
location ~/api/ {
proxy_pass http://192.168.3.98:8200;
}
# 配置WebSocket
location ~/ws/ {
# WebSocket 代理配置
proxy_pass http://192.168.3.98:8200; # WebSocket 服务器地址和端口
proxy_http_version 1.1; # 使用 HTTP 1.1 版本
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 600s; # 保持连接的超时时间,根据需要调整
proxy_redirect off; # 关闭重定向
}
# mock 跨域
location ~/mock/ {
proxy_pass http://192.168.3.98:8200;
location ~/admin/ {
#proxy_pass http://z-bunny.cn:7070;
proxy_pass http://172.17.0.1:7070;
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;
}
error_page 404 404.html;
@ -40,4 +29,4 @@ server {
location = /50x.html {
root html;
}
}
}

BIN
images/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -118,7 +118,7 @@ class PureHttp {
private httpInterceptorsResponse(): void {
const instance = PureHttp.axiosInstance;
instance.interceptors.response.use(
(response: PureHttpResponse) => {
async (response: PureHttpResponse) => {
const $config = response.config;
const data = response.data;
@ -128,8 +128,8 @@ class PureHttp {
// 登录过期,和异常处理
if (data.code === 208) {
message(data.message, { type: 'warning' });
router.push('/').then();
removeToken();
await router.push('/login');
} else if (data.code >= 201 && data.code < 300) {
message(data.message, { type: 'warning' });
} else if (data.code > 300) {

View File

@ -40,7 +40,7 @@ export const fetchDeleteI18n = (data: any) => {
* ---
*/
export const fetchGetI18nTypeList = () => {
return http.request<BaseResult<ResultTable>>('get', 'i18nType/getI18nTypeList');
return http.request<BaseResult<ResultTable>>('get', 'i18nType/noAuth/getI18nTypeList');
};
/**

View File

@ -3,7 +3,7 @@ import Motion from './utils/motion';
import { useNav } from '@/layout/hooks/useNav';
import { useLayout } from '@/layout/hooks/useLayout';
import { avatar, bg, illustration } from './utils/static';
import { toRaw } from 'vue';
import { onMounted, toRaw } from 'vue';
import { useTranslationLang } from '@/layout/hooks/useTranslationLang';
import { useDataThemeChange } from '@/layout/hooks/useDataThemeChange';
@ -27,6 +27,10 @@ dataThemeChange(overallStyle.value);
const { title, getDropdownItemStyle, getDropdownItemClass } = useNav();
const { locale, translation } = useTranslationLang();
const i18nTypeStore = userI18nTypeStore();
onMounted(() => {
i18nTypeStore.getI18nTypeList();
});
</script>
<template>

View File

@ -130,7 +130,7 @@ onBeforeUnmount(() => {
</template>
</el-input>
<el-checkbox v-model="userStore.isRemembered">
<el-text size="small" type="primary">{{ userStore.readMeDay }}天免登录</el-text>
<el-text size="small" type="primary">{{ userStore.readMeDay }}天免登录(邮箱验证码随便输入,后端校验验证码已注释) </el-text>
</el-checkbox>
</el-form-item>
</Motion>

View File

@ -26,6 +26,10 @@ export const columns: TableColumnList = [
{ label: $t('adminUser_sex'), prop: 'sex', slot: 'sex' },
// 个人描述
{ label: $t('adminUser_summary'), prop: 'summary', width: 460 },
// 登录的IP地址
{ label: $t('lastLoginIp'), prop: 'lastLoginIp', width: 130 },
// IP地区
{ label: $t('lastLoginIpAddress'), prop: 'lastLoginIpAddress', width: 130 },
{ label: $t('table.updateTime'), prop: 'updateTime', sortable: true, width: 160 },
{ label: $t('table.createTime'), prop: 'createTime', sortable: true, width: 160 },
{ label: $t('table.updateUser'), prop: 'updateUser', slot: 'updateUser', width: 90, fixed: 'right' },