Commit 2ae44490 by ningjihai

UI修改,字典管理

parent 4f51b614
......@@ -89,4 +89,21 @@
> .el-submenu__title
.el-submenu__icon-arrow {
display: none;
}
/* 全局修复,确保所有 el-select 在表单中宽度为 100% */
.page-wrapper-search .el-select {
width: 100%;
}
.page-wrapper-search .el-form-item__content .el-select {
width: 100%;
}
.page-wrapper-search .el-form-item__content .el-date-editor {
width: 100%;
}
.page-wrapper-search .el-form-item {
display: flex;
}
.page-wrapper-search .el-form-item__content {
flex: 1;
}
\ No newline at end of file
......@@ -4,7 +4,9 @@
**/
/* theme color */
$--color-primary: #1890ff;
// $--color-primary: #1890ff;
$--color-primary: #356CEF;
$--color-success: #13ce66;
$--color-warning: #ffba00;
$--color-danger: #ff4949;
......
......@@ -122,6 +122,31 @@ aside {
//main-container全局样式
.app-container {
padding: 20px;
padding-top: 10px;
flex: 1;
border-radius: 4px;
box-sizing: border-box;
// box-shadow: 2px 2px 4px rgba(30, 92, 235, 0.1);
// margin: 10px;
// background-color: #fff;
display: flex;
flex-direction: column;
min-height: 200px;
}
.page-container {
padding: 20px;
flex: 1;
border-radius: 4px;
box-sizing: border-box;
box-shadow: 2px 2px 4px rgba(30, 92, 235, 0.1);
background-color: #fff;
display: flex;
flex-direction: column;
min-height: 200px;
}
.table-container{
flex: 1;
min-height: 200px;
}
.components-container {
......
......@@ -5,6 +5,8 @@
transition: margin-left .28s;
margin-left: $base-sidebar-width;
position: relative;
display: flex;
flex-direction: column;
}
.sidebarHide {
......@@ -74,6 +76,7 @@
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
// menu hover
......@@ -86,6 +89,7 @@
& .theme-dark .is-active > .el-submenu__title {
color: $base-menu-color-active !important;
}
& .nest-menu .el-submenu>.el-submenu__title,
......@@ -224,4 +228,113 @@
border-radius: 20px;
}
}
.theme-dark{
.el-submenu__title {
i{
color: #fff;
}
}
}
}
.theme-dark {
.el-submenu__title {
i {
color: #fff !important;
}
// 或者更具体地选择箭头图标
.el-icon-arrow-down,
.el-icon-arrow-up {
color: #fff !important;
}
}
.svg-icon {
color: #fff !important;
}
span {
color: #fff !important;
}
}
.el-menu {
// 鼠标悬浮在菜单项上的样式
.el-menu-item:hover,
.el-submenu__title:hover {
position: relative;
&::after {
content: '';
position: absolute;
top: 5%;
bottom: 5%;
left: 5%;
right: 5%;
background-color: rgba(255,255,255,0.15);
border-radius: 6px;
transition: all 0.3s ease;
pointer-events: none;
}
}
// 选中的子菜单项样式
.el-menu-item.is-active {
position: relative;
&::after {
content: '';
position: absolute;
top: 5%;
bottom: 5%;
left: 5%;
right: 5%;
background-color: rgba(255,255,255,0.15);
border-radius: 6px;
transition: all 0.3s ease;
pointer-events: none;
}
}
// 打开的父级菜单样式
.el-submenu.is-opened {
> .el-submenu__title {
position: relative;
&::after {
content: '';
position: absolute;
top: 5%;
bottom: 5%;
left: 5%;
right: 5%;
background-color: rgba(255,255,255,0.15);
border-radius: 6px;
transition: all 0.3s ease;
pointer-events: none;
}
}
}
// 选中的父级菜单样式(如果有的话)
.el-submenu.is-active {
> .el-submenu__title {
position: relative;
&::after {
content: '';
position: absolute;
top: 5%;
bottom: 5%;
left: 5%;
right: 5%;
background-color: rgba(255,255,255,0.15);
border-radius: 6px;
transition: all 0.3s ease;
pointer-events: none;
}
}
}
}
\ No newline at end of file
......@@ -9,17 +9,17 @@ $yellow:#FEC171;
$panGreen: #30B08F;
// 默认菜单主题风格
$base-menu-color:#bfcbd9;
$base-menu-color:#fff;
$base-menu-color-active:#f4f4f5;
$base-menu-background:#304156;
$base-menu-background:#356cec;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#1f2d3d;
$base-sub-menu-hover:#001528;
$base-sub-menu-background:#356cec;
$base-sub-menu-hover:#2f61d4;
// 自定义暗色菜单风格
/**
......
<template>
<div class="page-title">
<div
class="page-title-container">
<div class="left-part">
<el-button
v-if="back"
icon="el-icon-back"
class="page-back-logo"
type="text"
size="large"
@click="handlePageBack"
/>
<div class="title">
<slot>{{ titleStr }}</slot>
</div>
</div>
<div class="right-part">
<slot name="buttons" />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PageTitle',
props: {
back: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
}
},
data() {
return {
settingsStore: null,
appStore: null,
route: null
}
},
computed: {
titleStr() {
return this.title || String(this.route?.meta?.title || '')
},
},
mounted() {
// 模拟 Vue 3 的 store 和 route
this.initStores()
},
methods: {
initStores() {
// 这里需要根据您的实际 store 结构进行调整
// 假设您有类似 Vuex store 的结构
try {
this.settingsStore = this.$store?.state?.settings || {}
this.appStore = this.$store?.state?.app || {}
this.route = this.$route || {}
} catch (error) {
console.warn('Store or route not available, using default values')
this.settingsStore = {}
this.appStore = {}
this.route = {}
}
},
handlePageBack() {
this.$emit('back')
}
}
}
</script>
<style lang="scss" scoped>
.page-title {
margin-bottom: 10px;
.page-title-container {
height: 48px;
padding: 0 20px;
display: flex;
justify-content: space-between;
border-radius: 4px;
background: rgba(255, 255, 255, 1);
box-shadow: 2px 2px 4px rgba(30, 92, 235, 0.1);
align-items: center;
.left-part {
font-size: 16px;
color: rgb(46, 46, 46);
}
}
}
</style>
\ No newline at end of file
<script>
const XS = 0
const SM = 768
const MD = 992
const LG = 1200
const XL = 1920
export default {
name: 'PageWrapperSearch',
emits: ['update:advanced', 'search', 'reset'],
components: {
ElRow: () => import('element-ui/lib/row'),
ElCol: () => import('element-ui/lib/col'),
ElForm: () => import('element-ui/lib/form'),
ElFormItem: () => import('element-ui/lib/form-item'),
ElIcon: () => import('element-ui/lib/icon'),
ElButton: () => import('element-ui/lib/button')
},
props: {
xs: {
type: Number,
default: 24
},
sm: {
type: Number,
default: 24
},
md: {
type: Number,
default: 12
},
lg: {
type: Number,
default: 8
},
xl: {
type: Number,
default: 6
},
labelWidth: [Number, String]
},
data() {
return {
observer: null,
ElFormRef: null,
max: 0,
isAdvanced: true,
isFold: true, // 默认折叠状态
labelWidthValue: '',
inputEvents: [],
screenWidth: 1920
}
},
computed: {
gutter() {
return (24 / this.max % 24) || 0
},
// 计算每行最多能显示的列数
maxItemsPerRow() {
return Math.floor(24 / this.currentColWidth)
},
// 获取当前屏幕尺寸对应的列宽
currentColWidth() {
if (this.screenWidth >= XL) return this.xl
if (this.screenWidth >= LG) return this.lg
if (this.screenWidth >= MD) return this.md
if (this.screenWidth >= SM) return this.sm
return this.xs
},
// 是否显示折叠按钮
shouldShowFoldButton() {
const formItems = this.extractFormItems(this.$slots.default || [])
return formItems.length > this.maxItemsPerRow - 1
},
// 折叠状态下每行最多显示的表单项数量(包括按钮列)
maxVisibleItemsWhenFold() {
return Math.max(1, this.maxItemsPerRow - 1) // 减去按钮列
},
// 是否需要将按钮放在单独一行
shouldWrapButtons() {
return !this.isFold && this.shouldShowFoldButton
}
},
mounted() {
this.screenWidth = document.documentElement.clientWidth
this.observer = new ResizeObserver((entries) => {
if (entries[0].contentRect.width > 0) {
this.initSize()
}
})
if (this.ElFormRef?.$el) {
this.observer.observe(this.ElFormRef.$el)
}
this.initSize()
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
if (this.observer) {
this.observer.disconnect()
if (this.ElFormRef?.$el) {
this.observer.unobserve(this.ElFormRef.$el)
}
}
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.screenWidth = document.documentElement.clientWidth
this.initSize()
},
initSize() {
this.max = 24 / this.currentColWidth
this.resetLabelWidth()
},
resetLabelWidth() {
this.labelWidthValue = ''
this.$nextTick().then(() => {
const formItemLabels = this.ElFormRef?.$el ? this.ElFormRef.$el.querySelectorAll('.el-form-item__label') : []
const arr = []
formItemLabels.forEach(item => {
arr.push(item.offsetWidth)
})
const max = Math.max.apply(null, arr)
this.labelWidthValue = String(max + 16)
})
},
toggleFold() {
this.isFold = !this.isFold
this.labelWidthValue = ''
this.resetLabelWidth()
},
// 判断是否应该隐藏表单项
shouldHideItem(index) {
if (!this.isFold) return false
return index >= this.maxVisibleItemsWhenFold
},
// 更可靠的 el-form-item 检测方法
isFormItemNode(node) {
if (!node) return false
if (node.componentOptions && node.componentOptions.tag === 'el-form-item') {
return true
}
if (node.data && node.data.attrs) {
const attrs = node.data.attrs
if (attrs.label || attrs.prop) {
return true
}
}
if (node.data && node.data.staticClass) {
if (node.data.staticClass.includes('el-form-item')) {
return true
}
}
return false
},
// 递归查找所有表单项
extractFormItems(nodes, result = []) {
if (!nodes || !Array.isArray(nodes)) return result
nodes.forEach(node => {
if (!node) return
if (this.isFormItemNode(node)) {
result.push(node)
} else if (node.children) {
this.extractFormItems(node.children, result)
} else if (node.componentOptions && node.componentOptions.children) {
this.extractFormItems(node.componentOptions.children, result)
}
})
return result
}
},
render() {
// 提取所有 el-form-item
const defaultSlots = this.$slots.default || []
const formItems = this.extractFormItems(defaultSlots)
// 渲染表单项
const formItemCols = formItems.map((item, index) => {
const isHidden = this.shouldHideItem(index)
return (
<el-col
class={{ 'hidden': isHidden }}
key={`formitem-${index}`}
xs={24}
sm={this.sm}
md={this.md}
lg={this.lg}
xl={this.xl}
>
{item}
</el-col>
)
})
// 渲染按钮
const buttons = (
<div class="buttons-space">
<el-button
plain={true}
on-click={() => {
this.$emit('reset', this.ElFormRef)
}}
>
重置
</el-button>
<el-button
type="primary"
on-click={() => {
this.$emit('search')
}}
>
查询
</el-button>
{this.shouldShowFoldButton ? (
<div
class="advanced"
on-click={this.toggleFold}
>
<span>{this.isFold ? '展开' : '收起'}</span>
<i class={`el-icon-arrow-${this.isFold ? 'down' : 'up'} advanced-icon`}></i>
</div>
) : null}
</div>
)
// 按钮列
const buttonsCol = (
<el-col
class="ElColButtons"
xs={24}
sm={this.sm}
md={this.md}
lg={this.lg}
xl={this.xl}
style={this.shouldWrapButtons ? 'margin-top: 18px;' : ''}
>
{this.$slots.buttons ? this.$slots.buttons : buttons}
</el-col>
)
return (
<el-form
{...{ attrs: this.$attrs }}
label-width={this.labelWidth || this.labelWidthValue}
label-position="right"
ref="ElFormRef"
class="page-wrapper-search"
>
{/* 第一行:表单项 */}
<el-row gutter={this.gutter}>
{formItemCols}
{/* 折叠状态:按钮列与表单项在同一行 */}
{!this.shouldWrapButtons && buttonsCol}
</el-row>
{/* 展开状态:按钮列在第二行 */}
{this.shouldWrapButtons && (
<el-row gutter={this.gutter} style="margin-top: 0;display: flex;justify-content: flex-end;">
{buttonsCol}
</el-row>
)}
</el-form>
)
}
}
</script>
<style lang="scss" scoped>
.page-wrapper-search {
position: relative;
background: white;
padding: 16px;
}
:deep(.el-form-item) {
margin-bottom: 18px;
.el-form-item__label {
color: #606266;
font-weight: normal;
}
.el-form-item__content {
> div {
width: 100%;
}
.el-input,
.el-select,
.el-date-editor {
width: 100%;
.el-input__inner {
border-radius: 4px;
border: 1px solid #DCDFE6;
&:focus {
border-color: #356CEF;
}
}
}
.el-select .el-input__inner {
cursor: pointer;
}
}
}
.advanced {
display: inline-flex;
align-items: center;
color: #356CEF;
font-size: 14px;
white-space: nowrap;
cursor: pointer;
margin-left: 10px;
vertical-align: middle;
&:hover {
color: #1257f7;
}
&-icon {
margin-left: 4px;
}
}
.buttons-space {
display: flex;
justify-content: flex-end;
align-items: center;
width: 100%;
gap: 12px;
.el-button {
border-radius: 4px;
font-size: 14px;
padding: 10px 20px;
height: 32px;
line-height: 1;
display: flex;
align-items: center;
justify-self: center;
&.is-plain {
border-color: #DCDFE6;
color: #606266;
&:hover {
border-color: #356CEF;
color: #356CEF;
background-color: #ecf5ff;
}
}
&.el-button--primary {
background-color: #356CEF;
border-color: #356CEF;
&:hover {
background-color: #1257f7;
border-color: #1257f7;
}
}
}
}
.ElColButtons {
:deep(.el-form-item__content) {
display: flex;
justify-content: flex-end;
align-items: center;
height: 40px;
}
}
.hidden {
display: none !important;
}
@media (max-width: 768px) {
.page-wrapper-search {
padding: 12px;
}
.ElColButtons {
:deep(.el-form-item__content) {
justify-content: flex-start;
height: auto;
}
}
.buttons-space {
justify-content: flex-start;
flex-direction: column;
align-items: flex-start;
gap: 8px;
.el-button, .advanced {
width: 100%;
justify-content: center;
}
}
}
</style>
\ No newline at end of file
......@@ -47,17 +47,25 @@ export default {
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
// min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
flex: 1;
display: flex;
flex-direction: column;
background-color: #F3F5FB;
}
.fixed-header + .app-main {
overflow-y: auto;
scrollbar-gutter: auto;
height: calc(100vh - 50px);
min-height: 0px;
// height: calc(100vh - 50px);
// min-height: 0px;
flex: 1;
display: flex;
flex-direction: column;
background-color: #F3F5FB;
}
.app-main:has(.copyright) {
......@@ -71,12 +79,16 @@ export default {
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
// min-height: calc(100vh - 84px);
flex: 1;
display: flex;
flex-direction: column;
background-color: #F3F5FB;
}
.fixed-header + .app-main {
margin-top: 84px;
height: calc(100vh - 84px);
// height: calc(100vh - 84px);
min-height: 0px;
}
}
......
......@@ -36,6 +36,10 @@ import DictTag from '@/components/DictTag'
// 字典数据组件
import DictData from '@/components/DictData'
import PageWrapperSearch from '@/components/Search/PageWrapperSearch.vue'
import PageTitle from '@/components/PageTitle/index.vue'
// 全局方法挂载
Vue.prototype.getDicts = getDicts
Vue.prototype.getConfigKey = getConfigKey
......@@ -55,6 +59,8 @@ Vue.component('Editor', Editor)
Vue.component('FileUpload', FileUpload)
Vue.component('ImageUpload', ImageUpload)
Vue.component('ImagePreview', ImagePreview)
Vue.component('PageWrapperSearch', PageWrapperSearch)
Vue.component('PageTitle', PageTitle)
Vue.use(directive)
Vue.use(plugins)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论