-
+
+
+
+
+
@@ -140,6 +158,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import {
ArrowLeftBold,
CloseBold,
+ Menu,
MoreFilled,
Picture as IconPicture,
Plus,
@@ -149,6 +168,7 @@ import selectComponent from '@/components/selectImage/selectComponent.vue'
import { addCategory, deleteCategory, getCategoryList } from '@/api/attachmentCategory'
import CropperImage from "@/components/upload/cropper.vue";
import QRCodeUpload from "@/components/upload/QR-code.vue";
+import draggable from 'vuedraggable'
const imageUrl = ref('')
const imageCommon = ref('')
@@ -424,6 +444,20 @@ const useSelectedImages = () => {
selectedImages.value = []
}
+const onDragStart = () => {
+ // 拖拽开始时的处理
+ document.body.style.cursor = 'grabbing'
+}
+
+const onDragEnd = () => {
+ // 拖拽结束时的处理
+ document.body.style.cursor = 'default'
+ // 确保model是数组类型
+ if (!Array.isArray(model.value)) {
+ model.value = []
+ }
+}
+
diff --git a/src/core/config.js b/src/core/config.js
index 4cb3892..d84481a 100644
--- a/src/core/config.js
+++ b/src/core/config.js
@@ -1,10 +1,12 @@
/**
* 网站配置文件
*/
+import packageInfo from '../../package.json'
+
const greenText = (text) => `\x1b[32m${text}\x1b[0m`
const config = {
- appName: 'Lckt-Admin',
+ appName: 'Gin-Vue-Admin',
appLogo: 'logo.png',
showViteLogo: true,
logs: []
@@ -12,20 +14,7 @@ const config = {
export const viteLogo = (env) => {
if (config.showViteLogo) {
- console.log(
- greenText(
- `> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`
- )
- )
- console.log(greenText(`> 当前版本:v2.8.0`))
- console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`))
- console.log(
- greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`)
- )
- console.log(greenText(`> 插件市场:https://plugin.gin-vue-admin.com`))
- console.log(
- greenText(`> GVA讨论社区:https://support.qq.com/products/371961`)
- )
+ console.log(greenText(`> 当前版本:v${packageInfo.version}`))
console.log(
greenText(
`> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`
@@ -34,18 +23,6 @@ export const viteLogo = (env) => {
console.log(
greenText(`> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`)
)
- console.log(
- greenText(
- `--------------------------------------版权声明--------------------------------------`
- )
- )
- console.log(greenText(`** 版权所有方:flipped-aurora开源团队 **`))
- console.log(greenText(`** 版权持有公司:北京翻转极光科技有限责任公司 **`))
- console.log(
- greenText(
- `** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **`
- )
- )
console.log('\n')
}
}
diff --git a/src/core/gin-vue-admin.js b/src/core/gin-vue-admin.js
index 764da3f..e0d8306 100644
--- a/src/core/gin-vue-admin.js
+++ b/src/core/gin-vue-admin.js
@@ -4,24 +4,10 @@
* */
// 加载网站配置文件夹
import { register } from './global'
+import packageInfo from '../../package.json'
export default {
install: (app) => {
register(app)
- console.log(`
- 欢迎使用 Gin-Vue-Admin
- 当前版本:v2.8.0
- 加群方式:微信:shouzi_1994 QQ群:622360840
- 项目地址:https://github.com/flipped-aurora/gin-vue-admin
- 插件市场:https://plugin.gin-vue-admin.com
- GVA讨论社区:https://support.qq.com/products/371961
- 默认自动化文档地址:http://127.0.0.1:${import.meta.env.VITE_SERVER_PORT}/swagger/index.html
- 默认前端文件运行地址:http://127.0.0.1:${import.meta.env.VITE_CLI_PORT}
- 如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html
- --------------------------------------版权声明--------------------------------------
- ** 版权所有方:flipped-aurora开源团队 **
- ** 版权持有公司:北京翻转极光科技有限责任公司 **
- ** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **
- `)
}
}
diff --git a/src/directive/auth.js b/src/directive/auth.js
index d2b9b6a..2517299 100644
--- a/src/directive/auth.js
+++ b/src/directive/auth.js
@@ -7,22 +7,7 @@ export default {
// 当被绑定的元素插入到 DOM 中时……
mounted: function (el, binding) {
const userInfo = userStore.userInfo
- let type = ''
- switch (Object.prototype.toString.call(binding.value)) {
- case '[object Array]':
- type = 'Array'
- break
- case '[object String]':
- type = 'String'
- break
- case '[object Number]':
- type = 'Number'
- break
- default:
- type = ''
- break
- }
- if (type === '') {
+ if (!binding.value){
el.parentNode.removeChild(el)
return
}
diff --git a/src/main.js b/src/main.js
index 372b491..18ba072 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,5 +1,6 @@
import './style/element_visiable.scss'
import 'element-plus/theme-chalk/dark/css-vars.css'
+import 'uno.css';
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
diff --git a/src/pathInfo.json b/src/pathInfo.json
index 0fa9f30..00a1e2f 100644
--- a/src/pathInfo.json
+++ b/src/pathInfo.json
@@ -35,13 +35,21 @@
"/src/view/layout/aside/headMode.vue": "GvaAside",
"/src/view/layout/aside/index.vue": "Index",
"/src/view/layout/aside/normalMode.vue": "GvaAside",
+ "/src/view/layout/aside/sidebarMode.vue": "SidebarMode",
"/src/view/layout/header/index.vue": "Index",
"/src/view/layout/header/tools.vue": "Tools",
"/src/view/layout/iframe.vue": "GvaLayoutIframe",
"/src/view/layout/index.vue": "GvaLayout",
"/src/view/layout/screenfull/index.vue": "Screenfull",
"/src/view/layout/search/search.vue": "BtnBox",
+ "/src/view/layout/setting/components/layoutModeCard.vue": "LayoutModeCard",
+ "/src/view/layout/setting/components/settingItem.vue": "SettingItem",
+ "/src/view/layout/setting/components/themeColorPicker.vue": "ThemeColorPicker",
+ "/src/view/layout/setting/components/themeModeSelector.vue": "ThemeModeSelector",
"/src/view/layout/setting/index.vue": "GvaSetting",
+ "/src/view/layout/setting/modules/appearance/index.vue": "AppearanceSettings",
+ "/src/view/layout/setting/modules/general/index.vue": "GeneralSettings",
+ "/src/view/layout/setting/modules/layout/index.vue": "LayoutSettings",
"/src/view/layout/setting/title.vue": "layoutSettingTitle",
"/src/view/layout/tabs/index.vue": "HistoryComponent",
"/src/view/login/index.vue": "Login",
@@ -69,6 +77,9 @@
"/src/view/systemTools/autoCode/component/fieldDialog.vue": "FieldDialog",
"/src/view/systemTools/autoCode/component/previewCodeDialog.vue": "PreviewCodeDialog",
"/src/view/systemTools/autoCode/index.vue": "AutoCode",
+ "/src/view/systemTools/autoCode/mcp.vue": "MCP",
+ "/src/view/systemTools/autoCode/mcpTest.vue": "MCPTest",
+ "/src/view/systemTools/autoCode/picture.vue": "Picture",
"/src/view/systemTools/autoCodeAdmin/index.vue": "AutoCodeAdmin",
"/src/view/systemTools/autoPkg/autoPkg.vue": "AutoPkg",
"/src/view/systemTools/exportTemplate/exportTemplate.vue": "ExportTemplate",
@@ -77,6 +88,7 @@
"/src/view/systemTools/installPlugin/index.vue": "Index",
"/src/view/systemTools/pubPlug/pubPlug.vue": "PubPlug",
"/src/view/systemTools/system/system.vue": "Config",
+ "/src/view/systemTools/version/version.vue": "SysVersion",
"/src/view/user/index.vue": "UserManage",
"/src/view/user/user/index.vue": "Index",
"/src/view/user/user/teacherApply.vue": "TeacherApply",
diff --git a/src/permission.js b/src/permission.js
index 3b48995..5276aea 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -115,7 +115,7 @@ router.beforeEach(async (to, from) => {
return {
name: 'Login',
- query: { redirect: to.href }
+ query: { redirect: to.fullPath }
}
}
@@ -126,7 +126,7 @@ router.beforeEach(async (to, from) => {
return {
name: 'Login',
query: {
- redirect: document.location.hash
+ redirect: to.fullPath
}
}
})
diff --git a/src/pinia/modules/app.js b/src/pinia/modules/app.js
index 8b32235..9eb9dea 100644
--- a/src/pinia/modules/app.js
+++ b/src/pinia/modules/app.js
@@ -99,6 +99,27 @@ export const useAppStore = defineStore('app', () => {
config.transition_type = e
}
+ const baseCoinfg = {
+ weakness: false,
+ grey: false,
+ primaryColor: '#3b82f6',
+ showTabs: true,
+ darkMode: 'auto',
+ layout_side_width: 256,
+ layout_side_collapsed_width: 80,
+ layout_side_item_height: 48,
+ show_watermark: true,
+ side_mode: 'normal',
+ // 页面过渡动画配置
+ transition_type: 'slide'
+ }
+
+ const resetConfig = () => {
+ for (let baseCoinfgKey in baseCoinfg) {
+ config[baseCoinfgKey] = baseCoinfg[baseCoinfgKey]
+ }
+ }
+
// 监听色弱模式和灰色模式
watchEffect(() => {
document.documentElement.classList.toggle('html-weakenss', config.weakness)
@@ -128,6 +149,7 @@ export const useAppStore = defineStore('app', () => {
toggleConfigSideItemHeight,
toggleConfigWatermark,
toggleSideMode,
- toggleTransition
+ toggleTransition,
+ resetConfig
}
})
diff --git a/src/pinia/modules/router.js b/src/pinia/modules/router.js
index 359f9ff..ff1eb76 100644
--- a/src/pinia/modules/router.js
+++ b/src/pinia/modules/router.js
@@ -1,9 +1,10 @@
import { asyncRouterHandle } from '@/utils/asyncRouter'
import { emitter } from '@/utils/bus.js'
-import { asyncMenu, getMenuList } from '@/api/menu'
+import { asyncMenu } from '@/api/menu'
import { defineStore } from 'pinia'
import { ref, watchEffect } from 'vue'
import pathInfo from '@/pathInfo.json'
+import {useRoute} from "vue-router";
const notLayoutRouterArr = []
const keepAliveRoutersArr = []
@@ -51,13 +52,33 @@ export const useRouterStore = defineStore('router', () => {
const asyncRouterFlag = ref(0)
const setKeepAliveRouters = (history) => {
const keepArrTemp = []
+
+ // 1. 首先添加原有的keepAlive配置
+ keepArrTemp.push(...keepAliveRoutersArr)
+
history.forEach((item) => {
+ // 2. 为所有history中的路由强制启用keep-alive
+ // 通过routeMap获取路由信息,然后通过pathInfo获取组件名
+ const routeInfo = routeMap[item.name]
+ if (routeInfo && routeInfo.meta && routeInfo.meta.path) {
+ const componentName = pathInfo[routeInfo.meta.path]
+ if (componentName) {
+ keepArrTemp.push(componentName)
+ }
+ }
+
+ // 3. 如果子路由在tabs中打开,父路由也需要keepAlive
if (nameMap[item.name]) {
keepArrTemp.push(nameMap[item.name])
}
})
+
keepAliveRouters.value = Array.from(new Set(keepArrTemp))
}
+
+
+ const route = useRoute()
+
emitter.on('setKeepAlive', setKeepAliveRouters)
const asyncRouters = ref([])
@@ -80,14 +101,32 @@ export const useRouterStore = defineStore('router', () => {
return menuMap[name]?.children
}
+ const findTopActive = (menuMap, routeName) => {
+ for (let topName in menuMap) {
+ const topItem = menuMap[topName];
+ if (topItem.children?.some(item => item.name === routeName)) {
+ return topName;
+ }
+ const foundName = findTopActive(topItem.children || {}, routeName);
+ if (foundName) {
+ return topName;
+ }
+ }
+ return null;
+ };
+
watchEffect(() => {
let topActive = sessionStorage.getItem('topActive')
+ // 初始化菜单内容,防止重复添加
+ topMenu.value = [];
asyncRouters.value[0]?.children.forEach((item) => {
if (item.hidden) return
menuMap[item.name] = item
topMenu.value.push({ ...item, children: [] })
})
-
+ if (!topActive || topActive === 'undefined' || topActive === 'null') {
+ topActive = findTopActive(menuMap, route.name);
+ }
setLeftMenu(topActive)
})
@@ -106,10 +145,8 @@ export const useRouterStore = defineStore('router', () => {
children: []
}
]
- // const asyncRouterRes = await asyncMenu()
- const asyncRouterRes = await getMenuList()
- // const asyncRouter = asyncRouterRes.data.menus
- const asyncRouter = asyncRouterRes.data
+ const asyncRouterRes = await asyncMenu()
+ const asyncRouter = asyncRouterRes.data.menus
asyncRouter &&
asyncRouter.push({
path: 'reload',
diff --git a/src/pinia/modules/user.js b/src/pinia/modules/user.js
index b103ec7..5b1f55c 100644
--- a/src/pinia/modules/user.js
+++ b/src/pinia/modules/user.js
@@ -71,7 +71,6 @@ export const useUserStore = defineStore('user', () => {
const res = await login(loginInfo)
if (res.code !== 0) {
- ElMessage.error(res.message || '登录失败')
return false
}
// 登陆成功,设置用户信息和权限相关信息
@@ -88,8 +87,13 @@ export const useUserStore = defineStore('user', () => {
router.addRoute(asyncRouter)
})
+ if(router.currentRoute.value.query.redirect) {
+ await router.replace(router.currentRoute.value.query.redirect)
+ return true
+ }
+
if (!router.hasRoute(userInfo.value.authority.defaultRouter)) {
- ElMessage.error('请联系管理员进行授权')
+ ElMessage.error('不存在可以登陆的首页,请联系管理员进行配置')
} else {
await router.replace({ name: userInfo.value.authority.defaultRouter })
}
@@ -124,9 +128,12 @@ export const useUserStore = defineStore('user', () => {
/* 清理数据 */
const ClearStorage = async () => {
token.value = ''
- xToken.value = ''
+ // 使用remove方法正确删除cookie
+ xToken.remove()
sessionStorage.clear()
+ // 清理所有相关的localStorage项
localStorage.removeItem('originSetting')
+ localStorage.removeItem('token')
}
return {
diff --git a/src/plugin/announcement/view/info.vue b/src/plugin/announcement/view/info.vue
index a684e97..7ccdcb3 100644
--- a/src/plugin/announcement/view/info.vue
+++ b/src/plugin/announcement/view/info.vue
@@ -99,7 +99,7 @@
>
-
+
{{ formatDate(scope.row.CreatedAt) }}
diff --git a/src/router/index.js b/src/router/index.js
index 19adec7..4181603 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -31,30 +31,6 @@ const routes = [
},
component: () => import('@/view/error/index.vue')
},
- {
- path: '/kefu/login',
- name: 'ServiceLogin',
- component: () => import('@/plugin/customerservice/view/login/index.vue'),
- meta:{
- client:true
- }
- },
- {
- path: '/kefu/main',
- name: 'ServiceMain',
- component: () => import('@/plugin/customerservice/view/chat/index.vue'),
- meta:{
- client:true
- }
- },
- {
- path: '/kefu/test',
- name: 'ServiceUserTest',
- component: () => import('@/plugin/customerservice/view/chat/test.vue'),
- meta:{
- client:true
- }
- },
]
const router = createRouter({
diff --git a/src/style/element_visiable.scss b/src/style/element_visiable.scss
index 4d33aef..59f4583 100644
--- a/src/style/element_visiable.scss
+++ b/src/style/element_visiable.scss
@@ -1,9 +1,6 @@
@use '@/style/main.scss';
@use '@/style/reset';
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
.el-button {
font-weight: 400;
@@ -118,6 +115,10 @@
}
}
+.el-menu-item.is-active{
+ color: var(--el-color-primary)!important;
+}
+
.el-sub-menu__title.el-tooltip__trigger,
.el-menu-item .el-menu-tooltip__trigger {
justify-content: center;
diff --git a/src/style/main.scss b/src/style/main.scss
index 6a48e1f..21a3d12 100644
--- a/src/style/main.scss
+++ b/src/style/main.scss
@@ -17,7 +17,15 @@
}
.gva-btn-list {
- @apply mb-3 flex items-center;
+ @apply mb-3 flex items-center flex-wrap gap-2;
+ .el-button+.el-button{
+ @apply ml-0 !important;
+ }
+ .el-upload{
+ .el-button{
+ @apply ml-0 !important;
+ }
+ }
}
#nprogress .bar {
@@ -34,9 +42,7 @@
.gva-search-box {
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
}
-.search-form{
- @apply p-4 bg-white dark:text-slate-400 dark:bg-slate-900
-}
+
.gva-form-box {
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
}
@@ -51,18 +57,3 @@
outline: none;
}
}
-.container-wrapper{
- min-height: calc(100vh - 12rem);
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- position: relative;
-}
-.footer-box{
- display: flex;
- justify-content: center;
- padding: 1rem 0;
- position: sticky;
- bottom: 0;
- //border-top: 1px solid #ededed;
-}
diff --git a/src/style/reset.scss b/src/style/reset.scss
index 2cd44c7..55b476f 100644
--- a/src/style/reset.scss
+++ b/src/style/reset.scss
@@ -393,7 +393,7 @@ fieldset,
table,
th,
td {
- border: none;
+ // border: none;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
font-size: 14px;
diff --git a/src/utils/request.js b/src/utils/request.js
index 342ce8f..1c62bd3 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -1,8 +1,8 @@
import axios from 'axios' // 引入axios
-import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/pinia/modules/user'
+import { ElLoading, ElMessage } from 'element-plus'
+import { emitter } from '@/utils/bus'
import router from '@/router/index'
-import { ElLoading } from 'element-plus'
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
@@ -11,6 +11,9 @@ const service = axios.create({
let activeAxios = 0
let timer
let loadingInstance
+let isLoadingVisible = false
+let forceCloseTimer
+
const showLoading = (
option = {
target: null
@@ -18,13 +21,33 @@ const showLoading = (
) => {
const loadDom = document.getElementById('gva-base-load-dom')
activeAxios++
+
+ // 清除之前的定时器
if (timer) {
clearTimeout(timer)
}
+
+ // 清除强制关闭定时器
+ if (forceCloseTimer) {
+ clearTimeout(forceCloseTimer)
+ }
+
timer = setTimeout(() => {
- if (activeAxios > 0) {
+ // 再次检查activeAxios状态,防止竞态条件
+ if (activeAxios > 0 && !isLoadingVisible) {
if (!option.target) option.target = loadDom
loadingInstance = ElLoading.service(option)
+ isLoadingVisible = true
+
+ // 设置强制关闭定时器,防止loading永远不关闭(30秒超时)
+ forceCloseTimer = setTimeout(() => {
+ if (isLoadingVisible && loadingInstance) {
+ console.warn('Loading强制关闭:超时30秒')
+ loadingInstance.close()
+ isLoadingVisible = false
+ activeAxios = 0 // 重置计数器
+ }
+ }, 30000)
}
}, 400)
}
@@ -32,10 +55,47 @@ const showLoading = (
const closeLoading = () => {
activeAxios--
if (activeAxios <= 0) {
+ activeAxios = 0 // 确保不会变成负数
clearTimeout(timer)
- loadingInstance && loadingInstance.close()
+
+ if (forceCloseTimer) {
+ clearTimeout(forceCloseTimer)
+ forceCloseTimer = null
+ }
+
+ if (isLoadingVisible && loadingInstance) {
+ loadingInstance.close()
+ isLoadingVisible = false
+ }
+ loadingInstance = null
}
}
+
+// 全局重置loading状态的函数,用于异常情况
+const resetLoading = () => {
+ activeAxios = 0
+ isLoadingVisible = false
+
+ if (timer) {
+ clearTimeout(timer)
+ timer = null
+ }
+
+ if (forceCloseTimer) {
+ clearTimeout(forceCloseTimer)
+ forceCloseTimer = null
+ }
+
+ if (loadingInstance) {
+ try {
+ loadingInstance.close()
+ } catch (e) {
+ console.warn('关闭loading时出错:', e)
+ }
+ loadingInstance = null
+ }
+}
+
// http request 拦截器
service.interceptors.request.use(
(config) => {
@@ -55,15 +115,18 @@ service.interceptors.request.use(
if (!error.config.donNotShowLoading) {
closeLoading()
}
- ElMessage({
- showClose: true,
- message: error,
- type: 'error'
+ emitter.emit('show-error', {
+ code: 'request',
+ message: error.message || '请求发送失败'
})
return error
}
)
+function getErrorMessage(error) {
+ return error.response?.data?.msg || '请求失败'
+}
+
// http response 拦截器
service.interceptors.response.use(
(response) => {
@@ -74,6 +137,9 @@ service.interceptors.response.use(
if (response.headers['new-token']) {
userStore.setToken(response.headers['new-token'])
}
+ if (typeof response.data.code === 'undefined') {
+ return response
+ }
if (response.data.code === 0 || response.headers.success === 'true') {
if (response.headers.msg) {
response.data.msg = decodeURI(response.headers.msg)
@@ -94,79 +160,43 @@ service.interceptors.response.use(
}
if (!error.response) {
- ElMessageBox.confirm(
- `
- 检测到请求错误
- ${error}
- `,
- '请求报错',
- {
- dangerouslyUseHTMLString: true,
- distinguishCancelAndClose: true,
- confirmButtonText: '稍后重试',
- cancelButtonText: '取消'
+ // 网络错误
+ resetLoading()
+ emitter.emit('show-error', {
+ code: 'network',
+ message: getErrorMessage(error)
+ })
+ return Promise.reject(error)
+ }
+
+ // HTTP 状态码错误
+ if (error.response.status === 401) {
+ emitter.emit('show-error', {
+ code: '401',
+ message: getErrorMessage(error),
+ fn: () => {
+ const userStore = useUserStore()
+ userStore.ClearStorage()
+ router.push({ name: 'Login', replace: true })
}
- )
- return
+ })
+ return Promise.reject(error)
}
- switch (error.response.status) {
- case 500:
- ElMessageBox.confirm(
- `
- 检测到接口错误${error}
- 错误码 500 :此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存
- `,
- '接口报错',
- {
- dangerouslyUseHTMLString: true,
- distinguishCancelAndClose: true,
- confirmButtonText: '清理缓存',
- cancelButtonText: '取消'
- }
- ).then(() => {
- const userStore = useUserStore()
- userStore.ClearStorage()
- router.push({ name: 'Login', replace: true })
- })
- break
- case 404:
- ElMessageBox.confirm(
- `
- 检测到接口错误${error}
- 错误码 404 :此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格
- `,
- '接口报错',
- {
- dangerouslyUseHTMLString: true,
- distinguishCancelAndClose: true,
- confirmButtonText: '我知道了',
- cancelButtonText: '取消'
- }
- )
- break
- case 401:
- ElMessageBox.confirm(
- `
- 无效的令牌
- 错误码: 401 错误信息:${error}
- `,
- '身份信息',
- {
- dangerouslyUseHTMLString: true,
- distinguishCancelAndClose: true,
- confirmButtonText: '重新登录',
- cancelButtonText: '取消'
- }
- ).then(() => {
- const userStore = useUserStore()
- userStore.ClearStorage()
- router.push({ name: 'Login', replace: true })
- })
- break
- }
-
- return error
+ emitter.emit('show-error', {
+ code: error.response.status,
+ message: getErrorMessage(error)
+ })
+ return Promise.reject(error)
}
)
+
+// 监听页面卸载事件,确保loading被正确清理
+if (typeof window !== 'undefined') {
+ window.addEventListener('beforeunload', resetLoading)
+ window.addEventListener('unload', resetLoading)
+}
+
+// 导出service和resetLoading函数
+export { resetLoading }
export default service
diff --git a/src/view/error/index.vue b/src/view/error/index.vue
index 1f0079f..ec91562 100644
--- a/src/view/error/index.vue
+++ b/src/view/error/index.vue
@@ -24,6 +24,7 @@
diff --git a/src/view/init/index.vue b/src/view/init/index.vue
index 211ec4a..5d76976 100644
--- a/src/view/init/index.vue
+++ b/src/view/init/index.vue
@@ -136,7 +136,7 @@
// @ts-ignore
import { initDB } from '@/api/initdb'
import { reactive, ref } from 'vue'
- import { ElLoading, ElMessage } from 'element-plus'
+ import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
defineOptions({
@@ -274,7 +274,25 @@
type: 'success',
message: res.msg
})
- router.push({ name: 'Login' })
+
+ // 显示AI助手配置提示弹窗
+ ElMessageBox.confirm(
+ '已经完成基础数据库初始化!建议先进行编辑器AI助手配置,以获得更好的开发体验。',
+ '配置完成',
+ {
+ confirmButtonText: '查看AI配置文档',
+ cancelButtonText: '稍后配置',
+ type: 'success',
+ center: true
+ }
+ ).then(() => {
+ // 点击确认按钮,打开AI配置文档
+ window.open('https://www.gin-vue-admin.com/guide/server/mcp.html', '_blank')
+ router.push({ name: 'Login' })
+ }).catch(() => {
+ // 点击取消按钮或关闭弹窗,直接跳转到登录页
+ router.push({ name: 'Login' })
+ })
}
loading.close()
} catch (_) {
diff --git a/src/view/layout/aside/asideComponent/index.vue b/src/view/layout/aside/asideComponent/index.vue
index 32e7d41..cebcc4a 100644
--- a/src/view/layout/aside/asideComponent/index.vue
+++ b/src/view/layout/aside/asideComponent/index.vue
@@ -37,7 +37,7 @@
const menuComponent = computed(() => {
if (
props.routerInfo.children &&
- props.routerInfo.children.filter((item) => !item.hidden).length
+ props.routerInfo.children?.filter((item) => !item.hidden).length
) {
return AsyncSubmenu
} else {
diff --git a/src/view/layout/aside/asideComponent/menuItem.vue b/src/view/layout/aside/asideComponent/menuItem.vue
index b6b4ff7..1bcf67f 100644
--- a/src/view/layout/aside/asideComponent/menuItem.vue
+++ b/src/view/layout/aside/asideComponent/menuItem.vue
@@ -1,14 +1,16 @@
+
+ {{ isCollapse ? routerInfo.meta.title[0] : "" }}
+
{{ routerInfo.meta.title }}
@@ -16,7 +18,7 @@
-
diff --git a/src/view/layout/setting/components/settingItem.vue b/src/view/layout/setting/components/settingItem.vue
new file mode 100644
index 0000000..bc5d7d8
--- /dev/null
+++ b/src/view/layout/setting/components/settingItem.vue
@@ -0,0 +1,113 @@
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/layout/setting/components/themeColorPicker.vue b/src/view/layout/setting/components/themeColorPicker.vue
new file mode 100644
index 0000000..4523c92
--- /dev/null
+++ b/src/view/layout/setting/components/themeColorPicker.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
当前主题色
+
+
+
+ {{ modelValue }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/layout/setting/components/themeModeSelector.vue b/src/view/layout/setting/components/themeModeSelector.vue
new file mode 100644
index 0000000..72eb4e8
--- /dev/null
+++ b/src/view/layout/setting/components/themeModeSelector.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+ {{ mode.label }}
+
+
+
+
+
+
diff --git a/src/view/layout/setting/index.vue b/src/view/layout/setting/index.vue
index 12a7f2a..6e2f3f6 100644
--- a/src/view/layout/setting/index.vue
+++ b/src/view/layout/setting/index.vue
@@ -5,208 +5,175 @@
direction="rtl"
:size="width"
:show-close="false"
+ class="theme-config-drawer"
>
-
-
系统配置
-
保存配置
+
+
系统配置
+
+ 重置配置
+
-
-
-
-
-
-
-
-
-
-
-
-
-
页面切换动画
-
+
+
+
+
-
-
-
-
-
+ {{ tab.label }}
+
-
-
-
diff --git a/src/view/layout/setting/modules/appearance/index.vue b/src/view/layout/setting/modules/appearance/index.vue
new file mode 100644
index 0000000..70fb98d
--- /dev/null
+++ b/src/view/layout/setting/modules/appearance/index.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 降低色彩饱和度
+
+
+
+
+
+
+ 优化色彩对比度
+
+
+
+
+
+
+ 在页面显示水印标识
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/layout/setting/modules/general/index.vue b/src/view/layout/setting/modules/general/index.vue
new file mode 100644
index 0000000..31e2a85
--- /dev/null
+++ b/src/view/layout/setting/modules/general/index.vue
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+ 版本
+ v2.7.4
+
+
+ 前端框架
+ Vue 3
+
+
+ UI 组件库
+ Element Plus
+
+
+ 构建工具
+ Vite
+
+
+ 浏览器
+ {{ browserInfo }}
+
+
+ 屏幕分辨率
+ {{ screenResolution }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📤
+
+
+
导出配置
+
导出当前配置为 JSON 文件
+
+
+
+ 导出配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
Gin-Vue-Admin
+
+ 基于 Vue3 + Gin 的全栈开发基础平台,提供完整的后台管理解决方案
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/layout/setting/modules/layout/index.vue b/src/view/layout/setting/modules/layout/index.vue
new file mode 100644
index 0000000..bcc4809
--- /dev/null
+++ b/src/view/layout/setting/modules/layout/index.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+ 页面标签导航
+
+
+
+
+
+
+ 页面过渡效果
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
侧边栏展开宽度
+
侧边栏完全展开时的宽度
+
+
+
+ px
+
+
+
+
+
+
+
+
侧边栏收缩宽度
+
侧边栏收缩时的最小宽度
+
+
+
+ px
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/view/layout/tabs/index.vue b/src/view/layout/tabs/index.vue
index 4ad54f3..6a6ad8a 100644
--- a/src/view/layout/tabs/index.vue
+++ b/src/view/layout/tabs/index.vue
@@ -8,7 +8,7 @@
v-model="activeValue"
:closable="!(historys.length === 1 && $route.name === defaultRouter)"
type="card"
- class="bg-white text-slate-700 dark:text-slate-500 dark:bg-slate-900"
+ class="bg-white text-slate-700 dark:text-slate-500 dark:bg-slate-900 pt-1"
@contextmenu.prevent="openContextMenu($event)"
@tab-click="changeTab"
@tab-remove="removeTab"
diff --git a/src/view/superAdmin/api/api.vue b/src/view/superAdmin/api/api.vue
index 21e971c..db0d21a 100644
--- a/src/view/superAdmin/api/api.vue
+++ b/src/view/superAdmin/api/api.vue
@@ -531,7 +531,7 @@
if (res.code === 0) {
ElMessage({
type: 'success',
- message: '添加成功',
+ message: '添加成功,请到角色管理页面分配权限',
showClose: true
})
syncApiData.value.newApis = syncApiData.value.newApis.filter(
diff --git a/src/view/superAdmin/authority/components/menus.vue b/src/view/superAdmin/authority/components/menus.vue
index 8e2d1c6..fd00f8d 100644
--- a/src/view/superAdmin/authority/components/menus.vue
+++ b/src/view/superAdmin/authority/components/menus.vue
@@ -23,7 +23,7 @@
{{ node.label }}
-
+
setDefault(data)"
+ @click.stop="() => setDefault(data)"
>
{{ row.defaultRouter === data.name ? '首页' : '设为首页' }}
- OpenBtn(data)">
+ OpenBtn(data)">
分配按钮
@@ -132,7 +132,7 @@
defaultRouter: data.name
})
if (res.code === 0) {
- ElMessage({ type: 'success', message: '设置成功' })
+ relation()
emit('changeRow', 'defaultRouter', res.data.authority.defaultRouter)
}
}
diff --git a/src/view/superAdmin/menu/menu.vue b/src/view/superAdmin/menu/menu.vue
index ec4a7e0..c32c1c9 100644
--- a/src/view/superAdmin/menu/menu.vue
+++ b/src/view/superAdmin/menu/menu.vue
@@ -119,287 +119,394 @@
-
-
-
-
-
- 如果菜单包含子菜单,请创建router-view二级路由页面或者
-
- 点我设置
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 路由Path
- 添加参数
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 生成随机密码
+
+
+
+
+
+
+
+
+
{
- ElMessageBox.confirm('是否将此用户密码重置为123456?', '警告', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(async () => {
- const res = await resetPassword({
- ID: row.ID
+ // 重置密码对话框相关
+ const resetPwdDialog = ref(false)
+ const resetPwdForm = ref(null)
+ const resetPwdInfo = ref({
+ ID: '',
+ userName: '',
+ nickName: '',
+ password: ''
+ })
+
+ // 生成随机密码
+ const generateRandomPassword = () => {
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
+ let password = ''
+ for (let i = 0; i < 12; i++) {
+ password += chars.charAt(Math.floor(Math.random() * chars.length))
+ }
+ resetPwdInfo.value.password = password
+ // 复制到剪贴板
+ navigator.clipboard.writeText(password).then(() => {
+ ElMessage({
+ type: 'success',
+ message: '密码已复制到剪贴板'
+ })
+ }).catch(() => {
+ ElMessage({
+ type: 'error',
+ message: '复制失败,请手动复制'
})
- if (res.code === 0) {
- ElMessage({
- type: 'success',
- message: res.msg
- })
- } else {
- ElMessage({
- type: 'error',
- message: res.msg
- })
- }
})
}
+
+ // 打开重置密码对话框
+ const resetPasswordFunc = (row) => {
+ resetPwdInfo.value.ID = row.ID
+ resetPwdInfo.value.userName = row.userName
+ resetPwdInfo.value.nickName = row.nickName
+ resetPwdInfo.value.password = ''
+ resetPwdDialog.value = true
+ }
+
+ // 确认重置密码
+ const confirmResetPassword = async () => {
+ if (!resetPwdInfo.value.password) {
+ ElMessage({
+ type: 'warning',
+ message: '请输入或生成密码'
+ })
+ return
+ }
+
+ const res = await resetPassword({
+ ID: resetPwdInfo.value.ID,
+ password: resetPwdInfo.value.password
+ })
+
+ if (res.code === 0) {
+ ElMessage({
+ type: 'success',
+ message: res.msg || '密码重置成功'
+ })
+ resetPwdDialog.value = false
+ } else {
+ ElMessage({
+ type: 'error',
+ message: res.msg || '密码重置失败'
+ })
+ }
+ }
+
+ // 关闭重置密码对话框
+ const closeResetPwdDialog = () => {
+ resetPwdInfo.value.password = ''
+ resetPwdDialog.value = false
+ }
const setAuthorityIds = () => {
tableData.value &&
tableData.value.forEach((user) => {
diff --git a/src/view/systemTools/autoCode/index.vue b/src/view/systemTools/autoCode/index.vue
index a1a9cff..a9c4f5c 100644
--- a/src/view/systemTools/autoCode/index.vue
+++ b/src/view/systemTools/autoCode/index.vue
@@ -206,7 +206,7 @@
-
+
-
+
@@ -534,7 +535,7 @@
width="160"
>
-
+
route.params.id,
- () => {
- if (route.name === 'autoCodeEdit') {
- init()
- }
- }
- )
-
watch(()=>form.value.generateServer,()=>{
if(!form.value.generateServer){
form.value.autoCreateApiToSql = false
@@ -1566,6 +1558,7 @@
const catchData = () => {
window.sessionStorage.setItem('autoCode', JSON.stringify(form.value))
+ ElMessage.success('暂存成功')
}
const getCatch = () => {
@@ -1619,6 +1612,8 @@
reader.onload = (e) => {
try {
form.value = JSON.parse(e.target.result)
+ form.value.generateServer = true
+ form.value.generateWeb = true
ElMessage.success('JSON 文件导入成功')
} catch (_) {
ElMessage.error('无效的 JSON 文件')
diff --git a/src/view/systemTools/autoCode/mcp.vue b/src/view/systemTools/autoCode/mcp.vue
new file mode 100644
index 0000000..0113a7b
--- /dev/null
+++ b/src/view/systemTools/autoCode/mcp.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
diff --git a/src/view/systemTools/autoCode/mcpTest.vue b/src/view/systemTools/autoCode/mcpTest.vue
new file mode 100644
index 0000000..c20704e
--- /dev/null
+++ b/src/view/systemTools/autoCode/mcpTest.vue
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+ MCP 服务器配置示例
+
+
+
+
+
+ {{ mcpServerConfig }}
+
+
+
+
+
+
+
+
+ {{ tool.name }}
+
+
+
+
+
+ {{ tool.description }}
+
+
+ 参数列表
+ ({{ Object.keys(tool.inputSchema.properties).length }})
+
+
+
+
+
+ {{ propName }}
+ *
+
+
{{ propDetails.type }}
+
+
+ {{ propDetails.description || '无描述' }}
+
+
+
+
+
+ 无输入参数
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
API 返回结果:
+
+
{{ apiDialogResponse }}
+
+
+
+
+
+
{{ apiDialogResponse.content }}
+
+
+
{{ JSON.stringify(apiDialogResponse, null, 2) }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/view/systemTools/autoCode/picture.vue b/src/view/systemTools/autoCode/picture.vue
new file mode 100644
index 0000000..4863d36
--- /dev/null
+++ b/src/view/systemTools/autoCode/picture.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+
+
+
+
+
页面用途
+
+ 企业官网
+ 电商页面
+ 个人博客
+ 产品介绍
+ 活动落地页
+ 其他
+
+
+
+
+
+
主要内容板块
+
+ Banner轮播图
+ 产品/服务介绍
+ 功能特点展示
+ 客户案例
+ 团队介绍
+ 联系表单
+ 新闻/博客列表
+ 价格表
+ FAQ/常见问题
+ 用户评价
+ 数据统计
+ 商品列表
+ 商品卡片
+ 购物车
+ 结算页面
+ 订单跟踪
+ 商品分类
+ 热门推荐
+ 限时特惠
+ 其他
+
+
+
+
+
+
风格偏好
+
+ 简约
+ 科技感
+ 温馨
+ 专业
+ 创意
+ 复古
+ 奢华
+ 其他
+
+
+
+
+
+
设计布局
+
+ 单栏布局
+ 双栏布局
+ 三栏布局
+ 网格布局
+ 画廊布局
+ 瀑布流
+ 卡片式
+ 侧边栏+内容布局
+ 分屏布局
+ 全屏滚动布局
+ 混合布局
+ 响应式
+ 其他
+
+
+
+
+
+
配色方案
+
+ 蓝色系
+ 绿色系
+ 红色系
+ 黑白灰
+ 纯黑白
+ 暖色调
+ 冷色调
+ 其他
+
+
+
+
+
+
+
+
详细描述(可选)
+
+
+
+
+
+
+
+
+
+
+ 生成
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 复制
+
+
{{ htmlFromLLM }}
+
+
+
+
+
+
+
+
+
diff --git a/src/view/systemTools/autoPkg/autoPkg.vue b/src/view/systemTools/autoPkg/autoPkg.vue
index 4ef2c5a..7a60a75 100644
--- a/src/view/systemTools/autoPkg/autoPkg.vue
+++ b/src/view/systemTools/autoPkg/autoPkg.vue
@@ -123,6 +123,8 @@
callback(new Error('不能为中文'))
} else if (/^\d+$/.test(value[0])) {
callback(new Error('不能够以数字开头'))
+ } else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
+ callback(new Error('只能包含英文字母、数字和下划线'))
} else {
callback()
}
diff --git a/src/view/systemTools/exportTemplate/exportTemplate.vue b/src/view/systemTools/exportTemplate/exportTemplate.vue
index 9136556..86449bf 100644
--- a/src/view/systemTools/exportTemplate/exportTemplate.vue
+++ b/src/view/systemTools/exportTemplate/exportTemplate.vue
@@ -509,7 +509,15 @@ JOINS模式下不支持导入
{
label: 'NOT BETWEEN',
value: 'NOT BETWEEN'
- }
+ },
+ {
+ label: 'IN',
+ value: 'IN'
+ },
+ {
+ label: 'NOT IN',
+ value: 'NOT IN'
+ },
])
const addCondition = () => {
diff --git a/src/view/systemTools/system/system.vue b/src/view/systemTools/system/system.vue
index dfbc913..8411518 100644
--- a/src/view/systemTools/system/system.vue
+++ b/src/view/systemTools/system/system.vue
@@ -202,6 +202,9 @@
+
+
+
立即更新
- 重启服务
+ 重载服务
@@ -1010,7 +1013,7 @@
}
initForm()
const reload = () => {
- ElMessageBox.confirm('确定要重启服务?', '警告', {
+ ElMessageBox.confirm('确定要重载服务?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
diff --git a/src/view/systemTools/version/version.vue b/src/view/systemTools/version/version.vue
new file mode 100644
index 0000000..6f48382
--- /dev/null
+++ b/src/view/systemTools/version/version.vue
@@ -0,0 +1,991 @@
+
+
+
+
+
+
+
+ 创建日期
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+ 展开
+ 收起
+
+
+
+
+
+ 创建发版
+ 导入版本
+ 删除
+
+
+
+
+
+ {{ formatDate(scope.row.CreatedAt) }}
+
+
+
+
+
+
+
+
+
+
+ 查看
+ 下载发版包
+ 删除
+
+
+
+
+
+
+
+
+
+ {{ detailForm.versionName }}
+
+
+ {{ detailForm.versionCode }}
+
+
+ {{ detailForm.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择API
+
+
+
+
+
+
+
+
+
+ {{ data.description }}
+
+
+ {{ data.path }}
+
+
+
+
+
+
+
+
+
+
+
+ 选择字典
+
+
+
+
+
+
+
+
+ {{ data.name || data.label }}
+
+
+ {{ data.type || (data.value ? `值: ${data.value}` : '') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 将JSON文件拖到此处,或点击上传
+
+
+
+ 只能上传JSON文件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
菜单 ({{ getTotalMenuCount() }}项)
+
+
+
+
+
+ {{ data.meta?.title || data.title }}
+ {{ data.path }}
+
+
+
+
+
+
+
+
+
+
API ({{ importPreviewData.apis?.length || 0 }}项)
+
+
+
+
+
+ {{ data.description }}
+ {{ data.path }} [{{ data.method }}]
+
+
+
+
+
+
+
+
+
+
字典 ({{ importPreviewData.dictionaries?.length || 0 }}项)
+
+
+
+
+
+ {{ data.name || data.label }}
+
+ {{ data.type || (data.value ? `值: ${data.value}` : '') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uno.config.js b/uno.config.js
new file mode 100644
index 0000000..779a77e
--- /dev/null
+++ b/uno.config.js
@@ -0,0 +1,26 @@
+import { defineConfig } from '@unocss/vite';
+import presetWind3 from '@unocss/preset-wind3';
+import transformerDirectives from '@unocss/transformer-directives'
+
+export default defineConfig({
+ theme: {
+ backgroundColor: {
+ main: '#F5F5F5'
+ },
+ textColor: {
+ active: 'var(--el-color-primary)'
+ },
+ boxShadowColor: {
+ active: 'var(--el-color-primary)'
+ },
+ borderColor: {
+ 'table-border': 'var(--el-border-color-lighter)'
+ }
+ },
+ presets: [
+ presetWind3({ dark: 'class' })
+ ],
+ transformers: [
+ transformerDirectives(),
+ ],
+})
diff --git a/vite.config.js b/vite.config.js
index 45a40a9..c653ce2 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,4 +1,5 @@
import legacyPlugin from '@vitejs/plugin-legacy'
+import { viteLogo } from './src/core/config'
import Banner from 'vite-plugin-banner'
import * as path from 'path'
import * as dotenv from 'dotenv'
@@ -8,6 +9,8 @@ import vueDevTools from 'vite-plugin-vue-devtools'
import VueFilePathPlugin from './vitePlugin/componentName/index.js'
import { svgBuilder } from 'vite-auto-import-svg'
import { AddSecret } from './vitePlugin/secret'
+import UnoCSS from '@unocss/vite'
+
// @see https://cn.vitejs.dev/config/
export default ({ mode }) => {
AddSecret('')
@@ -20,6 +23,8 @@ export default ({ mode }) => {
}
}
+ viteLogo(process.env)
+
const timestamp = Date.parse(new Date())
const optimizeDeps = {}
@@ -39,9 +44,13 @@ export default ({ mode }) => {
}
}
+ const base = "/"
+ const root = "./"
+ const outDir = "dist"
+
const config = {
- base: '/', // 编译后js导入的资源路径
- root: './', // index.html文件所在位置
+ base: base, // 编译后js导入的资源路径
+ root: root, // index.html文件所在位置
publicDir: 'public', // 静态资源文件夹
resolve: {
alias
@@ -70,14 +79,13 @@ export default ({ mode }) => {
rewrite: (path) =>
path.replace(new RegExp('^' + process.env.VITE_BASE_API), '')
}
- },
- allowedHosts: ['all','lckt.echol.top','lckt.hnlc5588.cn'],
+ }
},
build: {
minify: 'terser', // 是否进行压缩,boolean | 'terser' | 'esbuild',默认使用terser
manifest: false, // 是否产出manifest.json
sourcemap: false, // 是否产出sourcemap.json
- outDir: 'dist', // 产出目录
+ outDir: outDir, // 产出目录
terserOptions: {
compress: {
//生产环境时移除console
@@ -103,10 +111,10 @@ export default ({ mode }) => {
]
}),
vuePlugin(),
- svgBuilder('./src/assets/icons/'),
- svgBuilder('./src/plugin/'),
+ svgBuilder(['./src/plugin/','./src/assets/icons/'],base, outDir,'assets', NODE_ENV),
[Banner(`\n Build based on gin-vue-admin \n Time : ${timestamp}`)],
- VueFilePathPlugin('./src/pathInfo.json')
+ VueFilePathPlugin('./src/pathInfo.json'),
+ UnoCSS()
]
}
return config