mirror of
https://gitee.com/JavaLionLi/plus-ui.git
synced 2026-09-15 08:25:10 +08:00
[重大更新] 整体主题样式重写 改为卡片式布局 样式更企业化
This commit is contained in:
parent
b83755e626
commit
833dfa67fc
@ -22,6 +22,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.3.2",
|
"@element-plus/icons-vue": "2.3.2",
|
||||||
"@highlightjs/vue-plugin": "2.1.2",
|
"@highlightjs/vue-plugin": "2.1.2",
|
||||||
|
"@iconify/vue": "^5.0.0",
|
||||||
"@vueup/vue-quill": "1.2.0",
|
"@vueup/vue-quill": "1.2.0",
|
||||||
"@vueuse/core": "14.2.1",
|
"@vueuse/core": "14.2.1",
|
||||||
"animate.css": "4.1.1",
|
"animate.css": "4.1.1",
|
||||||
|
|||||||
@ -64,6 +64,8 @@
|
|||||||
/*-------------Dialog-------------**/
|
/*-------------Dialog-------------**/
|
||||||
.el-overlay {
|
.el-overlay {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: var(--app-overlay-mask);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
|
||||||
.el-overlay-dialog {
|
.el-overlay-dialog {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -71,21 +73,72 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
.el-dialog {
|
.el-dialog {
|
||||||
margin: 0 auto !important;
|
margin: 0 auto !important;
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: var(--app-radius-lg);
|
||||||
box-shadow: var(--app-shadow-md);
|
box-shadow: var(--app-shadow-md);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0)) padding-box,
|
||||||
|
var(--app-surface-bg);
|
||||||
|
|
||||||
|
.el-dialog__header {
|
||||||
|
padding: 18px 20px 14px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
margin-right: 0;
|
||||||
|
background: var(--app-elevated-soft-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__headerbtn {
|
||||||
|
top: 15px;
|
||||||
|
right: 16px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--app-elevated-close-bg);
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
transform 0.2s ease,
|
||||||
|
color 0.2s ease;
|
||||||
|
|
||||||
|
.el-dialog__close {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-elevated-close-hover-bg);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
|
||||||
|
.el-dialog__close {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.el-dialog__body {
|
.el-dialog__body {
|
||||||
padding: 15px !important;
|
padding: 18px 20px 12px !important;
|
||||||
}
|
}
|
||||||
.el-dialog__header {
|
|
||||||
padding: 16px 16px 8px 16px;
|
.el-dialog__footer {
|
||||||
box-sizing: border-box;
|
display: flex;
|
||||||
border-bottom: 1px solid var(--brder-color);
|
align-items: center;
|
||||||
margin-right: 0;
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 14px 20px 20px;
|
||||||
|
border-top: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,6 +150,10 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer .el-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
// refine element ui upload
|
// refine element ui upload
|
||||||
.upload-container {
|
.upload-container {
|
||||||
.el-upload {
|
.el-upload {
|
||||||
@ -111,8 +168,46 @@
|
|||||||
|
|
||||||
// dropdown
|
// dropdown
|
||||||
.el-dropdown-menu {
|
.el-dropdown-menu {
|
||||||
border-radius: var(--app-radius-md);
|
padding: 8px;
|
||||||
box-shadow: var(--app-shadow-sm);
|
border-radius: 14px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
box-shadow: var(--app-shadow-md);
|
||||||
|
|
||||||
|
.el-dropdown-menu__item {
|
||||||
|
min-height: 36px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dropdown-menu__item.is-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dropdown-menu__item--divided {
|
||||||
|
margin-top: 8px;
|
||||||
|
position: relative;
|
||||||
|
border-top: none;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 2px;
|
||||||
|
right: 2px;
|
||||||
|
top: -6px;
|
||||||
|
width: auto;
|
||||||
|
background: rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -128,7 +223,7 @@
|
|||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu--collapse > div > .el-submenu > .el-submenu__title .el-submenu__icon-arrow {
|
.el-menu--collapse > div > .el-sub-menu > .el-sub-menu__title .el-sub-menu__icon-arrow {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,14 +247,104 @@
|
|||||||
width: 240px;
|
width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-form--inline .el-date-editor {
|
||||||
|
width: 308px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 设置 el-message-box 消息弹框内容强制换行 */
|
/* 设置 el-message-box 消息弹框内容强制换行 */
|
||||||
.el-message-box .el-message-box__message {
|
.el-message-box .el-message-box__message {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-message-box {
|
.el-message-box {
|
||||||
border-radius: var(--app-radius-lg);
|
width: min(440px, calc(100vw - 32px));
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
border-radius: 20px;
|
||||||
box-shadow: var(--app-shadow-md);
|
box-shadow: var(--app-shadow-md);
|
||||||
|
|
||||||
|
.el-message-box__header {
|
||||||
|
padding: 18px 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__headerbtn {
|
||||||
|
top: 14px;
|
||||||
|
right: 16px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--app-elevated-close-bg);
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
|
||||||
|
.el-message-box__close {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-elevated-close-hover-bg);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
|
||||||
|
.el-message-box__close {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__content {
|
||||||
|
padding: 16px 20px 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__container {
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__status {
|
||||||
|
position: static;
|
||||||
|
margin-top: 1px;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 18px !important;
|
||||||
|
background: var(--app-elevated-soft-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__message {
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 16px 20px 20px;
|
||||||
|
border-top: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__btns .el-button {
|
||||||
|
margin-left: 0;
|
||||||
|
min-width: 88px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message-box__input {
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-message,
|
.el-message,
|
||||||
@ -169,6 +354,281 @@
|
|||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-message {
|
||||||
|
min-width: 320px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-message__icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message__content {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message__closeBtn {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--success {
|
||||||
|
border-color: var(--el-color-success-light-7);
|
||||||
|
background: var(--el-color-success-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--warning {
|
||||||
|
border-color: var(--el-color-warning-light-7);
|
||||||
|
background: var(--el-color-warning-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--error {
|
||||||
|
border-color: var(--el-color-danger-light-7);
|
||||||
|
background: var(--el-color-danger-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--info {
|
||||||
|
border-color: var(--el-color-primary-light-7);
|
||||||
|
background: var(--el-color-primary-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification {
|
||||||
|
width: 340px;
|
||||||
|
padding: 16px 18px 16px 16px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
|
||||||
|
.el-notification__group {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification__title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification__content {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.65;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification__closeBtn {
|
||||||
|
top: 18px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification.right,
|
||||||
|
.el-notification.left {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification--success {
|
||||||
|
border-color: var(--el-color-success-light-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification--warning {
|
||||||
|
border-color: var(--el-color-warning-light-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification--error {
|
||||||
|
border-color: var(--el-color-danger-light-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-notification--info {
|
||||||
|
border-color: var(--el-color-primary-light-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select__popper.el-popper,
|
||||||
|
.el-picker__popper.el-popper,
|
||||||
|
.el-autocomplete__popper.el-popper,
|
||||||
|
.el-cascader__dropdown,
|
||||||
|
.el-dropdown__popper.el-popper,
|
||||||
|
.el-popover.el-popper {
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
box-shadow: var(--app-shadow-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select__popper.el-popper,
|
||||||
|
.el-autocomplete__popper.el-popper,
|
||||||
|
.el-cascader__dropdown,
|
||||||
|
.el-dropdown__popper.el-popper,
|
||||||
|
.el-popover.el-popper {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__list,
|
||||||
|
.el-autocomplete-suggestion__list,
|
||||||
|
.el-cascader-menu {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item,
|
||||||
|
.el-autocomplete-suggestion li,
|
||||||
|
.el-cascader-node {
|
||||||
|
min-height: 38px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
line-height: 38px;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item.hover,
|
||||||
|
.el-select-dropdown__item:hover,
|
||||||
|
.el-autocomplete-suggestion li:hover,
|
||||||
|
.el-cascader-node:not(.is-disabled):hover,
|
||||||
|
.el-cascader-node.in-active-path {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item.is-selected,
|
||||||
|
.el-autocomplete-suggestion li.highlighted {
|
||||||
|
background: rgba(64, 158, 255, 0.12);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item.is-disabled,
|
||||||
|
.el-cascader-node.is-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-autocomplete-suggestion li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-autocomplete-suggestion li div {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-cascader-menu {
|
||||||
|
min-width: 180px;
|
||||||
|
border-right-color: rgba(148, 163, 184, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-cascader-node__prefix,
|
||||||
|
.el-cascader-node__postfix {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-dark {
|
||||||
|
border-color: rgba(15, 23, 42, 0.72);
|
||||||
|
background: rgba(15, 23, 42, 0.92);
|
||||||
|
color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-dark .el-popper__arrow::before {
|
||||||
|
background: rgba(15, 23, 42, 0.92);
|
||||||
|
border-color: rgba(15, 23, 42, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-light {
|
||||||
|
border-color: var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-light .el-popper__arrow::before {
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
border-color: var(--app-surface-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-picker__popper.el-popper {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-picker,
|
||||||
|
.el-date-range-picker,
|
||||||
|
.el-time-panel,
|
||||||
|
.el-time-range-picker,
|
||||||
|
.el-picker-panel {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-picker-panel__body-wrapper,
|
||||||
|
.el-date-range-picker__content {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-picker-panel__icon-btn,
|
||||||
|
.el-date-picker__header-label,
|
||||||
|
.el-date-range-picker__header-label {
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-table td,
|
||||||
|
.el-month-table td .cell,
|
||||||
|
.el-year-table td .cell {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-table td.today .el-date-table-cell__text,
|
||||||
|
.el-month-table td.today .cell,
|
||||||
|
.el-year-table td.today .cell {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-table td.available:hover,
|
||||||
|
.el-month-table td .cell:hover,
|
||||||
|
.el-year-table td .cell:hover {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-table td.current:not(.disabled) .el-date-table-cell__text,
|
||||||
|
.el-month-table td.current:not(.disabled) .cell,
|
||||||
|
.el-year-table td.current:not(.disabled) .cell {
|
||||||
|
background: var(--app-accent-strong);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-date-editor .el-range-separator {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-time-panel__content::before,
|
||||||
|
.el-time-panel__content::after {
|
||||||
|
border-color: rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-scrollbar__thumb {
|
||||||
|
background: rgba(148, 163, 184, 0.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-scrollbar__thumb:hover {
|
||||||
|
background: rgba(100, 116, 139, 0.56);
|
||||||
|
}
|
||||||
|
|
||||||
// Modern rounded inputs
|
// Modern rounded inputs
|
||||||
.el-input__wrapper,
|
.el-input__wrapper,
|
||||||
.el-textarea__inner,
|
.el-textarea__inner,
|
||||||
@ -193,11 +653,10 @@
|
|||||||
// Buttons
|
// Buttons
|
||||||
.el-button {
|
.el-button {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
transition: transform 0.15s ease, box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
|
transition: box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button:not(.is-text):not(.is-link):hover {
|
.el-button:not(.is-text):not(.is-link):hover {
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,32 +673,200 @@
|
|||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-popover {
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tooltip__popper {
|
||||||
|
max-width: 320px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popconfirm {
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popconfirm__main {
|
||||||
|
gap: 10px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popconfirm__action {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popconfirm__action .el-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.el-drawer {
|
.el-drawer {
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: var(--app-radius-lg);
|
||||||
box-shadow: var(--app-shadow-md);
|
box-shadow: var(--app-shadow-md);
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-drawer__header {
|
.el-drawer__header {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding: 16px 20px;
|
padding: 18px 20px 16px;
|
||||||
border-bottom: 1px solid var(--el-border-color-light);
|
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
background: var(--app-elevated-soft-bg);
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-drawer__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-drawer__body {
|
||||||
|
padding: 18px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-drawer__close-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--app-elevated-close-bg);
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-elevated-close-hover-bg);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-loading-mask {
|
||||||
|
background: rgba(248, 250, 252, 0.76);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-loading-spinner .path {
|
||||||
|
stroke: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-descriptions {
|
||||||
|
--el-descriptions-table-border: rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-descriptions__body .el-descriptions__table {
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-descriptions__label.el-descriptions__cell {
|
||||||
|
background: var(--app-elevated-soft-bg) !important;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-descriptions__content.el-descriptions__cell {
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree {
|
||||||
|
color: var(--app-text-title);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree-node__content {
|
||||||
|
min-height: 34px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree-node__content:hover,
|
||||||
|
.el-tree-node.is-current > .el-tree-node__content {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio-button__inner,
|
||||||
|
.el-checkbox-button__inner {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio-button:first-child .el-radio-button__inner,
|
||||||
|
.el-checkbox-button:first-child .el-checkbox-button__inner,
|
||||||
|
.el-radio-button:last-child .el-radio-button__inner,
|
||||||
|
.el-checkbox-button:last-child .el-checkbox-button__inner {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-empty__image {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-empty__description p {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-color-dropdown {
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
box-shadow: var(--app-shadow-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark {
|
||||||
|
.el-message--success {
|
||||||
|
background: rgba(31, 138, 90, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--warning {
|
||||||
|
background: rgba(184, 121, 34, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--error {
|
||||||
|
background: rgba(178, 74, 74, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-message--info {
|
||||||
|
background: rgba(43, 107, 211, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-loading-mask {
|
||||||
|
background: rgba(6, 11, 22, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-dark {
|
||||||
|
border-color: rgba(30, 41, 59, 0.92);
|
||||||
|
background: rgba(15, 23, 42, 0.96);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-popper.is-dark .el-popper__arrow::before {
|
||||||
|
background: rgba(15, 23, 42, 0.96);
|
||||||
|
border-color: rgba(30, 41, 59, 0.92);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table polish
|
// Table polish
|
||||||
.el-table {
|
.el-table {
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: var(--app-shadow-sm);
|
border: 1px solid var(--app-surface-border);
|
||||||
border: 1px solid var(--el-border-color-lighter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table__header-wrapper,
|
.el-table__header-wrapper,
|
||||||
.el-table__body-wrapper {
|
.el-table__body-wrapper {
|
||||||
background: var(--el-bg-color);
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table__row:hover td.el-table__cell {
|
.el-table__row:hover td.el-table__cell {
|
||||||
background-color: var(--el-fill-color-light) !important;
|
background-color: rgba(53, 109, 255, 0.05) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tabs
|
// Tabs
|
||||||
@ -264,6 +891,27 @@
|
|||||||
transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-pagination {
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-pagination .el-pagination__total,
|
||||||
|
.el-pagination .el-pagination__jump {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-pagination .btn-prev,
|
||||||
|
.el-pagination .btn-next,
|
||||||
|
.el-pagination .el-pager li,
|
||||||
|
.el-pagination .el-pagination__sizes .el-input__wrapper {
|
||||||
|
min-width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
}
|
||||||
|
|
||||||
.el-pagination .el-pager li.is-active {
|
.el-pagination .el-pager li.is-active {
|
||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
background: var(--el-bg-color-page);
|
background: var(--app-shell-bg);
|
||||||
font-family:
|
font-family:
|
||||||
'MiSans',
|
'MiSans',
|
||||||
'HarmonyOS Sans SC',
|
'HarmonyOS Sans SC',
|
||||||
@ -44,6 +44,12 @@ html.dark svg {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
*:before,
|
*:before,
|
||||||
*:after {
|
*:after {
|
||||||
@ -147,7 +153,7 @@ aside {
|
|||||||
|
|
||||||
//main-container全局样式
|
//main-container全局样式
|
||||||
.app-container {
|
.app-container {
|
||||||
padding: 20px;
|
padding: 16px;
|
||||||
background: var(--app-surface-bg);
|
background: var(--app-surface-bg);
|
||||||
border: 1px solid var(--app-surface-border);
|
border: 1px solid var(--app-surface-border);
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: var(--app-radius-lg);
|
||||||
@ -159,19 +165,62 @@ aside {
|
|||||||
.search {
|
.search {
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: var(--app-radius-lg);
|
||||||
border: 1px solid var(--el-border-color-light);
|
border: 1px solid var(--app-surface-border);
|
||||||
background-color: var(--el-bg-color-overlay);
|
background-color: var(--app-surface-bg);
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
||||||
transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
|
transition: box-shadow 0.2s ease, border-color 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
border-color: var(--el-border-color);
|
border-color: rgba(64, 158, 255, 0.2);
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-card,
|
||||||
|
.el-dialog,
|
||||||
|
.el-drawer,
|
||||||
|
.el-popover.el-popper,
|
||||||
|
.el-dropdown__popper .el-dropdown-menu,
|
||||||
|
.el-picker__popper,
|
||||||
|
.el-select__popper.el-popper {
|
||||||
|
border-radius: var(--app-radius-lg);
|
||||||
|
border-color: var(--app-surface-border);
|
||||||
|
box-shadow: var(--app-shadow-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card,
|
||||||
|
.el-dialog,
|
||||||
|
.el-drawer {
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button--primary {
|
||||||
|
--el-button-bg-color: var(--app-accent-strong);
|
||||||
|
--el-button-border-color: var(--app-accent-strong);
|
||||||
|
--el-button-hover-bg-color: #4a7cff;
|
||||||
|
--el-button-hover-border-color: #4a7cff;
|
||||||
|
--el-button-active-bg-color: #2e5ce0;
|
||||||
|
--el-button-active-border-color: #2e5ce0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table {
|
||||||
|
--el-table-border-color: var(--app-surface-border);
|
||||||
|
--el-table-header-bg-color: var(--tableHeaderBg);
|
||||||
|
--el-table-tr-bg-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__wrapper,
|
||||||
|
.el-textarea__inner,
|
||||||
|
.el-select__wrapper {
|
||||||
|
box-shadow: 0 0 0 1px transparent inset;
|
||||||
|
}
|
||||||
|
|
||||||
.components-container {
|
.components-container {
|
||||||
margin: 30px 50px;
|
margin: 30px 50px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@ -76,6 +76,41 @@ h6 {
|
|||||||
.el-form .el-form-item__label {
|
.el-form .el-form-item__label {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-2 {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-main > .page-shell,
|
||||||
|
.app-main > .page-shell.p-2 {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-2 > .el-row,
|
||||||
|
.p-2 > .el-card,
|
||||||
|
.p-2 > .search-wrap,
|
||||||
|
.p-2 > div,
|
||||||
|
.p-2 > section {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-shell > .el-row,
|
||||||
|
.page-shell > .el-card,
|
||||||
|
.page-shell > .search-wrap,
|
||||||
|
.page-shell > div,
|
||||||
|
.page-shell > section {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.el-dialog:not(.is-fullscreen) {
|
.el-dialog:not(.is-fullscreen) {
|
||||||
margin-top: 6vh !important;
|
margin-top: 6vh !important;
|
||||||
}
|
}
|
||||||
@ -84,7 +119,7 @@ h6 {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
padding: 10px 20px 0;
|
padding: 14px 22px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table {
|
.el-table {
|
||||||
@ -118,17 +153,18 @@ h6 {
|
|||||||
.pagination-container {
|
.pagination-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 20px;
|
margin-top: 18px;
|
||||||
padding: 10px 20px !important;
|
padding: 10px 0 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tree border */
|
/* tree border */
|
||||||
.tree-border {
|
.tree-border {
|
||||||
margin-top: 5px;
|
margin-top: 8px;
|
||||||
border: 1px solid #e5e6e7;
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||||
background: #ffffff none;
|
background: rgba(255, 255, 255, 0.42) none;
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: 22px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@ -188,27 +224,28 @@ h6 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.el-card__header {
|
.el-card__header {
|
||||||
padding: 14px 15px 7px !important;
|
padding: 14px 16px 10px !important;
|
||||||
min-height: 40px;
|
min-height: auto;
|
||||||
background: var(--el-fill-color-blank);
|
background: transparent;
|
||||||
border-bottom: 1px solid var(--el-border-color-light);
|
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-card__body {
|
.el-card__body {
|
||||||
padding: 15px 20px 20px 20px !important;
|
padding: 16px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-card {
|
.el-card {
|
||||||
border-radius: var(--app-radius-lg);
|
border-radius: var(--app-radius-lg);
|
||||||
box-shadow: var(--app-shadow-sm);
|
box-shadow: var(--app-shadow-sm);
|
||||||
border-color: var(--el-border-color-lighter);
|
border-color: var(--app-surface-border);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
transition: box-shadow 0.2s ease, border-color 0.2s ease;
|
||||||
|
background: var(--app-surface-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-card:hover {
|
.el-card:hover {
|
||||||
box-shadow: var(--app-shadow-md);
|
box-shadow: var(--app-shadow-md);
|
||||||
transform: translateY(-1px);
|
border-color: rgba(64, 158, 255, 0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-box {
|
.card-box {
|
||||||
@ -298,6 +335,287 @@ h6 {
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-heading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-heading h3,
|
||||||
|
.table-heading h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-kicker {
|
||||||
|
display: none;
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-shell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-heading p {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions::-webkit-scrollbar {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions > * {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions .top-right-btn {
|
||||||
|
margin-left: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions .el-button + .el-button,
|
||||||
|
.toolbar-actions .el-dropdown + .el-button,
|
||||||
|
.toolbar-actions .el-button + .el-dropdown,
|
||||||
|
.toolbar-actions .el-dropdown + .el-dropdown,
|
||||||
|
.toolbar-actions .top-right-btn + .el-button,
|
||||||
|
.toolbar-actions .el-button + .top-right-btn,
|
||||||
|
.toolbar-actions .top-right-btn + .el-dropdown,
|
||||||
|
.toolbar-actions .el-dropdown + .top-right-btn {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-panel .toolbar-actions .el-button:not(.is-circle):not(.is-link) {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px 14px;
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item__content {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item:last-child {
|
||||||
|
margin-left: auto;
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item:last-child .el-form-item__content {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item:last-child .el-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item:last-child .el-button + .el-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-input__wrapper,
|
||||||
|
.query-form .el-select__wrapper,
|
||||||
|
.query-form .el-textarea__inner,
|
||||||
|
.query-form .el-date-editor,
|
||||||
|
.query-form .el-range-editor,
|
||||||
|
.query-form .el-cascader .el-input__wrapper,
|
||||||
|
.query-form .el-input-number,
|
||||||
|
.query-form .el-input-number__decrease,
|
||||||
|
.query-form .el-input-number__increase {
|
||||||
|
border-radius: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-button {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.query-form {
|
||||||
|
gap: 10px 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.query-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-input,
|
||||||
|
.query-form .el-select,
|
||||||
|
.query-form .el-date-editor,
|
||||||
|
.query-form .el-cascader,
|
||||||
|
.query-form .el-input-number {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-form .el-form-item:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table .el-button.is-link {
|
||||||
|
width: 28px !important;
|
||||||
|
height: 28px !important;
|
||||||
|
min-width: 28px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
background: rgba(53, 109, 255, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table .el-button.is-link + .el-button.is-link {
|
||||||
|
margin-left: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrap {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.search-panel,
|
||||||
|
.el-card.side-panel {
|
||||||
|
border-radius: 16px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.table-panel {
|
||||||
|
border-radius: 14px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.search-panel .el-card__header,
|
||||||
|
.el-card.side-panel .el-card__header {
|
||||||
|
border-top-left-radius: 16px;
|
||||||
|
border-top-right-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.table-panel .el-card__header {
|
||||||
|
border-top-left-radius: 14px;
|
||||||
|
border-top-right-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.search-panel .el-card__body,
|
||||||
|
.el-card.side-panel .el-card__body {
|
||||||
|
border-bottom-left-radius: 16px;
|
||||||
|
border-bottom-right-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card.table-panel .el-card__body {
|
||||||
|
border-bottom-left-radius: 14px;
|
||||||
|
border-bottom-right-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel {
|
||||||
|
.el-card__header {
|
||||||
|
display: block;
|
||||||
|
padding: 12px 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card__body {
|
||||||
|
padding-top: 16px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
max-height: 560px;
|
||||||
|
opacity: 1;
|
||||||
|
transition:
|
||||||
|
max-height 0.32s cubic-bezier(0.22, 1, 0.36, 1),
|
||||||
|
opacity 0.24s ease,
|
||||||
|
padding-top 0.24s ease,
|
||||||
|
padding-bottom 0.24s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel.is-collapsed {
|
||||||
|
.el-card__body {
|
||||||
|
max-height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel-toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: color 0.24s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
margin-left: auto;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
border-right: 2px solid currentColor;
|
||||||
|
border-bottom: 2px solid currentColor;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
transform: rotate(-135deg);
|
||||||
|
transition:
|
||||||
|
transform 0.24s ease,
|
||||||
|
color 0.24s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-panel.is-collapsed .search-panel-toggle::after {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.tree-border {
|
||||||
|
background: rgba(15, 23, 42, 0.42);
|
||||||
|
border-color: rgba(100, 116, 139, 0.22);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* horizontal el menu */
|
/* horizontal el menu */
|
||||||
.el-menu--horizontal .el-menu-item .svg-icon + span,
|
.el-menu--horizontal .el-menu-item .svg-icon + span,
|
||||||
.el-menu--horizontal .el-sub-menu__title .svg-icon + span {
|
.el-menu--horizontal .el-sub-menu__title .svg-icon + span {
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
.main-container {
|
.main-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
transition: margin-left 0.28s;
|
transition: margin-left 0.28s;
|
||||||
margin-left: $base-sidebar-width;
|
margin-left: calc(#{$base-sidebar-width} + 12px);
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--el-bg-color-page);
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarHide {
|
.sidebarHide {
|
||||||
@ -17,17 +17,19 @@
|
|||||||
-webkit-transition: width 0.28s;
|
-webkit-transition: width 0.28s;
|
||||||
transition: width 0.28s;
|
transition: width 0.28s;
|
||||||
width: $base-sidebar-width !important;
|
width: $base-sidebar-width !important;
|
||||||
background-color: $base-menu-background;
|
background: transparent;
|
||||||
height: 100%;
|
height: calc(100vh - 24px);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
top: 0;
|
top: 12px;
|
||||||
bottom: 0;
|
left: 12px;
|
||||||
left: 0;
|
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-webkit-box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
|
box-sizing: border-box;
|
||||||
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.1);
|
padding: 0;
|
||||||
|
border-right: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
// reset element-ui css
|
// reset element-ui css
|
||||||
.horizontal-collapse-transition {
|
.horizontal-collapse-transition {
|
||||||
@ -49,10 +51,24 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.has-logo {
|
.el-scrollbar.theme-light {
|
||||||
.el-scrollbar {
|
--side-menu-text: #1f2937;
|
||||||
height: calc(100% - 50px);
|
--side-menu-hover-bg: rgba(64, 158, 255, 0.08);
|
||||||
}
|
--side-menu-hover-text: #111827;
|
||||||
|
--side-menu-active-bg: rgba(64, 158, 255, 0.12);
|
||||||
|
--side-menu-active-text: #409eff;
|
||||||
|
--side-menu-active-border: rgba(64, 158, 255, 0.16);
|
||||||
|
--side-menu-active-line: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-scrollbar.theme-dark {
|
||||||
|
--side-menu-text: #e5edf8;
|
||||||
|
--side-menu-hover-bg: rgba(255, 255, 255, 0.08);
|
||||||
|
--side-menu-hover-text: #ffffff;
|
||||||
|
--side-menu-active-bg: rgba(64, 158, 255, 0.22);
|
||||||
|
--side-menu-active-text: #ffffff;
|
||||||
|
--side-menu-active-border: rgba(96, 165, 250, 0.24);
|
||||||
|
--side-menu-active-line: #60a5fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-horizontal {
|
.is-horizontal {
|
||||||
@ -73,6 +89,11 @@
|
|||||||
border: none;
|
border: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu--inline {
|
||||||
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu-item,
|
.el-menu-item,
|
||||||
@ -82,89 +103,123 @@
|
|||||||
white-space: nowrap !important;
|
white-space: nowrap !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-menu-item,
|
||||||
|
.el-sub-menu__title,
|
||||||
|
.el-menu-item .svg-icon,
|
||||||
|
.el-sub-menu__title .svg-icon,
|
||||||
|
.el-sub-menu__icon-arrow {
|
||||||
|
color: var(--side-menu-text) !important;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item,
|
||||||
|
.el-sub-menu__title {
|
||||||
|
position: relative;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.el-menu-item .el-menu-tooltip__trigger {
|
.el-menu-item .el-menu-tooltip__trigger {
|
||||||
display: inline-block !important;
|
display: inline-block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// menu hover
|
// menu hover
|
||||||
.theme-dark .sub-menu-title-noDropdown,
|
.theme-dark .submenu-title-noDropdown,
|
||||||
.theme-dark .el-sub-menu__title {
|
.theme-dark .el-sub-menu__title {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $base-sub-menu-title-hover !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sub-menu-title-noDropdown,
|
.submenu-title-noDropdown,
|
||||||
.el-sub-menu__title {
|
.el-sub-menu__title {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
|
color: var(--side-menu-text) !important;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.05) !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .theme-dark .is-active > .el-sub-menu__title {
|
& .theme-dark .is-active > .el-sub-menu__title {
|
||||||
color: $base-menu-color-active !important;
|
color: var(--side-menu-active-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
& .el-sub-menu .el-menu-item {
|
& .el-sub-menu .el-menu-item {
|
||||||
min-width: calc($base-sidebar-width - 20px) !important;
|
min-width: calc($base-sidebar-width - 16px) !important;
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
height: 45px;
|
height: 40px;
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
|
background: transparent !important;
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
background-color: rgba(0, 0, 0, 0.1) !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
|
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
& .theme-dark .el-sub-menu .el-menu-item {
|
& .theme-dark .el-sub-menu .el-menu-item {
|
||||||
background-color: $base-sub-menu-background !important;
|
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
height: 45px;
|
height: 40px;
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
|
background: transparent !important;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: var(--el-menu-active-color) !important;
|
background: var(--side-menu-active-bg) !important;
|
||||||
color: #fff;
|
color: var(--side-menu-active-text) !important;
|
||||||
|
box-shadow:
|
||||||
|
inset 3px 0 0 var(--side-menu-active-line),
|
||||||
|
inset 0 0 0 1px var(--side-menu-active-border);
|
||||||
}
|
}
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
// you can use $sub-menuHover
|
// you can use $sub-menuHover
|
||||||
background-color: $base-sub-menu-hover !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
|
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
& .theme-dark .el-menu-item {
|
& .theme-dark .el-menu-item {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
height: 45px;
|
height: 40px;
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
|
background: transparent !important;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: var(--el-menu-active-color) !important;
|
background: var(--side-menu-active-bg) !important;
|
||||||
color: #fff;
|
color: var(--side-menu-active-text) !important;
|
||||||
|
box-shadow:
|
||||||
|
inset 3px 0 0 var(--side-menu-active-line),
|
||||||
|
inset 0 0 0 1px var(--side-menu-active-border);
|
||||||
}
|
}
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
// you can use $sub-menuHover
|
// you can use $sub-menuHover
|
||||||
background-color: $base-menu-hover !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
& .nest-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
& .el-menu-item {
|
& .el-menu-item {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
height: 45px;
|
height: 40px;
|
||||||
margin: 1px 5px 1px 5px;
|
margin: 3px 8px;
|
||||||
|
background: transparent !important;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: var(--el-menu-active-color) !important;
|
background: var(--side-menu-active-bg) !important;
|
||||||
color: #fff;
|
color: var(--side-menu-active-text) !important;
|
||||||
|
box-shadow:
|
||||||
|
inset 3px 0 0 var(--side-menu-active-line),
|
||||||
|
inset 0 0 0 1px var(--side-menu-active-border);
|
||||||
}
|
}
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
// you can use $sub-menuHover
|
// you can use $sub-menuHover
|
||||||
background-color: rgba(0, 0, 0, 0.04) !important;
|
background-color: var(--side-menu-hover-bg) !important;
|
||||||
|
color: var(--side-menu-hover-text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,74 +227,137 @@
|
|||||||
// 收起菜单后的样式
|
// 收起菜单后的样式
|
||||||
.hideSidebar {
|
.hideSidebar {
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
width: 54px !important;
|
width: 58px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-container {
|
.main-container {
|
||||||
margin-left: 54px;
|
margin-left: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-menu-title-noDropdown {
|
.sidebar-shell {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-title-noDropdown {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 45px;
|
height: 40px;
|
||||||
|
width: 40px !important;
|
||||||
|
min-width: 40px !important;
|
||||||
|
margin: 3px auto !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center !important;
|
||||||
|
box-sizing: border-box;
|
||||||
// 选中状态的菜单
|
// 选中状态的菜单
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: var(--el-menu-active-color) !important;
|
background-color: var(--side-menu-active-bg) !important;
|
||||||
color: #fff !important;
|
color: var(--side-menu-active-text) !important;
|
||||||
|
box-shadow: inset 3px 0 0 var(--side-menu-active-line);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tooltip {
|
.el-tooltip {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-menu-tooltip__trigger {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
& .el-sub-menu {
|
& .el-sub-menu {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
|
.el-sub-menu__title,
|
||||||
.el-sub-menu__title.el-tooltip__trigger {
|
.el-sub-menu__title.el-tooltip__trigger {
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
height: 45px;
|
height: 40px;
|
||||||
|
padding: 0 !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center !important;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选中状态的菜单
|
// 选中状态的菜单
|
||||||
|
&.is-active .el-sub-menu__title,
|
||||||
&.is-active .el-sub-menu__title.el-tooltip__trigger {
|
&.is-active .el-sub-menu__title.el-tooltip__trigger {
|
||||||
background-color: var(--el-menu-active-color) !important;
|
background-color: var(--side-menu-active-bg) !important;
|
||||||
|
box-shadow: inset 3px 0 0 var(--side-menu-active-line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
& > .el-sub-menu__title {
|
& > .el-sub-menu__title {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu--collapse {
|
.el-menu--collapse {
|
||||||
|
> div > .el-sub-menu {
|
||||||
|
width: 40px !important;
|
||||||
|
min-width: 40px !important;
|
||||||
|
margin: 3px auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div > .el-sub-menu > .el-sub-menu__title,
|
||||||
|
> div > .el-sub-menu > .el-sub-menu__title.el-tooltip__trigger {
|
||||||
|
width: 100% !important;
|
||||||
|
min-width: 100% !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transform: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.is-active .svg-icon {
|
.is-active .svg-icon {
|
||||||
fill: #fff;
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
.svg-icon {
|
|
||||||
display: flex;
|
> div > .el-sub-menu > .el-sub-menu__title .svg-icon {
|
||||||
margin: auto;
|
position: absolute;
|
||||||
height: 100%;
|
left: 50%;
|
||||||
// 这里设置width会跟随sidebar-container的transition 不符合预期
|
top: 50%;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
display: block;
|
||||||
|
margin: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
.el-sub-menu {
|
|
||||||
& > .el-sub-menu__title {
|
> div > .el-sub-menu > .el-sub-menu__title {
|
||||||
& > span {
|
justify-content: center !important;
|
||||||
height: 0;
|
|
||||||
width: 0;
|
.el-sub-menu__icon-arrow {
|
||||||
overflow: hidden;
|
display: none !important;
|
||||||
visibility: hidden;
|
width: 0 !important;
|
||||||
display: inline-block;
|
margin: 0 !important;
|
||||||
}
|
overflow: hidden !important;
|
||||||
& > i {
|
}
|
||||||
height: 0;
|
|
||||||
width: 0;
|
& > span {
|
||||||
overflow: hidden;
|
height: 0;
|
||||||
visibility: hidden;
|
width: 0;
|
||||||
display: inline-block;
|
overflow: hidden;
|
||||||
}
|
visibility: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
& > i {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
visibility: hidden;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,7 +382,7 @@
|
|||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition-duration: 0.3s;
|
transition-duration: 0.3s;
|
||||||
transform: translate3d(-$base-sidebar-width, 0, 0);
|
transform: translate3d(calc(-#{$base-sidebar-width} - 12px), 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,6 +406,7 @@
|
|||||||
// 收起菜单后悬浮的菜单样式
|
// 收起菜单后悬浮的菜单样式
|
||||||
.el-popper.is-pure{
|
.el-popper.is-pure{
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
|
box-shadow: var(--app-shadow-md);
|
||||||
.el-menu--popup{
|
.el-menu--popup{
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: var(--app-radius-md);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
// 全局SCSS变量
|
// 全局SCSS变量
|
||||||
:root {
|
:root {
|
||||||
--menuBg: #1f2d3d;
|
--menuBg: #ffffff;
|
||||||
--menuColor: #bfcbd9;
|
--menuColor: #1f2937;
|
||||||
--menuActiveText: #f4f4f5;
|
--menuActiveText: #111827;
|
||||||
--menuHover: #263445;
|
--menuHover: rgba(64, 158, 255, 0.12);
|
||||||
|
|
||||||
--subMenuBg: #1f2d3d;
|
--subMenuBg: #ffffff;
|
||||||
--subMenuActiveText: #f4f4f5;
|
--subMenuActiveText: #111827;
|
||||||
--subMenuHover: #001528;
|
--subMenuHover: rgba(64, 158, 255, 0.12);
|
||||||
--subMenuTitleHover: #293444;
|
--subMenuTitleHover: rgba(64, 158, 255, 0.08);
|
||||||
|
|
||||||
// 菜单栏缩进
|
// 菜单栏缩进
|
||||||
--el-menu-base-level-padding: 12px;
|
--el-menu-base-level-padding: 12px;
|
||||||
@ -16,8 +16,8 @@
|
|||||||
--el-menu-item-height: 50px;
|
--el-menu-item-height: 50px;
|
||||||
|
|
||||||
--fixedHeaderBg: #ffffff;
|
--fixedHeaderBg: #ffffff;
|
||||||
--tableHeaderBg: #f8f8f9;
|
--tableHeaderBg: #f8fafc;
|
||||||
--tableHeaderTextColor: #515a6e;
|
--tableHeaderTextColor: #475569;
|
||||||
|
|
||||||
// ele
|
// ele
|
||||||
--brder-color: #e8e8e8;
|
--brder-color: #e8e8e8;
|
||||||
@ -28,13 +28,28 @@
|
|||||||
|
|
||||||
// Modern rounded style + soft shadows
|
// Modern rounded style + soft shadows
|
||||||
--app-radius-sm: 6px;
|
--app-radius-sm: 6px;
|
||||||
--app-radius-md: 10px;
|
--app-radius-md: 12px;
|
||||||
--app-radius-lg: 14px;
|
--app-radius-lg: 18px;
|
||||||
--app-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.08), 0 6px 16px rgba(15, 23, 42, 0.08);
|
--app-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05);
|
||||||
--app-shadow-md: 0 8px 24px rgba(15, 23, 42, 0.12);
|
--app-shadow-md: 0 8px 24px rgba(15, 23, 42, 0.06);
|
||||||
--app-shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.16);
|
--app-shadow-lg: 0 14px 36px rgba(15, 23, 42, 0.1);
|
||||||
--app-surface-bg: #ffffff;
|
--app-surface-bg: #ffffff;
|
||||||
--app-surface-border: var(--el-border-color-lighter);
|
--app-surface-border: #e5e7eb;
|
||||||
|
--app-shell-bg: #f5f7fa;
|
||||||
|
--app-shell-spot-1: rgba(64, 158, 255, 0.08);
|
||||||
|
--app-shell-spot-2: rgba(64, 158, 255, 0.04);
|
||||||
|
--app-sidebar-border: #e5e7eb;
|
||||||
|
--app-navbar-bg: #ffffff;
|
||||||
|
--app-navbar-border: #e5e7eb;
|
||||||
|
--app-navbar-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
|
||||||
|
--app-accent-soft: rgba(64, 158, 255, 0.08);
|
||||||
|
--app-accent-strong: #409eff;
|
||||||
|
--app-text-title: #1f2937;
|
||||||
|
--app-text-muted: #6b7280;
|
||||||
|
--app-overlay-mask: rgba(15, 23, 42, 0.22);
|
||||||
|
--app-elevated-soft-bg: #f8fafc;
|
||||||
|
--app-elevated-close-bg: rgba(148, 163, 184, 0.14);
|
||||||
|
--app-elevated-close-hover-bg: rgba(64, 158, 255, 0.14);
|
||||||
|
|
||||||
// Element Plus tokens
|
// Element Plus tokens
|
||||||
--el-border-radius-base: var(--app-radius-md);
|
--el-border-radius-base: var(--app-radius-md);
|
||||||
@ -42,21 +57,21 @@
|
|||||||
--el-border-radius-round: 999px;
|
--el-border-radius-round: 999px;
|
||||||
--el-box-shadow-light: var(--app-shadow-sm);
|
--el-box-shadow-light: var(--app-shadow-sm);
|
||||||
--el-box-shadow: var(--app-shadow-md);
|
--el-box-shadow: var(--app-shadow-md);
|
||||||
--el-bg-color-page: #f5f7fb;
|
--el-bg-color-page: var(--app-shell-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--menuBg: #1d1e1f;
|
--menuBg: #111827;
|
||||||
--menuColor: #bfcbd9;
|
--menuColor: #e5edf8;
|
||||||
--menuActiveText: #f4f4f5;
|
--menuActiveText: #f8fbff;
|
||||||
--menuHover: #171819;
|
--menuHover: rgba(85, 129, 255, 0.2);
|
||||||
|
|
||||||
--subMenuBg: #1d1e1f;
|
--subMenuBg: #111827;
|
||||||
--subMenuActiveText: #1d1e1f;
|
--subMenuActiveText: #f8fbff;
|
||||||
--subMenuHover: #171819;
|
--subMenuHover: rgba(85, 129, 255, 0.18);
|
||||||
--subMenuTitleHover: #171819;
|
--subMenuTitleHover: rgba(148, 163, 184, 0.12);
|
||||||
|
|
||||||
--fixedHeaderBg: #171819;
|
--fixedHeaderBg: #0f172a;
|
||||||
--tableHeaderBg: var(--el-bg-color);
|
--tableHeaderBg: var(--el-bg-color);
|
||||||
--tableHeaderTextColor: var(--el-text-color);
|
--tableHeaderTextColor: var(--el-text-color);
|
||||||
|
|
||||||
@ -204,12 +219,27 @@ html.dark {
|
|||||||
--tags-view-active-border-color: var(--el-color-primary-light-2);
|
--tags-view-active-border-color: var(--el-color-primary-light-2);
|
||||||
|
|
||||||
// Modern rounded style + soft shadows (dark)
|
// Modern rounded style + soft shadows (dark)
|
||||||
--app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.28), 0 8px 18px rgba(0, 0, 0, 0.25);
|
--app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.28);
|
||||||
--app-shadow-md: 0 10px 26px rgba(0, 0, 0, 0.35);
|
--app-shadow-md: 0 12px 28px rgba(0, 0, 0, 0.28);
|
||||||
--app-shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.4);
|
--app-shadow-lg: 0 20px 44px rgba(0, 0, 0, 0.32);
|
||||||
--app-surface-bg: #151922;
|
--app-surface-bg: #111827;
|
||||||
--app-surface-border: var(--el-border-color);
|
--app-surface-border: rgba(71, 85, 105, 0.5);
|
||||||
--el-bg-color-page: #0f1115;
|
--app-shell-bg: #060b16;
|
||||||
|
--app-shell-spot-1: rgba(69, 120, 255, 0.18);
|
||||||
|
--app-shell-spot-2: rgba(45, 212, 191, 0.14);
|
||||||
|
--app-sidebar-border: rgba(148, 163, 184, 0.1);
|
||||||
|
--app-navbar-bg: #111827;
|
||||||
|
--app-navbar-border: rgba(71, 85, 105, 0.48);
|
||||||
|
--app-navbar-shadow: 0 1px 2px rgba(0, 0, 0, 0.22);
|
||||||
|
--app-accent-soft: rgba(64, 158, 255, 0.14);
|
||||||
|
--app-accent-strong: #60a5fa;
|
||||||
|
--app-text-title: #f3f7ff;
|
||||||
|
--app-text-muted: #8ea0bd;
|
||||||
|
--app-overlay-mask: rgba(2, 6, 23, 0.58);
|
||||||
|
--app-elevated-soft-bg: rgba(148, 163, 184, 0.08);
|
||||||
|
--app-elevated-close-bg: rgba(148, 163, 184, 0.18);
|
||||||
|
--app-elevated-close-hover-bg: rgba(96, 165, 250, 0.18);
|
||||||
|
--el-bg-color-page: var(--app-shell-bg);
|
||||||
// vxe-table 主题
|
// vxe-table 主题
|
||||||
--vxe-font-color: #98989e;
|
--vxe-font-color: #98989e;
|
||||||
--vxe-primary-color: #2c7ecf;
|
--vxe-primary-color: #2c7ecf;
|
||||||
|
|||||||
@ -78,12 +78,18 @@ onMounted(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.app-breadcrumb.el-breadcrumb {
|
.app-breadcrumb.el-breadcrumb {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
line-height: 50px;
|
line-height: 1.2;
|
||||||
margin-left: 8px;
|
margin-left: 4px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
|
||||||
|
:deep(.el-breadcrumb__inner) {
|
||||||
|
color: inherit;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.no-redirect {
|
.no-redirect {
|
||||||
color: #97a8be;
|
color: var(--app-text-title);
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,19 @@
|
|||||||
|
|
||||||
<el-input v-model="filterValue" class="p-2" placeholder="搜索图标" clearable @input="filterIcons" />
|
<el-input v-model="filterValue" class="p-2" placeholder="搜索图标" clearable @input="filterIcons" />
|
||||||
|
|
||||||
|
<div class="iconify-panel">
|
||||||
|
<div class="iconify-heading">也可以直接输入 Iconify 图标名</div>
|
||||||
|
<div class="iconify-form">
|
||||||
|
<el-input
|
||||||
|
v-model="customIcon"
|
||||||
|
placeholder="例如:mdi:account-circle-outline"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="applyCustomIcon"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" plain @click="applyCustomIcon">使用</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-scrollbar height="w-[200px]">
|
<el-scrollbar height="w-[200px]">
|
||||||
<ul class="icon-list">
|
<ul class="icon-list">
|
||||||
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
<el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
|
||||||
@ -44,6 +57,7 @@ const { modelValue, width } = toRefs(props);
|
|||||||
const iconNames = ref<string[]>(icons);
|
const iconNames = ref<string[]>(icons);
|
||||||
|
|
||||||
const filterValue = ref('');
|
const filterValue = ref('');
|
||||||
|
const customIcon = ref('');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 筛选图标
|
* 筛选图标
|
||||||
@ -63,6 +77,21 @@ const selectedIcon = (iconName: string) => {
|
|||||||
emit('update:modelValue', iconName);
|
emit('update:modelValue', iconName);
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const applyCustomIcon = () => {
|
||||||
|
const value = customIcon.value.trim();
|
||||||
|
if (!value) return;
|
||||||
|
emit('update:modelValue', value);
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(value) => {
|
||||||
|
customIcon.value = value?.includes(':') ? value : '';
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -73,31 +102,59 @@ const selectedIcon = (iconName: string) => {
|
|||||||
.el-divider--horizontal {
|
.el-divider--horizontal {
|
||||||
margin: 10px auto !important;
|
margin: 10px auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconify-panel {
|
||||||
|
padding: 2px 4px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconify-heading {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconify-form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-list {
|
.icon-list {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: repeat(auto-fill, minmax(48px, 1fr));
|
||||||
padding-left: 10px;
|
gap: 8px;
|
||||||
|
padding: 4px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
.icon-item {
|
.icon-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 10%;
|
min-height: 44px;
|
||||||
margin: 0 10px 10px 0;
|
padding: 8px 6px;
|
||||||
padding: 5px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-items: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
transition:
|
||||||
|
border-color 0.2s ease,
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--el-color-primary);
|
border-color: var(--el-color-primary);
|
||||||
|
background: var(--app-accent-soft);
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
transition: all 0.2s;
|
transform: translateY(-1px);
|
||||||
transform: scaleX(1.1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
border-color: var(--el-color-primary);
|
border-color: var(--el-color-primary);
|
||||||
|
background: rgba(64, 158, 255, 0.12);
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,15 @@ const handleLanguageChange = (lang: any) => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.lang-select--style {
|
.lang-select--style {
|
||||||
font-size: 18px;
|
display: inline-flex;
|
||||||
line-height: 50px;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
:deep(.svg-icon) {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -68,8 +68,15 @@ function handleCurrentChange(val: number) {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 18px;
|
||||||
|
margin-top: 18px;
|
||||||
|
border-top: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
.el-pagination {
|
.el-pagination {
|
||||||
float: v-bind(float);
|
float: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pagination-container.hidden {
|
.pagination-container.hidden {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="top-right-btn" :style="style">
|
<div class="top-right-btn" :style="style">
|
||||||
<el-row>
|
<el-row class="toolbar-row">
|
||||||
<el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
|
<el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
|
||||||
<el-button circle icon="Search" @click="toggleSearch()" />
|
<el-button circle icon="Search" @click="toggleSearch()" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -79,6 +79,27 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-button.is-circle) {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: rgba(255, 255, 255, 0.62);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
transition:
|
||||||
|
transform 0.25s ease,
|
||||||
|
border-color 0.25s ease,
|
||||||
|
color 0.25s ease,
|
||||||
|
background 0.25s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
border-color: rgba(53, 109, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.el-transfer__button) {
|
:deep(.el-transfer__button) {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: block;
|
display: block;
|
||||||
@ -91,12 +112,27 @@ onMounted(() => {
|
|||||||
.my-el-transfer {
|
.my-el-transfer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-row {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-header {
|
.tree-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--app-text-title);
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-btn {
|
.show-btn {
|
||||||
margin-left: 12px;
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.top-right-btn :deep(.el-button.is-circle) {
|
||||||
|
background: rgba(15, 23, 42, 0.56);
|
||||||
|
border-color: rgba(100, 116, 139, 0.22);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog v-model="roleDialog.visible.value" :title="roleDialog.title.value" width="80%" append-to-body>
|
<el-dialog v-model="roleDialog.visible.value" :title="roleDialog.title.value" width="80%" append-to-body class="role-select-dialog">
|
||||||
|
<div class="page-shell role-select-shell">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="search-panel selector-card">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -21,15 +22,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel selector-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-tag v-for="role in selectRoleList" :key="role.roleId" closable style="margin: 2px" @close="handleCloseTag(role)">
|
<div class="toolbar-shell selector-header">
|
||||||
{{ role.roleName }}
|
<div class="table-heading">
|
||||||
</el-tag>
|
<h3>角色列表</h3>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectRoleList.length" class="selector-tags">
|
||||||
|
<el-tag v-for="role in selectRoleList" :key="role.roleId" closable @close="handleCloseTag(role)">
|
||||||
|
{{ role.roleName }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<vxe-table
|
<vxe-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
|
class="selector-table"
|
||||||
height="400px"
|
height="400px"
|
||||||
border
|
border
|
||||||
show-overflow
|
show-overflow
|
||||||
@ -66,6 +75,7 @@
|
|||||||
@pagination="pageList"
|
@pagination="pageList"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="close">取消</el-button>
|
<el-button @click="close">取消</el-button>
|
||||||
<el-button type="primary" @click="confirm">确定</el-button>
|
<el-button type="primary" @click="confirm">确定</el-button>
|
||||||
@ -91,7 +101,6 @@ const prop = withDefaults(defineProps<PropType>(), {
|
|||||||
});
|
});
|
||||||
const emit = defineEmits(['update:modelValue', 'confirmCallBack']);
|
const emit = defineEmits(['update:modelValue', 'confirmCallBack']);
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
|
||||||
|
|
||||||
@ -248,3 +257,66 @@ defineExpose({
|
|||||||
close: roleDialog.closeDialog
|
close: roleDialog.closeDialog
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.role-select-shell {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-header {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 6px;
|
||||||
|
max-width: min(100%, 520px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tags :deep(.el-tag) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-select-dialog :deep(.el-dialog__body) {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table {
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-table--render-default) {
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-header--column) {
|
||||||
|
background: var(--tableHeaderBg);
|
||||||
|
color: var(--tableHeaderTextColor);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-body--column),
|
||||||
|
.selector-table :deep(.vxe-header--column) {
|
||||||
|
border-color: var(--app-surface-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-body--row.row--hover),
|
||||||
|
.selector-table :deep(.vxe-body--row:hover) {
|
||||||
|
background-color: rgba(53, 109, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.selector-tags {
|
||||||
|
justify-content: flex-start;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -34,8 +34,15 @@ const handleSetSize = (size: 'large' | 'default' | 'small') => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.size-icon--style {
|
.size-icon--style {
|
||||||
font-size: 18px;
|
display: inline-flex;
|
||||||
line-height: 50px;
|
align-items: center;
|
||||||
padding-right: 7px;
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
:deep(.svg-icon) {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,24 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg :class="svgClass" aria-hidden="true">
|
<Icon v-if="isIconify" :icon="normalizedIcon" :class="svgClass" :style="iconStyle" aria-hidden="true" />
|
||||||
|
<svg v-else :class="svgClass" aria-hidden="true" :style="iconStyle">
|
||||||
<use :xlink:href="iconName" :fill="color" />
|
<use :xlink:href="iconName" :fill="color" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { Icon } from '@iconify/vue';
|
||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
iconClass: propTypes.string.isRequired,
|
iconClass: propTypes.string.isRequired,
|
||||||
className: propTypes.string.def(''),
|
className: propTypes.string.def(''),
|
||||||
color: propTypes.string.def('')
|
color: propTypes.string.def(''),
|
||||||
|
size: propTypes.string.def('')
|
||||||
});
|
});
|
||||||
const iconName = computed(() => `#icon-${props.iconClass}`);
|
const normalizedIcon = computed(() => props.iconClass.replace(/^i-/, ''));
|
||||||
|
const isIconify = computed(() => normalizedIcon.value.includes(':'));
|
||||||
|
const iconName = computed(() => `#icon-${normalizedIcon.value}`);
|
||||||
const svgClass = computed(() => {
|
const svgClass = computed(() => {
|
||||||
if (props.className) {
|
if (props.className) {
|
||||||
return `svg-icon ${props.className}`;
|
return `svg-icon ${props.className}`;
|
||||||
}
|
}
|
||||||
return 'svg-icon';
|
return 'svg-icon';
|
||||||
});
|
});
|
||||||
|
const iconStyle = computed(() => ({
|
||||||
|
color: props.color || undefined,
|
||||||
|
fontSize: props.size || undefined
|
||||||
|
}));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -36,5 +45,6 @@ const svgClass = computed(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
vertical-align: -2px;
|
vertical-align: -2px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-menu :default-active="activeMenu" mode="horizontal" :ellipsis="false" @select="handleSelect">
|
<el-menu class="mix-topnav-menu" :default-active="activeMenu" mode="horizontal" :ellipsis="false" @select="handleSelect">
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path"
|
<el-menu-item v-if="index < visibleNumber" :key="index" :index="item.path"
|
||||||
><svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
|
><svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
{{ item.meta?.title }}</el-menu-item
|
{{ item.meta?.title }}</el-menu-item
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 顶部菜单超出数量折叠 -->
|
<!-- 顶部菜单超出数量折叠 -->
|
||||||
<el-sub-menu v-if="topMenus.length > visibleNumber" :style="{ '--theme': theme }" index="more">
|
<el-sub-menu v-if="topMenus.length > visibleNumber" class="el-sub-menu__hide-arrow" popper-class="mix-topnav-popper" index="more">
|
||||||
<template #title>更多菜单</template>
|
<template #title>更多菜单</template>
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item v-if="index >= visibleNumber" :key="index" :index="item.path"
|
<el-menu-item v-if="index >= visibleNumber" :key="index" :index="item.path"
|
||||||
@ -29,8 +29,6 @@ import { RouteRecordRaw } from 'vue-router';
|
|||||||
|
|
||||||
// 顶部栏初始数
|
// 顶部栏初始数
|
||||||
const visibleNumber = ref<number>(-1);
|
const visibleNumber = ref<number>(-1);
|
||||||
// 当前激活菜单的 index
|
|
||||||
const currentIndex = ref<string>();
|
|
||||||
// 隐藏侧边栏路由
|
// 隐藏侧边栏路由
|
||||||
const hideList = ['/index', '/user/profile'];
|
const hideList = ['/index', '/user/profile'];
|
||||||
|
|
||||||
@ -104,12 +102,14 @@ const activeMenu = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const setVisibleNumber = () => {
|
const setVisibleNumber = () => {
|
||||||
const width = document.body.getBoundingClientRect().width / 3;
|
let width = document.body.getBoundingClientRect().width;
|
||||||
visibleNumber.value = parseInt(String(width / 85));
|
if (width >= 1000) {
|
||||||
|
width -= 420;
|
||||||
|
}
|
||||||
|
visibleNumber.value = Math.max(1, Math.floor(width / 3 / 92) + 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelect = (key: string) => {
|
const handleSelect = (key: string) => {
|
||||||
currentIndex.value = key;
|
|
||||||
const route = routers.value.find((item) => item.path === key);
|
const route = routers.value.find((item) => item.path === key);
|
||||||
if (isHttp(key)) {
|
if (isHttp(key)) {
|
||||||
// http(s):// 路径新窗口打开
|
// http(s):// 路径新窗口打开
|
||||||
@ -161,40 +161,214 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.topmenu-container.el-menu--horizontal > .el-menu-item {
|
.mix-topnav-menu.el-menu--horizontal {
|
||||||
float: left;
|
--topbar-pill-bg: rgba(255, 255, 255, 0.7);
|
||||||
height: 50px !important;
|
--topbar-pill-hover-bg: rgba(255, 255, 255, 0.9);
|
||||||
line-height: 50px !important;
|
--topbar-pill-active-bg: rgba(255, 255, 255, 0.82);
|
||||||
color: #999093 !important;
|
--topbar-pill-text: var(--app-text-title);
|
||||||
padding: 0 5px !important;
|
--topbar-pill-muted: var(--app-text-muted);
|
||||||
margin: 0 10px !important;
|
--topbar-pill-border: rgba(148, 163, 184, 0.12);
|
||||||
|
--topbar-pill-active-border: rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0;
|
||||||
|
border: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.topmenu-container.el-menu--horizontal > .el-menu-item.is-active,
|
#app .mix-topnav-menu.el-menu--horizontal > .el-menu-item,
|
||||||
.el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
|
#app .mix-topnav-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title {
|
||||||
border-bottom: 2px solid #{'var(--theme)'} !important;
|
display: inline-flex;
|
||||||
color: #303133;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 7px;
|
||||||
|
height: 36px !important;
|
||||||
|
line-height: 36px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 18px !important;
|
||||||
|
border: 1px solid transparent !important;
|
||||||
|
border-radius: 13px;
|
||||||
|
color: var(--topbar-pill-text) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease,
|
||||||
|
border-color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sub-menu item */
|
#app .mix-topnav-menu.el-menu--horizontal > .el-menu-item:hover,
|
||||||
.topmenu-container.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
|
#app .mix-topnav-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title:hover {
|
||||||
float: left;
|
background: linear-gradient(180deg, var(--topbar-pill-hover-bg), var(--topbar-pill-bg)) !important;
|
||||||
height: 50px !important;
|
border-color: var(--topbar-pill-border) !important;
|
||||||
line-height: 50px !important;
|
color: v-bind(theme) !important;
|
||||||
color: #999093 !important;
|
transform: translateY(-1px);
|
||||||
padding: 0 5px !important;
|
|
||||||
margin: 0 10px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 背景色隐藏 */
|
#app .mix-topnav-menu.el-menu--horizontal > .el-menu-item.is-active,
|
||||||
.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):focus,
|
#app .mix-topnav-menu.el-menu--horizontal > .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):hover,
|
background: linear-gradient(180deg, var(--topbar-pill-hover-bg), var(--topbar-pill-active-bg)) !important;
|
||||||
.topmenu-container.el-menu--horizontal > .el-submenu .el-submenu__title:hover {
|
border-color: var(--topbar-pill-active-border) !important;
|
||||||
background-color: #ffffff !important;
|
color: v-bind(theme) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 图标右间距 */
|
#app .mix-topnav-menu.el-menu--horizontal > .el-menu-item .svg-icon,
|
||||||
.topmenu-container .svg-icon {
|
#app .mix-topnav-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title .svg-icon {
|
||||||
margin-right: 4px;
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .mix-topnav-menu.el-menu--horizontal > .el-menu-item span,
|
||||||
|
#app .mix-topnav-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title span {
|
||||||
|
color: inherit !important;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-menu .el-sub-menu .el-sub-menu__icon-arrow {
|
||||||
|
position: static;
|
||||||
|
margin: 0 0 0 2px;
|
||||||
|
display: block !important;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-menu.el-menu--horizontal > .el-menu-item::after,
|
||||||
|
.mix-topnav-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-menu.el-menu--horizontal > .el-sub-menu.el-sub-menu__hide-arrow > .el-sub-menu__title {
|
||||||
|
color: var(--topbar-pill-muted) !important;
|
||||||
|
padding-right: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper.el-popper {
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 18px !important;
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper.el-popper .el-popper__arrow {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup {
|
||||||
|
min-width: 188px;
|
||||||
|
padding: 10px !important;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.94)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 18px 40px rgba(15, 23, 42, 0.12),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-menu-item,
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
padding: 0 14px !important;
|
||||||
|
margin: 0 0 4px !important;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: var(--app-text-title) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-menu-item:last-child,
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu:last-child > .el-sub-menu__title {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-menu-item:hover,
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu__title:hover {
|
||||||
|
background: rgba(64, 158, 255, 0.08) !important;
|
||||||
|
color: v-bind(theme) !important;
|
||||||
|
transform: translateX(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-menu-item.is-active,
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
|
background: linear-gradient(180deg, rgba(64, 158, 255, 0.16), rgba(64, 158, 255, 0.1)) !important;
|
||||||
|
color: v-bind(theme) !important;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(64, 158, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .svg-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu__title > span,
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-menu-item > span {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-topnav-popper .el-menu--popup .el-sub-menu__icon-arrow {
|
||||||
|
position: static;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .mix-topnav-menu.el-menu--horizontal {
|
||||||
|
--topbar-pill-bg: rgba(30, 41, 59, 0.64);
|
||||||
|
--topbar-pill-hover-bg: rgba(51, 65, 85, 0.88);
|
||||||
|
--topbar-pill-active-bg: rgba(51, 65, 85, 0.78);
|
||||||
|
--topbar-pill-border: rgba(71, 85, 105, 0.28);
|
||||||
|
--topbar-pill-active-border: rgba(71, 85, 105, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup {
|
||||||
|
border-color: rgba(71, 85, 105, 0.34);
|
||||||
|
background: linear-gradient(180deg, rgba(15, 23, 42, 0.98), rgba(30, 41, 59, 0.94)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 20px 42px rgba(0, 0, 0, 0.34),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-menu-item,
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-sub-menu__title {
|
||||||
|
color: #e5edf8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-menu-item:hover,
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-sub-menu__title:hover {
|
||||||
|
background: rgba(96, 165, 250, 0.14) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-menu-item.is-active,
|
||||||
|
html.dark .mix-topnav-popper .el-menu--popup .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
|
background: linear-gradient(180deg, rgba(37, 99, 235, 0.28), rgba(59, 130, 246, 0.18)) !important;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(96, 165, 250, 0.16);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,14 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog v-model="userDialog.visible.value" :title="userDialog.title.value" width="80%" append-to-body>
|
<el-dialog v-model="userDialog.visible.value" :title="userDialog.title.value" width="80%" append-to-body class="user-select-dialog">
|
||||||
<el-row :gutter="20">
|
<div class="page-shell user-select-shell">
|
||||||
|
<el-row :gutter="12" class="selector-layout">
|
||||||
<!-- 部门树 -->
|
<!-- 部门树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="5" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel selector-card selector-side-card">
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
<template #header>
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>部门结构</h3>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-input v-model="deptName" class="selector-dept-input" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="deptTreeRef"
|
ref="deptTreeRef"
|
||||||
class="mt-2"
|
class="selector-tree"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="deptOptions"
|
:data="deptOptions"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' } as any"
|
||||||
@ -20,11 +26,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="19" :xs="24">
|
||||||
|
<div class="page-shell user-select-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="search-panel selector-card">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -40,15 +47,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel selector-card">
|
||||||
<template v-if="prop.multiple" #header>
|
<template #header>
|
||||||
<el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)">
|
<div class="toolbar-shell selector-header">
|
||||||
{{ user.nickName }}
|
<div class="table-heading">
|
||||||
</el-tag>
|
<h3>用户列表</h3>
|
||||||
|
</div>
|
||||||
|
<div v-if="prop.multiple && selectUserList.length" class="selector-tags">
|
||||||
|
<el-tag v-for="user in selectUserList" :key="user.userId" closable @close="handleCloseTag(user)">
|
||||||
|
{{ user.nickName }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<vxe-table
|
<vxe-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
|
class="selector-table"
|
||||||
height="400px"
|
height="400px"
|
||||||
border
|
border
|
||||||
show-overflow
|
show-overflow
|
||||||
@ -86,8 +101,10 @@
|
|||||||
@pagination="pageList"
|
@pagination="pageList"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="close">取消</el-button>
|
<el-button @click="close">取消</el-button>
|
||||||
@ -309,3 +326,87 @@ defineExpose({
|
|||||||
close: userDialog.closeDialog
|
close: userDialog.closeDialog
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.user-select-shell,
|
||||||
|
.user-select-main {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-layout {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-side-card {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-dept-input {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tree {
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-header {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 6px;
|
||||||
|
max-width: min(100%, 520px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tags :deep(.el-tag) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-select-dialog :deep(.el-dialog__body) {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table {
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-table--render-default) {
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-header--column) {
|
||||||
|
background: var(--tableHeaderBg);
|
||||||
|
color: var(--tableHeaderTextColor);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-body--column),
|
||||||
|
.selector-table :deep(.vxe-header--column) {
|
||||||
|
border-color: var(--app-surface-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-table :deep(.vxe-body--row.row--hover),
|
||||||
|
.selector-table :deep(.vxe-body--row:hover) {
|
||||||
|
background-color: rgba(53, 109, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.selector-tree {
|
||||||
|
min-height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-tags {
|
||||||
|
justify-content: flex-start;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -22,11 +22,9 @@ const tagsViewStore = useTagsViewStore();
|
|||||||
|
|
||||||
// 随机动画集合
|
// 随机动画集合
|
||||||
const animate = ref<string>('');
|
const animate = ref<string>('');
|
||||||
const animationEnable = ref(useSettingsStore().animationEnable);
|
|
||||||
watch(
|
watch(
|
||||||
() => useSettingsStore().animationEnable,
|
() => useSettingsStore().animationEnable,
|
||||||
(val: boolean) => {
|
(val: boolean) => {
|
||||||
animationEnable.value = val;
|
|
||||||
if (val) {
|
if (val) {
|
||||||
animate.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
|
animate.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
|
||||||
} else {
|
} else {
|
||||||
@ -36,10 +34,6 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
addIframe();
|
|
||||||
});
|
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
addIframe();
|
addIframe();
|
||||||
});
|
});
|
||||||
@ -53,26 +47,21 @@ function addIframe() {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.app-main {
|
.app-main {
|
||||||
/* 50= navbar 50 */
|
min-height: 100vh;
|
||||||
min-height: calc(100vh - 50px);
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-header + .app-main {
|
.app-main.with-fixed-header {
|
||||||
padding-top: 50px;
|
padding-top: 76px;
|
||||||
|
min-height: calc(100vh - 76px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hasTagsView {
|
.app-main.with-fixed-header.with-tags-view {
|
||||||
.app-main {
|
min-height: calc(100vh - 111px);
|
||||||
/* 84 = navbar + tags-view = 50 + 34 */
|
padding-top: 111px;
|
||||||
min-height: calc(100vh - 84px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-header + .app-main {
|
|
||||||
padding-top: 84px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -1,14 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="navbar" :class="'nav' + navType">
|
<div class="navbar" :class="'nav' + navType">
|
||||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
|
<div class="navbar-left">
|
||||||
|
<div v-if="navType !== NavTypeEnum.TOP" class="hamburger-shell">
|
||||||
|
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
|
||||||
|
</div>
|
||||||
|
<router-link v-else-if="showLogo" to="/" class="navtop-logo-shell">
|
||||||
|
<img :src="appLogo" class="navtop-logo-icon" alt="logo" />
|
||||||
|
</router-link>
|
||||||
|
|
||||||
<breadcrumb v-if="navType == NavTypeEnum.LEFT" id="breadcrumb-container" class="breadcrumb-container" />
|
<div class="nav-context">
|
||||||
<top-nav v-if="navType == NavTypeEnum.MIX" id="topmenu-container" class="topmenu-container" />
|
<breadcrumb v-if="navType == NavTypeEnum.LEFT" id="breadcrumb-container" class="breadcrumb-container" />
|
||||||
|
<top-nav v-if="navType == NavTypeEnum.MIX" id="topmenu-container" class="topmenu-container" />
|
||||||
|
|
||||||
<template v-if="navType == NavTypeEnum.TOP">
|
<template v-if="navType == NavTypeEnum.TOP">
|
||||||
<logo v-show="showLogo" :collapse="false"></logo>
|
<top-bar id="topbar-container" class="topbar-container" />
|
||||||
<top-bar id="topbar-container" class="topbar-container" />
|
</template>
|
||||||
</template>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="right-menu flex align-center">
|
<div class="right-menu flex align-center">
|
||||||
<template v-if="appStore.device !== 'mobile'">
|
<template v-if="appStore.device !== 'mobile'">
|
||||||
<search-menu ref="searchMenuRef" />
|
<search-menu ref="searchMenuRef" />
|
||||||
@ -23,7 +31,7 @@
|
|||||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-badge :value="newNotice > 0 ? newNotice : ''" :max="99">
|
<el-badge :value="newNotice > 0 ? newNotice : ''" :max="99">
|
||||||
<div class="right-menu-item hover-effect" style="display: block"><svg-icon icon-class="message" /></div>
|
<div class="right-menu-item hover-effect message-trigger"><svg-icon icon-class="message" /></div>
|
||||||
</el-badge>
|
</el-badge>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
@ -53,10 +61,14 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
<el-dropdown class="avatar-dropdown" trigger="click" @command="handleCommand">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img :src="userStore.avatar" class="user-avatar" />
|
<img :src="userStore.avatar" class="user-avatar" />
|
||||||
<el-icon><caret-bottom /></el-icon>
|
<div class="avatar-meta">
|
||||||
|
<span class="avatar-name">{{ displayName }}</span>
|
||||||
|
<span class="avatar-role">Workspace</span>
|
||||||
|
</div>
|
||||||
|
<el-icon class="avatar-arrow"><caret-bottom /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
@ -87,8 +99,9 @@ import notice from './notice/index.vue';
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import type { ElMessageBoxOptions } from 'element-plus';
|
import type { ElMessageBoxOptions } from 'element-plus';
|
||||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||||
import Logo from "@/layout/components/Sidebar/Logo.vue";
|
|
||||||
import TopBar from './TopBar/index.vue';
|
import TopBar from './TopBar/index.vue';
|
||||||
|
import { CaretBottom } from '@element-plus/icons-vue';
|
||||||
|
import appLogo from '@/assets/logo/logo.png';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@ -98,9 +111,9 @@ const newNotice = ref(<number>0);
|
|||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const userId = ref(userStore.userId);
|
|
||||||
const navType = computed(() => settingsStore.navType);
|
const navType = computed(() => settingsStore.navType);
|
||||||
const showLogo = computed(() => settingsStore.sidebarLogo);
|
const showLogo = computed(() => settingsStore.sidebarLogo);
|
||||||
|
const displayName = computed(() => userStore.nickname || '管理员');
|
||||||
|
|
||||||
// 搜索菜单
|
// 搜索菜单
|
||||||
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
|
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
|
||||||
@ -157,8 +170,56 @@ watch(
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.navbar.navtop {
|
.navbar.navtop {
|
||||||
.hamburger-container {
|
.nav-context {
|
||||||
display: none !important;
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navtop-logo-shell {
|
||||||
|
width: 48px;
|
||||||
|
height: 40px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(248, 250, 252, 0.82));
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.72),
|
||||||
|
0 6px 14px rgba(15, 23, 42, 0.04);
|
||||||
|
transition:
|
||||||
|
transform 0.2s ease,
|
||||||
|
border-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: rgba(64, 158, 255, 0.22);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.76),
|
||||||
|
0 10px 22px rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navtop-logo-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: block;
|
||||||
|
border-radius: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-container {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(248, 250, 252, 0.58));
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.72),
|
||||||
|
0 6px 18px rgba(15, 23, 42, 0.04);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +228,17 @@ watch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-badge__content.is-fixed) {
|
:deep(.el-badge__content.is-fixed) {
|
||||||
top: 12px;
|
top: 8px;
|
||||||
|
right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-badge) {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dropdown) {
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
@ -179,42 +250,71 @@ watch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
height: 50px;
|
min-height: 52px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--el-bg-color);
|
background: var(--app-navbar-bg);
|
||||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
border: 1px solid var(--app-navbar-border);
|
||||||
box-shadow: none;
|
box-shadow: var(--app-navbar-shadow);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// padding: 0 8px;
|
justify-content: space-between;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 6px 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.navbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
gap: 10px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-shell {
|
||||||
|
width: 36px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
}
|
||||||
|
|
||||||
.hamburger-container {
|
.hamburger-container {
|
||||||
line-height: 46px;
|
line-height: 32px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
//float: left;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.3s;
|
transition: background 0.3s;
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 8px;
|
justify-content: center;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--el-fill-color-lighter);
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-context {
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumb-container {
|
.breadcrumb-container {
|
||||||
//float: left;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topmenu-container {
|
.topmenu-container {
|
||||||
position: absolute;
|
position: static;
|
||||||
left: 50px;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar-container {
|
.topbar-container {
|
||||||
@ -226,66 +326,159 @@ watch(
|
|||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.errLog-container {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-menu {
|
.right-menu {
|
||||||
//float: right;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
line-height: 50px;
|
line-height: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.right-menu-item {
|
.right-menu-item {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
padding: 0 8px;
|
align-items: center;
|
||||||
height: 100%;
|
justify-content: center;
|
||||||
font-size: 18px;
|
width: 32px;
|
||||||
color: var(--el-text-color-regular);
|
height: 32px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
border-radius: 12px;
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
:deep(.svg-icon),
|
||||||
|
:deep(svg),
|
||||||
|
:deep(.el-icon) {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
&.hover-effect {
|
&.hover-effect {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.3s;
|
transition:
|
||||||
|
background 0.3s,
|
||||||
|
color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--el-fill-color-lighter);
|
background: var(--app-accent-soft);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
border-color: rgba(64, 158, 255, 0.16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-trigger {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar-container {
|
.avatar-container {
|
||||||
margin-right: 40px;
|
margin-left: 6px;
|
||||||
|
margin-right: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.avatar-dropdown {
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar-wrapper {
|
.avatar-wrapper {
|
||||||
margin-top: 5px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 4px 8px 4px 4px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
min-width: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
background 0.3s,
|
||||||
|
border-color 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
border-color: rgba(64, 158, 255, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 40px;
|
width: 28px;
|
||||||
height: 40px;
|
height: 28px;
|
||||||
border-radius: var(--app-radius-md);
|
border-radius: 12px;
|
||||||
margin-top: 10px;
|
object-fit: cover;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
i {
|
.avatar-meta {
|
||||||
cursor: pointer;
|
display: flex;
|
||||||
position: absolute;
|
flex-direction: column;
|
||||||
right: -20px;
|
min-width: 0;
|
||||||
top: 25px;
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-name {
|
||||||
|
max-width: 88px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--app-text-title);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-role {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-arrow {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.navbar.navtop .navtop-logo-shell {
|
||||||
|
background: linear-gradient(180deg, rgba(15, 23, 42, 0.92), rgba(30, 41, 59, 0.82));
|
||||||
|
border-color: rgba(71, 85, 105, 0.42);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06),
|
||||||
|
0 8px 18px rgba(0, 0, 0, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar.navtop .topbar-container {
|
||||||
|
background: linear-gradient(180deg, rgba(15, 23, 42, 0.82), rgba(15, 23, 42, 0.7));
|
||||||
|
border-color: rgba(71, 85, 105, 0.34);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.05),
|
||||||
|
0 8px 22px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .right-menu .right-menu-item,
|
||||||
|
.navbar .right-menu .avatar-wrapper {
|
||||||
|
background: var(--app-navbar-bg);
|
||||||
|
border-color: var(--app-navbar-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="showSettings" :with-header="false" direction="rtl" size="300px" close-on-click-modal>
|
<el-drawer v-model="showSettings" class="settings-drawer" :with-header="false" direction="rtl" size="300px" close-on-click-modal>
|
||||||
<h3 class="drawer-title">菜单导航设置</h3>
|
<h3 class="drawer-title">菜单导航设置</h3>
|
||||||
<div class="nav-wrap">
|
<div class="nav-wrap">
|
||||||
<el-tooltip content="左侧菜单" placement="bottom">
|
<el-tooltip content="左侧菜单" placement="bottom">
|
||||||
@ -229,6 +229,15 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.settings-drawer {
|
||||||
|
:deep(.el-drawer__body) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 18px 18px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.setting-drawer-title {
|
.setting-drawer-title {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
color: rgba(0, 0, 0, 0.85);
|
color: rgba(0, 0, 0, 0.85);
|
||||||
@ -248,12 +257,23 @@ defineExpose({
|
|||||||
.setting-drawer-block-checbox-item {
|
.setting-drawer-block-checbox-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
border-radius: 2px;
|
border-radius: 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||||
|
transition:
|
||||||
|
border-color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(64, 158, 255, 0.28);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-img {
|
.custom-img {
|
||||||
@ -281,6 +301,8 @@ defineExpose({
|
|||||||
.drawer-item {
|
.drawer-item {
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
border-bottom: 1px solid rgba(148, 163, 184, 0.08);
|
||||||
|
|
||||||
.comp-style {
|
.comp-style {
|
||||||
float: right;
|
float: right;
|
||||||
@ -306,9 +328,16 @@ defineExpose({
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
border-radius: 4px;
|
border-radius: 12px;
|
||||||
background: #f0f2f5;
|
background: var(--app-elevated-soft-bg);
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
|
transition:
|
||||||
|
transform 0.2s ease,
|
||||||
|
border-color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
@ -317,6 +346,7 @@ defineExpose({
|
|||||||
height: 30%;
|
height: 30%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
b:last-child {
|
b:last-child {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
background: #1b2a47;
|
background: #1b2a47;
|
||||||
@ -326,6 +356,7 @@ defineExpose({
|
|||||||
border-radius: 4px 0 0 4px;
|
border-radius: 4px 0 0 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mix {
|
.mix {
|
||||||
b:first-child {
|
b:first-child {
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
@ -333,6 +364,7 @@ defineExpose({
|
|||||||
height: 30%;
|
height: 30%;
|
||||||
background: #1b2a47;
|
background: #1b2a47;
|
||||||
}
|
}
|
||||||
|
|
||||||
b:last-child {
|
b:last-child {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
background: #1b2a47;
|
background: #1b2a47;
|
||||||
@ -341,6 +373,7 @@ defineExpose({
|
|||||||
border-radius: 0 0 0 4px;
|
border-radius: 0 0 0 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
b:first-child {
|
b:first-child {
|
||||||
display: block;
|
display: block;
|
||||||
@ -348,6 +381,10 @@ defineExpose({
|
|||||||
background: #1b2a47;
|
background: #1b2a47;
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -21,7 +21,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import variables from '@/assets/styles/variables.module.scss';
|
|
||||||
import logo from '@/assets/logo/logo.png';
|
import logo from '@/assets/logo/logo.png';
|
||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -37,28 +36,11 @@ defineProps({
|
|||||||
const title = import.meta.env.VITE_APP_LOGO_TITLE;
|
const title = import.meta.env.VITE_APP_LOGO_TITLE;
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||||
|
const isTopNav = computed(() => settingsStore.navType === NavTypeEnum.TOP);
|
||||||
// 获取Logo背景色
|
const isDarkSide = computed(() => !isTopNav.value && sideTheme.value === 'theme-dark');
|
||||||
const getLogoBackground = computed(() => {
|
const logoSurface = computed(() => (isDarkSide.value ? 'rgba(255, 255, 255, 0.04)' : '#f8fafc'));
|
||||||
if (settingsStore.isDark) {
|
const logoBorder = computed(() => (isDarkSide.value ? 'rgba(148, 163, 184, 0.12)' : '#e5e7eb'));
|
||||||
return 'var(--sidebar-bg)'
|
const logoTextColor = computed(() => (isDarkSide.value ? '#f8fbff' : 'var(--app-text-title)'));
|
||||||
}
|
|
||||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
|
||||||
return variables.menuLightBackground
|
|
||||||
}
|
|
||||||
return sideTheme.value === 'theme-dark' ? variables.menuBg : variables.menuLightBackground
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取Logo文字颜色
|
|
||||||
const getLogoTextColor = computed(() => {
|
|
||||||
if (settingsStore.isDark) {
|
|
||||||
return 'var(--sidebar-text)'
|
|
||||||
}
|
|
||||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
|
||||||
return variables.logoLightTitleColor
|
|
||||||
}
|
|
||||||
return sideTheme.value === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -73,39 +55,61 @@ const getLogoTextColor = computed(() => {
|
|||||||
|
|
||||||
.sidebar-logo-container {
|
.sidebar-logo-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 50px;
|
flex-shrink: 0;
|
||||||
line-height: 50px;
|
height: 46px;
|
||||||
background: v-bind(getLogoBackground);
|
line-height: 46px;
|
||||||
|
padding: 0 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
background: transparent;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
& .sidebar-logo-link {
|
& .sidebar-logo-link {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: v-bind(logoSurface);
|
||||||
|
border: 1px solid v-bind(logoBorder);
|
||||||
|
|
||||||
& .sidebar-logo {
|
& .sidebar-logo {
|
||||||
width: 32px;
|
width: 28px;
|
||||||
height: 32px;
|
height: 28px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 12px;
|
margin-right: 0;
|
||||||
margin-left: 12px;
|
margin-left: 0;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .sidebar-title {
|
& .sidebar-title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: v-bind(getLogoTextColor);
|
color: v-bind(logoTextColor);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 50px;
|
line-height: 1;
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
letter-spacing: 0.02em;
|
||||||
|
font-family:
|
||||||
|
'MiSans',
|
||||||
|
'HarmonyOS Sans SC',
|
||||||
|
'PingFang SC',
|
||||||
|
sans-serif;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.collapse {
|
&.collapse {
|
||||||
|
.sidebar-logo-link {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
margin-right: 0px;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
</app-link>
|
</app-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
|
<el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" :popper-offset="isNest ? 4 : 12" :popper-class="popperClass" teleported>
|
||||||
<template v-if="item.meta" #title>
|
<template v-if="item.meta" #title>
|
||||||
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
||||||
@ -22,6 +22,7 @@
|
|||||||
:key="child.path + index"
|
:key="child.path + index"
|
||||||
:is-nest="true"
|
:is-nest="true"
|
||||||
:item="child"
|
:item="child"
|
||||||
|
:popper-class="popperClass"
|
||||||
:base-path="resolvePath(child.path)"
|
:base-path="resolvePath(child.path)"
|
||||||
class="nest-menu"
|
class="nest-menu"
|
||||||
/>
|
/>
|
||||||
@ -47,6 +48,10 @@ const props = defineProps({
|
|||||||
basePath: {
|
basePath: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
popperClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: bgColor }">
|
<div class="sidebar-shell" :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: bgColor }">
|
||||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||||
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
||||||
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
||||||
@ -24,7 +24,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Logo from './Logo.vue';
|
import Logo from './Logo.vue';
|
||||||
import SidebarItem from './SidebarItem.vue';
|
import SidebarItem from './SidebarItem.vue';
|
||||||
import variables from '@/assets/styles/variables.module.scss';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
import { usePermissionStore } from '@/store/modules/permission';
|
import { usePermissionStore } from '@/store/modules/permission';
|
||||||
@ -51,6 +50,37 @@ const activeMenu = computed(() => {
|
|||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
|
||||||
const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground));
|
const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? '#111827' : '#ffffff'));
|
||||||
const textColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor));
|
const textColor = computed(() => (sideTheme.value === 'theme-dark' ? '#e5edf8' : '#1f2937'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.sidebar-shell {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 8px 12px;
|
||||||
|
border: 1px solid var(--app-sidebar-border);
|
||||||
|
border-radius: 22px;
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
background: v-bind(bgColor) !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__view) {
|
||||||
|
min-height: 0;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__wrap) {
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,30 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-menu class="topbar-menu" :ellipsis="false" :default-active="activeMenu" :active-text-color="theme" mode="horizontal">
|
<el-menu class="topbar-menu" :ellipsis="false" :default-active="activeMenu" :active-text-color="theme" mode="horizontal">
|
||||||
<sidebar-item :key="route.path + index" v-for="(route, index) in topMenus" :item="route" :base-path="route.path" />
|
<sidebar-item :key="route.path + index" v-for="(route, index) in topMenus" :item="route" :base-path="route.path" popper-class="topbar-menu-popper" />
|
||||||
|
|
||||||
<el-sub-menu index="more" class="el-sub-menu__hide-arrow" v-if="moreRoutes.length > 0">
|
<el-sub-menu index="more" class="el-sub-menu__hide-arrow" popper-class="topbar-menu-popper" v-if="moreRoutes.length > 0">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>更多菜单</span>
|
<span>更多菜单</span>
|
||||||
</template>
|
</template>
|
||||||
<sidebar-item :key="route.path + index" v-for="(route, index) in moreRoutes" :item="route" :base-path="route.path" />
|
<sidebar-item :key="route.path + index" v-for="(route, index) in moreRoutes" :item="route" :base-path="route.path" popper-class="topbar-menu-popper" />
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import SidebarItem from '../Sidebar/SidebarItem'
|
import SidebarItem from '../Sidebar/SidebarItem'
|
||||||
import {useAppStore} from '@/store/modules/app'
|
|
||||||
import {useSettingsStore} from '@/store/modules/settings'
|
import {useSettingsStore} from '@/store/modules/settings'
|
||||||
import {usePermissionStore} from '@/store/modules/permission'
|
import {usePermissionStore} from '@/store/modules/permission'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const appStore = useAppStore()
|
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters)
|
|
||||||
const theme = computed(() => settingsStore.theme)
|
const theme = computed(() => settingsStore.theme)
|
||||||
const device = computed(() => appStore.device)
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const { meta, path } = route
|
const { meta, path } = route
|
||||||
if (meta.activeMenu) {
|
if (meta.activeMenu) {
|
||||||
@ -38,14 +34,14 @@ const topMenus = computed(() => {
|
|||||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(0, visibleNumber.value)
|
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(0, visibleNumber.value)
|
||||||
})
|
})
|
||||||
const moreRoutes = computed(() => {
|
const moreRoutes = computed(() => {
|
||||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(visibleNumber.value, sidebarRouters.value.length - visibleNumber.value)
|
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(visibleNumber.value)
|
||||||
})
|
})
|
||||||
function setVisibleNumber() {
|
function setVisibleNumber() {
|
||||||
let width = document.body.getBoundingClientRect().width
|
let width = document.body.getBoundingClientRect().width
|
||||||
if (width >= 1000) {
|
if (width >= 1000) {
|
||||||
width -= 500
|
width -= 420
|
||||||
}
|
}
|
||||||
visibleNumber.value = parseInt(width / 3 / 85)
|
visibleNumber.value = Math.max(1, Math.floor(width / 3 / 92) + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -61,43 +57,234 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.topbar-menu.el-menu--horizontal {
|
||||||
|
--topbar-pill-bg: rgba(255, 255, 255, 0.7);
|
||||||
|
--topbar-pill-hover-bg: rgba(255, 255, 255, 0.9);
|
||||||
|
--topbar-pill-active-bg: rgba(255, 255, 255, 0.82);
|
||||||
|
--topbar-pill-text: var(--app-text-title);
|
||||||
|
--topbar-pill-muted: var(--app-text-muted);
|
||||||
|
--topbar-pill-border: rgba(148, 163, 184, 0.12);
|
||||||
|
--topbar-pill-active-border: rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
/* menu item */
|
display: flex;
|
||||||
#app .topbar-menu.el-menu--horizontal .el-sub-menu__title, #app .topbar-menu.el-menu--horizontal .el-menu-item {
|
align-items: center;
|
||||||
padding: 0 10px !important;
|
gap: 6px;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0;
|
||||||
|
border: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar-menu.el-menu--horizontal > .el-menu-item {
|
#app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item,
|
||||||
float: left;
|
#app .topbar-menu.el-menu--horizontal > div > .el-sub-menu > .el-sub-menu__title,
|
||||||
height: 50px !important;
|
#app .topbar-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title {
|
||||||
line-height: 50px !important;
|
display: inline-flex;
|
||||||
color: #303133 !important;
|
align-items: center;
|
||||||
padding: 0 5px !important;
|
justify-content: center;
|
||||||
margin: 0 10px !important;
|
gap: 7px;
|
||||||
|
height: 36px !important;
|
||||||
|
line-height: 36px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 18px !important;
|
||||||
|
border: 1px solid transparent !important;
|
||||||
|
border-radius: 13px;
|
||||||
|
color: var(--topbar-pill-text) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease,
|
||||||
|
border-color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu.is-active .svg-icon, .el-menu-item.is-active .svg-icon + span, .el-sub-menu.is-active .svg-icon + span, .el-sub-menu.is-active .el-sub-menu__title span {
|
#app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item:hover,
|
||||||
color: v-bind(theme);
|
#app .topbar-menu.el-menu--horizontal > div > .el-sub-menu > .el-sub-menu__title:hover,
|
||||||
|
#app .topbar-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title:hover {
|
||||||
|
background: linear-gradient(180deg, var(--topbar-pill-hover-bg), var(--topbar-pill-bg)) !important;
|
||||||
|
border-color: var(--topbar-pill-border) !important;
|
||||||
|
color: v-bind(theme) !important;
|
||||||
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sub-menu item */
|
#app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item.is-active,
|
||||||
.topbar-menu.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
|
#app .topbar-menu.el-menu--horizontal > div > .el-sub-menu.is-active > .el-sub-menu__title,
|
||||||
float: left;
|
#app .topbar-menu.el-menu--horizontal > .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
line-height: 50px !important;
|
background: linear-gradient(180deg, var(--topbar-pill-hover-bg), var(--topbar-pill-active-bg)) !important;
|
||||||
color: #303133 !important;
|
border-color: var(--topbar-pill-active-border) !important;
|
||||||
margin: 0 15px -3px!important;
|
color: v-bind(theme) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item .svg-icon,
|
||||||
|
#app .topbar-menu.el-menu--horizontal > div > .el-sub-menu > .el-sub-menu__title .svg-icon,
|
||||||
|
#app .topbar-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title .svg-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item span,
|
||||||
|
#app .topbar-menu.el-menu--horizontal > div > .el-sub-menu > .el-sub-menu__title span,
|
||||||
|
#app .topbar-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title span {
|
||||||
|
color: inherit !important;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu.el-menu--horizontal > div > a > .el-menu-item.is-active span,
|
||||||
|
.topbar-menu.el-menu--horizontal > div > .el-sub-menu.is-active > .el-sub-menu__title span,
|
||||||
|
.topbar-menu.el-menu--horizontal > .el-sub-menu.is-active > .el-sub-menu__title span {
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* topbar more arrow */
|
|
||||||
.topbar-menu .el-sub-menu .el-sub-menu__icon-arrow {
|
.topbar-menu .el-sub-menu .el-sub-menu__icon-arrow {
|
||||||
position: static;
|
position: static;
|
||||||
margin-left: 8px;
|
margin: 0 0 0 2px;
|
||||||
margin-top: 0px;
|
|
||||||
display: block !important;
|
display: block !important;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* menu__title el-menu-item */
|
.topbar-menu.el-menu--horizontal > div > a > .el-menu-item::after,
|
||||||
.topbar-menu.el-menu--horizontal .el-sub-menu__title, .topbar-menu.el-menu--horizontal .el-menu-item {
|
.topbar-menu.el-menu--horizontal > div > .el-sub-menu > .el-sub-menu__title::after,
|
||||||
height: 60px;
|
.topbar-menu.el-menu--horizontal > .el-sub-menu > .el-sub-menu__title::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu.el-menu--horizontal > .el-sub-menu.el-sub-menu__hide-arrow > .el-sub-menu__title {
|
||||||
|
color: var(--topbar-pill-muted) !important;
|
||||||
|
padding-right: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .topbar-menu.el-menu--horizontal {
|
||||||
|
--topbar-pill-bg: rgba(30, 41, 59, 0.64);
|
||||||
|
--topbar-pill-hover-bg: rgba(51, 65, 85, 0.88);
|
||||||
|
--topbar-pill-active-bg: rgba(51, 65, 85, 0.78);
|
||||||
|
--topbar-pill-border: rgba(71, 85, 105, 0.28);
|
||||||
|
--topbar-pill-active-border: rgba(71, 85, 105, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark #app .topbar-menu.el-menu--horizontal > div > a > .el-menu-item.is-active,
|
||||||
|
html.dark #app .topbar-menu.el-menu--horizontal > div > .el-sub-menu.is-active > .el-sub-menu__title,
|
||||||
|
html.dark #app .topbar-menu.el-menu--horizontal > .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper.el-popper {
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 18px !important;
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper.el-popper .el-popper__arrow {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup {
|
||||||
|
min-width: 188px;
|
||||||
|
padding: 10px !important;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.94)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 18px 40px rgba(15, 23, 42, 0.12),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-menu-item,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
padding: 0 14px !important;
|
||||||
|
margin: 0 0 4px !important;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: var(--app-text-title) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-menu-item:last-child,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu:last-child > .el-sub-menu__title {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-menu-item:hover,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu__title:hover {
|
||||||
|
background: rgba(64, 158, 255, 0.08) !important;
|
||||||
|
color: v-bind(theme) !important;
|
||||||
|
transform: translateX(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-menu-item.is-active,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
|
background: linear-gradient(180deg, rgba(64, 158, 255, 0.16), rgba(64, 158, 255, 0.1)) !important;
|
||||||
|
color: v-bind(theme) !important;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(64, 158, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .svg-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .menu-title,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu__title > span,
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-menu-item > span {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-menu-popper .el-menu--popup .el-sub-menu__icon-arrow {
|
||||||
|
position: static;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup {
|
||||||
|
border-color: rgba(71, 85, 105, 0.34);
|
||||||
|
background: linear-gradient(180deg, rgba(15, 23, 42, 0.98), rgba(30, 41, 59, 0.94)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 20px 42px rgba(0, 0, 0, 0.34),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-menu-item,
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-sub-menu__title {
|
||||||
|
color: #e5edf8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-menu-item:hover,
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-sub-menu__title:hover {
|
||||||
|
background: rgba(96, 165, 250, 0.14) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-menu-item.is-active,
|
||||||
|
html.dark .topbar-menu-popper .el-menu--popup .el-sub-menu.is-active > .el-sub-menu__title {
|
||||||
|
background: linear-gradient(180deg, rgba(37, 99, 235, 0.28), rgba(59, 130, 246, 0.18)) !important;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(96, 165, 250, 0.16);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -145,6 +145,9 @@ defineExpose({
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
top: -53vh;
|
top: -53vh;
|
||||||
|
padding: 0;
|
||||||
|
border-top: none;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:deep(.el-autocomplete) {
|
:deep(.el-autocomplete) {
|
||||||
|
|||||||
@ -66,59 +66,101 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.layout-navbars-breadcrumb-user-news {
|
.layout-navbars-breadcrumb-user-news {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
.head-box {
|
.head-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: var(--el-text-color-primary);
|
color: var(--app-text-title);
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 35px;
|
height: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0 2px 10px;
|
||||||
|
|
||||||
|
.head-box-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.head-box-btn {
|
.head-box-btn {
|
||||||
color: var(--el-color-primary);
|
color: var(--app-accent-strong);
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box {
|
.content-box {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
.content-box-item {
|
.content-box-item {
|
||||||
padding-top: 12px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
&:last-of-type {
|
gap: 10px;
|
||||||
padding-bottom: 12px;
|
align-items: flex-start;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 4px 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
background-color 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-accent-soft);
|
||||||
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box-msg {
|
.content-box-msg {
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-secondary);
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box-time {
|
.content-box-time {
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--app-text-muted);
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-conten {
|
.item-conten {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.read {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.foot-box {
|
.foot-box {
|
||||||
height: 35px;
|
height: 40px;
|
||||||
color: var(--el-color-primary);
|
color: var(--app-accent-strong);
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-top: 1px solid var(--el-border-color-lighter);
|
border-top: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
margin-top: 4px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
||||||
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||||
<side-bar v-if="!sidebar.hide" class="sidebar-container" />
|
<side-bar v-if="showSidebar" class="sidebar-container" />
|
||||||
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
||||||
<!-- <el-scrollbar>
|
<div :class="{ 'fixed-header': fixedHeader }" class="layout-header">
|
||||||
<div :class="{ 'fixed-header': fixedHeader }">
|
<navbar @set-layout="setLayout" />
|
||||||
<navbar ref="navbarRef" @setLayout="setLayout" />
|
|
||||||
<tags-view v-if="needTagsView" />
|
|
||||||
</div>
|
|
||||||
<app-main />
|
|
||||||
<settings ref="settingRef" />
|
|
||||||
</el-scrollbar> -->
|
|
||||||
<div :class="{ 'fixed-header': fixedHeader }">
|
|
||||||
<navbar ref="navbarRef" @set-layout="setLayout" />
|
|
||||||
<tags-view v-if="needTagsView" />
|
<tags-view v-if="needTagsView" />
|
||||||
</div>
|
</div>
|
||||||
<app-main />
|
<app-main :class="{ 'with-fixed-header': fixedHeader, 'with-tags-view': needTagsView }" />
|
||||||
<settings ref="settingRef" />
|
<settings ref="settingRef" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -66,7 +58,6 @@ watchEffect(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const navbarRef = ref<InstanceType<typeof Navbar>>();
|
|
||||||
const settingRef = ref<InstanceType<typeof Settings>>();
|
const settingRef = ref<InstanceType<typeof Settings>>();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -96,6 +87,7 @@ const setLayout = () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background: var(--app-shell-bg);
|
||||||
|
|
||||||
&.mobile.openSidebar {
|
&.mobile.openSidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -105,7 +97,7 @@ const setLayout = () => {
|
|||||||
|
|
||||||
.drawer-bg {
|
.drawer-bg {
|
||||||
background: #000;
|
background: #000;
|
||||||
opacity: 0.3;
|
opacity: 0.4;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -113,18 +105,26 @@ const setLayout = () => {
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layout-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 9;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
padding: 12px 12px 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.fixed-header {
|
.fixed-header {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
width: calc(100% - #{$base-sidebar-width} - 12px);
|
||||||
width: calc(100% - #{$base-sidebar-width});
|
|
||||||
transition: width 0.28s;
|
transition: width 0.28s;
|
||||||
background: $fixed-header-bg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hideSidebar .fixed-header {
|
.hideSidebar .fixed-header {
|
||||||
width: calc(100% - 54px);
|
width: calc(100% - 70px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarHide .fixed-header {
|
.sidebarHide .fixed-header {
|
||||||
@ -133,5 +133,6 @@ const setLayout = () => {
|
|||||||
|
|
||||||
.mobile .fixed-header {
|
.mobile .fixed-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -71,7 +71,7 @@ export default {
|
|||||||
loadingInstance = ElLoading.service({
|
loadingInstance = ElLoading.service({
|
||||||
lock: true,
|
lock: true,
|
||||||
text: content,
|
text: content,
|
||||||
background: 'rgba(0, 0, 0, 0.7)'
|
background: 'var(--app-overlay-mask)'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 关闭遮罩层
|
// 关闭遮罩层
|
||||||
|
|||||||
@ -31,7 +31,7 @@ const setting: DefaultSettings = {
|
|||||||
/**
|
/**
|
||||||
* 显示页签图标
|
* 显示页签图标
|
||||||
*/
|
*/
|
||||||
tagsIcon: false,
|
tagsIcon: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否固定头部
|
* 是否固定头部
|
||||||
@ -46,7 +46,7 @@ const setting: DefaultSettings = {
|
|||||||
/**
|
/**
|
||||||
* 是否显示动态标题
|
* 是否显示动态标题
|
||||||
*/
|
*/
|
||||||
dynamicTitle: false,
|
dynamicTitle: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否开启动画 开启随机 关闭渐进渐出
|
* 是否开启动画 开启随机 关闭渐进渐出
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell demo-demo-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="key键" prop="testKey">
|
<el-form-item label="key键" prop="testKey">
|
||||||
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -17,30 +21,24 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>测试单列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
<el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="demoList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="demoList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="true" label="主键" align="center" prop="id" />
|
<el-table-column v-if="true" label="主键" align="center" prop="id" />
|
||||||
<el-table-column label="部门id" align="center" prop="deptId" />
|
<el-table-column label="部门id" align="center" prop="deptId" />
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell demo-tree-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="树节点名" prop="treeName">
|
<el-form-item label="树节点名" prop="treeName">
|
||||||
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -14,23 +18,24 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>测试树列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
ref="treeTableRef"
|
ref="treeTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
|
class="data-table"
|
||||||
:data="treeList"
|
:data="treeList"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
border
|
border
|
||||||
|
|||||||
@ -1,100 +1,101 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container home">
|
<div class="home">
|
||||||
<el-row :gutter="20">
|
<section class="hero-panel">
|
||||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
<div class="hero-copy">
|
||||||
<h2>RuoYi-Vue-Plus后台管理系统</h2>
|
<h1>RuoYi-Vue-Plus 控制台</h1>
|
||||||
<p>
|
<p>企业级后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token、Mybatis-Plus、WarmFlow、SpringDoc、Hutool、OSS 等组件</p>
|
||||||
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
|
<div class="hero-actions">
|
||||||
<br />
|
<el-button type="primary" @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">查看源码</el-button>
|
||||||
* 前端开发框架 Vue3、TS、Element Plus<br />
|
<el-button plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')">更新日志</el-button>
|
||||||
* 后端开发框架 Spring Boot<br />
|
</div>
|
||||||
* 容器框架 Undertow 基于 Netty 的高性能容器<br />
|
</div>
|
||||||
* 权限认证框架 Sa-Token 支持多终端认证系统<br />
|
</section>
|
||||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
|
||||||
* 缓存数据库 Redis 适配 6.X 最低 4.X<br />
|
|
||||||
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br />
|
|
||||||
* 数据库框架 p6spy 更强劲的 SQL 分析<br />
|
|
||||||
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br />
|
|
||||||
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br />
|
|
||||||
* Redis客户端 Redisson 性能强劲、API丰富<br />
|
|
||||||
* 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br />
|
|
||||||
* 分布式锁 Lock4j 注解锁、工具锁 多种多样<br />
|
|
||||||
* 分布式幂等 Lock4j 基于分布式锁实现<br />
|
|
||||||
* 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br />
|
|
||||||
* 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br />
|
|
||||||
* 文件存储 Minio 本地存储<br />
|
|
||||||
* 文件存储 七牛、阿里、腾讯 云存储<br />
|
|
||||||
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
|
|
||||||
* 校验框架 Validation 增强接口安全性 严谨性<br />
|
|
||||||
* Excel框架 FastExcel(原Alibaba EasyExcel) 性能优异 扩展性强<br />
|
|
||||||
* 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br />
|
|
||||||
* 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br />
|
|
||||||
* 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br />
|
|
||||||
* 部署方式 Docker 容器编排 一键部署业务集群<br />
|
|
||||||
* 国际化 SpringMessage Spring标准国际化方案<br />
|
|
||||||
</p>
|
|
||||||
<p><b>当前版本:</b> <span>v5.5.3</span></p>
|
|
||||||
<p>
|
|
||||||
<el-tag type="danger">¥免费开源</el-tag>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
|
|
||||||
>更新日志</el-button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
<div class="content-grid">
|
||||||
<h2>RuoYi-Cloud-Plus微服务后台管理系统</h2>
|
<section class="section-card">
|
||||||
<p>
|
<div class="section-head">
|
||||||
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
|
<div>
|
||||||
<br />
|
<h2>项目矩阵</h2>
|
||||||
* 前端开发框架 Vue3、TS、Element UI<br />
|
</div>
|
||||||
* 后端开发框架 Spring Boot<br />
|
</div>
|
||||||
* 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br />
|
<div class="product-list">
|
||||||
* 容器框架 Undertow 基于 XNIO 的高性能容器<br />
|
<article v-for="product in products" :key="product.name" class="product-card">
|
||||||
* 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br />
|
<div class="product-top">
|
||||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
<div>
|
||||||
* 关系数据库 Oracle 适配 11g 12c<br />
|
<h3>{{ product.name }}</h3>
|
||||||
* 关系数据库 PostgreSQL 适配 13 14<br />
|
<p>{{ product.summary }}</p>
|
||||||
* 关系数据库 SQLServer 适配 2017 2019<br />
|
</div>
|
||||||
* 缓存数据库 Redis 适配 6.X 最低 5.X<br />
|
<span class="product-version">{{ product.version }}</span>
|
||||||
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
</div>
|
||||||
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
<div class="product-tags">
|
||||||
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br />
|
<el-tag v-for="tag in product.tags" :key="tag" effect="plain">{{ tag }}</el-tag>
|
||||||
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
|
</div>
|
||||||
* RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br />
|
<div class="product-actions">
|
||||||
* 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br />
|
<el-button type="primary" plain @click="goTarget(product.primaryUrl)">{{ product.primaryLabel }}</el-button>
|
||||||
* 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br />
|
<el-button plain @click="goTarget(product.secondaryUrl)">{{ product.secondaryLabel }}</el-button>
|
||||||
* 分布式消息队列 Apache Kafka 高性能高速度<br />
|
</div>
|
||||||
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br />
|
</article>
|
||||||
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br />
|
</div>
|
||||||
* 分布式搜索引擎 ElasticSearch 业界知名<br />
|
</section>
|
||||||
* 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br />
|
|
||||||
* 分布式日志中心 ELK 业界成熟解决方案<br />
|
<section class="section-card capability-card">
|
||||||
* 分布式监控 Prometheus、Grafana 全方位性能监控<br />
|
<div class="section-head">
|
||||||
* 其余与 Vue 版本一致<br />
|
<div>
|
||||||
</p>
|
<h2>能力地图</h2>
|
||||||
<p><b>当前版本:</b> <span>v2.5.3</span></p>
|
</div>
|
||||||
<p>
|
</div>
|
||||||
<el-tag type="danger">¥免费开源</el-tag>
|
<div class="capability-groups">
|
||||||
</p>
|
<article v-for="group in capabilityGroups" :key="group.title" class="capability-group">
|
||||||
<p>
|
<h3>{{ group.title }}</h3>
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
|
<ul>
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
|
<li v-for="item in group.items" :key="item">{{ item }}</li>
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')"
|
</ul>
|
||||||
>更新日志</el-button
|
</article>
|
||||||
>
|
</div>
|
||||||
</p>
|
</section>
|
||||||
</el-col>
|
</div>
|
||||||
</el-row>
|
|
||||||
<el-divider />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Index" lang="ts">
|
<script setup name="Index" lang="ts">
|
||||||
|
const products = [
|
||||||
|
{
|
||||||
|
name: 'RuoYi-Vue-Plus',
|
||||||
|
version: 'v5.5.3',
|
||||||
|
summary: '面向分布式集群场景的后台管理系统,保持现有业务接口与权限逻辑,适合先完成前端壳升级。',
|
||||||
|
tags: ['Vue 3', 'Element Plus', 'Spring Boot', 'Sa-Token'],
|
||||||
|
primaryLabel: '访问 GitHub',
|
||||||
|
primaryUrl: 'https://github.com/dromara/RuoYi-Vue-Plus',
|
||||||
|
secondaryLabel: '查看更新日志',
|
||||||
|
secondaryUrl: 'https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'RuoYi-Cloud-Plus',
|
||||||
|
version: 'v2.5.3',
|
||||||
|
summary: '微服务通用权限管理系统,适合更复杂的服务治理场景,也可以沿用同样的前端升级思路。',
|
||||||
|
tags: ['Spring Cloud', 'Gateway', 'Nacos', 'Dubbo'],
|
||||||
|
primaryLabel: '访问 GitHub',
|
||||||
|
primaryUrl: 'https://github.com/dromara/RuoYi-Cloud-Plus',
|
||||||
|
secondaryLabel: '查看文档',
|
||||||
|
secondaryUrl: 'https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const capabilityGroups = [
|
||||||
|
{
|
||||||
|
title: '后端基建',
|
||||||
|
items: ['Spring Boot / Spring Cloud', 'Sa-Token 认证与权限', 'MySQL / Redis', '代码生成器与国际化']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台能力',
|
||||||
|
items: ['动态菜单与按钮权限', '监控、日志、在线用户', '任务调度与工作流', '文件存储与多云适配']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '前端方向',
|
||||||
|
items: ['UI 壳层重构', '主题与布局统一', '通用页面容器规范化', '逐模块迁移业务页']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const goTarget = (url: string) => {
|
const goTarget = (url: string) => {
|
||||||
window.open(url, '__blank');
|
window.open(url, '__blank');
|
||||||
};
|
};
|
||||||
@ -102,64 +103,272 @@ const goTarget = (url: string) => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.home {
|
.home {
|
||||||
blockquote {
|
display: flex;
|
||||||
padding: 10px 20px;
|
flex-direction: column;
|
||||||
margin: 0 0 20px;
|
gap: 20px;
|
||||||
font-size: 17.5px;
|
}
|
||||||
border-left: 5px solid #eee;
|
|
||||||
}
|
|
||||||
hr {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
.col-item {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
.hero-panel,
|
||||||
padding: 0;
|
.section-card {
|
||||||
|
border-radius: 28px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-panel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1.3fr) minmax(280px, 0.7fr);
|
||||||
|
gap: 18px;
|
||||||
|
padding: 30px;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, rgba(53, 109, 255, 0.16), transparent 30%),
|
||||||
|
linear-gradient(135deg, rgba(255, 255, 255, 0.68), rgba(255, 255, 255, 0.42));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
font-size: clamp(30px, 4vw, 46px);
|
||||||
|
line-height: 1.06;
|
||||||
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
letter-spacing: -0.04em;
|
||||||
font-size: 13px;
|
color: var(--app-text-title);
|
||||||
color: #676a6c;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 10px;
|
|
||||||
font-size: 26px;
|
|
||||||
font-weight: 100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-top: 10px;
|
margin: 0;
|
||||||
|
max-width: 760px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b {
|
.hero-badge {
|
||||||
font-weight: 700;
|
display: inline-flex;
|
||||||
}
|
width: fit-content;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(53, 109, 255, 0.12);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-stats {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-radius: 22px;
|
||||||
|
background: rgba(255, 255, 255, 0.54);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-size: 24px;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.update-log {
|
span {
|
||||||
ol {
|
color: var(--app-text-muted);
|
||||||
display: block;
|
font-size: 13px;
|
||||||
list-style-type: decimal;
|
}
|
||||||
margin-block-start: 1em;
|
}
|
||||||
margin-block-end: 1em;
|
|
||||||
margin-inline-start: 0;
|
.content-grid {
|
||||||
margin-inline-end: 0;
|
display: grid;
|
||||||
padding-inline-start: 40px;
|
grid-template-columns: minmax(0, 1.15fr) minmax(300px, 0.85fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-size: 26px;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-kicker {
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-list,
|
||||||
|
.capability-groups {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card {
|
||||||
|
padding: 22px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
transition:
|
||||||
|
transform 0.25s ease,
|
||||||
|
box-shadow 0.25s ease,
|
||||||
|
border-color 0.25s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
border-color: rgba(53, 109, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-size: 22px;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-version {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(53, 109, 255, 0.12);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capability-card {
|
||||||
|
background: radial-gradient(circle at top right, rgba(14, 165, 233, 0.12), transparent 28%), var(--app-surface-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.capability-group {
|
||||||
|
padding: 18px 18px 18px 20px;
|
||||||
|
border-radius: 22px;
|
||||||
|
background: rgba(255, 255, 255, 0.46);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
color: var(--app-text-title);
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 16px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
line-height: 1.7;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 10px;
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--app-accent-strong);
|
||||||
|
box-shadow: 0 0 0 5px rgba(53, 109, 255, 0.12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.hero-panel,
|
||||||
|
.content-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.hero-panel,
|
||||||
|
.section-card {
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-top {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.hero-panel {
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, rgba(53, 109, 255, 0.18), transparent 30%),
|
||||||
|
linear-gradient(135deg, rgba(15, 23, 42, 0.76), rgba(15, 23, 42, 0.48));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card,
|
||||||
|
.product-card,
|
||||||
|
.capability-group {
|
||||||
|
background: rgba(15, 23, 42, 0.5);
|
||||||
|
border-color: rgba(100, 116, 139, 0.16);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,73 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
<div class="login-shell">
|
||||||
<div class="title-box">
|
<section class="login-brand">
|
||||||
<h3 class="title">{{ title }}</h3>
|
<span class="brand-pill">Plus UI Workspace</span>
|
||||||
<lang-select />
|
<h1 class="brand-title">企业级后台管理系统</h1>
|
||||||
</div>
|
<p class="brand-desc">
|
||||||
<el-form-item prop="username">
|
真正面向企业级的应用框架 组件化 模块化 轻耦合 高扩展 针对企业痛点 业界一流技术栈<br />
|
||||||
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
|
重写 RuoYi-Vue 所有功能 集成 Sa-Token、Mybatis-Plus、WarmFlow、SpringDoc、Hutool、OSS 定期同步。
|
||||||
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
</p>
|
||||||
</el-input>
|
<div class="brand-highlights">
|
||||||
</el-form-item>
|
<span v-for="item in highlights" :key="item" class="highlight-chip">{{ item }}</span>
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input
|
|
||||||
v-model="loginForm.password"
|
|
||||||
type="password"
|
|
||||||
size="large"
|
|
||||||
auto-complete="off"
|
|
||||||
:placeholder="proxy.$t('login.password')"
|
|
||||||
@keyup.enter="handleLogin"
|
|
||||||
>
|
|
||||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="captchaEnabled" prop="code">
|
|
||||||
<el-input
|
|
||||||
v-model="loginForm.code"
|
|
||||||
size="large"
|
|
||||||
auto-complete="off"
|
|
||||||
:placeholder="proxy.$t('login.code')"
|
|
||||||
style="width: 63%"
|
|
||||||
@keyup.enter="handleLogin"
|
|
||||||
>
|
|
||||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
|
||||||
</el-input>
|
|
||||||
<div class="login-code">
|
|
||||||
<img :src="codeUrl" class="login-code-img" @click="getCode" />
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
<div class="brand-metrics">
|
||||||
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
<article v-for="item in quickStats" :key="item.label" class="metric-card">
|
||||||
<el-form-item style="float: right">
|
<strong>{{ item.value }}</strong>
|
||||||
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
|
<span>{{ item.label }}</span>
|
||||||
<svg-icon icon-class="wechat" />
|
</article>
|
||||||
</el-button>
|
|
||||||
<el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">
|
|
||||||
<svg-icon icon-class="maxkey" />
|
|
||||||
</el-button>
|
|
||||||
<el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">
|
|
||||||
<svg-icon icon-class="topiam" />
|
|
||||||
</el-button>
|
|
||||||
<el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">
|
|
||||||
<svg-icon icon-class="gitee" />
|
|
||||||
</el-button>
|
|
||||||
<el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">
|
|
||||||
<svg-icon icon-class="github" />
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item style="width: 100%">
|
|
||||||
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
|
|
||||||
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
|
|
||||||
<span v-else>{{ proxy.$t('login.logging') }}</span>
|
|
||||||
</el-button>
|
|
||||||
<div v-if="register" style="float: right">
|
|
||||||
<router-link class="link-type" :to="'/register'">{{ proxy.$t('login.switchRegisterPage') }}</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</section>
|
||||||
</el-form>
|
|
||||||
<!-- 底部 -->
|
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||||
|
<div class="title-box">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Workspace Sign In</p>
|
||||||
|
<h3 class="title">{{ title }}</h3>
|
||||||
|
<p class="subtitle">使用当前账号体系登录到业务工作台。</p>
|
||||||
|
</div>
|
||||||
|
<lang-select />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
|
||||||
|
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
v-model="loginForm.password"
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
auto-complete="off"
|
||||||
|
:placeholder="proxy.$t('login.password')"
|
||||||
|
@keyup.enter="handleLogin"
|
||||||
|
>
|
||||||
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="captchaEnabled" prop="code" class="captcha-row">
|
||||||
|
<el-input v-model="loginForm.code" size="large" auto-complete="off" :placeholder="proxy.$t('login.code')" @keyup.enter="handleLogin">
|
||||||
|
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
<div class="login-code">
|
||||||
|
<img :src="codeUrl" class="login-code-img" @click="getCode" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="form-meta">
|
||||||
|
<el-checkbox v-model="loginForm.rememberMe">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
||||||
|
<router-link v-if="register" class="link-type" :to="'/register'">{{ proxy.$t('login.switchRegisterPage') }}</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="social-panel">
|
||||||
|
<span class="social-label">第三方登录</span>
|
||||||
|
<div class="social-actions">
|
||||||
|
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
|
||||||
|
<svg-icon icon-class="wechat" />
|
||||||
|
</el-button>
|
||||||
|
<el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">
|
||||||
|
<svg-icon icon-class="maxkey" />
|
||||||
|
</el-button>
|
||||||
|
<el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">
|
||||||
|
<svg-icon icon-class="topiam" />
|
||||||
|
</el-button>
|
||||||
|
<el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">
|
||||||
|
<svg-icon icon-class="gitee" />
|
||||||
|
</el-button>
|
||||||
|
<el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">
|
||||||
|
<svg-icon icon-class="github" />
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item class="submit-row">
|
||||||
|
<el-button :loading="loading" size="large" type="primary" class="submit-button" @click.prevent="handleLogin">
|
||||||
|
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
|
||||||
|
<span v-else>{{ proxy.$t('login.logging') }}</span>
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="el-login-footer">
|
<div class="el-login-footer">
|
||||||
<span>Copyright © 2018-2026 疯狂的狮子Li All Rights Reserved.</span>
|
<span>Copyright © 2018-{{ currentYear }} 疯狂的狮子Li All Rights Reserved.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -84,6 +110,13 @@ import { useI18n } from 'vue-i18n';
|
|||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const title = import.meta.env.VITE_APP_TITLE;
|
const title = import.meta.env.VITE_APP_TITLE;
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const quickStats = [
|
||||||
|
{ label: '细粒度权限管理', value: '动态权限控制' },
|
||||||
|
{ label: '主流技术栈', value: '全栈技术集成' },
|
||||||
|
{ label: 'UI样式', value: '卡片式' }
|
||||||
|
];
|
||||||
|
const highlights = ['技术栈全面升级', '动态菜单', '多主题布局', '深浅色主题'];
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -104,10 +137,8 @@ const loginRules: ElFormRules = {
|
|||||||
|
|
||||||
const codeUrl = ref('');
|
const codeUrl = ref('');
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
// 验证码开关
|
|
||||||
const captchaEnabled = ref(true);
|
const captchaEnabled = ref(true);
|
||||||
// 注册开关
|
const register = ref(true);
|
||||||
const register = ref(false);
|
|
||||||
const redirect = ref('/');
|
const redirect = ref('/');
|
||||||
const loginRef = ref<ElFormInstance>();
|
const loginRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
@ -123,18 +154,15 @@ const handleLogin = () => {
|
|||||||
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
// 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
|
|
||||||
if (loginForm.value.rememberMe) {
|
if (loginForm.value.rememberMe) {
|
||||||
localStorage.setItem('username', String(loginForm.value.username));
|
localStorage.setItem('username', String(loginForm.value.username));
|
||||||
localStorage.setItem('password', String(loginForm.value.password));
|
localStorage.setItem('password', String(loginForm.value.password));
|
||||||
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
||||||
} else {
|
} else {
|
||||||
// 否则移除
|
|
||||||
localStorage.removeItem('username');
|
localStorage.removeItem('username');
|
||||||
localStorage.removeItem('password');
|
localStorage.removeItem('password');
|
||||||
localStorage.removeItem('rememberMe');
|
localStorage.removeItem('rememberMe');
|
||||||
}
|
}
|
||||||
// 调用action的登录方法
|
|
||||||
const [err] = await to(userStore.login(loginForm.value));
|
const [err] = await to(userStore.login(loginForm.value));
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const redirectUrl = redirect.value || '/';
|
const redirectUrl = redirect.value || '/';
|
||||||
@ -142,7 +170,6 @@ const handleLogin = () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
} else {
|
} else {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
// 重新获取验证码
|
|
||||||
if (captchaEnabled.value) {
|
if (captchaEnabled.value) {
|
||||||
await getCode();
|
await getCode();
|
||||||
}
|
}
|
||||||
@ -153,15 +180,11 @@ const handleLogin = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取验证码
|
|
||||||
*/
|
|
||||||
const getCode = async () => {
|
const getCode = async () => {
|
||||||
const res = await getCodeImg();
|
const res = await getCodeImg();
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
|
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
|
||||||
if (captchaEnabled.value) {
|
if (captchaEnabled.value) {
|
||||||
// 刷新验证码时清空输入框
|
|
||||||
loginForm.value.code = '';
|
loginForm.value.code = '';
|
||||||
codeUrl.value = 'data:image/gif;base64,' + data.img;
|
codeUrl.value = 'data:image/gif;base64,' + data.img;
|
||||||
loginForm.value.uuid = data.uuid;
|
loginForm.value.uuid = data.uuid;
|
||||||
@ -179,14 +202,9 @@ const getLoginData = () => {
|
|||||||
} as LoginData;
|
} as LoginData;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 第三方登录
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
const doSocialLogin = (type: string) => {
|
const doSocialLogin = (type: string) => {
|
||||||
authRouterUrl(type).then((res: any) => {
|
authRouterUrl(type).then((res: any) => {
|
||||||
if (res.code === HttpStatus.SUCCESS) {
|
if (res.code === HttpStatus.SUCCESS) {
|
||||||
// 获取授权地址跳转
|
|
||||||
window.location.href = res.data;
|
window.location.href = res.data;
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.msg);
|
ElMessage.error(res.msg);
|
||||||
@ -202,105 +220,266 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login {
|
.login {
|
||||||
|
min-height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
justify-content: center;
|
||||||
background-image: url('../assets/images/login-background.jpg');
|
padding: 40px 24px 88px;
|
||||||
background-size: cover;
|
background:
|
||||||
background-position: center;
|
radial-gradient(circle at 12% 12%, rgba(53, 109, 255, 0.22), transparent 24%),
|
||||||
|
radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.18), transparent 24%), linear-gradient(135deg, #071120 0%, #0f1b33 42%, #15345f 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-box {
|
.login-shell {
|
||||||
display: flex;
|
width: min(1180px, 100%);
|
||||||
align-items: center;
|
display: grid;
|
||||||
gap: 8px;
|
grid-template-columns: minmax(0, 1.05fr) minmax(360px, 440px);
|
||||||
|
gap: 26px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.login-brand,
|
||||||
margin: 0px auto 26px auto;
|
.login-form {
|
||||||
text-align: center;
|
border-radius: 28px;
|
||||||
color: var(--el-text-color-primary);
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
font-weight: 600;
|
box-shadow: 0 30px 80px rgba(2, 8, 23, 0.32);
|
||||||
letter-spacing: 0.5px;
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand {
|
||||||
|
padding: 42px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #eef4ff;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02)),
|
||||||
|
linear-gradient(135deg, rgba(53, 109, 255, 0.32), rgba(15, 23, 42, 0.24));
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-title {
|
||||||
|
margin: 22px 0 14px;
|
||||||
|
font-size: clamp(34px, 4vw, 52px);
|
||||||
|
line-height: 1.08;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-desc {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 580px;
|
||||||
|
color: rgba(226, 232, 240, 0.88);
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-highlights {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 28px 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight-chip {
|
||||||
|
padding: 9px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
color: #f8fbff;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-metrics {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
padding: 18px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.lang-select--style) {
|
span {
|
||||||
line-height: 0;
|
color: rgba(226, 232, 240, 0.72);
|
||||||
color: var(--el-text-color-secondary);
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form {
|
.login-form {
|
||||||
border-radius: var(--app-radius-lg);
|
width: 100%;
|
||||||
background: rgba(255, 255, 255, 0.94);
|
padding: 34px 30px 26px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
width: min(420px, 90vw);
|
|
||||||
padding: 32px 30px 12px 30px;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
box-shadow: var(--app-shadow-lg);
|
background: rgba(248, 250, 252, 0.92);
|
||||||
backdrop-filter: blur(6px);
|
}
|
||||||
-webkit-backdrop-filter: blur(6px);
|
|
||||||
.el-input {
|
.title-box {
|
||||||
height: 40px;
|
display: flex;
|
||||||
input {
|
align-items: flex-start;
|
||||||
height: 40px;
|
justify-content: space-between;
|
||||||
}
|
gap: 12px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
color: var(--app-accent-strong);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-icon {
|
.title {
|
||||||
height: 39px;
|
margin: 0;
|
||||||
width: 14px;
|
color: var(--app-text-title);
|
||||||
margin-left: 0px;
|
font-weight: 700;
|
||||||
|
font-size: 30px;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.lang-select--style) {
|
||||||
|
line-height: 0;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: rgba(255, 255, 255, 0.72);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-tip {
|
.login-form .el-input {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form .input-icon {
|
||||||
|
height: 46px;
|
||||||
|
width: 14px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-row {
|
||||||
|
:deep(.el-form-item__content) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 122px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin: -2px 0 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-panel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
margin-bottom: 22px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.58);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-label {
|
||||||
|
color: var(--app-text-muted);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
text-align: center;
|
font-weight: 600;
|
||||||
color: #bfbfbf;
|
}
|
||||||
|
|
||||||
|
.social-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 18px 34px rgba(53, 109, 255, 0.22);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form :deep(.el-input__wrapper) {
|
.login-form :deep(.el-input__wrapper) {
|
||||||
background-color: rgba(255, 255, 255, 0.9);
|
min-height: 48px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.88);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 0 0 1px rgba(148, 163, 184, 0.12) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form :deep(.el-input__wrapper.is-focus) {
|
.login-form :deep(.el-input__wrapper.is-focus) {
|
||||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(53, 109, 255, 0.24) inset,
|
||||||
|
0 0 0 4px rgba(53, 109, 255, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form :deep(.el-button--primary) {
|
.login-form :deep(.el-checkbox__label) {
|
||||||
border-radius: var(--app-radius-md);
|
color: var(--app-text-muted);
|
||||||
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.25);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form :deep(.el-button.is-circle) {
|
.login-form :deep(.el-button.is-circle) {
|
||||||
background: rgba(15, 23, 42, 0.04);
|
background: rgba(255, 255, 255, 0.82);
|
||||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||||
color: var(--el-text-color-regular);
|
color: var(--app-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form :deep(.el-button.is-circle:hover) {
|
.login-form :deep(.el-button.is-circle:hover) {
|
||||||
background: rgba(59, 130, 246, 0.1);
|
background: rgba(53, 109, 255, 0.12);
|
||||||
border-color: rgba(59, 130, 246, 0.2);
|
border-color: rgba(53, 109, 255, 0.2);
|
||||||
|
color: var(--app-accent-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-code {
|
.login-code {
|
||||||
width: calc(37% - 10px);
|
height: 48px;
|
||||||
height: 40px;
|
|
||||||
float: right;
|
|
||||||
margin-left: 10px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: var(--app-radius-sm);
|
border-radius: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.88);
|
||||||
border: 1px solid var(--el-border-color-light);
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
img {
|
img {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,35 +491,74 @@ onMounted(() => {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: rgba(255, 255, 255, 0.75);
|
color: rgba(226, 232, 240, 0.68);
|
||||||
font-family: Arial, serif;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 0.08em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-code-img {
|
.login-code-img {
|
||||||
height: 40px;
|
height: 48px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.login {
|
||||||
|
padding: 24px 14px 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-shell {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand {
|
||||||
|
padding: 28px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-metrics {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.login-brand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
padding: 26px 18px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-box {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-panel {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-actions {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-row :deep(.el-form-item__content) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:global(html.dark) {
|
:global(html.dark) {
|
||||||
.login-form {
|
.login-form {
|
||||||
background: rgba(17, 24, 39, 0.9);
|
background: rgba(12, 18, 30, 0.88);
|
||||||
border-color: rgba(148, 163, 184, 0.2);
|
border-color: rgba(100, 116, 139, 0.2);
|
||||||
}
|
|
||||||
|
|
||||||
.login-form :deep(.el-input__wrapper) {
|
|
||||||
background-color: rgba(17, 24, 39, 0.7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-form :deep(.el-input__wrapper),
|
||||||
|
.login-code,
|
||||||
|
.title-box :deep(.lang-select--style),
|
||||||
|
.social-panel,
|
||||||
.login-form :deep(.el-button.is-circle) {
|
.login-form :deep(.el-button.is-circle) {
|
||||||
background: rgba(148, 163, 184, 0.12);
|
background: rgba(15, 23, 42, 0.56);
|
||||||
border-color: rgba(148, 163, 184, 0.25);
|
border-color: rgba(100, 116, 139, 0.2);
|
||||||
color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-login-footer {
|
|
||||||
color: rgba(226, 232, 240, 0.65);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="p-2 page-shell iframe-page">
|
||||||
<i-frame v-model:src="url"></i-frame>
|
<div class="iframe-page__inner">
|
||||||
|
<i-frame v-model:src="url"></i-frame>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const url = ref(import.meta.env.VITE_APP_MONITOR_ADMIN);
|
const url = ref(import.meta.env.VITE_APP_MONITOR_ADMIN);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.iframe-page__inner {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
65
src/views/monitor/cache/index.vue
vendored
65
src/views/monitor/cache/index.vue
vendored
@ -1,14 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell monitor-cache-page">
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="12" class="cache-grid">
|
||||||
<el-col :span="24" class="card-box">
|
<el-col :span="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<Monitor style="width: 1em; height: 1em; vertical-align: middle" />
|
<div class="toolbar-shell">
|
||||||
<span style="vertical-align: middle">基本信息</span>
|
<div class="table-heading">
|
||||||
|
<h3>缓存概览</h3>
|
||||||
|
<p>Redis 运行状态、资源消耗与实时统计。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium cache-table">
|
||||||
<table style="width: 100%">
|
<table style="width: 100%">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@ -97,24 +101,31 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="card-box">
|
<el-col :xs="24" :lg="12">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<PieChart style="width: 1em; height: 1em; vertical-align: middle" />
|
<div class="toolbar-shell">
|
||||||
<span style="vertical-align: middle">命令统计</span>
|
<div class="table-heading">
|
||||||
|
<h3>命令统计</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium cache-chart">
|
||||||
<div ref="commandstats" style="height: 420px" />
|
<div ref="commandstats" style="height: 420px" />
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="card-box">
|
<el-col :xs="24" :lg="12">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<Odometer style="width: 1em; height: 1em; vertical-align: middle" /> <span style="vertical-align: middle">内存信息</span>
|
<div class="toolbar-shell">
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>内存信息</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<div class="el-table el-table--enable-row-hover el-table--medium cache-chart">
|
||||||
<div ref="usedmemory" style="height: 420px" />
|
<div ref="usedmemory" style="height: 420px" />
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -190,3 +201,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cache-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
row-gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cache-table {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cache-table table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cache-chart {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell monitor-logininfo-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="登录地址" prop="ipaddr">
|
<el-form-item label="登录地址" prop="ipaddr">
|
||||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -33,35 +40,34 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Access Logs</span>
|
||||||
|
<h3>登录日志</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持排序、批量清理、导出和账号解锁。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['monitor:logininfo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['monitor:logininfo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['monitor:logininfo:remove']" type="danger" plain icon="Delete" @click="handleClean">清空</el-button>
|
<el-button v-hasPermi="['monitor:logininfo:remove']" type="danger" plain icon="Delete" @click="handleClean">清空</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['monitor:logininfo:unlock']" type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock">
|
<el-button v-hasPermi="['monitor:logininfo:unlock']" type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock">
|
||||||
解锁
|
解锁
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['monitor:logininfo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['monitor:logininfo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
ref="loginInfoTableRef"
|
ref="loginInfoTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="loginInfoList"
|
:data="loginInfoList"
|
||||||
|
class="data-table"
|
||||||
:default-sort="defaultSort"
|
:default-sort="defaultSort"
|
||||||
border
|
border
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@ -207,3 +213,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,8 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell monitor-online-page">
|
||||||
<div class="mb-[10px]">
|
<div class="search-wrap">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="search-panel">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<template #header>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="登录地址" prop="ipaddr">
|
<el-form-item label="登录地址" prop="ipaddr">
|
||||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -16,10 +24,20 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="toolbar-shell">
|
||||||
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Online Sessions</span>
|
||||||
|
<h3>在线用户</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持按账号或地址检索并执行会话强退。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
border
|
border
|
||||||
|
class="data-table"
|
||||||
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
|
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
@ -115,3 +133,19 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell monitor-operlog-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="操作地址" prop="operIp">
|
<el-form-item label="操作地址" prop="operIp">
|
||||||
<el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -41,30 +48,31 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Operation Logs</span>
|
||||||
|
<h3>操作日志</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持类型过滤、详情查看、批量清空和导出。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="WarnTriangleFilled" @click="handleClean">清空</el-button>
|
<el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="WarnTriangleFilled" @click="handleClean">清空</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['monitor:operlog:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['monitor:operlog:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
ref="operLogTableRef"
|
ref="operLogTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="operlogList"
|
:data="operlogList"
|
||||||
|
class="data-table"
|
||||||
border
|
border
|
||||||
:default-sort="defaultSort"
|
:default-sort="defaultSort"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@ -259,3 +267,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="p-2 page-shell iframe-page">
|
||||||
<i-frame v-model:src="url"></i-frame>
|
<div class="iframe-page__inner">
|
||||||
|
<i-frame v-model:src="url"></i-frame>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const url = ref(import.meta.env.VITE_APP_SNAILJOB_ADMIN);
|
const url = ref(import.meta.env.VITE_APP_SNAILJOB_ADMIN);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.iframe-page__inner {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: var(--app-surface-bg);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,67 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="register">
|
<div class="register">
|
||||||
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
|
<div class="register-shell">
|
||||||
<div class="title-box">
|
<section class="register-brand">
|
||||||
<h3 class="title">{{ title }}</h3>
|
<span class="brand-pill">Plus UI Workspace</span>
|
||||||
<lang-select />
|
<h1 class="brand-title">企业级后台管理系统</h1>
|
||||||
</div>
|
<p class="brand-desc">
|
||||||
<el-form-item prop="username">
|
真正面向企业级的应用框架 组件化 模块化 轻耦合 高扩展 针对企业痛点 业界一流技术栈<br />
|
||||||
<el-input v-model="registerForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('register.username')">
|
重写 RuoYi-Vue 所有功能 集成 Sa-Token、Mybatis-Plus、WarmFlow、SpringDoc、Hutool、OSS 定期同步。
|
||||||
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
</p>
|
||||||
</el-input>
|
<div class="brand-highlights">
|
||||||
</el-form-item>
|
<span v-for="item in highlights" :key="item" class="highlight-chip">{{ item }}</span>
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input
|
|
||||||
v-model="registerForm.password"
|
|
||||||
type="password"
|
|
||||||
size="large"
|
|
||||||
auto-complete="off"
|
|
||||||
:placeholder="proxy.$t('register.password')"
|
|
||||||
@keyup.enter="handleRegister"
|
|
||||||
>
|
|
||||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="confirmPassword">
|
|
||||||
<el-input
|
|
||||||
v-model="registerForm.confirmPassword"
|
|
||||||
type="password"
|
|
||||||
size="large"
|
|
||||||
auto-complete="off"
|
|
||||||
:placeholder="proxy.$t('register.confirmPassword')"
|
|
||||||
@keyup.enter="handleRegister"
|
|
||||||
>
|
|
||||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="captchaEnabled" prop="code">
|
|
||||||
<el-input
|
|
||||||
v-model="registerForm.code"
|
|
||||||
size="large"
|
|
||||||
auto-complete="off"
|
|
||||||
:placeholder="proxy.$t('register.code')"
|
|
||||||
style="width: 63%"
|
|
||||||
@keyup.enter="handleRegister"
|
|
||||||
>
|
|
||||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
|
||||||
</el-input>
|
|
||||||
<div class="register-code">
|
|
||||||
<img :src="codeUrl" class="register-code-img" @click="getCode" />
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
<div class="brand-metrics">
|
||||||
<el-form-item style="width: 100%">
|
<article v-for="item in quickStats" :key="item.label" class="metric-card">
|
||||||
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleRegister">
|
<strong>{{ item.value }}</strong>
|
||||||
<span v-if="!loading">{{ proxy.$t('register.register') }}</span>
|
<span>{{ item.label }}</span>
|
||||||
<span v-else>{{ proxy.$t('register.registering') }}</span>
|
</article>
|
||||||
</el-button>
|
</div>
|
||||||
<div style="float: right">
|
</section>
|
||||||
|
|
||||||
|
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
|
||||||
|
<div class="title-box">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Workspace Register</p>
|
||||||
|
<h3 class="title">{{ title }}</h3>
|
||||||
|
<p class="subtitle">创建新的业务工作台账号,接入当前系统权限与登录体系。</p>
|
||||||
|
</div>
|
||||||
|
<lang-select />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model="registerForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('register.username')">
|
||||||
|
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
v-model="registerForm.password"
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
auto-complete="off"
|
||||||
|
:placeholder="proxy.$t('register.password')"
|
||||||
|
@keyup.enter="handleRegister"
|
||||||
|
>
|
||||||
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="confirmPassword">
|
||||||
|
<el-input
|
||||||
|
v-model="registerForm.confirmPassword"
|
||||||
|
type="password"
|
||||||
|
size="large"
|
||||||
|
auto-complete="off"
|
||||||
|
:placeholder="proxy.$t('register.confirmPassword')"
|
||||||
|
@keyup.enter="handleRegister"
|
||||||
|
>
|
||||||
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="captchaEnabled" prop="code" class="captcha-row">
|
||||||
|
<el-input v-model="registerForm.code" size="large" auto-complete="off" :placeholder="proxy.$t('register.code')" @keyup.enter="handleRegister">
|
||||||
|
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||||
|
</el-input>
|
||||||
|
<div class="register-code">
|
||||||
|
<img :src="codeUrl" class="register-code-img" @click="getCode" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="form-meta">
|
||||||
|
<span class="register-tip">注册后将返回登录页继续完成认证</span>
|
||||||
<router-link class="link-type" :to="'/login'">{{ proxy.$t('register.switchLoginPage') }}</router-link>
|
<router-link class="link-type" :to="'/login'">{{ proxy.$t('register.switchLoginPage') }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
<el-form-item class="submit-row">
|
||||||
<!-- 底部 -->
|
<el-button :loading="loading" size="large" type="primary" class="submit-button" @click.prevent="handleRegister">
|
||||||
|
<span v-if="!loading">{{ proxy.$t('register.register') }}</span>
|
||||||
|
<span v-else>{{ proxy.$t('register.registering') }}</span>
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="el-register-footer">
|
<div class="el-register-footer">
|
||||||
<span>Copyright © 2018-2026 疯狂的狮子Li All Rights Reserved.</span>
|
<span>Copyright © 2018-{{ currentYear }} 疯狂的狮子Li All Rights Reserved.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -75,6 +96,13 @@ import { useI18n } from 'vue-i18n';
|
|||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const title = import.meta.env.VITE_APP_TITLE;
|
const title = import.meta.env.VITE_APP_TITLE;
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const quickStats = [
|
||||||
|
{ label: '细粒度权限管理', value: '动态权限控制' },
|
||||||
|
{ label: '主流技术栈', value: '全栈技术集成' },
|
||||||
|
{ label: 'UI样式', value: '卡片式' }
|
||||||
|
];
|
||||||
|
const highlights = ['技术栈全面升级', '动态菜单', '多主题布局', '深浅色主题'];
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -157,67 +185,234 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.register {
|
.register {
|
||||||
|
min-height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
justify-content: center;
|
||||||
background-image: url('../assets/images/login-background.jpg');
|
padding: 40px 24px 88px;
|
||||||
background-size: cover;
|
background:
|
||||||
|
radial-gradient(circle at 12% 12%, rgba(53, 109, 255, 0.22), transparent 24%),
|
||||||
|
radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.18), transparent 24%), linear-gradient(135deg, #071120 0%, #0f1b33 42%, #15345f 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-box {
|
.register-shell {
|
||||||
display: flex;
|
width: min(1180px, 100%);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1.05fr) minmax(360px, 440px);
|
||||||
|
gap: 26px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.register-brand,
|
||||||
margin: 0px auto 30px auto;
|
.register-form {
|
||||||
text-align: center;
|
border-radius: 28px;
|
||||||
color: #707070;
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
box-shadow: 0 30px 80px rgba(2, 8, 23, 0.32);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-brand {
|
||||||
|
padding: 42px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #eef4ff;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02)),
|
||||||
|
linear-gradient(135deg, rgba(53, 109, 255, 0.32), rgba(15, 23, 42, 0.24));
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-title {
|
||||||
|
margin: 22px 0 14px;
|
||||||
|
font-size: clamp(34px, 4vw, 52px);
|
||||||
|
line-height: 1.08;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-desc {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 580px;
|
||||||
|
color: rgba(226, 232, 240, 0.88);
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-highlights {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 28px 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight-chip {
|
||||||
|
padding: 9px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
color: #f8fbff;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-metrics {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
padding: 18px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.lang-select--style) {
|
span {
|
||||||
line-height: 0;
|
color: rgba(226, 232, 240, 0.72);
|
||||||
color: #7483a3;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-form {
|
.register-form {
|
||||||
border-radius: 6px;
|
width: 100%;
|
||||||
background: #ffffff;
|
padding: 34px 30px 26px;
|
||||||
width: 400px;
|
z-index: 1;
|
||||||
padding: 25px 25px 5px 25px;
|
background: rgba(248, 250, 252, 0.92);
|
||||||
|
}
|
||||||
|
|
||||||
.el-input {
|
.title-box {
|
||||||
height: 40px;
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
|
||||||
input {
|
.eyebrow {
|
||||||
height: 40px;
|
margin: 0 0 8px;
|
||||||
}
|
color: var(--app-accent-strong);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-icon {
|
.title {
|
||||||
height: 39px;
|
margin: 0;
|
||||||
width: 14px;
|
color: var(--app-text-title);
|
||||||
margin-left: 0;
|
font-weight: 700;
|
||||||
|
font-size: 30px;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.lang-select--style) {
|
||||||
|
line-height: 0;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: rgba(255, 255, 255, 0.72);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form .el-input {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form .input-icon {
|
||||||
|
height: 46px;
|
||||||
|
width: 14px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-row {
|
||||||
|
:deep(.el-form-item__content) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 122px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin: -2px 0 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-tip {
|
.register-tip {
|
||||||
|
color: var(--app-text-muted);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
text-align: center;
|
|
||||||
color: #bfbfbf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-code {
|
.register-code {
|
||||||
width: 33%;
|
height: 48px;
|
||||||
height: 40px;
|
box-sizing: border-box;
|
||||||
float: right;
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(255, 255, 255, 0.88);
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||||
|
|
||||||
img {
|
img {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.submit-row {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 18px 34px rgba(53, 109, 255, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form :deep(.el-input__wrapper) {
|
||||||
|
min-height: 48px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.88);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 0 0 1px rgba(148, 163, 184, 0.12) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form :deep(.el-input__wrapper.is-focus) {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(53, 109, 255, 0.24) inset,
|
||||||
|
0 0 0 4px rgba(53, 109, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
.el-register-footer {
|
.el-register-footer {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
@ -225,14 +420,68 @@ onMounted(() => {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #fff;
|
color: rgba(226, 232, 240, 0.68);
|
||||||
font-family: Arial, serif;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 0.08em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-code-img {
|
.register-code-img {
|
||||||
height: 40px;
|
height: 48px;
|
||||||
padding-left: 12px;
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.register {
|
||||||
|
padding: 24px 14px 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-shell {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-brand {
|
||||||
|
padding: 28px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-metrics {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.register-brand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form {
|
||||||
|
padding: 26px 18px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-box {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-meta {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-row :deep(.el-form-item__content) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.register-form {
|
||||||
|
background: rgba(12, 18, 30, 0.88);
|
||||||
|
border-color: rgba(100, 116, 139, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form :deep(.el-input__wrapper),
|
||||||
|
.register-code,
|
||||||
|
.title-box :deep(.lang-select--style) {
|
||||||
|
background: rgba(15, 23, 42, 0.56);
|
||||||
|
border-color: rgba(100, 116, 139, 0.2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,51 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-client-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="search">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="85px">
|
<template #header>
|
||||||
<el-form-item label="客户端key" prop="clientKey">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" />
|
<div><h3>筛选条件</h3></div>
|
||||||
</el-form-item>
|
</div>
|
||||||
<el-form-item label="客户端秘钥" prop="clientSecret">
|
</template>
|
||||||
<el-input v-model="queryParams.clientSecret" placeholder="请输入客户端秘钥" clearable @keyup.enter="handleQuery" />
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="85px" class="query-form">
|
||||||
</el-form-item>
|
<el-form-item label="客户端key" prop="clientKey">
|
||||||
<el-form-item label="状态" prop="status">
|
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" />
|
||||||
<el-select v-model="queryParams.status" placeholder="状态" clearable>
|
</el-form-item>
|
||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-form-item label="客户端秘钥" prop="clientSecret">
|
||||||
</el-select>
|
<el-input v-model="queryParams.clientSecret" placeholder="请输入客户端秘钥" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item label="状态" prop="status">
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-select v-model="queryParams.status" placeholder="状态" clearable>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-form-item>
|
</el-select>
|
||||||
</el-form>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="never">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>客户端列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:client:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['system:client:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:client:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
<el-button v-hasPermi="['system:client:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:client:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:client:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:client:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['system:client:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="clientList" border @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="clientList" border class="data-table" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="true" label="id" align="center" prop="id" />
|
<el-table-column v-if="true" label="id" align="center" prop="id" />
|
||||||
<el-table-column label="客户端id" align="center" prop="clientId" />
|
<el-table-column label="客户端id" align="center" prop="clientId" />
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-config-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="参数名称" prop="configName">
|
<el-form-item label="参数名称" prop="configName">
|
||||||
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -33,34 +40,31 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Config Dataset</span>
|
||||||
|
<h3>参数列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持键值维护、导出和缓存刷新。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:config:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['system:config:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:config:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
<el-button v-hasPermi="['system:config:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:config:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['system:config:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
|
<el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="configList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="configList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="参数主键" align="center" prop="configId" />
|
<el-table-column v-if="false" label="参数主键" align="center" prop="configId" />
|
||||||
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
|
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
|
||||||
@ -259,3 +263,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-dept-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="部门名称" prop="deptName">
|
<el-form-item label="部门名称" prop="deptName">
|
||||||
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -22,24 +29,27 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
<span class="panel-kicker">Department Dataset</span>
|
||||||
</el-col>
|
<h3>部门列表</h3>
|
||||||
<el-col :span="1.5">
|
<p>支持树形层级维护、负责人绑定和部门状态管理。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
ref="deptTableRef"
|
ref="deptTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
|
class="data-table"
|
||||||
:data="deptList"
|
:data="deptList"
|
||||||
row-key="deptId"
|
row-key="deptId"
|
||||||
border
|
border
|
||||||
@ -318,3 +328,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,35 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2 dict-page">
|
<div class="p-2 page-shell dict-page">
|
||||||
<el-row :gutter="16" class="dict-grid">
|
<el-row :gutter="16" class="dict-grid">
|
||||||
<!-- 字典类型 -->
|
<!-- 字典类型 -->
|
||||||
<el-col :xs="24" :lg="12">
|
<el-col :xs="24" :lg="12">
|
||||||
<el-card shadow="hover" class="dict-card">
|
<el-card shadow="hover" class="dict-card table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="dict-card__header">
|
<div class="toolbar-shell dict-card__header">
|
||||||
<div class="dict-card__title">字典管理</div>
|
<div class="table-heading">
|
||||||
<right-toolbar v-model:show-search="showTypeSearch" @query-table="getTypeList" />
|
<div class="panel-heading search-panel-toggle dict-title-toggle" @click.stop="showTypeSearch = !showTypeSearch">
|
||||||
|
<div>
|
||||||
|
<h3>字典管理</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showTypeSearch" :search="false" @query-table="getTypeList" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-show="showTypeSearch" class="dict-form-scroll">
|
<div class="dict-search" :class="{ 'is-collapsed': !showTypeSearch }">
|
||||||
<el-form ref="typeQueryFormRef" :model="typeQueryParams" :inline="true">
|
<el-form ref="typeQueryFormRef" :model="typeQueryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="字典名称" prop="dictName">
|
<el-form-item label="字典名称" prop="dictName">
|
||||||
<el-input v-model="typeQueryParams.dictName" placeholder="请输入字典名称" clearable @keyup.enter="handleTypeQuery" />
|
<el-input v-model="typeQueryParams.dictName" placeholder="请输入字典名称" clearable @keyup.enter="handleTypeQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="字典类型" prop="dictType">
|
<el-form-item label="字典类型" prop="dictType">
|
||||||
<el-input v-model="typeQueryParams.dictType" placeholder="请输入字典类型" clearable @keyup.enter="handleTypeQuery" />
|
<el-input v-model="typeQueryParams.dictType" placeholder="请输入字典类型" clearable @keyup.enter="handleTypeQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px">
|
|
||||||
<el-date-picker
|
|
||||||
v-model="dateRange"
|
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
type="daterange"
|
|
||||||
range-separator="-"
|
|
||||||
start-placeholder="开始日期"
|
|
||||||
end-placeholder="结束日期"
|
|
||||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleTypeQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleTypeQuery">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="handleTypeResetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="handleTypeResetQuery">重置</el-button>
|
||||||
@ -37,7 +34,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dict-actions">
|
<div class="toolbar-actions dict-actions">
|
||||||
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleTypeAdd">新增</el-button>
|
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleTypeAdd">新增</el-button>
|
||||||
<el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="typeSingle" @click="handleTypeUpdate()"
|
<el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="typeSingle" @click="handleTypeUpdate()"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
@ -54,6 +51,7 @@
|
|||||||
ref="typeTableRef"
|
ref="typeTableRef"
|
||||||
v-loading="typeLoading"
|
v-loading="typeLoading"
|
||||||
border
|
border
|
||||||
|
class="data-table"
|
||||||
:data="typeList"
|
:data="typeList"
|
||||||
highlight-current-row
|
highlight-current-row
|
||||||
@row-click="handleTypeRowClick"
|
@row-click="handleTypeRowClick"
|
||||||
@ -98,19 +96,25 @@
|
|||||||
|
|
||||||
<!-- 字典数据 -->
|
<!-- 字典数据 -->
|
||||||
<el-col :xs="24" :lg="12">
|
<el-col :xs="24" :lg="12">
|
||||||
<el-card shadow="hover" class="dict-card">
|
<el-card shadow="hover" class="dict-card table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="dict-card__header">
|
<div class="toolbar-shell dict-card__header">
|
||||||
<div class="dict-card__title">
|
<div class="table-heading">
|
||||||
字典数据
|
<div class="panel-heading search-panel-toggle dict-title-toggle" @click.stop="showDataSearch = !showDataSearch">
|
||||||
<span class="dict-card__subtitle">{{ currentDictLabel }}</span>
|
<div>
|
||||||
|
<h3>字典数据</h3>
|
||||||
|
<p v-if="hasCurrentDict" class="dict-card__subtitle">{{ currentDictLabel }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showDataSearch" :search="false" @query-table="getDataList" />
|
||||||
</div>
|
</div>
|
||||||
<right-toolbar v-model:show-search="showDataSearch" @query-table="getDataList" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-show="showDataSearch" class="dict-form-scroll">
|
<div class="dict-search" :class="{ 'is-collapsed': !showDataSearch }">
|
||||||
<el-form ref="dataQueryFormRef" :model="dataQueryParams" :inline="true">
|
<el-form ref="dataQueryFormRef" :model="dataQueryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="字典标签" prop="dictLabel">
|
<el-form-item label="字典标签" prop="dictLabel">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="dataQueryParams.dictLabel"
|
v-model="dataQueryParams.dictLabel"
|
||||||
@ -127,7 +131,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dict-actions">
|
<div class="toolbar-actions dict-actions">
|
||||||
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" :disabled="!hasCurrentDict" @click="handleDataAdd"
|
<el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" :disabled="!hasCurrentDict" @click="handleDataAdd"
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
>
|
>
|
||||||
@ -155,10 +159,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dict-table-wrap">
|
<div class="dict-table-wrap">
|
||||||
<el-table v-loading="dataLoading" border :data="dataList" @selection-change="handleDataSelectionChange">
|
<el-table v-loading="dataLoading" border class="data-table" :data="dataList" @selection-change="handleDataSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="字典编码" align="center" prop="dictCode" />
|
<el-table-column v-if="false" label="字典编码" align="center" prop="dictCode" />
|
||||||
<el-table-column label="字典标签" align="center" prop="dictLabel" width="80">
|
<el-table-column label="字典标签" align="center" prop="dictLabel" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
@ -174,7 +178,7 @@
|
|||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="字典键值" align="center" prop="dictValue" width="80" />
|
<el-table-column label="字典键值" align="center" prop="dictValue" width="100" />
|
||||||
<el-table-column label="字典排序" align="center" prop="dictSort" width="80" />
|
<el-table-column label="字典排序" align="center" prop="dictSort" width="80" />
|
||||||
<el-table-column label="备注" align="center" prop="remark" width="100" />
|
<el-table-column label="备注" align="center" prop="remark" width="100" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
@ -213,13 +217,15 @@
|
|||||||
<el-input v-model="typeForm.dictName" placeholder="请输入字典名称" />
|
<el-input v-model="typeForm.dictName" placeholder="请输入字典名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="dictType">
|
<el-form-item prop="dictType">
|
||||||
|
<template #label>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="数据存储中的Key值,如:sys_user_sex" placement="top">
|
||||||
|
<i class="el-icon-question"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
字典类型
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
<el-input v-model="typeForm.dictType" placeholder="请输入字典类型" maxlength="100" />
|
<el-input v-model="typeForm.dictType" placeholder="请输入字典类型" maxlength="100" />
|
||||||
<span slot="label">
|
|
||||||
<el-tooltip content="数据存储中的Key值,如:sys_user_sex" placement="top">
|
|
||||||
<i class="el-icon-question"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
字典类型
|
|
||||||
</span>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="typeForm.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="typeForm.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
@ -291,7 +297,6 @@ const typeIds = ref<Array<number | string>>([]);
|
|||||||
const typeSingle = ref(true);
|
const typeSingle = ref(true);
|
||||||
const typeMultiple = ref(true);
|
const typeMultiple = ref(true);
|
||||||
const typeTotal = ref(0);
|
const typeTotal = ref(0);
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
|
||||||
|
|
||||||
const typeFormRef = ref<ElFormInstance>();
|
const typeFormRef = ref<ElFormInstance>();
|
||||||
const typeQueryFormRef = ref<ElFormInstance>();
|
const typeQueryFormRef = ref<ElFormInstance>();
|
||||||
@ -387,7 +392,7 @@ const { queryParams: dataQueryParams, form: dataForm, rules: dataRules } = toRef
|
|||||||
|
|
||||||
const getTypeList = () => {
|
const getTypeList = () => {
|
||||||
typeLoading.value = true;
|
typeLoading.value = true;
|
||||||
listType(proxy?.addDateRange(typeQueryParams.value, dateRange.value)).then((res) => {
|
listType(typeQueryParams.value).then((res) => {
|
||||||
typeList.value = res.rows;
|
typeList.value = res.rows;
|
||||||
typeTotal.value = res.total;
|
typeTotal.value = res.total;
|
||||||
typeLoading.value = false;
|
typeLoading.value = false;
|
||||||
@ -438,7 +443,6 @@ const handleTypeQuery = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleTypeResetQuery = () => {
|
const handleTypeResetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
|
||||||
typeQueryFormRef.value?.resetFields();
|
typeQueryFormRef.value?.resetFields();
|
||||||
handleTypeQuery();
|
handleTypeQuery();
|
||||||
};
|
};
|
||||||
@ -614,54 +618,55 @@ onMounted(() => {
|
|||||||
row-gap: 16px;
|
row-gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-card__header {
|
.dict-card {
|
||||||
display: flex;
|
height: 100%;
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-card__title {
|
.dict-card__header {
|
||||||
display: inline-flex;
|
gap: 12px;
|
||||||
align-items: baseline;
|
}
|
||||||
gap: 8px;
|
|
||||||
font-weight: 600;
|
.dict-title-toggle {
|
||||||
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-card__subtitle {
|
.dict-card__subtitle {
|
||||||
|
margin: 4px 0 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-form-scroll {
|
.dict-search {
|
||||||
max-height: 200px;
|
overflow: hidden;
|
||||||
overflow: auto;
|
max-height: 240px;
|
||||||
|
opacity: 1;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
padding-right: 6px;
|
transition:
|
||||||
padding-bottom: 4px;
|
max-height 0.32s cubic-bezier(0.22, 1, 0.36, 1),
|
||||||
|
opacity 0.24s ease,
|
||||||
|
margin-bottom 0.24s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-form-scroll :deep(.el-form) {
|
.dict-search.is-collapsed {
|
||||||
display: flex;
|
max-height: 0;
|
||||||
flex-wrap: wrap;
|
opacity: 0;
|
||||||
column-gap: 12px;
|
margin-bottom: 0;
|
||||||
row-gap: 10px;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-form-scroll :deep(.el-form-item) {
|
.dict-search :deep(.el-form-item) {
|
||||||
margin: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-actions {
|
.dict-actions {
|
||||||
display: flex;
|
margin: 0 0 12px;
|
||||||
flex-wrap: wrap;
|
padding-bottom: 0;
|
||||||
gap: 10px;
|
|
||||||
margin: 8px 0 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-actions :deep(.el-button) {
|
.dict-actions :deep(.el-button) {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
padding: 0 14px;
|
padding: 0 14px;
|
||||||
|
border-radius: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dict-actions :deep(.el-button + .el-button) {
|
.dict-actions :deep(.el-button + .el-button) {
|
||||||
@ -671,5 +676,4 @@ onMounted(() => {
|
|||||||
.dict-table-wrap {
|
.dict-table-wrap {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-menu-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -19,24 +26,27 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Menu Dataset</span>
|
||||||
|
<h3>菜单列表</h3>
|
||||||
|
<p>支持树形加载、图标选择、级联删除和目录/菜单/按钮三级维护。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:menu:remove']" type="danger" plain icon="Delete" @click="handleCascadeDelete" :loading="deleteLoading">级联删除</el-button>
|
<el-button v-hasPermi="['system:menu:remove']" type="danger" plain icon="Delete" @click="handleCascadeDelete" :loading="deleteLoading">级联删除</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
ref="menuTableRef"
|
ref="menuTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
|
class="data-table"
|
||||||
:data="menuList"
|
:data="menuList"
|
||||||
row-key="menuId"
|
row-key="menuId"
|
||||||
border
|
border
|
||||||
@ -532,6 +542,28 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.tree-border {
|
.tree-border {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-notice-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="公告标题" prop="noticeTitle">
|
<el-form-item label="公告标题" prop="noticeTitle">
|
||||||
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -22,29 +29,29 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Notice Dataset</span>
|
||||||
|
<h3>公告列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持类型筛选、内容编辑和状态管理。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:notice:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['system:notice:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
<el-button v-hasPermi="['system:notice:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
<el-col :span="1.5">
|
修改
|
||||||
<el-button v-hasPermi="['system:notice:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
</el-button>
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:notice:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:notice:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="noticeList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="noticeList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="序号" align="center" prop="noticeId" width="100" />
|
<el-table-column v-if="false" label="序号" align="center" prop="noticeId" width="100" />
|
||||||
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
|
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
|
||||||
@ -241,3 +248,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-oss-config-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="配置key" prop="configKey">
|
<el-form-item label="配置key" prop="configKey">
|
||||||
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -23,29 +30,29 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Storage Config</span>
|
||||||
|
<h3>OSS 配置</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持默认桶切换、权限策略维护和站点配置。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:ossConfig:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['system:ossConfig:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
<el-button v-hasPermi="['system:ossConfig:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
<el-col :span="1.5">
|
修改
|
||||||
<el-button v-hasPermi="['system:ossConfig:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
</el-button>
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:ossConfig:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:ossConfig:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="ossConfigList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="ossConfigList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="columns[0].visible" label="主建" align="center" prop="ossConfigId" />
|
<el-table-column v-if="columns[0].visible" label="主建" align="center" prop="ossConfigId" />
|
||||||
<el-table-column v-if="columns[1].visible" label="配置key" align="center" prop="configKey" />
|
<el-table-column v-if="columns[1].visible" label="配置key" align="center" prop="configKey" />
|
||||||
@ -342,3 +349,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-oss-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="文件名" prop="fileName">
|
<el-form-item label="文件名" prop="fileName">
|
||||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -34,42 +41,40 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Object Storage</span>
|
||||||
|
<h3>文件列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持文件上传、预览切换和 OSS 配置跳转。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleFile">上传文件</el-button>
|
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleFile">上传文件</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">上传图片</el-button>
|
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">上传图片</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['system:oss:edit']"
|
v-hasPermi="['system:oss:edit']"
|
||||||
:type="previewListResource ? 'danger' : 'warning'"
|
:type="previewListResource ? 'danger' : 'warning'"
|
||||||
plain
|
plain
|
||||||
@click="handlePreviewListResource(!previewListResource)"
|
@click="handlePreviewListResource(!previewListResource)"
|
||||||
>预览开关 : {{ previewListResource ? '禁用' : '启用' }}</el-button
|
|
||||||
>
|
>
|
||||||
</el-col>
|
预览开关 : {{ previewListResource ? '禁用' : '启用' }}
|
||||||
<el-col :span="1.5">
|
</el-button>
|
||||||
<el-button v-hasPermi="['system:ossConfig:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
|
<el-button v-hasPermi="['system:ossConfig:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
v-if="showTable"
|
v-if="showTable"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="ossList"
|
:data="ossList"
|
||||||
|
class="data-table"
|
||||||
border
|
border
|
||||||
:header-cell-class-name="handleHeaderClass"
|
:header-cell-class-name="handleHeaderClass"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@ -307,12 +312,10 @@ const handleDownload = (row: OssVO) => {
|
|||||||
};
|
};
|
||||||
/** 预览开关按钮 */
|
/** 预览开关按钮 */
|
||||||
const handlePreviewListResource = async (preview: boolean) => {
|
const handlePreviewListResource = async (preview: boolean) => {
|
||||||
const text = preview ? '启用' : '停用';
|
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
|
|
||||||
await proxy?.updateConfigByKey('sys.oss.previewListResource', preview);
|
await proxy?.updateConfigByKey('sys.oss.previewListResource', preview);
|
||||||
await getList();
|
await getList();
|
||||||
proxy?.$modal.msgSuccess(text + '成功');
|
proxy?.$modal.msgSuccess((preview ? '启用' : '停用') + '成功');
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -331,3 +334,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell system-post-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="content-grid">
|
||||||
<!-- 部门树 -->
|
<!-- 部门树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="5" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Department Filter</span>
|
||||||
|
<h3>部门结构</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="deptTreeRef"
|
ref="deptTreeRef"
|
||||||
class="mt-2"
|
class="mt-2 dept-tree"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="deptOptions"
|
:data="deptOptions"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' } as any"
|
||||||
@ -19,11 +27,18 @@
|
|||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="19" :xs="24" class="content-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="岗位编码" prop="postCode">
|
<el-form-item label="岗位编码" prop="postCode">
|
||||||
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -61,30 +76,28 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Post Dataset</span>
|
||||||
|
<h3>岗位列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持按部门筛选、岗位维护和导出。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
<el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
|
||||||
<el-col :span="1.5">
|
修改
|
||||||
<el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
</el-button>
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-table v-loading="loading" border :data="postList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="postList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="岗位编号" align="center" prop="postId" />
|
<el-table-column v-if="false" label="岗位编号" align="center" prop="postId" />
|
||||||
<el-table-column label="岗位编码" align="center" prop="postCode" />
|
<el-table-column label="岗位编码" align="center" prop="postCode" />
|
||||||
@ -359,3 +372,39 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dept-tree {
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell role-auth-user-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="search">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<template #header>
|
||||||
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -13,27 +18,26 @@
|
|||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="never">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>已授权用户</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="openSelectUser">添加用户</el-button>
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="openSelectUser">添加用户</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:role:remove']" type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll">
|
<el-button v-hasPermi="['system:role:remove']" type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll">
|
||||||
批量取消授权
|
批量取消授权
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="userList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="page-shell system-role-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -34,28 +41,26 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Role Dataset</span>
|
||||||
|
<h3>角色列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持菜单权限、数据权限和分配用户等完整配置流程。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
<el-button v-hasPermi="['system:role:remove']" type="danger" plain :disabled="ids.length === 0" icon="Delete" @click="handleDelete()">删除</el-button>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:role:remove']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table ref="roleTableRef" border v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-table ref="roleTableRef" border class="data-table" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
@ -501,3 +506,25 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,38 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body>
|
<el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body class="select-user-dialog">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="page-shell select-user-shell">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-card shadow="hover" class="search-panel select-user-card">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
</el-form-item>
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
<el-form-item>
|
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-form-item>
|
||||||
</el-form-item>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
</el-form>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
<el-row>
|
</el-form-item>
|
||||||
<el-table ref="tableRef" border :data="userList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
|
</el-form>
|
||||||
<el-table-column type="selection" width="55"></el-table-column>
|
</el-card>
|
||||||
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
<el-card shadow="hover" class="table-panel select-user-card">
|
||||||
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
|
<el-table ref="tableRef" border class="data-table" :data="userList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
|
||||||
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
|
<el-table-column type="selection" width="55"></el-table-column>
|
||||||
<el-table-column label="状态" align="center" prop="status">
|
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||||
<template #default="scope">
|
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
|
||||||
</template>
|
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
|
||||||
</el-table-column>
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<template #default="scope">
|
||||||
<template #default="scope">
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
</template>
|
||||||
</template>
|
</el-table-column>
|
||||||
</el-table-column>
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
</el-table>
|
<template #default="scope">
|
||||||
<pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
</el-row>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button type="primary" @click="handleSelectUser">确 定</el-button>
|
<el-button type="primary" @click="handleSelectUser">确 定</el-button>
|
||||||
@ -128,3 +133,17 @@ defineExpose({
|
|||||||
show
|
show
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.select-user-shell {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-user-card :deep(.el-card__body) {
|
||||||
|
padding: 14px 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-user-dialog :deep(.el-dialog__body) {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,57 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell auth-role-page">
|
||||||
<div class="panel">
|
<el-card shadow="hover" class="search-panel auth-role-info">
|
||||||
<h4 class="panel-title">基本信息</h4>
|
<template #header>
|
||||||
<el-form :model="form" :inline="true">
|
<div class="panel-heading">
|
||||||
<el-row :gutter="10">
|
<div><h3>基本信息</h3></div>
|
||||||
<el-col :span="2.5">
|
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
|
||||||
<el-input v-model="form.nickName" disabled />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2.5">
|
|
||||||
<el-form-item label="登录账号" prop="userName">
|
|
||||||
<el-input v-model="form.userName" disabled />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
<div class="panel">
|
|
||||||
<h4 class="panel-title">角色信息</h4>
|
|
||||||
<div>
|
|
||||||
<el-table
|
|
||||||
ref="tableRef"
|
|
||||||
v-loading="loading"
|
|
||||||
border
|
|
||||||
:row-key="getRowKey"
|
|
||||||
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
|
||||||
@row-click="clickRow"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
>
|
|
||||||
<el-table-column label="序号" width="55" type="index" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
|
|
||||||
<el-table-column label="角色编号" align="center" prop="roleId" />
|
|
||||||
<el-table-column label="角色名称" align="center" prop="roleName" />
|
|
||||||
<el-table-column label="权限字符" align="center" prop="roleKey" />
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
|
|
||||||
<div style="text-align: center; margin-left: -120px; margin-top: 30px">
|
|
||||||
<el-button type="primary" @click="submitForm()">提交</el-button>
|
|
||||||
<el-button @click="close()">返回</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
</template>
|
||||||
</div>
|
<el-form :model="form" :inline="true" class="query-form auth-role-form">
|
||||||
</div>
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
|
<el-input v-model="form.nickName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="登录账号" prop="userName">
|
||||||
|
<el-input v-model="form.userName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="hover" class="table-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="toolbar-shell">
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>角色信息</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<el-button type="primary" @click="submitForm()">提交</el-button>
|
||||||
|
<el-button @click="close()">返回</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table
|
||||||
|
ref="tableRef"
|
||||||
|
v-loading="loading"
|
||||||
|
border
|
||||||
|
class="data-table"
|
||||||
|
:row-key="getRowKey"
|
||||||
|
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
||||||
|
@row-click="clickRow"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column label="序号" width="55" type="index" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
|
||||||
|
<el-table-column label="角色编号" align="center" prop="roleId" />
|
||||||
|
<el-table-column label="角色名称" align="center" prop="roleName" />
|
||||||
|
<el-table-column label="权限字符" align="center" prop="roleKey" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -144,3 +147,17 @@ onMounted(() => {
|
|||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.auth-role-form :deep(.el-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-role-form :deep(.el-input) {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-role-info :deep(.el-card__body) {
|
||||||
|
padding-top: 14px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="page-shell system-user-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="content-grid">
|
||||||
<!-- 部门树 -->
|
<!-- 部门树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="5" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Department Filter</span>
|
||||||
|
<h3>部门结构</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="deptTreeRef"
|
ref="deptTreeRef"
|
||||||
class="mt-2"
|
class="mt-2 dept-tree"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:data="deptOptions"
|
:data="deptOptions"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' } as any"
|
||||||
@ -19,11 +27,18 @@
|
|||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="19" :xs="24" class="content-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="用户名称" prop="userName">
|
<el-form-item label="用户名称" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -57,25 +72,23 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">User Dataset</span>
|
||||||
|
<h3>用户列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持部门筛选、状态切换、导入导出和角色分配。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||||||
修改
|
修改
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
|
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-dropdown class="mt-[1px]">
|
<el-dropdown class="mt-[1px]">
|
||||||
<el-button plain type="info">
|
<el-button plain type="info">
|
||||||
更多
|
更多
|
||||||
@ -90,12 +103,12 @@
|
|||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :columns="columns" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="userList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
|
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
|
||||||
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
|
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
|
||||||
@ -677,3 +690,39 @@ async function handleDeptChange(value: number | string) {
|
|||||||
form.value.postIds = [];
|
form.value.postIds = [];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dept-tree {
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,54 +1,76 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell profile-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="profile-grid">
|
||||||
<el-col :span="6" :xs="24">
|
<el-col :span="6" :xs="24">
|
||||||
<el-card class="box-card">
|
<el-card shadow="hover" class="side-panel profile-summary-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="clearfix">
|
<div class="panel-heading">
|
||||||
<span>个人信息</span>
|
<div><h3>个人信息</h3></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div class="profile-summary">
|
||||||
<div class="text-center">
|
<div class="text-center profile-avatar">
|
||||||
<userAvatar />
|
<userAvatar />
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group list-group-striped">
|
<ul class="list-group list-group-striped">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="user" />用户名称
|
<div class="profile-item-label">
|
||||||
<div class="pull-right">{{ state.user.userName }}</div>
|
<svg-icon icon-class="user" />
|
||||||
|
<span>用户名称</span>
|
||||||
|
</div>
|
||||||
|
<span class="profile-item-value">{{ state.user.userName || '-' }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="phone" />手机号码
|
<div class="profile-item-label">
|
||||||
<div class="pull-right">{{ state.user.phonenumber }}</div>
|
<svg-icon icon-class="phone" />
|
||||||
|
<span>手机号码</span>
|
||||||
|
</div>
|
||||||
|
<span class="profile-item-value">{{ state.user.phonenumber || '-' }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="email" />用户邮箱
|
<div class="profile-item-label">
|
||||||
<div class="pull-right">{{ state.user.email }}</div>
|
<svg-icon icon-class="email" />
|
||||||
|
<span>用户邮箱</span>
|
||||||
|
</div>
|
||||||
|
<span class="profile-item-value">{{ state.user.email || '-' }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="tree" />所属部门
|
<div class="profile-item-label">
|
||||||
<div v-if="state.user.deptName" class="pull-right">{{ state.user.deptName }} / {{ state.postGroup }}</div>
|
<svg-icon icon-class="tree" />
|
||||||
|
<span>所属部门</span>
|
||||||
|
</div>
|
||||||
|
<span v-if="state.user.deptName" class="profile-item-value">{{ state.user.deptName }} / {{ state.postGroup }}</span>
|
||||||
|
<span v-else class="profile-item-value">-</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="peoples" />所属角色
|
<div class="profile-item-label">
|
||||||
<div class="pull-right">{{ state.roleGroup }}</div>
|
<svg-icon icon-class="peoples" />
|
||||||
|
<span>所属角色</span>
|
||||||
|
</div>
|
||||||
|
<span class="profile-item-value">{{ state.roleGroup || '-' }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<svg-icon icon-class="date" />创建日期
|
<div class="profile-item-label">
|
||||||
<div class="pull-right">{{ state.user.createTime }}</div>
|
<svg-icon icon-class="date" />
|
||||||
|
<span>创建日期</span>
|
||||||
|
</div>
|
||||||
|
<span class="profile-item-value">{{ state.user.createTime || '-' }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="18" :xs="24">
|
<el-col :span="18" :xs="24">
|
||||||
<el-card>
|
<el-card shadow="hover" class="table-panel profile-main-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="clearfix">
|
<div class="toolbar-shell">
|
||||||
<span>基本资料</span>
|
<div class="table-heading">
|
||||||
|
<h3>个人设置</h3>
|
||||||
|
<p>维护个人资料、密码、第三方应用和在线设备。</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="activeTab">
|
<el-tabs v-model="activeTab" class="profile-tabs">
|
||||||
<el-tab-pane label="基本资料" name="userinfo">
|
<el-tab-pane label="基本资料" name="userinfo">
|
||||||
<userInfo :user="userForm" />
|
<userInfo :user="userForm" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@ -120,3 +142,88 @@ onMounted(() => {
|
|||||||
getOnlines();
|
getOnlines();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-grid {
|
||||||
|
row-gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-summary-card,
|
||||||
|
.profile-main-card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-summary {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-item-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-item-value {
|
||||||
|
max-width: 58%;
|
||||||
|
text-align: right;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-summary :deep(.list-group-item) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__header) {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__nav-wrap::after),
|
||||||
|
.profile-tabs :deep(.el-tabs__active-bar) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__nav) {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__item) {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 36px;
|
||||||
|
min-width: 88px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__item:nth-child(2)),
|
||||||
|
.profile-tabs :deep(.el-tabs__item.is-top:first-child),
|
||||||
|
.profile-tabs :deep(.el-tabs__item.is-top:last-child) {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tabs :deep(.el-tabs__item.is-active) {
|
||||||
|
background: rgba(53, 109, 255, 0.1);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.profile-item-value {
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="profile-table-wrap">
|
||||||
<el-table :data="devices" border style="width: 100%; height: 100%; font-size: 14px">
|
<el-table :data="devices" border class="data-table profile-device-table">
|
||||||
<el-table-column label="设备类型" align="center">
|
<el-table-column label="设备类型" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :options="sys_device_type" :value="scope.row.deviceType" />
|
<dict-tag :options="sys_device_type" :value="scope.row.deviceType" />
|
||||||
@ -52,6 +52,12 @@ const handldDelOnline = (row: any) => {
|
|||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-table-wrap {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
|
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px" class="profile-form">
|
||||||
<el-form-item label="旧密码" prop="oldPassword">
|
<el-form-item label="旧密码" prop="oldPassword">
|
||||||
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
|
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -9,9 +9,9 @@
|
|||||||
<el-form-item label="确认密码" prop="confirmPassword">
|
<el-form-item label="确认密码" prop="confirmPassword">
|
||||||
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
|
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item class="profile-form__actions">
|
||||||
<el-button type="primary" @click="submit">保存</el-button>
|
<el-button type="primary" @click="submit">保存</el-button>
|
||||||
<el-button type="danger" @click="close">关闭</el-button>
|
<el-button @click="close">关闭</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
@ -71,3 +71,22 @@ const close = () => {
|
|||||||
proxy?.$tab.closePage();
|
proxy?.$tab.closePage();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-form {
|
||||||
|
max-width: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form :deep(.el-input__wrapper) {
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form :deep(.el-button) {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form__actions :deep(.el-form-item__content) {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="profile-auth">
|
||||||
<el-table :data="auths" border style="width: 100%; height: 100%; font-size: 14px">
|
<el-table :data="auths" border class="data-table profile-auth-table">
|
||||||
<el-table-column label="序号" width="50" type="index" />
|
<el-table-column label="序号" width="50" type="index" />
|
||||||
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
|
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
|
||||||
<el-table-column label="头像" width="120" align="center" prop="avatar">
|
<el-table-column label="头像" width="120" align="center" prop="avatar">
|
||||||
@ -12,43 +12,48 @@
|
|||||||
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
|
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
|
||||||
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
|
<el-tooltip content="解绑" placement="top">
|
||||||
|
<el-button link type="primary" icon="CircleClose" @click="unlockAuth(scope.row)"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<div id="git-user-binding">
|
<div class="provider-section">
|
||||||
<h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
|
<div class="provider-heading">
|
||||||
<div id="authlist" class="user-bind">
|
<h4 class="provider-desc">可绑定的第三方应用</h4>
|
||||||
|
<p>点击下方平台完成账号绑定。</p>
|
||||||
|
</div>
|
||||||
|
<div class="user-bind">
|
||||||
<a class="third-app" href="#" title="使用 微信 账号授权登录" @click="authUrl('wechat')">
|
<a class="third-app" href="#" title="使用 微信 账号授权登录" @click="authUrl('wechat')">
|
||||||
<div class="git-other-login-icon">
|
<div class="third-app__icon">
|
||||||
<svg-icon icon-class="wechat" />
|
<svg-icon icon-class="wechat" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">WeiXin</span>
|
<span class="app-name">微信</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" title="使用 MaxKey 账号授权登录" @click="authUrl('maxkey')">
|
<a class="third-app" href="#" title="使用 MaxKey 账号授权登录" @click="authUrl('maxkey')">
|
||||||
<div class="git-other-login-icon">
|
<div class="third-app__icon">
|
||||||
<svg-icon icon-class="maxkey" />
|
<svg-icon icon-class="maxkey" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">MaxKey</span>
|
<span class="app-name">MaxKey</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" title="使用 TopIam 账号授权登录" @click="authUrl('topiam')">
|
<a class="third-app" href="#" title="使用 TopIam 账号授权登录" @click="authUrl('topiam')">
|
||||||
<div class="git-other-login-icon">
|
<div class="third-app__icon">
|
||||||
<svg-icon icon-class="topiam" />
|
<svg-icon icon-class="topiam" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">TopIam</span>
|
<span class="app-name">TopIam</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" title="使用 Gitee 账号授权登录" @click="authUrl('gitee')">
|
<a class="third-app" href="#" title="使用 Gitee 账号授权登录" @click="authUrl('gitee')">
|
||||||
<div class="git-other-login-icon">
|
<div class="third-app__icon">
|
||||||
<svg-icon icon-class="gitee" />
|
<svg-icon icon-class="gitee" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">Gitee</span>
|
<span class="app-name">Gitee</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="third-app" href="#" title="使用 GitHub 账号授权登录" @click="authUrl('github')">
|
<a class="third-app" href="#" title="使用 GitHub 账号授权登录" @click="authUrl('github')">
|
||||||
<div class="git-other-login-icon">
|
<div class="third-app__icon">
|
||||||
<svg-icon icon-class="github" />
|
<svg-icon icon-class="github" />
|
||||||
</div>
|
</div>
|
||||||
<span class="app-name">Github</span>
|
<span class="app-name">GitHub</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -94,44 +99,77 @@ const authUrl = (source: string) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.user-bind .third-app {
|
.profile-auth {
|
||||||
display: -webkit-box;
|
display: flex;
|
||||||
display: -ms-flexbox;
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-auth-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-heading p {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-bind .third-app {
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-box-direction: normal;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 80px;
|
justify-content: center;
|
||||||
float: left;
|
gap: 8px;
|
||||||
|
min-height: 84px;
|
||||||
|
padding: 12px 10px;
|
||||||
|
border: 1px solid var(--app-surface-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(248, 250, 252, 0.82);
|
||||||
|
transition:
|
||||||
|
transform 0.2s ease,
|
||||||
|
border-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-bind {
|
.user-bind {
|
||||||
font-size: 1rem;
|
display: grid;
|
||||||
text-align: start;
|
grid-template-columns: repeat(auto-fill, minmax(96px, 108px));
|
||||||
height: 50px;
|
gap: 10px;
|
||||||
margin-top: 10px;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.git-other-login-icon > img {
|
.third-app:hover {
|
||||||
height: 32px;
|
transform: translateY(-1px);
|
||||||
|
border-color: rgba(53, 109, 255, 0.3);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.third-app__icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #005980;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.provider-desc {
|
.provider-desc {
|
||||||
font-family:
|
margin: 0;
|
||||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Liberation Sans',
|
font-size: 16px;
|
||||||
'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun,
|
|
||||||
'WenQuanYi Zen Hei Sharp', sans-serif;
|
|
||||||
font-size: 1.071rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td > img {
|
td > img {
|
||||||
@ -141,4 +179,18 @@ td > img {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.dark) {
|
||||||
|
.user-bind .third-app {
|
||||||
|
background: rgba(15, 23, 42, 0.64);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -159,7 +159,18 @@ const closeDialog = () => {
|
|||||||
.user-info-head {
|
.user-info-head {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
width: 120px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info-head :deep(.img-circle) {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4px solid rgba(255, 255, 255, 0.92);
|
||||||
|
box-shadow: var(--app-shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info-head:hover:after {
|
.user-info-head:hover:after {
|
||||||
@ -176,7 +187,21 @@ const closeDialog = () => {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
line-height: 110px;
|
line-height: 120px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-upload-preview {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(248, 250, 252, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-upload-preview img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
|
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px" class="profile-form">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
<el-input v-model="userForm.nickName" maxlength="30" />
|
<el-input v-model="userForm.nickName" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -15,9 +15,9 @@
|
|||||||
<el-radio value="1">女</el-radio>
|
<el-radio value="1">女</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item class="profile-form__actions">
|
||||||
<el-button type="primary" @click="submit">保存</el-button>
|
<el-button type="primary" @click="submit">保存</el-button>
|
||||||
<el-button type="danger" @click="close">关闭</el-button>
|
<el-button @click="close">关闭</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
@ -67,3 +67,26 @@ const close = () => {
|
|||||||
proxy?.$tab.closePage();
|
proxy?.$tab.closePage();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-form {
|
||||||
|
max-width: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form :deep(.el-input__wrapper) {
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form :deep(.el-radio-group) {
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form :deep(.el-button) {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form__actions :deep(.el-form-item__content) {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell tool-gen-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div>
|
||||||
|
<span class="panel-kicker">Search Filters</span>
|
||||||
|
<h3>筛选条件</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="数据源" prop="dataName">
|
<el-form-item label="数据源" prop="dataName">
|
||||||
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称">
|
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称">
|
||||||
<el-option key="" label="全部" value="" />
|
<el-option key="" label="全部" value="" />
|
||||||
@ -33,30 +40,28 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<span class="panel-kicker">Code Generator</span>
|
||||||
|
<h3>数据表列表</h3>
|
||||||
|
<p>共 {{ total }} 条记录,支持导入表结构、同步数据库和代码预览生成。</p>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['tool:gen:code']" type="primary" plain icon="Download" @click="handleGenTable()">生成</el-button>
|
<el-button v-hasPermi="['tool:gen:code']" type="primary" plain icon="Download" @click="handleGenTable()">生成</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['tool:gen:import']" type="info" plain icon="Upload" @click="openImportTable">导入</el-button>
|
<el-button v-hasPermi="['tool:gen:import']" type="info" plain icon="Upload" @click="openImportTable">导入</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['tool:gen:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()">修改</el-button>
|
<el-button v-hasPermi="['tool:gen:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()">修改</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['tool:gen:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
<el-button v-hasPermi="['tool:gen:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="tableList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="tableList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" align="center" width="55"></el-table-column>
|
<el-table-column type="selection" align="center" width="55"></el-table-column>
|
||||||
<el-table-column label="序号" type="index" width="50" align="center">
|
<el-table-column label="序号" type="index" width="50" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -250,10 +255,30 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.page-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(53, 109, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.el-tab-pane {
|
.el-tab-pane {
|
||||||
background-color: #282c34;
|
background-color: #282c34;
|
||||||
.el-link {
|
.el-link {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.toolbar-shell {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,34 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-category-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="search">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<template #header>
|
||||||
<el-form-item label="分类名称" prop="categoryName">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
<el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable @keyup.enter="handleQuery" />
|
<div><h3>筛选条件</h3></div>
|
||||||
</el-form-item>
|
</div>
|
||||||
<el-form-item>
|
</template>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-form-item label="分类名称" prop="categoryName">
|
||||||
</el-form-item>
|
<el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="never">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>流程分类</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflow:category:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflow:category:add']">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:showSearch="showSearch" :search="false" @queryTable="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
ref="categoryTableRef"
|
ref="categoryTableRef"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
|
class="data-table"
|
||||||
:data="categoryList"
|
:data="categoryList"
|
||||||
row-key="categoryId"
|
row-key="categoryId"
|
||||||
border
|
border
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-leave-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="search">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<template #header>
|
||||||
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="请假天数" prop="startLeaveDays">
|
<el-form-item label="请假天数" prop="startLeaveDays">
|
||||||
<el-input v-model="queryParams.startLeaveDays" placeholder="请输入请假天数" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.startLeaveDays" placeholder="请输入请假天数" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -14,24 +19,25 @@
|
|||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="never">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>请假列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button v-hasPermi="['workflow:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
<el-button v-hasPermi="['workflow:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button v-hasPermi="['workflow:leave:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
<el-button v-hasPermi="['workflow:leave:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="leaveList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="leaveList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column v-if="false" label="主键" align="center" prop="id" />
|
<el-table-column v-if="false" label="主键" align="center" prop="id" />
|
||||||
<el-table-column label="请假类型" align="center">
|
<el-table-column label="请假类型" align="center">
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-process-definition-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="content-grid">
|
||||||
<!-- 流程分类树 -->
|
<!-- 流程分类树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="4" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>流程分类</h3>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="categoryTreeRef"
|
ref="categoryTreeRef"
|
||||||
@ -19,50 +24,48 @@
|
|||||||
></el-tree>
|
></el-tree>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24" class="content-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
<el-form-item label="流程定义名称" prop="flowName">
|
<div><h3>筛选条件</h3></div>
|
||||||
<el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" clearable @keyup.enter="handleQuery" />
|
</div>
|
||||||
</el-form-item>
|
</template>
|
||||||
<el-form-item label="流程定义编码" prop="flowCode">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px" class="query-form">
|
||||||
<el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" clearable @keyup.enter="handleQuery" />
|
<el-form-item label="流程定义名称" prop="flowName">
|
||||||
</el-form-item>
|
<el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" clearable @keyup.enter="handleQuery" />
|
||||||
<el-form-item>
|
</el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-form-item label="流程定义编码" prop="flowCode">
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
<el-form-item>
|
||||||
</el-card>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
</div>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</transition>
|
</el-form-item>
|
||||||
<el-card shadow="hover">
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>流程定义</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button type="primary" icon="Plus" @click="handleAdd()">添加</el-button>
|
<el-button type="primary" icon="Plus" @click="handleAdd()">添加</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="success" icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
<el-button type="success" icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
<el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">部署流程文件</el-button>
|
<el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">部署流程文件</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="warning" icon="Download" :disabled="single" @click="handleExportDef">导出</el-button>
|
<el-button type="warning" icon="Download" :disabled="single" @click="handleExportDef">导出</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||||
<el-tab-pane label="已发布" name="0"></el-tab-pane>
|
<el-tab-pane label="已发布" name="0"></el-tab-pane>
|
||||||
<el-tab-pane label="未发布" name="1"></el-tab-pane>
|
<el-tab-pane label="未发布" name="1"></el-tab-pane>
|
||||||
<el-table v-loading="loading" border :data="processDefinitionList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="processDefinitionList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" prop="id" label="主键" v-if="false"></el-table-column>
|
<el-table-column align="center" prop="id" label="主键" v-if="false"></el-table-column>
|
||||||
<el-table-column align="center" prop="flowName" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column>
|
<el-table-column align="center" prop="flowName" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column>
|
||||||
@ -88,27 +91,19 @@
|
|||||||
<el-tag v-else type="danger">失效</el-tag>
|
<el-tag v-else type="danger">失效</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column fixed="right" label="操作" align="center" width="170" class-name="small-padding fixed-width">
|
<el-table-column fixed="right" label="操作" align="center" width="236" class-name="small-padding fixed-width">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="process-action-group">
|
||||||
<el-col :span="1.5">
|
<el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">删除流程</el-button>
|
||||||
<el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">删除流程</el-button>
|
<el-button link type="primary" size="small" icon="CopyDocument" @click="handleCopyDef(scope.row)">复制流程</el-button>
|
||||||
</el-col>
|
<el-button link type="primary" v-if="scope.row.isPublish === 0" icon="Pointer" size="small" @click="design(scope.row)">
|
||||||
<el-col :span="1.5">
|
流程设计
|
||||||
<el-button link type="primary" size="small" icon="CopyDocument" @click="handleCopyDef(scope.row)">复制流程</el-button>
|
</el-button>
|
||||||
</el-col>
|
<el-button link type="primary" v-else icon="View" size="small" @click="designView(scope.row)">查看流程</el-button>
|
||||||
</el-row>
|
<el-button link type="primary" v-if="scope.row.isPublish !== 1" size="small" icon="CircleCheck" @click="handlePublish(scope.row)">
|
||||||
<el-row :gutter="10" class="mb8">
|
发布流程
|
||||||
<el-col :span="1.5">
|
</el-button>
|
||||||
<el-button link type="primary" v-if="scope.row.isPublish === 0" icon="Pointer" size="small" @click="design(scope.row)"
|
</div>
|
||||||
>流程设计</el-button
|
|
||||||
>
|
|
||||||
<el-button link type="primary" v-else icon="View" size="small" @click="designView(scope.row)">查看流程</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col v-if="scope.row.isPublish !== 1" :span="1.5">
|
|
||||||
<el-button link type="primary" size="small" icon="CircleCheck" @click="handlePublish(scope.row)">发布流程</el-button>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -239,11 +234,6 @@ const uploadDialog = reactive<DialogOption>({
|
|||||||
title: '部署流程文件'
|
title: '部署流程文件'
|
||||||
});
|
});
|
||||||
|
|
||||||
const processDefinitionDialog = reactive<DialogOption>({
|
|
||||||
visible: false,
|
|
||||||
title: '历史版本'
|
|
||||||
});
|
|
||||||
|
|
||||||
const modelDialog = reactive<DialogOption>({
|
const modelDialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
@ -395,7 +385,6 @@ const handlePublish = async (row?: FlowDefinitionVo) => {
|
|||||||
);
|
);
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await publish(row.id).finally(() => (loading.value = false));
|
await publish(row.id).finally(() => (loading.value = false));
|
||||||
processDefinitionDialog.visible = false;
|
|
||||||
activeName.value = '0';
|
activeName.value = '0';
|
||||||
await handleQuery();
|
await handleQuery();
|
||||||
proxy?.$modal.msgSuccess('发布成功');
|
proxy?.$modal.msgSuccess('发布成功');
|
||||||
@ -559,3 +548,40 @@ const handleExportDef = () => {
|
|||||||
proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.json`);
|
proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.json`);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-action-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-action-group :deep(.el-button.is-link) {
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
height: 30px !important;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
background: rgba(53, 109, 255, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-action-group :deep(.el-button.is-link + .el-button.is-link) {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-action-group :deep(.el-button .el-icon) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-process-instance-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="content-grid">
|
||||||
<!-- 流程分类树 -->
|
<!-- 流程分类树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="4" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>流程分类</h3>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="categoryTreeRef"
|
ref="categoryTreeRef"
|
||||||
@ -19,11 +24,15 @@
|
|||||||
></el-tree>
|
></el-tree>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24" class="content-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||||
@ -45,20 +54,22 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>流程实例</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="tab" @tab-click="changeTab">
|
<el-tabs v-model="tab" @tab-click="changeTab">
|
||||||
<el-tab-pane name="running" label="运行中"></el-tab-pane>
|
<el-tab-pane name="running" label="运行中"></el-tab-pane>
|
||||||
<el-tab-pane name="finish" label="已完成"></el-tab-pane>
|
<el-tab-pane name="finish" label="已完成"></el-tab-pane>
|
||||||
<el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="processInstanceList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
||||||
@ -476,3 +487,15 @@ onMounted(() => {
|
|||||||
getTreeselect();
|
getTreeselect();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-spel-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="组件名称" prop="componentName">
|
<el-form-item label="组件名称" prop="componentName">
|
||||||
<el-input v-model="queryParams.componentName" placeholder="请输入组件名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.componentName" placeholder="请输入组件名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -17,25 +21,23 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
|
|
||||||
<el-card shadow="never">
|
<el-card shadow="hover" class="table-panel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5">
|
<div class="table-heading">
|
||||||
|
<h3>流程表达式</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['workflow:spel:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['workflow:spel:add']">新增</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['workflow:spel:edit']">修改</el-button>
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['workflow:spel:edit']">修改</el-button>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['workflow:spel:remove']">删除</el-button>
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['workflow:spel:remove']">删除</el-button>
|
||||||
</el-col>
|
<right-toolbar v-model:showSearch="showSearch" :search="false" @queryTable="getList"></right-toolbar>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="spelList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="spelList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="序号" type="index" width="60" align="center">
|
<el-table-column label="序号" type="index" width="60" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-all-task-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||||
@ -22,25 +26,29 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<el-col :span="1.5" v-if="tab === 'waiting'">
|
<div class="table-heading">
|
||||||
|
<h3>全部任务</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<template v-if="tab === 'waiting'">
|
||||||
<el-button class="todo-action-btn todo-action-btn--primary" type="primary" plain icon="Edit" :disabled="multiple" @click="handleUserOpen()"
|
<el-button class="todo-action-btn todo-action-btn--primary" type="primary" plain icon="Edit" :disabled="multiple" @click="handleUserOpen()"
|
||||||
>修改办理人
|
>修改办理人
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button class="todo-action-btn todo-action-btn--warning" type="warning" plain icon="Bell" :disabled="multiple" @click="handleUrgeTaskOpen()"
|
<el-button class="todo-action-btn todo-action-btn--warning" type="warning" plain icon="Bell" :disabled="multiple" @click="handleUrgeTaskOpen()"
|
||||||
>催办
|
>催办
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</template>
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
</el-row>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="tab" @tab-click="changeTab">
|
<el-tabs v-model="tab" @tab-click="changeTab">
|
||||||
<el-tab-pane name="waiting" label="待办任务"> </el-tab-pane>
|
<el-tab-pane name="waiting" label="待办任务"> </el-tab-pane>
|
||||||
<el-tab-pane name="finish" label="已办任务"> </el-tab-pane>
|
<el-tab-pane name="finish" label="已办任务"> </el-tab-pane>
|
||||||
<el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="taskList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-my-document-page">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20" class="content-grid">
|
||||||
<!-- 流程分类树 -->
|
<!-- 流程分类树 -->
|
||||||
<el-col :lg="4" :xs="24" style="">
|
<el-col :lg="4" :xs="24">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover" class="side-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>流程分类</h3>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
<el-input v-model="categoryName" placeholder="请输入流程分类名" prefix-icon="Search" clearable />
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="categoryTreeRef"
|
ref="categoryTreeRef"
|
||||||
@ -19,11 +24,15 @@
|
|||||||
></el-tree>
|
></el-tree>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="20" :xs="24">
|
<el-col :lg="20" :xs="24" class="content-main">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px" class="query-form">
|
||||||
<el-form-item label="流程定义编码" prop="flowCode">
|
<el-form-item label="流程定义编码" prop="flowCode">
|
||||||
<el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -34,15 +43,19 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
<div class="table-heading">
|
||||||
</el-row>
|
<h3>我的单据</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="processInstanceList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column v-if="false" align="center" prop="id" label="id"></el-table-column>
|
<el-table-column v-if="false" align="center" prop="id" label="id"></el-table-column>
|
||||||
@ -244,3 +257,15 @@ const handleOpen = async (row, type) => {
|
|||||||
workflowCommon.routerJump(routerJumpVo, proxy);
|
workflowCommon.routerJump(routerJumpVo, proxy);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-grid {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-task-copy-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item label="任务名称" prop="nodeName">
|
<el-form-item label="任务名称" prop="nodeName">
|
||||||
<el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -20,15 +24,19 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
<div class="table-heading">
|
||||||
</el-row>
|
<h3>抄送任务</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="taskList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-task-finish-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||||
@ -25,15 +29,19 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
<div class="table-heading">
|
||||||
</el-row>
|
<h3>已办任务</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="taskList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 page-shell workflow-task-waiting-page">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<div class="search-wrap">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
<el-card shadow="hover">
|
<template #header>
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||||
@ -25,15 +29,19 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<el-card shadow="hover" class="table-panel">
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<div class="toolbar-shell">
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
|
<div class="table-heading">
|
||||||
</el-row>
|
<h3>待办任务</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="handleQuery"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" border class="data-table" :data="taskList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
<el-table-column :show-overflow-tooltip="true" prop="businessCode" align="center" label="业务编码"></el-table-column>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user