@@ -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'
import { useI18n } from 'vue-i18n' // added by mohamed hassan to support multilingual
const { t } = useI18n() // added by mohamed hassan to support multilingual
@@ -427,6 +447,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/web/src/components/upload/common.vue b/web/src/components/upload/common.vue
index 84df41276..c80036e08 100644
--- a/web/src/components/upload/common.vue
+++ b/web/src/components/upload/common.vue
@@ -7,6 +7,7 @@
:on-success="uploadSuccess"
:show-file-list="false"
:data="{'classId': props.classId}"
+ :headers="{'x-token': token}"
multiple
class="upload-btn"
>
@@ -20,7 +21,8 @@
import { ElMessage } from 'element-plus'
import { isVideoMime, isImageMime } from '@/utils/image'
import { getBaseUrl } from '@/utils/format'
- import {Upload} from "@element-plus/icons-vue";
+ import { Upload } from "@element-plus/icons-vue";
+ import { useUserStore } from "@/pinia";
import { useI18n } from 'vue-i18n' // added by mohamed hassan to support multilingual
const { t } = useI18n() // added by mohamed hassan to support multilingual
@@ -29,6 +31,10 @@
name: 'UploadCommon'
})
+ const userStore = useUserStore()
+
+ const token = userStore.token
+
const props = defineProps({
classId: {
type: Number,
diff --git a/web/src/components/upload/cropper.vue b/web/src/components/upload/cropper.vue
index ae8cbd71d..1506a8f8c 100644
--- a/web/src/components/upload/cropper.vue
+++ b/web/src/components/upload/cropper.vue
@@ -8,6 +8,7 @@
:data="{'classId': props.classId}"
:on-success="handleImageSuccess"
:on-change="handleFileChange"
+ :headers="{'x-token': token}"
>
裁剪上传
@@ -87,6 +88,7 @@ import { RefreshLeft, RefreshRight, Plus, Minus } from '@element-plus/icons-vue'
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import { getBaseUrl } from '@/utils/format'
+import { useUserStore } from "@/pinia";
defineOptions({
name: 'CropperImage'
diff --git a/web/src/components/upload/image.vue b/web/src/components/upload/image.vue
index f7676ecec..5c21b004d 100644
--- a/web/src/components/upload/image.vue
+++ b/web/src/components/upload/image.vue
@@ -7,6 +7,7 @@
:before-upload="beforeImageUpload"
:multiple="false"
:data="{'classId': props.classId}"
+ :headers="{'x-token': token}"
>
{{ t('components.upload.image.compressedUpload') }}
@@ -17,7 +18,8 @@
import ImageCompress from '@/utils/image'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
- import {Upload} from "@element-plus/icons-vue";
+ import { Upload } from "@element-plus/icons-vue";
+ import { useUserStore } from "@/pinia";
import { useI18n } from 'vue-i18n' // added by mohamed hassan to support multilingual
const { t } = useI18n() // added by mohamed hassan to support multilingual
@@ -46,6 +48,10 @@
}
})
+ const userStore = useUserStore()
+
+ const token = userStore.token
+
const beforeImageUpload = (file) => {
const isJPG = file.type?.toLowerCase() === 'image/jpeg'
const isPng = file.type?.toLowerCase() === 'image/png'
diff --git a/web/src/core/config.js b/web/src/core/config.js
index a4c562e6e..bb44caffb 100644
--- a/web/src/core/config.js
+++ b/web/src/core/config.js
@@ -17,7 +17,7 @@ export const viteLogo = (env) => {
`> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`
)
)
- console.log(greenText(`> 当前版本:v2.7.9`))
+ console.log(greenText(`> 当前版本:v2.8.2`))
console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`))
console.log(
greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`)
diff --git a/web/src/core/gin-vue-admin.js b/web/src/core/gin-vue-admin.js
index af4289dd7..0823d950b 100644
--- a/web/src/core/gin-vue-admin.js
+++ b/web/src/core/gin-vue-admin.js
@@ -10,7 +10,7 @@ export default {
register(app)
console.log(`
欢迎使用 Gin-Vue-Admin
- 当前版本:v2.7.9
+ 当前版本:v2.8.2
加群方式:微信:shouzi_1994 QQ群:622360840
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
diff --git a/web/src/locales/ar.json b/web/src/locales/ar.json
index d92616626..e8821f66f 100644
--- a/web/src/locales/ar.json
+++ b/web/src/locales/ar.json
@@ -780,6 +780,7 @@
"enterSenderEmail": "يرجى إدخال البريد الإلكتروني للمرسل",
"enterHost": "يرجى إدخال المضيف",
"isSSL": "هل تريد تمكين SSL",
+ "useLoginAuth": "استخدام مصادقة LoginAuth",
"enterSecret": "يرجى إدخال السر",
"testEmail": "اختبار البريد الإلكتروني",
"mongodbOptions": "يرجى إدخال خيارات MongoDB",
diff --git a/web/src/locales/en.json b/web/src/locales/en.json
index 279a6fecb..d6df3928c 100644
--- a/web/src/locales/en.json
+++ b/web/src/locales/en.json
@@ -782,6 +782,7 @@
"enterSenderEmail": "Please Enter Sender Email",
"enterHost": "Please Enter Host",
"isSSL": "Is SSL",
+ "useLoginAuth": "Use LoginAuth authentication",
"enterSecret": "Please Enter Secret",
"testEmail": "Test Email",
"mongodbOptions": "Please Enter MongoDB Options",
diff --git a/web/src/locales/zh-TW.json b/web/src/locales/zh-TW.json
index d0498fcc0..52107d8fb 100644
--- a/web/src/locales/zh-TW.json
+++ b/web/src/locales/zh-TW.json
@@ -639,6 +639,7 @@
"enterSenderEmail": "請輸入發送者郵箱",
"enterHost": "請輸入host",
"isSSL": "是否為ssl",
+ "useLoginAuth": "是否LoginAuth認證",
"enterSecret": "請輸入secret",
"testEmail": "測試郵件",
"mongodbOptions": "請輸入mongodb 選項",
diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json
index 6a31bf243..8fb2f672a 100644
--- a/web/src/locales/zh.json
+++ b/web/src/locales/zh.json
@@ -782,6 +782,7 @@
"enterSenderEmail": "请输入发送者邮箱",
"enterHost": "请输入host",
"isSSL": "是否为ssl",
+ "useLoginAuth": "是否LoginAuth认证",
"enterSecret": "请输入secret",
"testEmail": "测试邮件",
"mongodbOptions": "请输入mongodb 选项",
diff --git a/web/src/pathInfo.json b/web/src/pathInfo.json
index 9757994d1..099d5d671 100644
--- a/web/src/pathInfo.json
+++ b/web/src/pathInfo.json
@@ -26,6 +26,7 @@
"/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",
@@ -56,6 +57,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",
diff --git a/web/src/permission.js b/web/src/permission.js
index 33cd6e1e2..5276aea53 100644
--- a/web/src/permission.js
+++ b/web/src/permission.js
@@ -13,7 +13,7 @@ Nprogress.configure({
})
// 白名单路由
-const WHITE_LIST = ['Login', 'Init', 'ScanUpload']
+const WHITE_LIST = ['Login', 'Init']
// 处理路由加载
const setupRouter = async (userStore) => {
@@ -86,14 +86,15 @@ router.beforeEach(async (to, from) => {
// 白名单路由处理
if (WHITE_LIST.includes(to.name)) {
- if (
- token &&
- !routerStore.asyncRouterFlag &&
- !WHITE_LIST.includes(from.name)
- ) {
- await setupRouter(userStore)
+ if (token) {
+ if(!routerStore.asyncRouterFlag){
+ await setupRouter(userStore)
+ }
+ if(userStore.userInfo.authority.defaultRouter){
+ return { name: userStore.userInfo.authority.defaultRouter }
+ }
}
- return true
+ return true
}
// 需要登录的路由处理
@@ -114,7 +115,7 @@ router.beforeEach(async (to, from) => {
return {
name: 'Login',
- query: { redirect: to.href }
+ query: { redirect: to.fullPath }
}
}
@@ -125,7 +126,7 @@ router.beforeEach(async (to, from) => {
return {
name: 'Login',
query: {
- redirect: document.location.hash
+ redirect: to.fullPath
}
}
})
diff --git a/web/src/pinia/modules/app.js b/web/src/pinia/modules/app.js
index 8b3223535..9eb9dea1f 100644
--- a/web/src/pinia/modules/app.js
+++ b/web/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/web/src/pinia/modules/router.js b/web/src/pinia/modules/router.js
index 15c4ae18e..8b9f8290f 100644
--- a/web/src/pinia/modules/router.js
+++ b/web/src/pinia/modules/router.js
@@ -5,6 +5,7 @@ import { defineStore } from 'pinia'
import { ref, watchEffect } from 'vue'
import i18n from '@/i18n' // added by mohamed hassan to multilangauge
import pathInfo from '@/pathInfo.json'
+import {useRoute} from "vue-router";
const notLayoutRouterArr = []
const keepAliveRoutersArr = []
@@ -59,6 +60,9 @@ export const useRouterStore = defineStore('router', () => {
})
keepAliveRouters.value = Array.from(new Set(keepArrTemp))
}
+
+ const route = useRoute()
+
emitter.on('setKeepAlive', setKeepAliveRouters)
const asyncRouters = ref([])
@@ -81,14 +85,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)
})
diff --git a/web/src/pinia/modules/user.js b/web/src/pinia/modules/user.js
index daee29013..ddd58a00f 100644
--- a/web/src/pinia/modules/user.js
+++ b/web/src/pinia/modules/user.js
@@ -32,7 +32,7 @@ export const useUserStore = defineStore('user', () => {
userInfo.value = val
if (val.originSetting) {
Object.keys(appStore.config).forEach((key) => {
- if (val.originSetting[key]) {
+ if (val.originSetting[key] !== undefined) {
appStore.config[key] = val.originSetting[key]
}
})
@@ -85,7 +85,6 @@ export const useUserStore = defineStore('user', () => {
const res = await login(loginInfo)
if (res.code !== 0) {
- ElMessage.error(res.message || i18n.global.t('pinia.modules.user.loginFailed'))
return false
}
// 登陆成功,设置用户信息和权限相关信息
@@ -102,8 +101,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(i18n.global.t('pinia.modules.user.connectAdmin'))
} else {
await router.replace({ name: userInfo.value.authority.defaultRouter })
}
@@ -138,9 +142,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/web/src/plugin/announcement/view/info.vue b/web/src/plugin/announcement/view/info.vue
index 6d102db89..2cbb83756 100644
--- a/web/src/plugin/announcement/view/info.vue
+++ b/web/src/plugin/announcement/view/info.vue
@@ -99,12 +99,7 @@
>
-
+
{{ formatDate(scope.row.CreatedAt) }}
diff --git a/web/src/router/index.js b/web/src/router/index.js
index e99c82af3..4181603c1 100644
--- a/web/src/router/index.js
+++ b/web/src/router/index.js
@@ -19,7 +19,8 @@ const routes = [
path: '/scanUpload',
name: 'ScanUpload',
meta: {
- title: '扫码上传'
+ title: '扫码上传',
+ client: true
},
component: () => import('@/view/example/upload/scanUpload.vue')
},
diff --git a/web/src/style/element_visiable.scss b/web/src/style/element_visiable.scss
index 4d33aef7b..112c0bf4f 100644
--- a/web/src/style/element_visiable.scss
+++ b/web/src/style/element_visiable.scss
@@ -118,6 +118,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/web/src/utils/request.js b/web/src/utils/request.js
index a0851a520..5913dbb6a 100644
--- a/web/src/utils/request.js
+++ b/web/src/utils/request.js
@@ -5,6 +5,9 @@ import router from '@/router/index'
import { ElLoading } from 'element-plus'
import i18n from '@/i18n' // added by mohamed hassan to multilangauge
+// 添加一个状态变量,用于跟踪是否已有错误弹窗显示
+let errorBoxVisible = false
+
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 99999
@@ -95,7 +98,13 @@ service.interceptors.response.use(
closeLoading()
}
+ // 如果已经有错误弹窗显示,则不再显示新的弹窗
+ if (errorBoxVisible) {
+ return error
+ }
+
if (!error.response) {
+ errorBoxVisible = true
ElMessageBox.confirm(
i18n.global.t('utils.request.requestErrorDetected') +
`${error}
@@ -107,11 +116,15 @@ service.interceptors.response.use(
confirmButtonText: i18n.global.t('utils.request.tryAgainLater'),
cancelButtonText: i18n.global.t('general.cancel')
}
- )
+ ).finally(() => {
+ // 弹窗关闭后重置状态
+ errorBoxVisible = false
+ })
return
}
switch (error.response.status) {
case 500:
+ errorBoxVisible = true
ElMessageBox.confirm(
i18n.global.t('utils.request.interfaceErrorDetected') +
`${error}
` +
@@ -131,9 +144,13 @@ service.interceptors.response.use(
const userStore = useUserStore()
userStore.ClearStorage()
router.push({ name: 'Login', replace: true })
+ }).finally(() => {
+ // 弹窗关闭后重置状态
+ errorBoxVisible = false
})
break
case 404:
+ errorBoxVisible = true
ElMessageBox.confirm(
i18n.global.t('utils.request.interfaceErrorDetected') +
`${error}
` +
@@ -149,9 +166,13 @@ service.interceptors.response.use(
confirmButtonText: i18n.global.t('utils.request.iGotIt'),
cancelButtonText: i18n.global.t('general.cancel')
}
- )
+ ).finally(() => {
+ // 弹窗关闭后重置状态
+ errorBoxVisible = false
+ })
break
case 401:
+ errorBoxVisible = true
ElMessageBox.confirm(
i18n.global.t('utils.request.invalidToken') +
`` +
@@ -170,6 +191,9 @@ service.interceptors.response.use(
const userStore = useUserStore()
userStore.ClearStorage()
router.push({ name: 'Login', replace: true })
+ }).finally(() => {
+ // 弹窗关闭后重置状态
+ errorBoxVisible = false
})
break
}
diff --git a/web/src/view/example/upload/scanUpload.vue b/web/src/view/example/upload/scanUpload.vue
index 8fd922673..59845d7e9 100644
--- a/web/src/view/example/upload/scanUpload.vue
+++ b/web/src/view/example/upload/scanUpload.vue
@@ -84,6 +84,7 @@ import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import { getBaseUrl } from '@/utils/format'
import { useRouter } from 'vue-router'
+import { useUserStore } from "@/pinia";
defineOptions({
name: 'scanUpload'
diff --git a/web/src/view/layout/aside/asideComponent/index.vue b/web/src/view/layout/aside/asideComponent/index.vue
index 32e7d4186..cebcc4a57 100644
--- a/web/src/view/layout/aside/asideComponent/index.vue
+++ b/web/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/web/src/view/layout/aside/asideComponent/menuItem.vue b/web/src/view/layout/aside/asideComponent/menuItem.vue
index b6b4ff777..1bcf67fca 100644
--- a/web/src/view/layout/aside/asideComponent/menuItem.vue
+++ b/web/src/view/layout/aside/asideComponent/menuItem.vue
@@ -1,14 +1,16 @@
+
+ {{ isCollapse ? routerInfo.meta.title[0] : "" }}
+
{{ routerInfo.meta.title }}
@@ -16,7 +18,7 @@
-