完善全局样式

This commit is contained in:
2026-04-28 16:52:22 +08:00
parent 6eca9768cc
commit 539889a346
5 changed files with 367 additions and 208 deletions

View File

@@ -128,7 +128,7 @@ redisson:
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
# 最小空闲连接数ACT_ID_PROPERTY
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64

View File

@@ -101,25 +101,9 @@
border-radius: 4px;
}
:global(.el-button) {
color: #fff !important;
}
:global(.el-button > span),
:global(.el-button > span *) ,
:global(.el-button .svg-icon),
:global(.el-button i) {
color: inherit !important;
fill: currentColor;
}
:global(.el-button--default) {
color: var(--app-primary) !important;
}
:global(.el-button--default > span),
:global(.el-button--default > span *),
:global(.el-button--default .svg-icon),
:global(.el-button--default i) {
color: inherit !important;
/* 按钮结构样式(颜色逻辑统一在 index.scss 管理) */
.el-button {
border-radius: 4px !important;
font-weight: 600 !important;
letter-spacing: 0.4px !important;
}

View File

@@ -53,63 +53,45 @@ body {
// ====================== 5. 组件尺寸样式(按优先级合并)======================
// ---------------------- 5.1 按钮(紧凑尺寸)----------------------
@mixin button-variant() {
border-radius: 6px;
transition: all .25s ease;
border-radius: 4px;
transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
height: $--btn-height;
padding: 0 var(--spacing-lg);
font-size: 13px;
font-weight: 600;
letter-spacing: 0.4px;
&:hover,
&:focus {
transform: translateY(-1px);
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15);
}
&:active {
transform: translateY(1px);
filter: brightness(0.88);
}
&.is-disabled,
&[disabled] {
cursor: not-allowed;
opacity: 0.55;
}
}
// 主按钮(尺寸相关
.el-button--primary {
@include button-variant();
background: $industrial-primary;
border-color: $industrial-primary;
color: #fff !important;
&:hover,
&:focus {
background: $industrial-secondary;
border-color: $industrial-secondary;
color: #fff !important;
}
}
// 功能按钮(尺寸相关)
// 各类型按钮统一套 mixin颜色由 index.scss CSS变量控制
.el-button--primary,
.el-button--success,
.el-button--danger,
.el-button--info {
@include button-variant();
}
.el-button--info,
.el-button--warning {
@include button-variant();
color: #1c2b3a !important;
&:hover,
&:focus {
color: #1c2b3a !important;
}
}
// 文本按钮(尺寸相关)
.el-button--text {
// 文本/Link按钮
.el-button--text,
.el-button.is-text {
height: auto;
padding: 4px 8px;
padding: 2px 6px;
border-radius: 4px !important;
}
// 图标按钮(圆形紧凑尺寸)

View File

@@ -219,49 +219,89 @@ aside {
}
.el-button {
--el-button-disabled-text-color: rgba(255, 255, 255, 0.72);
color: #ffffff;
/* 不在此设全局 color由各类型规则单独控制 */
}
.el-button__text,
.el-button span,
.el-button > span,
.el-button .svg-icon,
.el-button i {
color: inherit;
fill: currentColor;
}
.el-button--default {
--el-button-text-color: var(--app-primary);
color: var(--app-primary);
/* ════════════════════════════════════════════
按钮色彩系统
实心按钮 → 白字
Plain变体 → 浅底色 + 比边框更深的文字
Link/Text变体 → 透明底 + 各类型色文字
════════════════════════════════════════════ */
/* 子元素颜色继承 */
.el-button > span,
.el-button .svg-icon,
.el-button i {
color: inherit !important;
fill: currentColor;
}
.el-button--default .el-button__text,
.el-button--default span,
.el-button--default .svg-icon,
.el-button--default i {
color: inherit;
/* ── Default白底工业蓝描边 ── */
.el-button--default:not(.is-link):not(.is-text) {
color: #1d4e89 !important;
}
.el-button--default.is-link,
.el-button--default.is-text,
.el-button--text {
--el-button-text-color: var(--app-primary);
color: var(--app-primary);
background: transparent;
border-color: transparent;
padding: 0 4px;
color: #1d4e89 !important;
background: transparent !important;
border-color: transparent !important;
}
.el-button--text:hover,
.el-button--text:focus {
color: var(--app-secondary);
background: transparent;
border-color: transparent;
}
/* ── Primary ── */
.el-button.el-button--primary:not(.is-plain):not(.is-link):not(.is-text) { color: #ffffff !important; }
.el-button.el-button--primary.is-plain { color: #122f55 !important; }
.el-button.el-button--primary.is-link,
.el-button.el-button--primary.is-text { color: #1d4e89 !important; background: transparent !important; border-color: transparent !important; }
.el-button.el-button--primary.is-link:hover,
.el-button.el-button--primary.is-text:hover { color: #2471a3 !important; }
.el-button--text .el-button__text,
.el-button--text span,
.el-button--text .svg-icon,
.el-button--text i {
color: inherit;
/* ── Success ── */
.el-button.el-button--success:not(.is-plain):not(.is-link):not(.is-text) { color: #ffffff !important; }
.el-button.el-button--success.is-plain { color: #1b5e20 !important; }
.el-button.el-button--success.is-link,
.el-button.el-button--success.is-text { color: #388e3c !important; background: transparent !important; border-color: transparent !important; }
.el-button.el-button--success.is-link:hover,
.el-button.el-button--success.is-text:hover { color: #2e7d32 !important; }
/* ── Warning ── */
.el-button.el-button--warning:not(.is-plain):not(.is-link):not(.is-text) { color: #ffffff !important; }
.el-button.el-button--warning.is-plain { color: #7f3300 !important; }
.el-button.el-button--warning.is-link,
.el-button.el-button--warning.is-text { color: #e65100 !important; background: transparent !important; border-color: transparent !important; }
.el-button.el-button--warning.is-link:hover,
.el-button.el-button--warning.is-text:hover { color: #f57c00 !important; }
/* ── Danger ── */
.el-button.el-button--danger:not(.is-plain):not(.is-link):not(.is-text) { color: #ffffff !important; }
.el-button.el-button--danger.is-plain { color: #7f0000 !important; }
.el-button.el-button--danger.is-link,
.el-button.el-button--danger.is-text { color: #c62828 !important; background: transparent !important; border-color: transparent !important; }
.el-button.el-button--danger.is-link:hover,
.el-button.el-button--danger.is-text:hover { color: #e53935 !important; }
/* ── Info ── */
.el-button.el-button--info:not(.is-plain):not(.is-link):not(.is-text) { color: #ffffff !important; }
.el-button.el-button--info.is-plain { color: #263238 !important; }
.el-button.el-button--info.is-link,
.el-button.el-button--info.is-text { color: #455a64 !important; background: transparent !important; border-color: transparent !important; }
.el-button.el-button--info.is-link:hover,
.el-button.el-button--info.is-text:hover { color: #37474f !important; }
/* ── Link / Text hover 通用背景 ── */
.el-button.is-link:hover,
.el-button.is-text:hover,
.el-button--text:hover {
background: rgba(0, 0, 0, 0.04) !important;
border-color: transparent !important;
}
.el-card__header {
@@ -278,65 +318,97 @@ aside {
--el-table-row-hover-bg-color: #f7fbff;
}
.el-button--primary,
.el-button--success,
.el-button--danger,
.el-button--info {
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255, 255, 255, 0.72);
}
.el-button--warning {
--el-button-text-color: #ffffff;
--el-button-disabled-text-color: rgba(255, 255, 255, 0.72);
--el-button-bg-color: var(--app-warning);
--el-button-border-color: var(--app-warning);
--el-button-hover-bg-color: #e09a1b;
--el-button-hover-border-color: #e09a1b;
--el-button-active-bg-color: #c97f0f;
--el-button-active-border-color: #c97f0f;
color: #ffffff;
}
.el-button--warning.is-plain {
--el-button-text-color: #d68910;
--el-button-border-color: #f0c674;
--el-button-bg-color: #fff6e5;
--el-button-hover-text-color: #d68910;
--el-button-hover-bg-color: #fff0d6;
--el-button-hover-border-color: #d68910;
--el-button-active-text-color: #c97f0f;
--el-button-active-border-color: #c97f0f;
color: #d68910;
}
/* ── Element Plus CSS变量 → 各类型独立色彩系统 ── */
.el-button--primary {
--el-button-bg-color: #1d4e89;
--el-button-border-color: #1d4e89;
--el-button-hover-bg-color: #2471a3;
--el-button-hover-border-color: #2471a3;
--el-button-active-bg-color: #1c2b3a;
--el-button-active-border-color: #1c2b3a;
--el-button-active-bg-color: #163a68;
--el-button-active-border-color: #163a68;
--el-button-disabled-bg-color: #6b96c4;
--el-button-disabled-border-color: #6b96c4;
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255,255,255,.6);
}
.el-button--primary.is-plain {
--el-button-bg-color: #e8f0fb;
--el-button-border-color: #1d4e89;
--el-button-hover-bg-color: #d4e4f7;
--el-button-hover-border-color: #2471a3;
--el-button-text-color: #122f55;
}
.el-button--success {
--el-button-bg-color: #4b8b3b;
--el-button-border-color: #4b8b3b;
--el-button-bg-color: #388e3c;
--el-button-border-color: #388e3c;
--el-button-hover-bg-color: #2e7d32;
--el-button-hover-border-color: #2e7d32;
--el-button-active-bg-color: #1b5e20;
--el-button-active-border-color: #1b5e20;
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255,255,255,.6);
}
.el-button--success.is-plain {
--el-button-bg-color: #e8f5e9;
--el-button-border-color: #388e3c;
--el-button-hover-bg-color: #d4edda;
--el-button-hover-border-color: #2e7d32;
--el-button-text-color: #1b5e20;
}
.el-button--warning {
--el-button-bg-color: #d68910;
--el-button-border-color: #d68910;
--el-button-bg-color: #f57c00;
--el-button-border-color: #f57c00;
--el-button-hover-bg-color: #e65100;
--el-button-hover-border-color: #e65100;
--el-button-active-bg-color: #bf360c;
--el-button-active-border-color: #bf360c;
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255,255,255,.6);
}
.el-button--warning.is-plain {
--el-button-bg-color: #fff3e0;
--el-button-border-color: #f57c00;
--el-button-hover-bg-color: #ffe0b2;
--el-button-hover-border-color: #e65100;
--el-button-text-color: #bf360c;
}
.el-button--danger {
--el-button-bg-color: #c0392b;
--el-button-border-color: #c0392b;
--el-button-bg-color: #c62828;
--el-button-border-color: #c62828;
--el-button-hover-bg-color: #b71c1c;
--el-button-hover-border-color: #b71c1c;
--el-button-active-bg-color: #8b0000;
--el-button-active-border-color: #8b0000;
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255,255,255,.6);
}
.el-button--danger.is-plain {
--el-button-bg-color: #ffebee;
--el-button-border-color: #c62828;
--el-button-hover-bg-color: #ffcdd2;
--el-button-hover-border-color: #b71c1c;
--el-button-text-color: #8b0000;
}
.el-button--info {
--el-button-bg-color: #1c2b3a;
--el-button-border-color: #1c2b3a;
--el-button-bg-color: #455a64;
--el-button-border-color: #455a64;
--el-button-hover-bg-color: #37474f;
--el-button-hover-border-color: #37474f;
--el-button-active-bg-color: #263238;
--el-button-active-border-color: #263238;
--el-button-text-color: #fff;
--el-button-disabled-text-color: rgba(255,255,255,.6);
}
.el-button--info.is-plain {
--el-button-bg-color: #eceff1;
--el-button-border-color: #455a64;
--el-button-hover-bg-color: #cfd8dc;
--el-button-hover-border-color: #37474f;
--el-button-text-color: #263238;
}
.el-tag--success {

View File

@@ -1,16 +1,31 @@
<template>
<div :class="{ 'hidden': hidden }" class="pagination-container">
<el-pagination
:background="background"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:pager-count="pagerCount"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<div v-if="!hidden" class="gear-pagination">
<span class="gear-pg-info"> <b>{{ total }}</b> </span>
<select v-model="pageSize" class="gear-pg-select" @change="handleSizeChange">
<option v-for="s in pageSizes" :key="s" :value="s">{{ s }}/</option>
</select>
<div class="gear-pg-pager">
<button class="gear-pg-btn gear-pg-nav" :disabled="currentPage <= 1" @click="changePage(currentPage - 1)">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none"><path d="M5.5 1L2.5 4L5.5 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/></svg>
</button>
<template v-for="(p, i) in displayPages" :key="i">
<span v-if="p === '...'" class="gear-pg-ellipsis">···</span>
<button v-else :class="['gear-pg-btn', { active: p === currentPage }]" @click="changePage(p)">{{ p }}</button>
</template>
<button class="gear-pg-btn gear-pg-nav" :disabled="currentPage >= totalPages" @click="changePage(currentPage + 1)">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none"><path d="M2.5 1L5.5 4L2.5 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/></svg>
</button>
</div>
<div class="gear-pg-jumper">
<span class="gear-pg-label">前往</span>
<input v-model.number="jumpVal" type="number" class="gear-pg-input" :min="1" :max="totalPages" @keyup.enter="handleJump" />
<span class="gear-pg-label"></span>
</div>
</div>
</template>
@@ -18,88 +33,194 @@
import { scrollTo } from '@/utils/scroll-to'
const props = defineProps({
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
// 移动端页码按钮的数量端默认值5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
total: { required: true, type: Number },
page: { type: Number, default: 1 },
limit: { type: Number, default: 20 },
pageSizes: { type: Array, default: () => [10, 20, 30, 50] },
pagerCount: { type: Number, default: document.body.clientWidth < 992 ? 5 : 7 },
autoScroll: { type: Boolean, default: true },
hidden: { type: Boolean, default: false }
})
const emit = defineEmits()
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
const jumpVal = ref(props.page)
const currentPage = computed({
get() {
return props.page
},
set(val) {
emit('update:page', val)
}
get: () => props.page,
set: val => emit('update:page', val)
})
const pageSize = computed({
get() {
return props.limit
},
set(val){
emit('update:limit', val)
}
get: () => props.limit,
set: val => emit('update:limit', val)
})
function handleSizeChange(val) {
if (currentPage.value * val > props.total) {
currentPage.value = 1
}
emit('pagination', { page: currentPage.value, limit: val })
if (props.autoScroll) {
scrollTo(0, 800)
}
const totalPages = computed(() => Math.max(1, Math.ceil(props.total / props.limit)))
const displayPages = computed(() => {
const total = totalPages.value
const cur = currentPage.value
const count = props.pagerCount
if (total <= count) return Array.from({ length: total }, (_, i) => i + 1)
const half = Math.floor(count / 2)
let start = Math.max(1, cur - half)
let end = Math.min(total, start + count - 1)
if (end - start < count - 1) start = Math.max(1, end - count + 1)
const pages = []
if (start > 1) { pages.push(1); if (start > 2) pages.push('...') }
for (let i = start; i <= end; i++) pages.push(i)
if (end < total) { if (end < total - 1) pages.push('...'); pages.push(total) }
return pages
})
function changePage(p) {
if (p < 1 || p > totalPages.value || p === currentPage.value) return
currentPage.value = p
jumpVal.value = p
emit('pagination', { page: p, limit: pageSize.value })
if (props.autoScroll) scrollTo(0, 800)
}
function handleCurrentChange(val) {
emit('pagination', { page: val, limit: pageSize.value })
if (props.autoScroll) {
scrollTo(0, 800)
function handleSizeChange() {
const newPage = currentPage.value * pageSize.value > props.total ? 1 : currentPage.value
currentPage.value = newPage
emit('pagination', { page: newPage, limit: pageSize.value })
if (props.autoScroll) scrollTo(0, 800)
}
function handleJump() {
changePage(Math.min(Math.max(1, Math.round(jumpVal.value)), totalPages.value))
}
watch(() => props.page, val => { jumpVal.value = val })
</script>
<style scoped>
.pagination-container {
background: #fff;
<style scoped lang="scss">
$p: #1d4e89;
$pd: #122f55;
$pl: #2471a3;
$bd: #c8d4e4;
$h: 22px;
.gear-pagination {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
margin-top: 8px;
border-top: 2px solid $p;
flex-wrap: wrap;
}
.pagination-container.hidden {
display: none;
.gear-pg-info {
font-size: 12px;
color: #7a8fa6;
white-space: nowrap;
b { color: $p; font-weight: 700; }
}
.gear-pg-select {
height: $h;
padding: 0 18px 0 6px;
border: 1px solid $bd;
border-left: 2px solid $p;
background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%231d4e89'/%3E%3C/svg%3E") right 5px center no-repeat;
background-size: 7px;
appearance: none;
font-size: 12px;
font-weight: 600;
color: #1c2b3a;
cursor: pointer;
border-radius: 2px;
outline: none;
&:hover { border-color: $pl; }
}
.gear-pg-pager {
display: flex;
align-items: center;
gap: 2px;
}
.gear-pg-btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: $h;
height: $h;
padding: 0 4px;
border: 1px solid $bd;
background: #fff;
color: #1c2b3a;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border-radius: 2px;
transition: background .1s, color .1s, border-color .1s;
&:hover:not(:disabled) {
border-color: $p;
color: $p;
background: #f0f5ff;
}
&.active {
background: $p;
border-color: $p;
border-left: 2px solid $pd;
color: #fff;
}
}
.gear-pg-nav {
color: $p;
border-color: $p;
&:disabled { opacity: 0.3; cursor: not-allowed; }
}
.gear-pg-ellipsis {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: $h;
font-size: 11px;
color: #7a8fa6;
user-select: none;
}
.gear-pg-jumper {
display: flex;
align-items: center;
gap: 3px;
margin-left: auto;
}
.gear-pg-label {
font-size: 12px;
color: #7a8fa6;
white-space: nowrap;
}
.gear-pg-input {
width: 36px;
height: $h;
border: 1px solid $bd;
border-left: 2px solid $p;
border-radius: 2px;
padding: 0 3px;
font-size: 12px;
font-weight: 600;
color: #1c2b3a;
text-align: center;
outline: none;
-moz-appearance: textfield;
transition: border-color .1s;
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button { display: none; }
&:hover, &:focus { border-color: $pl; }
}
@media (max-width: 768px) {
.gear-pg-jumper, .gear-pg-select { display: none; }
}
</style>