8 Commits

Author SHA1 Message Date
RuoYi
ed36e23505 优化防重提交间隔时间可自定义 2026-01-08 13:39:52 +08:00
RuoYi
2e30c2cecc 优化yarn下富文本控制台警告异常 2026-01-07 15:51:59 +08:00
RuoYi
a1bee42238 暗黑模式底部版权效果优化 2026-01-05 16:32:20 +08:00
RuoYi
2a72074832 暗黑模式菜单效果优化 2026-01-05 16:21:45 +08:00
RuoYi
577376c807 copyright 2026 2026-01-05 14:32:28 +08:00
RuoYi
eee7482e04 update dicttag 2026-01-05 14:26:18 +08:00
RuoYi
c6f3d8b455 暗黑模式切换效果优化 2026-01-04 14:41:59 +08:00
RuoYi
686fd011a9 优化topbar顶部菜单样式 2025-12-18 14:40:52 +08:00
10 changed files with 141 additions and 29 deletions

View File

@@ -47,5 +47,8 @@
},
"overrides": {
"quill": "2.0.2"
},
"resolutions": {
"quill": "2.0.2"
}
}

View File

@@ -1 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg>
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path fill="#5a5e66" d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg>

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 226 B

View File

@@ -156,12 +156,10 @@
width: inherit;
}
/* el menu */
.el-menu-item,
.el-sub-menu {
.svg-icon + span {
margin-left: 5px;
}
/* horizontal el menu */
.el-menu--horizontal .el-menu-item .svg-icon + span,
.el-menu--horizontal .el-sub-menu__title .svg-icon + span {
margin-left: 3px;
}
.el-menu--horizontal .el-menu--popup {

View File

@@ -47,3 +47,34 @@
.breadcrumb-leave-active {
position: absolute;
}
/* 黑暗模式下过渡效果 */
::view-transition-new(root), ::view-transition-old(root) {
animation: none !important;
backface-visibility: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.dark::view-transition-old(root) {
z-index: 2147483646;
background: var(--bg-color-dark);
}
.dark::view-transition-new(root) {
z-index: 1;
background: var(--bg-color);
}
::view-transition-old(root) {
z-index: 1;
background: var(--bg-color);
}
::view-transition-new(root) {
z-index: 2147483646;
background: var(--bg-color-dark);
}

View File

@@ -89,6 +89,9 @@ html.dark {
--el-text-color-regular: #d0d0d0;
--el-border-color: #434343;
--el-border-color-light: #434343;
/* primary */
--primary-bg: #18212b;
/* 侧边栏 */
--sidebar-bg: #141414;
@@ -127,8 +130,8 @@ html.dark {
--splitpanes-default-bg: #141414;
/* 侧边栏菜单覆盖 */
.sidebar-container {
.el-menu-item, .menu-title {
.sidebar-container {
.el-menu-item:not(.is-active), .menu-title {
color: var(--el-text-color-regular);
}
& .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
@@ -137,13 +140,27 @@ html.dark {
}
}
.topmenu-container {
.el-menu-item,
.el-sub-menu .el-sub-menu__title {
color: var(--el-text-color-regular) !important;
}
}
.topbar-menu.el-menu--horizontal > .el-sub-menu .el-sub-menu__title{
color: var(--el-text-color-regular) !important;
}
/* 顶部栏栏菜单覆盖 */
.el-menu--horizontal {
.el-menu-item {
.el-menu-item, .el-sub-menu {
&:not(.is-disabled) {
&:hover,
&:focus {
background-color: var(--navbar-hover) !important;
.el-sub-menu__title {
background-color: var(--navbar-hover) !important;
}
}
}
}
@@ -173,6 +190,33 @@ html.dark {
}
}
/* 按钮样式覆盖 */
.el-button--primary.is-plain {
background-color: var(--primary-bg);
border: 1px solid var(--el-color-primary-light-2);
color: var(--el-color-primary-light-2);
&:hover {
background-color: var(--el-button-hover-bg-color);
border-color: var(--el-button-hover-border-color);
color: var(--el-button-hover-text-color);
}
&.is-disabled {
background-color: var(--link-active-bg-color);
border-color: var(--el-color-primary-light-3);
color: var(--el-color-primary-light-3);
opacity: 0.5;
}
}
/* primary tag 样式覆盖 */
.el-tag--primary {
background-color: var(--primary-bg);
border: 1px solid var(--el-border-color-light);
color: var(--el-color-primary);
}
/* 表格样式覆盖 */
.el-table {
--el-table-header-bg-color: var(--el-bg-color-overlay) !important;
@@ -217,5 +261,11 @@ html.dark {
background: var(--cron-border);
}
/* 底部版权样式覆盖 */
.copyright {
background-color: var(--el-bg-color) !important;
color: var(--el-text-color-regular) !important;
border-top: 1px solid var(--el-bg-color) !important;
}
}

View File

@@ -76,7 +76,7 @@ function handleArray(array) {
}
function isValueMatch(itemValue) {
return this.values.some(val => val == itemValue)
return values.value.some(val => val == itemValue)
}
</script>

View File

@@ -111,8 +111,44 @@ function setLayout() {
emits('setLayout')
}
function toggleTheme() {
settingsStore.toggleTheme()
async function toggleTheme(event) {
const x = event?.clientX || window.innerWidth / 2
const y = event?.clientY || window.innerHeight / 2
const wasDark = settingsStore.isDark
const isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches
const isSupported = document.startViewTransition && !isReducedMotion
if (!isSupported) {
settingsStore.toggleTheme()
return
}
try {
const transition = document.startViewTransition(async () => {
await new Promise((resolve) => setTimeout(resolve, 10))
settingsStore.toggleTheme()
await nextTick()
})
await transition.ready
const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y))
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
document.documentElement.animate(
{
clipPath: !wasDark ? [...clipPath].reverse() : clipPath
}, {
duration: 650,
easing: "cubic-bezier(0.4, 0, 0.2, 1)",
fill: "forwards",
pseudoElement: !wasDark ? "::view-transition-old(root)" : "::view-transition-new(root)"
}
)
await transition.finished
} catch (error) {
console.warn("View transition failed, falling back to immediate toggle:", error)
settingsStore.toggleTheme()
}
}
</script>

View File

@@ -58,6 +58,11 @@ onMounted(() => {
</script>
<style lang="scss">
/* menu item */
.topbar-menu.el-menu--horizontal .el-submenu__title, .topbar-menu.el-menu--horizontal .el-menu-item {
padding: 0 10px !important;
}
.topbar-menu.el-menu--horizontal > .el-menu-item {
float: left;
height: 50px !important;
@@ -74,21 +79,9 @@ onMounted(() => {
/* sub-menu item */
.topbar-menu.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
float: left;
height: 62px !important;
line-height: 50px !important;
color: #303133 !important;
padding: 0 5px !important;
margin: 0 20px -4px!important;
}
/* 背景色隐藏 */
.topbar-menu.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topbar-menu.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topbar-menu.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
background-color: #ffffff;
}
/* 图标右间距 */
.topbar-menu .svg-icon {
margin-right: 4px;
margin: 0 15px -3px!important;
}
/* topbar more arrow */

View File

@@ -52,6 +52,6 @@ export default {
/**
* 底部版权文本内容
*/
footerContent: 'Copyright © 2018-2025 RuoYi. All Rights Reserved.'
footerContent: 'Copyright © 2018-2026 RuoYi. All Rights Reserved.'
}

View File

@@ -26,6 +26,8 @@ service.interceptors.request.use(config => {
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
// 间隔时间(ms),小于此时间视为重复提交
const interval = (config.headers || {}).interval || 1000
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
@@ -55,7 +57,6 @@ service.interceptors.request.use(config => {
const s_url = sessionObj.url // 请求地址
const s_data = sessionObj.data // 请求数据
const s_time = sessionObj.time // 请求时间
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交'
console.warn(`[${s_url}]: ` + message)
@@ -115,7 +116,7 @@ service.interceptors.response.use(res => {
} else if (message.includes("timeout")) {
message = "系统接口请求超时"
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常"
message = "系统接口" + message.slice(-3) + "异常"
}
ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)