src/api/message/index.js
New file @@ -0,0 +1,50 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; // 获取消息详情 export function getMessage(params) { return request({ url: '/audit-message', method: 'get', params: params }); } //消息数量 export function getMessageCount() { return request({ url: '/message-count', method: 'get' }); } //获取阅读 export function getRead(id) { return request({ url: '/read-message', method: 'get', params: { id } }); } //代办 export function getTodo(params) { return request({ url: '/getPageByAllTaskWait', method: 'get', params: params }); } // 异常项目统计 export function getCountExceptionProject(params) { return request({ url: '/countExceptionProject', method: 'get', params: params }); } src/assets/styles/btn.scss
@@ -1,4 +1,4 @@ @import './variables.scss'; @import './variables.module.scss'; @mixin colorBtn($color) { background: $color; @@ -14,35 +14,35 @@ } .blue-btn { @include colorBtn($blue) @include colorBtn($blue); } .light-blue-btn { @include colorBtn($light-blue) @include colorBtn($light-blue); } .red-btn { @include colorBtn($red) @include colorBtn($red); } .pink-btn { @include colorBtn($pink) @include colorBtn($pink); } .green-btn { @include colorBtn($green) @include colorBtn($green); } .tiffany-btn { @include colorBtn($tiffany) @include colorBtn($tiffany); } .yellow-btn { @include colorBtn($yellow) @include colorBtn($yellow); } .pan-btn { font-size: 14px; font-size: 12px; color: #fff; padding: 14px 36px; border-radius: 8px; @@ -94,6 +94,6 @@ outline: 0; margin: 0; padding: 10px 15px; font-size: 14px; font-size: 12px; border-radius: 4px; } src/assets/styles/element-ui.scss
@@ -1,4 +1,20 @@ // cover some element-ui styles .el-collapse { .collapse__title { font-weight: 600; padding: 0 8px; font-size: 1.2em; line-height: 1.1em; } .el-collapse-item__content { padding: 0 8px; } } .el-divider--horizontal { margin-bottom: 10px; margin-top: 10px; } .el-breadcrumb__inner, .el-breadcrumb__inner a { @@ -6,7 +22,7 @@ } .el-upload { input[type="file"] { input[type='file'] { display: none !important; } } @@ -46,12 +62,37 @@ } } // to fixed https://github.com/ElemeFE/element/issues/2461 /*-------------Dialog-------------**/ .el-overlay { overflow: hidden; .el-overlay-dialog { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; .el-dialog { transform: none; left: 0; position: relative; margin: 0 auto; margin: 0 auto !important; .el-dialog__body { padding: 15px !important; } .el-dialog__header { padding: 16px 16px 8px 16px; box-sizing: border-box; border-bottom: 1px solid var(--brder-color); margin-right: 0; } } } } .el-dialog__body { max-height: calc(90vh - 111px) !important; overflow-y: auto; overflow-x: hidden; } // refine element ui upload @@ -69,7 +110,7 @@ // dropdown .el-dropdown-menu { a { display: block display: block; } } @@ -83,19 +124,57 @@ box-sizing: content-box; } .el-menu--collapse > div > .el-submenu > .el-submenu__title .el-submenu__icon-arrow { .el-menu--collapse > div > .el-submenu > .el-submenu__title .el-submenu__icon-arrow { display: none; } .el-tabs--border-card > .el-tabs__content { padding: 0; .el-dropdown .el-dropdown-link { color: var(--el-color-primary) !important; } .search-bar .el-button { height: 32px; /* 当 el-form 的 inline 属性为 true 时 */ /* 设置 label 的宽度默认为 68px */ .el-form--inline .el-form-item__label { width: 68px; } /* 设置 el-select 的宽度默认为 240px */ .el-form--inline .el-select { width: 240px; } /* 设置 el-input 的宽度默认为 240px */ .el-form--inline .el-input { width: 240px; } // 弹窗全局样式 .el-dialog__header { height: 55px; line-height: 55px; margin-bottom: 0px !important; border-bottom: 1px solid #e6f2fd; padding-top: 0 !important; justify-content: space-between; } .el-dialog__header > :first-child { flex: none !important; border-bottom: 2px solid #0068ff; color: #333333; } // 右侧弹窗全局样式 .el-drawer__header { height: 55px; line-height: 55px; margin-bottom: 0px !important; border-bottom: 1px solid #e6f2fd; padding-top: 0 !important; justify-content: space-between; } .el-drawer__header > :first-child { flex: none !important; border-bottom: 2px solid #0068ff; color: #333333; } src/assets/styles/index.scss
@@ -1,25 +1,41 @@ @import './variables.scss'; @import './variables.module.scss'; @import './mixin.scss'; @import './transition.scss'; @import './element-ui.scss'; @import './sidebar.scss'; @import './btn.scss'; @import './ruoyi.scss'; // @import 'animate.css'; // @import 'element-plus/dist/index.css'; :root{--el-color-white:#ffffff;--el-color-black:#000000;--el-color-primary-rgb:64,158,255;--el-color-success-rgb:103,194,58;--el-color-warning-rgb:230,162,60;--el-color-danger-rgb:245,108,108;--el-color-error-rgb:245,108,108;--el-color-info-rgb:144,147,153;--el-font-size-extra-large:20px;--el-font-size-large:18px;--el-font-size-medium:16px;--el-font-size-base:14px;--el-font-size-small:13px;--el-font-size-extra-small:12px;--el-font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;--el-font-weight-primary:500;--el-font-line-height-primary:24px;--el-index-normal:1;--el-index-top:1000;--el-index-popper:2000;--el-border-radius-base:4px;--el-border-radius-small:2px;--el-border-radius-round:20px;--el-border-radius-circle:100%;--el-transition-duration:0.3s;--el-transition-duration-fast:0.2s;--el-transition-function-ease-in-out-bezier:cubic-bezier(0.645,0.045,0.355,1);--el-transition-function-fast-bezier:cubic-bezier(0.23,1,0.32,1);--el-transition-all:all var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier);--el-transition-fade:opacity var(--el-transition-duration) var(--el-transition-function-fast-bezier);--el-transition-md-fade:transform var(--el-transition-duration) var(--el-transition-function-fast-bezier),opacity var(--el-transition-duration) var(--el-transition-function-fast-bezier);--el-transition-fade-linear:opacity var(--el-transition-duration-fast) linear;--el-transition-border:border-color var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-transition-box-shadow:box-shadow var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-transition-color:color var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-component-size-large:40px;--el-component-size:32px;--el-component-size-small:24px;color-scheme:light;--el-color-primary:#409eff;--el-color-primary-light-3:#79bbff;--el-color-primary-light-5:#a0cfff;--el-color-primary-light-7:#c6e2ff;--el-color-primary-light-8:#d9ecff;--el-color-primary-light-9:#ecf5ff;--el-color-primary-dark-2:#337ecc;--el-color-success:#67c23a;--el-color-success-light-3:#95d475;--el-color-success-light-5:#b3e19d;--el-color-success-light-7:#d1edc4;--el-color-success-light-8:#e1f3d8;--el-color-success-light-9:#f0f9eb;--el-color-success-dark-2:#529b2e;--el-color-warning:#e6a23c;--el-color-warning-light-3:#eebe77;--el-color-warning-light-5:#f3d19e;--el-color-warning-light-7:#f8e3c5;--el-color-warning-light-8:#faecd8;--el-color-warning-light-9:#fdf6ec;--el-color-warning-dark-2:#b88230;--el-color-danger:#f56c6c;--el-color-danger-light-3:#f89898;--el-color-danger-light-5:#fab6b6;--el-color-danger-light-7:#fcd3d3;--el-color-danger-light-8:#fde2e2;--el-color-danger-light-9:#fef0f0;--el-color-danger-dark-2:#c45656;--el-color-error:#f56c6c;--el-color-error-light-3:#f89898;--el-color-error-light-5:#fab6b6;--el-color-error-light-7:#fcd3d3;--el-color-error-light-8:#fde2e2;--el-color-error-light-9:#fef0f0;--el-color-error-dark-2:#c45656;--el-color-info:#909399;--el-color-info-light-3:#b1b3b8;--el-color-info-light-5:#c8c9cc;--el-color-info-light-7:#dedfe0;--el-color-info-light-8:#e9e9eb;--el-color-info-light-9:#f4f4f5;--el-color-info-dark-2:#73767a;--el-bg-color:#ffffff;--el-bg-color-page:#f2f3f5;--el-bg-color-overlay:#ffffff;--el-text-color-primary:#303133;--el-text-color-regular:#606266;--el-text-color-secondary:#909399;--el-text-color-placeholder:#a8abb2;--el-text-color-disabled:#c0c4cc;--el-border-color:#dcdfe6;--el-border-color-light:#e4e7ed;--el-border-color-lighter:#ebeef5;--el-border-color-extra-light:#f2f6fc;--el-border-color-dark:#d4d7de;--el-border-color-darker:#cdd0d6;--el-fill-color:#f0f2f5;--el-fill-color-light:#f5f7fa;--el-fill-color-lighter:#fafafa;--el-fill-color-extra-light:#fafcff;--el-fill-color-dark:#ebedf0;--el-fill-color-darker:#e6e8eb;--el-fill-color-blank:#ffffff;--el-box-shadow:0px 12px 32px 4px rgba(0,0,0,0.04),0px 8px 20px rgba(0,0,0,0.08);--el-box-shadow-light:0px 0px 12px rgba(0,0,0,0.12);--el-box-shadow-lighter:0px 0px 6px rgba(0,0,0,0.12);--el-box-shadow-dark:0px 16px 48px 16px rgba(0,0,0,0.08),0px 12px 32px rgba(0,0,0,0.12),0px 8px 16px -8px rgba(0,0,0,0.16);--el-disabled-bg-color:var(--el-fill-color-light);--el-disabled-text-color:var(--el-text-color-placeholder);--el-disabled-border-color:var(--el-border-color-light);--el-overlay-color:rgba(0,0,0,0.8);--el-overlay-color-light:rgba(0,0,0,0.7);--el-overlay-color-lighter:rgba(0,0,0,0.5);--el-mask-color:rgba(255,255,255,0.9);--el-mask-color-extra-light:rgba(255,255,255,0.3);--el-border-width:1px;--el-border-style:solid;--el-border-color-hover:var(--el-text-color-disabled);--el-border:var(--el-border-width) var(--el-border-style) var(--el-border-color);--el-svg-monochrome-grey:var(--el-border-color)}.fade-in-linear-enter-active,.fade-in-linear-leave-active{transition:var(--el-transition-fade-linear)}.fade-in-linear-enter-from,.fade-in-linear-leave-to{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{transition:var(--el-transition-fade-linear)}.el-fade-in-linear-enter-from,.el-fade-in-linear-leave-to{opacity:0}.el-fade-in-enter-active,.el-fade-in-leave-active{transition:all var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-fade-in-enter-from,.el-fade-in-leave-active{opacity:0}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{transition:all var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-from,.el-zoom-in-center-leave-active{opacity:0;transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;transform:scaleY(1);transform-origin:center top;transition:var(--el-transition-md-fade)}.el-zoom-in-top-enter-active[data-popper-placement^=top],.el-zoom-in-top-leave-active[data-popper-placement^=top]{transform-origin:center bottom}.el-zoom-in-top-enter-from,.el-zoom-in-top-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;transform:scaleY(1);transform-origin:center bottom;transition:var(--el-transition-md-fade)}.el-zoom-in-bottom-enter-from,.el-zoom-in-bottom-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;transform:scale(1);transform-origin:top left;transition:var(--el-transition-md-fade)}.el-zoom-in-left-enter-from,.el-zoom-in-left-leave-active{opacity:0;transform:scale(.45)}.collapse-transition{transition:var(--el-transition-duration) height ease-in-out,var(--el-transition-duration) padding-top ease-in-out,var(--el-transition-duration) padding-bottom ease-in-out}.el-collapse-transition-enter-active,.el-collapse-transition-leave-active{transition:var(--el-transition-duration) max-height ease-in-out,var(--el-transition-duration) padding-top ease-in-out,var(--el-transition-duration) padding-bottom ease-in-out}.horizontal-collapse-transition{transition:var(--el-transition-duration) width ease-in-out,var(--el-transition-duration) padding-left ease-in-out,var(--el-transition-duration) padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{transition:all 1s}.el-list-enter-from,.el-list-leave-to{opacity:0;transform:translateY(-30px)}.el-list-leave-active{position:absolute!important}.el-opacity-transition{transition:opacity var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-icon-loading{animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@keyframes rotating{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-icon{--color:inherit;align-items:center;display:inline-flex;height:1em;justify-content:center;line-height:1em;position:relative;width:1em;fill:currentColor;color:var(--color);font-size:inherit}.el-icon.is-loading{animation:rotating 2s linear infinite}.el-icon svg{height:1em;width:1em} body { height: 100%; margin: 0; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; } label { font-weight: 700; font-weight: 400; } html { height: 100%; box-sizing: border-box; } html.dark .svg-icon, html.dark svg { fill: var(--el-text-color-regular); } #app { @@ -90,7 +106,7 @@ visibility: hidden; display: block; font-size: 0; content: " "; content: ' '; clear: both; height: 0; } @@ -104,7 +120,8 @@ display: block; line-height: 32px; font-size: 16px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #2c3e50; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -124,6 +141,22 @@ padding: 20px; } // search面板样式 .panel, .search { margin-bottom: 0.75rem; border-radius: 0.25rem; border: 1px solid var(--el-border-color-light); background-color: var(--el-bg-color-overlay); padding: 0.75rem; transition: all ease 0.3s; &:hover { box-shadow: 0 2px 12px #0000001a; transition: all ease 0.3s; } } .components-container { margin: 30px 50px; position: relative; @@ -134,7 +167,7 @@ } .text-center { text-align: center text-align: center; } .sub-navbar { @@ -180,3 +213,16 @@ margin-bottom: 10px; } } .el-drawer__header { display: flex; justify-content: space-between; border-bottom: 1px solid #E9F4FD; padding: 100px; } .el-drawer__close-btn { width: 88%; display: flex; justify-content: flex-end; } src/assets/styles/mixin.scss
@@ -1,6 +1,6 @@ @mixin clearfix { &:after { content: ""; content: ''; display: table; clear: both; } @@ -44,21 +44,15 @@ border-bottom: $color-border-style; border-left: $transparent-border-style; border-right: $transparent-border-style; } @else if $direction==right { } @else if $direction==right { border-left: $color-border-style; border-top: $transparent-border-style; border-bottom: $transparent-border-style; } @else if $direction==down { } @else if $direction==down { border-top: $color-border-style; border-left: $transparent-border-style; border-right: $transparent-border-style; } @else if $direction==left { } @else if $direction==left { border-right: $color-border-style; border-top: $transparent-border-style; border-bottom: $transparent-border-style; src/assets/styles/ruoyi.scss
@@ -7,58 +7,45 @@ .pt5 { padding-top: 5px; } .pr5 { padding-right: 5px; } .pb5 { padding-bottom: 5px; } .mt5 { margin-top: 5px; } .mr5 { margin-right: 5px; } .mb5 { margin-bottom: 5px; } .mb8 { margin-bottom: 8px; } .ml5 { margin-left: 5px; } .mt10 { margin-top: 10px; } .mr10 { margin-right: 10px; } .mb10 { margin-bottom: 10px; } .ml10 { margin-left: 10px; } .mt20 { margin-top: 20px; } .mr20 { margin-right: 20px; } .mb20 { margin-bottom: 20px; } @@ -66,41 +53,56 @@ margin-left: 20px; } .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { font-family: inherit; font-weight: 500; line-height: 1.1; color: inherit; } .el-message-box__status + .el-message-box__message{ word-break: break-word; .el-form .el-form-item__label { font-size: 12px; font-weight: 400; color: #454B5E; } .el-dialog:not(.is-fullscreen) { margin-top: 6vh !important; } .el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { .el-dialog.scrollbar .el-dialog__body { overflow: auto; overflow-x: hidden; max-height: 70vh; padding: 10px 20px 0; .el-form .el-form-item__label{ color: red; } } .el-table { .el-table__header-wrapper, .el-table__fixed-header-wrapper { .el-table__header-wrapper, .el-table__fixed-header-wrapper { th { word-break: break-word; background-color: #f8f8f9; background-color: #f8f8f9 !important; color: #515a6e; height: 40px; height: 40px !important; font-size: 13px; } } .el-table__body-wrapper { .el-button [class*="el-icon-"] + span { .el-button [class*='el-icon-'] + span { margin-left: 1px; } } @@ -112,12 +114,12 @@ color: #6379bb; border-bottom: 1px solid #ddd; margin: 8px 10px 25px 10px; padding-bottom: 5px padding-bottom: 5px; } /** 表格布局 **/ .pagination-container { position: relative; // position: relative; height: 25px; margin-bottom: 10px; margin-top: 15px; @@ -128,13 +130,14 @@ .tree-border { margin-top: 5px; border: 1px solid #e5e6e7; background: #FFFFFF none; background: #ffffff none; border-radius: 4px; width: 100%; } .pagination-container .el-pagination { right: 0; position: absolute; //right: 0; //position: absolute; } @media (max-width: 768px) { @@ -146,19 +149,21 @@ } } .el-table .fixed-width .el-button--mini { .el-table .fixed-width .el-button--small { padding-left: 0; padding-right: 0; width: inherit; } /** 表格更多操作下拉样式 */ .el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { .el-table .el-dropdown-link { cursor: pointer; margin-left: 5px; color: #409eff; margin-left: 10px; } .el-table .el-dropdown, .el-icon-arrow-down { .el-table .el-dropdown, .el-icon-arrow-down { font-size: 12px; } @@ -192,12 +197,12 @@ } .el-card__header { padding: 14px 15px 7px; padding: 14px 15px 7px !important; min-height: 40px; } .el-card__body { padding: 15px 20px 20px 20px; padding: 15px 20px 20px 20px !important; } .card-box { @@ -209,22 +214,22 @@ /* button color */ .el-button--cyan.is-active, .el-button--cyan:active { background: #20B2AA; border-color: #20B2AA; color: #FFFFFF; background: #20b2aa; border-color: #20b2aa; color: #ffffff; } .el-button--cyan:focus, .el-button--cyan:hover { background: #48D1CC; border-color: #48D1CC; color: #FFFFFF; background: #48d1cc; border-color: #48d1cc; color: #ffffff; } .el-button--cyan { background-color: #20B2AA; border-color: #20B2AA; color: #FFFFFF; background-color: #20b2aa; border-color: #20b2aa; color: #ffffff; } /* text color */ @@ -267,10 +272,9 @@ } .avatar-upload-preview { position: relative; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); transform: translate(50%, -50%); width: 200px; height: 200px; border-radius: 50%; @@ -280,12 +284,12 @@ /* 拖拽列样式 */ .sortable-ghost { opacity: .8; opacity: 0.8; color: #fff !important; background: #42b983 !important; } /* 表格右侧工具栏样式 */ .top-right-btn { position: relative; float: right; margin-left: auto; } src/assets/styles/sidebar.scss
@@ -1,10 +1,10 @@ #app { .main-container { height: 100%; transition: margin-left .28s; margin-left: $base-sidebar-width; // height: 100%; transition: padding-left 0.28s; padding-left: $base-sidebar-width; position: relative; background-color: #F3F7FC; } .sidebarHide { @@ -12,21 +12,20 @@ } .sidebar-container { -webkit-transition: width .28s; -webkit-transition: width 0.28s; transition: width 0.28s; width: $base-sidebar-width !important; background-color: $base-menu-background; height: 100%; position: fixed; font-size: 0px; position: absolute; font-size: 0; top: 0; bottom: 0; left: 0; z-index: 1001; overflow: hidden; -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); box-shadow: 2px 0 6px rgba(0,21,41,.35); -webkit-box-shadow: 5px 0 10px -5px #d3d7de; box-shadow: 5px 0 10px -5px #d3d7de; // reset element-ui css .horizontal-collapse-transition { transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; @@ -37,7 +36,7 @@ } .el-scrollbar__bar.is-vertical { right: 0px; right: 0; } .el-scrollbar { @@ -70,39 +69,64 @@ width: 100% !important; } .el-menu-item, .el-submenu__title { .el-menu-item, .menu-title { overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; } .el-menu-item .el-menu-tooltip__trigger { display: inline-block !important; } // menu hover .submenu-title-noDropdown, .el-submenu__title { .theme-dark .sub-menu-title-noDropdown, .theme-dark .el-sub-menu__title { &:hover { background-color: rgba(0, 0, 0, 0.06) !important; background-color: $base-sub-menu-title-hover !important; } } .sub-menu-title-noDropdown, .el-sub-menu__title { &:hover { background-color: rgba(0, 0, 0, 0.05) !important; } } & .theme-dark .is-active > .el-submenu__title { & .theme-dark .is-active > .el-sub-menu__title { color: $base-menu-color-active !important; } & .nest-menu .el-submenu>.el-submenu__title, & .el-submenu .el-menu-item { & .nest-menu .el-sub-menu > .el-sub-menu__title, & .el-sub-menu .el-menu-item { min-width: $base-sidebar-width !important; &:hover { background-color: rgba(0, 0, 0, 0.06) !important; background-color: rgba(0, 0, 0, 0.1) !important; } } & .theme-dark .nest-menu .el-submenu>.el-submenu__title, & .theme-dark .el-submenu .el-menu-item { & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title, & .theme-dark .el-sub-menu .el-menu-item { background-color: $base-sub-menu-background !important; &:hover { background-color: $base-sub-menu-hover !important; } } & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title, & .theme-dark .el-menu-item { &:hover { // you can use $sub-menuHover background-color: $base-menu-hover !important; } } & .nest-menu .el-sub-menu > .el-sub-menu__title, & .el-menu-item { &:hover { // you can use $sub-menuHover background-color: rgba(0, 0, 0, 0.04) !important; } } } @@ -113,10 +137,10 @@ } .main-container { margin-left: 54px; padding-left: 54px; } .submenu-title-noDropdown { .sub-menu-title-noDropdown { padding: 0 !important; position: relative; @@ -129,23 +153,29 @@ } } .el-submenu { .el-sub-menu { overflow: hidden; &>.el-submenu__title { & > .el-sub-menu__title { padding: 0 !important; .svg-icon { margin-left: 20px; } } } .el-menu--collapse { .el-submenu { &>.el-submenu__title { .el-sub-menu { & > .el-sub-menu__title { &>span { height: 0; width: 0; overflow: hidden; visibility: hidden; display: inline-block; } & > i { height: 0; width: 0; overflow: hidden; @@ -157,7 +187,7 @@ } } .el-menu--collapse .el-menu .el-submenu { .el-menu--collapse .el-menu .el-sub-menu { min-width: $base-sidebar-width !important; } @@ -168,7 +198,7 @@ } .sidebar-container { transition: transform .28s; transition: transform 0.28s; width: $base-sidebar-width !important; } @@ -182,7 +212,6 @@ } .withoutAnimation { .main-container, .sidebar-container { transition: none; @@ -195,33 +224,6 @@ &>.el-menu { .svg-icon { margin-right: 16px; } } .nest-menu .el-submenu>.el-submenu__title, .el-menu-item { &:hover { // you can use $subMenuHover background-color: rgba(0, 0, 0, 0.06) !important; } } // the scroll bar appears when the subMenu is too long >.el-menu--popup { max-height: 100vh; overflow-y: auto; &::-webkit-scrollbar-track-piece { background: #d3dce6; } &::-webkit-scrollbar { width: 6px; } &::-webkit-scrollbar-thumb { background: #99a9bf; border-radius: 20px; } } } src/assets/styles/transition.scss
@@ -15,7 +15,7 @@ .fade-transform--move, .fade-transform-leave-active, .fade-transform-enter-active { transition: all .5s; transition: all 0.5s; } .fade-transform-enter { @@ -31,7 +31,7 @@ /* breadcrumb transition */ .breadcrumb-enter-active, .breadcrumb-leave-active { transition: all .5s; transition: all 0.5s; } .breadcrumb-enter, @@ -41,7 +41,7 @@ } .breadcrumb-move { transition: all .5s; transition: all 0.5s; } .breadcrumb-leave-active { src/assets/styles/variables.module.scss
@@ -80,7 +80,7 @@ $base-menu-background: var(--menuBg); $base-logo-title-color: #283146; $base-menu-light-color: rgba(0, 0, 0, 0.7); $base-menu-light-color: rgba(0, 0, 0); $base-menu-light-background: #ffffff; $base-logo-light-title-color: #001529; src/assets/styles/variables.scss
@@ -14,7 +14,7 @@ $base-menu-background:#304156; $base-logo-title-color: #ffffff; $base-menu-light-color:rgba(0,0,0,.70); $base-menu-light-color:rgba(0,0,0); $base-menu-light-background:#ffffff; $base-logo-light-title-color: #001529; src/components/TopNav/index.vue
@@ -181,7 +181,7 @@ .topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-submenu.is-active .el-submenu__title { border-bottom: 2px solid #{'var(--theme)'} !important; color: #303133; color: #000000; } /* submenu item */ src/layout/components/Navbar.vue
@@ -1,47 +1,73 @@ <template> <div class="navbar"> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/> <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/> <div class="right-menu"> <template v-if="device!=='mobile'"> <search id="header-search" class="right-menu-item" /> <el-tooltip content="源码地址" effect="dark" placement="bottom"> <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> <div class="ruoyi-logo"> <img src="@/assets/logo/logo.png" alt="" /> <span>射洪项目管理系统</span> </div> <div class="right-menu flex align-center"> <template> <search-menu ref="searchMenuRef" /> <el-tooltip content="搜索" effect="dark" placement="bottom"> <div class="right-menu-item hover-effect" @click="openSearchMenu" > <svg-icon class-name="search-icon" icon-class="search" /> </div> </el-tooltip> <el-tooltip content="文档地址" effect="dark" placement="bottom"> <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" /> </el-tooltip> <screenfull id="screenfull" class="right-menu-item hover-effect" /> <el-tooltip content="布局大小" effect="dark" placement="bottom"> <size-select id="size-select" class="right-menu-item hover-effect" /> </el-tooltip> <!-- 消息 --> <el-tooltip content="消息" effect="dark" placement="bottom"> <div class="right-menu-item hover-effect"> <el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false" > <template #reference> <el-badge :value="newNotice > 0 ? newNotice : ''" :max="99" > <svg-icon icon-class="message" /> </el-badge> </template> <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> <template #default> <notice></notice> </template> </el-popover> </div> </el-tooltip> <el-tooltip content="全屏" effect="dark" placement="bottom"> <screenfull id="screenfull" class="right-menu-item hover-effect" /> </el-tooltip> </template> <div class="avatar-container"> <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click" > <div class="avatar-wrapper"> <img :src="avatar" class="user-avatar"> <img :src="avatar" class="user-avatar" /> <i class="el-icon-caret-bottom" /> </div> <el-dropdown-menu slot="dropdown"> <router-link to="/user/profile"> <el-dropdown-item>个人中心</el-dropdown-item> </router-link> <el-dropdown-item @click.native="setting = true"> <span>布局设置</span> </el-dropdown-item> <el-dropdown-item divided @click.native="logout"> <span>退出登录</span> </el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </div> </div> </template> @@ -56,8 +82,15 @@ import Search from '@/components/HeaderSearch' import RuoYiGit from '@/components/RuoYi/Git' import RuoYiDoc from '@/components/RuoYi/Doc' import SearchMenu from './TopBar/search.vue'; import Notice from './Notice/index.vue'; export default { data() { return { newNotice: 0 } }, components: { Breadcrumb, TopNav, @@ -66,7 +99,9 @@ SizeSelect, Search, RuoYiGit, RuoYiDoc RuoYiDoc, SearchMenu, Notice }, computed: { ...mapGetters([ @@ -105,29 +140,70 @@ location.href = '/index'; }) }).catch(() => {}); } }, openSearchMenu() { this.searchMenuRef.value?.openSearch(); }, } } </script> <style lang="scss" scoped> ::v-deep.el-select .el-input__wrapper { height: 30px; } ::v-deep .el-badge__content.is-fixed { top: 12px; } .flex { display: flex; } .align-center { align-items: center; } .ruoyi-logo { float: left; line-height: 54px; font-weight: 400; font-size: 24px; font-style: italic; font-family: PangMenZhengDao; // color: #ffffff; // width: 220px; display: flex; align-items: center; > img { margin: 0 10px 0 21px; } > div { margin: 0 0 0 21px; } .down { margin-top: 22px; color: #ffffff; } } .navbar { height: 50px; overflow: hidden; position: relative; background: #fff; box-shadow: 0 1px 4px rgba(0,21,41,.08); //background: #fff; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); .hamburger-container { line-height: 46px; height: 100%; float: left; cursor: pointer; transition: background .3s; transition: background 0.3s; -webkit-tap-highlight-color:transparent; &:hover { background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025); } } @@ -149,6 +225,7 @@ float: right; height: 100%; line-height: 50px; display: flex; &:focus { outline: none; @@ -164,16 +241,17 @@ &.hover-effect { cursor: pointer; transition: background .3s; transition: background 0.3s; &:hover { background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025); } } } .avatar-container { margin-right: 30px; margin-right: 40px; margin-top: 10px; .avatar-wrapper { margin-top: 5px; @@ -184,9 +262,10 @@ width: 40px; height: 40px; border-radius: 10px; margin-top: 10px; } .el-icon-caret-bottom { i { cursor: pointer; position: absolute; right: -20px; src/layout/components/Notice/index.vue
New file @@ -0,0 +1,155 @@ <template> <div v-loading="state.loading" class="layout-navbars-breadcrumb-user-news"> <div class="head-box"> <div class="head-box-title">通知公告</div> <div class="head-box-btn" @click="readAll">全部已读</div> </div> <div v-loading="state.loading" class="content-box"> <template v-if="newsList.length > 0"> <div v-for="(v, k) in newsList" :key="k" class="content-box-item" @click="onNewsClick(k)" > <div class="item-conten"> <div>{{ v.message }}</div> <div class="content-box-msg"></div> <div class="content-box-time">{{ v.time }}</div> </div> <!-- 已读/未读 --> <span v-if="v.read" class="el-tag el-tag--success el-tag--mini read" >已读</span > <span v-else class="el-tag el-tag--danger el-tag--mini read" >未读</span > </div> </template> <el-empty v-else :description="'消息为空'"></el-empty> </div> </div> </template> <script > // import { storeToRefs } from 'pinia'; // import useNoticeStore from '@/store/modules/notice'; export default { data() { return { state: { loading: false }, newsList: [] } }, methods: { /** * 初始化数据 * @returns */ getTableData() { this.state.loading = true; // this.newsList.value = noticeStore.state.value.notices; this.state.loading = false; }, //点击消息,写入已读 onNewsClick(item) { this.newsList.value[item].read = true; //并且写入pinia this.noticeStore.state.value.notices = newsList.value; }, readAll() { }, // 前往通知中心点击 onGoToGiteeClick() { window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/'); } }, mounted: function () { this.$nextTick(() => { this.getTableData(); }); } } </script> <style scoped lang="scss"> .layout-navbars-breadcrumb-user-news { .head-box { display: flex; border-bottom: 1px solid var(--el-border-color-lighter); box-sizing: border-box; color: var(--el-text-color-primary); justify-content: space-between; height: 35px; align-items: center; .head-box-btn { color: var(--el-color-primary); font-size: 13px; cursor: pointer; opacity: 0.8; &:hover { opacity: 1; } } } .content-box { height: 300px; overflow: auto; font-size: 13px; .content-box-item { padding-top: 12px; display: flex; &:last-of-type { padding-bottom: 12px; } .content-box-msg { color: var(--el-text-color-secondary); margin-top: 5px; margin-bottom: 5px; } .content-box-time { color: var(--el-text-color-secondary); } .item-conten { width: 100%; display: flex; flex-direction: column; } } } .foot-box { height: 35px; color: var(--el-color-primary); font-size: 13px; cursor: pointer; opacity: 0.8; display: flex; align-items: center; justify-content: center; border-top: 1px solid var(--el-border-color-lighter); &:hover { opacity: 1; } } ::v-deep .el-empty__description p { font-size: 13px; } } </style> src/layout/components/Sidebar/index.vue
@@ -1,12 +1,29 @@ <template> <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }"> <logo v-if="showLogo" :collapse="isCollapse" /> <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper"> <div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: variables.menuLightBackground }" > <!-- <logo v-if="showLogo" :collapse="isCollapse" /> --> <div class="hamburger-container"> <div class="border"> <div class="menu-tip" v-show="sidebar.opened">菜单管理</div> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-icon" @toggleClick="toggleSideBar" /> </div> </div> <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper" > <el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground" :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor" :background-color="variables.menuLightBackground" :text-color="variables.menuLightColor" :unique-opened="true" :active-text-color="settings.theme" :collapse-transition="false" @@ -28,9 +45,10 @@ import Logo from "./Logo"; import SidebarItem from "./SidebarItem"; import variables from "@/assets/styles/variables.scss"; import Hamburger from '@/components/Hamburger' export default { components: { SidebarItem, Logo }, components: { SidebarItem, Logo, Hamburger }, computed: { ...mapState(["settings"]), ...mapGetters(["sidebarRouters", "sidebar"]), @@ -52,6 +70,45 @@ isCollapse() { return !this.sidebar.opened; } }, created() { // console.log(this.settings.sideTheme); }, methods: { toggleSideBar() { this.$store.dispatch('app/toggleSideBar') }, } }; </script> <style scoped> .hamburger-container { display: flex; color: #fff; justify-content: space-between; height: 59px; line-height: 59px; .border { margin: 0 auto; display: flex; justify-content: space-between; width: 180px; border-bottom: 1px solid #e6eaf5; } .menu-tip { height: 50px; font-size: 14px; font-weight: 400; color: #000000; padding-left: 20px; } .hamburger-icon { width: 54px; text-align: center; cursor: pointer; &:hover { background: rgba(0, 0, 0, 0.025); } } } </style> src/layout/components/TagsView/index.vue
@@ -1,29 +1,62 @@ <template> <div id="tags-view-container" class="tags-view-container"> <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll"> <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll" > <router-link v-for="tag in visitedViews" ref="tag" :key="tag.path" :class="isActive(tag)?'active':''" :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" tag="span" class="tags-view-item" :style="activeStyle(tag)" @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''" @click.middle.native=" !isAffix(tag) ? closeSelectedTag(tag) : '' " @contextmenu.prevent.native="openMenu(tag,$event)" > {{ tag.title }} <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> </router-link> </scroll-pane> <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li> <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li> <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li> <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li> <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li> <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu" > <li @click="refreshSelectedTag(selectedTag)"> <i class="el-icon-refresh-right"></i> 刷新页面 </li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)" > <i class="el-icon-close"></i> 关闭当前 </li> <li @click="closeOthersTags"> <i class="el-icon-circle-close"></i> 关闭其他 </li> <li v-if="!isFirstView()" @click="closeLeftTags"> <i class="el-icon-back"></i> 关闭左侧 </li> <li v-if="!isLastView()" @click="closeRightTags"> <i class="el-icon-right"></i> 关闭右侧 </li> <li @click="closeAllTags(selectedTag)"> <i class="el-icon-circle-close"></i> 全部关闭 </li> </ul> </div> </template> @@ -239,25 +272,30 @@ <style lang="scss" scoped> .tags-view-container { height: 34px; height: 44px; width: 100%; background: #fff; border-bottom: 1px solid #d8dce5; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04); background-color: var(--el-bg-color); border: 1px solid var(--el-border-color-light); line-height: 44px; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); .tags-view-wrapper { .tags-view-item { display: inline-block; position: relative; cursor: pointer; height: 26px; line-height: 26px; border: 1px solid #d8dce5; line-height: 23px; background-color: var(--el-bg-color); border: 1px solid var(--el-border-color-light); color: #495060; background: #fff; padding: 0 8px; font-size: 12px; margin-left: 5px; margin-top: 4px; &:hover { color: var(--el-color-primary); } &:first-of-type { margin-left: 15px; } @@ -276,14 +314,14 @@ height: 8px; border-radius: 50%; position: relative; margin-right: 2px; margin-right: 5px; } } } } .contextmenu { margin: 0; background: #fff; background: var(--el-bg-color); z-index: 3000; position: absolute; list-style-type: none; @@ -291,8 +329,7 @@ border-radius: 4px; font-size: 12px; font-weight: 400; color: #333; box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); li { margin: 0; padding: 7px 16px; @@ -315,10 +352,10 @@ vertical-align: 2px; border-radius: 50%; text-align: center; transition: all .3s cubic-bezier(.645, .045, .355, 1); transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); transform-origin: 100% 50%; &:before { transform: scale(.6); transform: scale(0.6); display: inline-block; vertical-align: -3px; } src/layout/components/TopBar/search.vue
New file @@ -0,0 +1,157 @@ <template> <div class="layout-search-dialog"> <el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false" > <template #footer> <el-autocomplete ref="layoutMenuAutocompleteRef" v-model="state.menuQuery" :fetch-suggestions="menuSearch" placeholder="搜索" :fit-input-width="true" @select="onHandleSelect" > <template #prefix> <svg-icon class-name="search-icon" icon-class="search" /> </template> <template #default="{ item }"> <div> <svg-icon :icon-class="item.icon" class="mr5" /> {{ item.title }} </div> </template> </el-autocomplete> </template> </el-dialog> </div> </template> <script> import { getNormalPath } from '@/utils/ruoyi'; import { isHttp } from '@/utils/validate'; import usePermissionStore from '@/store/modules/permission'; import { RouteRecordRaw } from 'vue-router'; export default { data() { return { state: { isShowSearch: false, menuQuery: '', menuList: [] } } }, created() { // this.openSearch() }, methods: { // 搜索弹窗打开 openSearch() { this.state.menuQuery = ''; this.state.isShowSearch = true; this.state.menuList = this.generateRoutes(usePermissionStore.state.routes); this.$nextTick(() => { setTimeout(() => { this.layoutMenuAutocompleteRef.value.focus(); }); }); }, // 搜索弹窗关闭 closeSearch() { this.state.isShowSearch = false; }, // 菜单搜索数据过滤 menuSearch(queryString, cb) { let options = state.menuList.filter((item) => { return item.title.indexOf(queryString) > -1; }); this.cb(options); }, // Filter out the routes that can be displayed in the sidebar // And generate the internationalized title generateRoutes(routes, basePath, prefixTitle) { let res = []; routes.forEach((r) => { // skip hidden router if (!r.hidden) { const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path; const data = { path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path, icon: r.meta?.icon, title: [...prefixTitle] }; if (r.meta && r.meta.title) { data.title = [...data.title, r.meta.title]; if (r.redirect !== 'noRedirect') { // only push the routes with title // special case: need to exclude parent router without redirect res.push(data); } } // recursive child routes if (r.children) { const tempRoutes = generateRoutes(r.children, data.path, data.title); if (tempRoutes.length >= 1) { res = [...res, ...tempRoutes]; } } } }); res.forEach((item) => { if (item.title instanceof Array) { item.title = item.title.join('/'); } }); return res; }, // 当前菜单选中时 onHandleSelect(val) { const paths = val.path; if (isHttp(paths)) { // http(s):// 路径新窗口打开 const pindex = paths.indexOf('http'); window.open(paths.substring(pindex, paths.length), '_blank'); } else { router.push(paths); } state.menuQuery = ''; closeSearch(); } } } </script> <style scoped lang="scss"> .layout-search-dialog { position: relative; ::v-deep .el-dialog { padding: 0; .el-dialog__header, .el-dialog__body { display: none; } .el-dialog__footer { width: 100%; position: absolute; left: 50%; transform: translateX(-50%); top: -53vh; } } ::v-deep.el-autocomplete { width: 560px; position: absolute; top: 150px; left: 50%; transform: translateX(-50%); } } </style> src/layout/index.vue
@@ -1,16 +1,34 @@ <template> <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}"> <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/> <sidebar v-if="!sidebar.hide" class="sidebar-container"/> <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container"> <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }" > <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> <navbar ref="navbarRef" @set-layout="setLayout" /> <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container" > <!-- <el-scrollbar> <div :class="{'fixed-header':fixedHeader}"> <navbar/> <navbar ref="navbarRef" @setLayout="setLayout" /> <tags-view v-if="needTagsView"/> </div> <app-main/> <right-panel> <settings/> </right-panel> <settings ref="settingRef" /> </el-scrollbar> --> <side-bar v-if="!sidebar.hide" class="sidebar-container" /> <div :class="{ 'fixed-header': fixedHeader }"> <tags-view v-if="needTagsView" /> </div> <app-main /> <settings ref="settingRef" /> </div> </div> </template> @@ -21,6 +39,7 @@ import ResizeMixin from './mixin/ResizeHandler' import { mapState } from 'vuex' import variables from '@/assets/styles/variables.scss' import SideBar from './components/Sidebar/index.vue'; export default { name: 'Layout', @@ -30,7 +49,8 @@ RightPanel, Settings, Sidebar, TagsView TagsView, SideBar }, mixins: [ResizeMixin], computed: { @@ -55,6 +75,9 @@ } }, methods: { setLayout() { this.settingRef.value?.openSetting(); }, handleClickOutside() { this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) } @@ -63,8 +86,8 @@ </script> <style lang="scss" scoped> @import "~@/assets/styles/mixin.scss"; @import "~@/assets/styles/variables.scss"; @import '~@/assets/styles/mixin.scss'; @import '~@/assets/styles/variables.scss'; .app-wrapper { @include clearfix; src/main.js
@@ -1,9 +1,21 @@ import Vue from 'vue' import Cookies from 'js-cookie' // global css // import 'virtual:uno.css'; import '@/assets/styles/index.scss'; import Element from 'element-ui' import './assets/styles/element-variables.scss' // 高亮组件 // import 'highlight.js/styles/a11y-light.css'; // import 'highlight.js/styles/atom-one-dark.css'; // import 'highlight.js/lib/common'; // import HighLight from '@highlightjs/vue-plugin'; // // svg图标 // import 'virtual:svg-icons-register'; // import ElementIcons from '@/plugins/svgicon'; import '@/assets/styles/index.scss' // global css import '@/assets/styles/ruoyi.scss' // ruoyi css @@ -61,6 +73,8 @@ Vue.use(directive) Vue.use(plugins) Vue.use(VueMeta) // Vue.use(HighLight); // Vue.use(ElementIcons); DictData.install() /** src/settings.js
@@ -2,7 +2,7 @@ /** * 侧边栏主题 深色主题theme-dark,浅色主题theme-light */ sideTheme: 'theme-dark', sideTheme: 'theme-light', /** * 是否系统布局配置 src/utils/ruoyi.js
@@ -1,5 +1,3 @@ /** * 通用js方法封装处理 * Copyright (c) 2019 ruoyi @@ -37,7 +35,9 @@ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { let value = formatObj[key] // Note: getDay() returns 0 on Sunday if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } if (result.length > 0 && value < 10) { value = '0' + value } @@ -114,7 +114,9 @@ // 字符串格式化(%s ) export function sprintf(str) { var args = arguments, flag = true, i = 1; var args = arguments, flag = true, i = 1; str = str.replace(/%s/g, function () { var arg = args[i++]; if (typeof arg === 'undefined') { @@ -231,3 +233,15 @@ export function blobValidate(data) { return data.type !== 'application/json' } export function getNormalPath(p) { if (p.length === 0 || !p || p === 'undefined') { return p; } const res = p.replace('//', '/'); if (res[res.length - 1] === '/') { return res.slice(0, res.length - 1); } return res; } src/utils/validate.js
@@ -78,3 +78,7 @@ } return Array.isArray(arg) } export function isHttp(url) { return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1; } src/views/components/noticeTable.vue
New file @@ -0,0 +1,183 @@ <template> <div> <div class="flex justify-between mb-[15px]"> <div class="block mb-3 font-semibold fonts">待办事项</div> <div class="flex text-[12px]"> <div :class="{ active: currentTab === 'process' }" class="tab" @click="switchTab('process')" > 流程待办 </div> <!-- <div :class="{ active: currentTab === 'progress' }" class="tab" @click="switchTab('progress')" > 进度待办 </div> --> </div> </div> <el-table :data="tableData" :header-cell-style="{ background: '#F5F7FC', color: '#454B5E', fontSize: '12px' }" height="280" max-height="280" > <el-table-column v-for="column in currentTableHeaders" :key="column.prop" :align="column.align" :label="column.label" :min-width="column.minWidth" :prop="column.prop" :show-overflow-tooltip="true" > </el-table-column> <el-table-column align="center" fixed="right" label="操作" min-width="150" > <template #default="scope"> <el-button plain size="small" type="primary" @click="handleDetail(scope.row)" > 查看</el-button > <el-button plain size="small" type="primary" @click="handleUpdate(scope.row)" > 处置</el-button > </template> </el-table-column> </el-table> <pagination v-show="total >= 0" :limit="queryParams.pageSize" :page="queryParams.pageNum" :total="total" @pagination="getList" /> </div> </template> <script> import { getTodo } from '@/api/message'; export default { data() { return { currentTab: "process", total: 0, queryParams: { pageNum: 1, pageSize: 10 }, tableData: [], currentTableHeaders: [ { label: '流程环节', prop: 'name', minWidth: 150, align: 'left' }, { label: '申请项目', prop: 'businessName', minWidth: 150, align: 'left' }, { label: '审批人', prop: 'assigneeName', minWidth: 100, align: 'left' }, { label: '剩余时间', prop: 'remainingTime', minWidth: 143, align: 'left' } ] } }, props: { calculation: [], countExceptionProjectData: {}, }, created() { this.getList(); }, methods: { async getList() { const resp = await getTodo(this.queryParams); if (resp.code === 200) { this.total.value = resp.total; this.tableData.value = resp.rows; } }, handleDetail(row) { console.log(111); this.$router.push({ path: '/projectManage/nodeDetails', query: { taskId: row.id, id: row.businessKey, disabled: 'true' } }); }, handleUpdate(row) { this.$router.push({ path: '/projectManage/nodeDetails', query: { taskId: row.id, id: row.businessKey } }); console.log(111); }, switchTab(tab) { this.currentTab = tab; } } } </script> <style lang="scss" scoped> .tab { padding: 8px; border: 1px solid #dbdeea; cursor: pointer; width: 72px; } .active { border: 1px solid #3369ff; color: #3369ff; } .fonts { font-size: 16px; color: #212a40; display: flex; align-items: center; } ::v-deep .el-table__row { font-size: 12px; } ::v-deep .el-pagination { margin: -15px; text-align: end; } ::v-deep .el-pagination .btn-prev .el-icon, ::v-deep .el-pagination .btn-next .el-icon { display: inline; } .flex { display: flex; justify-content: space-between; font-size: 12px; } </style> src/views/components/projectOverview.vue
New file @@ -0,0 +1,308 @@ <template> <div class="overview-bottom"> <div class="abnormal" @click="showAbnormal"> <div style="margin-bottom: 30px">异常项目情况统计</div> <div> <div class="abnormal-center"> 流程异常项目:<span style="font-size: 16px; font-weight: 700" >{{ countExceptionProjectData.processExceptionProject }}</span > </div> <div class="abnormal-center"> 资金异常项目:<span style="font-size: 16px; font-weight: 700" >0</span > </div> <div class="abnormal-center"> 进度异常项目:<span style="font-size: 16px; font-weight: 700" >0</span > </div> </div> <div class="abnormal-img"></div> </div> <div class="flex gap-[10px] ml-[10px] flex-wrap custom-min-width"> <div v-for="i in calculation" :key="i.text" :class="setbcStyle(i.text)" class="listings" @click="showDetail(i.text)" > <div :class="setTextStyle(i.text)" class="title"> {{ i.text }} </div> <div class="conter"> <div :class="setTextColor(i.text)" class="mun"> {{ i.mun }} </div> <div class="statistics"> <div>{{ i.statistics }}</div> <div :class="setTextColor(i.text)"> {{ i.statisticsMun }}<span style="font-size: 18px">亿</span> </div> </div> </div> </div> <!-- <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> <div class="listings"> <div class="title active"> 储 </div> <div class="conter"> <div class="mun">44</div> <div class="statistics"> <div>储备项目数量统计</div> <div class="statistics-mun">1233<span style="font-size: 18px;">亿</span></div> </div> </div> </div> --> </div> </div> </template> <script > export default { name: "Index", data() { return {} }, props: { calculation: [], countExceptionProjectData: {}, }, methods: { setTextStyle(text) { if (text === '储') return 'bg-[#3369FF]'; if (text === '建') return 'bg-[#64ADFD]'; if (text === '省') return 'bg-[#FF5E57]'; if (text === '市') return 'bg-[#FFA83F]'; if (text === '新') return 'bg-[#5DD1E5]'; if (text === '竣') return 'bg-[#576BF5]'; if (text === '县') return 'bg-[#3369FF]'; if (text === '普') return 'bg-[#64ADFD]'; return ''; }, setTextColor(text) { if (text === '储') return 'text-[#3369FF]'; if (text === '建') return 'text-[#64ADFD]'; if (text === '省') return 'text-[#FF5E57]'; if (text === '市') return 'text-[#FFA83F]'; if (text === '新') return 'text-[#5DD1E5]'; if (text === '竣') return 'text-[#576BF5]'; if (text === '县') return 'text-[#3369FF]'; if (text === '普') return 'text-[#64ADFD]'; return ''; }, // 跳转到异常项目 showAbnormal() { console.log('跳转异常项目'); this.$router.push({ path: 'projectEngineering/project/abnormalProject' }); }, // 跳转到对应的项目库 showDetail(text) { console.log('跳转到对应的项目库', text); switch (text) { case '储': this.$router.push({ path: '/projectEngineering/project/reserveProjects', query: { projectCategory: '1' } }); break; case '新': this.$router.push({ path: '/projectEngineering/project/previousProjects', query: { projectCategory: '2' } }); break; case '建': this.$router.push({ path: '/projectEngineering/project/implementationProject', query: { projectCategory: '3' } }); break; case '竣': this.$router.push({ path: '/projectEngineering/project/completedProjects', query: { projectCategory: '4' } }); break; default: break; } } } } </script> <style lang="scss" scoped> .overview-bottom { display: flex; justify-content: space-between; .abnormal { position: relative; width: 25%; min-width: 342px; height: 200px; background-image: url(../../assets/images/b.png); background-size: 100% auto; border-radius: 6px; font-size: 16px; color: #ffffff; padding: 20px 0 0 20px; .abnormal-center { margin-bottom: 15px; } .abnormal-img { position: absolute; right: 50px; bottom: 20px; width: 100px; height: 100px; background-image: url(../../assets/images/c.png); } } .custom-min-width { min-width: 1250px; width: 1250px; } .listings { width: 300px; height: 90px; border-radius: 6px; display: flex; align-items: center; .title { width: 45px; height: 45px; font-size: 24px; border-radius: 8px; line-height: 45px; text-align: center; margin-left: 15px; color: #ffffff; } .active { background-color: #3369ff; } .conter { margin-left: 10px; .mun { font-size: 30px; line-height: 32px; } .statistics { width: 200px; display: flex; justify-content: space-between; align-items: center; // .statistics-mun { // // color: #3369FF; // } } } } } </style> src/views/components/tidingsTable.vue
New file @@ -0,0 +1,283 @@ <template> <div> <div class="flex justify-between mb-[15px]"> <div class="block mb-3 font-semibold fonts">消息中心</div> <div class="flex text-[12px]"> <div v-for="tab in tabs" :key="tab.id" :class="{ active: currentTabId === tab.id }" class="tab relative" @click="switchTab(tab.id)" > {{ tab.label }} <div v-if="tab.num" class="w-[15px] h-[15px] num"> {{ tab.num }} </div> </div> </div> </div> <el-table :data="tableData" :header-cell-style="{ background: '#F5F7FC', color: '#454B5E', fontSize: '12px' }" height="280" max-height="280" > <el-table-column v-for="column in currentTableHeaders" :key="column.prop" :align="column.align" :label="column.label" :min-width="column.minWidth" :prop="column.prop" > <template v-if="column.slot === 'sort'" #default="scope"> <div :class=" getSortClass( (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 ) " class="sort" > <span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span> </div> </template> </el-table-column> <el-table-column align="center" class="relative" fixed="right" label="操作" min-width="72" > <template #default="scope"> <el-button plain size="small" type="primary" @click="handleDetail(scope.row)" > 查看</el-button > <div v-if="scope.row.isRead === '0'" class="viewRead"></div> </template> </el-table-column> </el-table> <pagination v-show="total >= 0" :limit="queryParams.pageSize" :page="queryParams.pageNum" :total="total" @pagination="getList" /> </div> </template> <script> import { getMessage, getMessageCount, getRead } from '@/api/message'; export default { name: "Index", data() { return { total: 0, queryParams: { pageNum: 1, pageSize: 10 }, tableData: [], tabs: [ // { id: 'process', label: '通知公告', num: '2' }, { id: 'review', label: '审核消息', num: '6' } // { id: 'supervision', label: '督办消息', num: '9' }, // { id: 'progress', label: '进度消息', num: '7' } ], currentTabId: 0, //配置表格表头数据 currentTableHeaders: [ { label: '排序', prop: 'index', minWidth: 50, align: 'center', slot: 'sort' }, { label: '发布单位', prop: 'commitDept', minWidth: 150, align: 'left' }, { label: '内容', prop: 'content', minWidth: 300, align: 'left' }, { label: '时间', prop: 'createTime', minWidth: 143, align: 'left' } ] } }, props: { calculation: [], countExceptionProjectData: {}, }, created() { this.currentTabId = this.tabs[0].id; // 默认选中的tab的id this.getList(); this.getMessageCountFun(); }, methods: { async getList() { const resp = await getMessage(this.queryParams); if (resp.code === 200) { this.total = resp.total; this.tableData = resp.rows; } }, async getMessageCountFun() { const resp = await getMessageCount(); if (resp.code === 200) { this.tabs = tabs.map((tab) => { if (tab.label === '审核消息') { tab.num = resp.data.auditCount; } return tab; }); } }, switchTab(tabId) { currentTabId = tabId; }, getSortClass(index) { if (index === 1) { return 'actives'; } else if (index === 2) { return 'two'; } else if (index === 3) { return 'three'; } else { return ''; } }, async getReadFun(id) { const resp = await this.getRead(id); if (resp.code === 200) { await this.getMessageCountFun(); } }, handleDetail(row) { this.getReadFun(row.id); if (row.auditType === '2') { this.$router.push({ path: '/projectManage/nodeDetails', query: { taskId: row.taskId, id: row.businessKey, auditType: row.auditType, disabled: 'true' } }); } else { this.$router.push({ path: '/projectManage/nodeDetails', query: { taskId: row.taskId, id: row.businessKey, disabled: 'true' } }); } } } } </script> <style lang="scss" scoped> .tab { padding: 8px; border: 1px solid #dbdeea; cursor: pointer; width: 72px; } .active { border: 1px solid #3369ff; color: #3369ff; } .fonts { font-size: 16px; color: #212a40; display: flex; align-items: center; } .num { position: absolute; z-index: 999; top: -5px; right: -5px; border-radius: 50%; background: #f63f41; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 12px; } ::v-deep .el-table__row { font-size: 12px; } .sort { width: 20px; height: 20px; border-radius: 50%; background-color: #eaf0ff; text-align: center; color: #3369ff; } .actives { background-color: #3369ff; color: #fff; } .two { background-color: #5c87ff; color: #fff; } .three { background-color: #85a5ff; color: #fff; } ::v-deep .el-pagination { margin: -15px; text-align: end; } ::v-deep .el-pagination .btn-prev .el-icon, ::v-deep .el-pagination .btn-next .el-icon { display: inline; } .viewRead { width: 4px; height: 4px; position: absolute; z-index: 999; top: 10px; right: 20px; border-radius: 50%; background: #f63f41; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 12px; } .flex { display: flex; justify-content: space-between; font-size: 12px; } </style> src/views/index.vue
@@ -1,1097 +1,348 @@ <template> <div class="app-container home"> <el-row :gutter="20"> <el-col :sm="24" :lg="24"> <blockquote class="text-warning" style="font-size: 14px"> 领取阿里云通用云产品1888优惠券 <br /> <el-link href="https://www.aliyun.com/minisite/goods?userCode=brki8iof" type="primary" target="_blank" >https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link > <br /> 领取腾讯云通用云产品2860优惠券 <br /> <el-link href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console" type="primary" target="_blank" >https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link > <br /> 阿里云服务器折扣区 <el-link href="http://aly.ruoyi.vip" type="primary" target="_blank" >>☛☛点我进入☚☚</el-link > 腾讯云服务器秒杀区 <el-link href="http://txy.ruoyi.vip" type="primary" target="_blank" >>☛☛点我进入☚☚</el-link ><br /> <h4 class="text-danger"> 云产品通用红包,可叠加官网常规优惠使用。(仅限新用户) </h4> </blockquote> <hr /> </el-col> </el-row> <el-row :gutter="20"> <el-col :sm="24" :lg="12" style="padding-left: 20px"> <h2>射洪项目后台管理框架</h2> <p> 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了射洪项目管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 </p> <p> <b>当前版本:</b> <span>v{{ version }}</span> </p> <p> <el-tag type="danger">¥免费开源</el-tag> </p> <p> <el-button type="primary" size="mini" icon="el-icon-cloudy" plain @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')" >访问码云</el-button > <el-button size="mini" icon="el-icon-s-home" plain @click="goTarget('http://ruoyi.vip')" >访问主页</el-button > </p> </el-col> <el-col :sm="24" :lg="12" style="padding-left: 50px"> <el-row> <el-col :span="12"> <h2>技术选型</h2> </el-col> </el-row> <el-row> <el-col :span="6"> <h4>后端技术</h4> <ul> <li>SpringBoot</li> <li>Spring Security</li> <li>JWT</li> <li>MyBatis</li> <li>Druid</li> <li>Fastjson</li> <li>...</li> </ul> </el-col> <el-col :span="6"> <h4>前端技术</h4> <ul> <li>Vue</li> <li>Vuex</li> <li>Element-ui</li> <li>Axios</li> <li>Sass</li> <li>Quill</li> <li>...</li> </ul> </el-col> </el-row> </el-col> </el-row> <el-divider /> <el-row :gutter="20"> <el-col :xs="24" :sm="24" :md="12" :lg="8"> <el-card class="update-log"> <div slot="header" class="clearfix"> <span>联系信息</span> </div> <div class="body"> <p> <i class="el-icon-s-promotion"></i> 官网:<el-link href="http://www.ruoyi.vip" target="_blank" >http://www.ruoyi.vip</el-link > </p> <p> <i class="el-icon-user-solid"></i> QQ群:<s> 满937441 </s> <s> 满887144332 </s> <s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s> <s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s> <s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s> <s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s> <s> 满161281055 </s> <s> 满138988063 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=SUc-msaypcqB2UTFif4eqGlBHkKcvMNP&authKey=JdQBouY2PG%2BS%2BCzAfIgbCGNgxyahpfh24IW%2F03rPxGilhqVbisLma%2FFFnt79DHNh&noverify=0&group_code=151450850" target="_blank">151450850</a> </p> <p> <i class="el-icon-chat-dot-round"></i> 微信:<a href="javascript:;" >/ *射洪项目</a > </p> <p> <i class="el-icon-money"></i> 支付宝:<a href="javascript:;" class="支付宝信息" >/ *射洪项目</a > </p> </div> </el-card> </el-col> <el-col :xs="24" :sm="24" :md="12" :lg="8"> <el-card class="update-log"> <div slot="header" class="clearfix"> <span>更新日志</span> </div> <el-collapse accordion> <el-collapse-item title="v3.8.8 - 2024-06-30"> <ol> <li>菜单管理新增路由名称</li> <li>新增数据脱敏过滤注解</li> <li>用户密码新增非法字符验证</li> <li>限制用户操作数据权限范围</li> <li>代码生成新增创建表结构功能</li> <li>定时任务白名单配置范围缩小</li> <li>优化代码生成主子表关联查询方式</li> <li>Excel注解新增属性comboReadDict</li> <li>Excel注解ColumnType类型新增文本</li> <li>新增国际化资源文件配置</li> <li>升级oshi到最新版本6.6.1</li> <li>升级druid到最新版本1.2.23</li> <li>升级core-js到最新版本3.37.1</li> <li>更新HttpUtils中的User-Agent</li> <li>更新compressionPlugin到6.1.2以兼容node18+</li> <li>升级spring-security到安全版本,防止漏洞风险</li> <li>升级spring-framework到安全版本,防止漏洞风险</li> <li>优化自定义XSS注解匹配方式</li> <li>优化缓存监控键名列表排序显示</li> <li>优化定时任务日志默认按时间排序</li> <li>优化默认文件大小超过2G无效的问题</li> <li>优化查表特殊字符使用反斜杠进行转义</li> <li>优化定时任务cron表达式小时配置显示错误问题</li> <li>优化多个自定数据权限使用in查询,避免多次拼接</li> <li>优化导入Excel时设置dictType属性重复查缓存问题</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.7 - 2023-12-08"> <ol> <li>操作日志记录部门名称</li> <li>全局数据存储用户编号</li> <li>新增编程式判断资源访问权限</li> <li>操作日志列表新增IP地址查询</li> <li>定时任务新增页去除状态选项</li> <li>代码生成支持选择前端模板类型</li> <li>显隐列组件支持复选框弹出类型</li> <li>通用排序属性orderBy参数限制长度</li> <li>Excel自定义数据处理器增加单元格/工作簿对象</li> <li>升级oshi到最新版本6.4.8</li> <li>升级druid到最新版本1.2.20</li> <li>升级fastjson到最新版2.0.43</li> <li>升级pagehelper到最新版1.4.7</li> <li>升级commons.io到最新版本2.13.0</li> <li>升级element-ui到最新版本2.15.14</li> <li>修复五级路由缓存无效问题</li> <li>修复外链带端口出现的异常</li> <li>修复树模板父级编码变量错误</li> <li>修复字典表详情页面搜索问题</li> <li>修复内链iframe没有传递参数问题</li> <li>修复自定义字典样式不生效的问题</li> <li>修复字典缓存删除方法参数错误问题</li> <li>修复Excel导入数据临时文件无法删除问题</li> <li>修复未登录带参数访问成功后参数丢失问题</li> <li>修复HeaderSearch组件跳转query参数丢失问题</li> <li>修复代码生成导入后必填项与数据库不匹配问题</li> <li>修复Excels导入时无法获取到dictType字典值问题</li> <li>优化下载zip方法新增遮罩层</li> <li>优化头像上传参数新增文件名称</li> <li>优化字典标签支持自定义分隔符</li> <li>优化菜单管理类型为按钮状态可选</li> <li>优化前端防重复提交数据大小限制</li> <li>优化TopNav菜单没有图标svg不显示</li> <li>优化数字金额大写转换精度丢失问题</li> <li>优化富文本Editor组件检验图片格式</li> <li>优化页签在Firefox浏览器被遮挡的问题</li> <li>优化个人中心/基本资料修改时数据显示问题</li> <li>优化缓存监控图表支持跟随屏幕大小自适应调整</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.6 - 2023-06-30"> <ol> <li>支持登录IP黑名单限制</li> <li>新增监控页面图标显示</li> <li>操作日志新增消耗时间属性</li> <li>屏蔽定时任务bean违规的字符</li> <li>日志管理使用索引提升查询性能</li> <li>日志注解支持排除指定的请求参数</li> <li>支持自定义隐藏属性列过滤子对象</li> <li>升级oshi到最新版本6.4.3</li> <li>升级druid到最新版本1.2.16</li> <li>升级fastjson到最新版2.0.34</li> <li>升级spring-boot到最新版本2.5.15</li> <li>升级element-ui到最新版本2.15.13</li> <li>移除apache/commons-fileupload依赖</li> <li>修复页面切换时布局错乱的问题</li> <li>修复匿名注解Anonymous空指针问题</li> <li>修复路由跳转被阻止时内部产生报错信息问题</li> <li>修复isMatchedIp的参数判断产生空指针的问题</li> <li>修复用户多角色数据权限可能出现权限抬升的情况</li> <li>修复开启TopNav后一级菜单路由参数设置无效问题</li> <li>修复DictTag组件value没有匹配的值时则展示value</li> <li>优化文件下载出现的异常</li> <li>优化选择图标组件高亮回显</li> <li>优化弹窗后导航栏偏移的问题</li> <li>优化修改密码日志存储明文问题</li> <li>优化页签栏关闭其他出现的异常问题</li> <li>优化页签关闭左侧选项排除首页选项</li> <li>优化关闭当前tab页跳转最右侧tab页</li> <li>优化缓存列表清除操作提示不变的问题</li> <li>优化字符未使用下划线不进行驼峰式处理</li> <li>优化用户导入更新时需获取用户编号问题</li> <li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li> <li>优化导出Excel时设置dictType属性重复查缓存问题</li> <li>连接池Druid支持新的配置connectTimeout和socketTimeout</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.5 - 2023-01-01"> <ol> <li>定时任务违规的字符</li> <li>重置时取消部门选中</li> <li>新增返回警告消息提示</li> <li>忽略不必要的属性数据返回</li> <li>修改参数键名时移除前缓存配置</li> <li>导入更新用户数据前校验数据权限</li> <li>兼容Excel下拉框内容过多无法显示的问题</li> <li>升级echarts到最新版本5.4.0</li> <li>升级core-js到最新版本3.25.3</li> <li>升级oshi到最新版本6.4.0</li> <li>升级kaptcha到最新版2.3.3</li> <li>升级druid到最新版本1.2.15</li> <li>升级fastjson到最新版2.0.20</li> <li>升级pagehelper到最新版1.4.6</li> <li>优化弹窗内容过多展示不全问题</li> <li>优化swagger-ui静态资源使用缓存</li> <li>开启TopNav没有子菜单隐藏侧边栏</li> <li>删除fuse无效选项maxPatternLength</li> <li>优化导出对象的子列表为空会出现[]问题</li> <li>优化编辑头像时透明部分会变成黑色问题</li> <li>优化小屏幕上修改头像界面布局错位的问题</li> <li>修复代码生成勾选属性无效问题</li> <li>修复文件上传组件格式验证问题</li> <li>修复回显数据字典数组异常问题</li> <li>修复sheet超出最大行数异常问题</li> <li>修复Log注解GET请求记录不到参数问题</li> <li>修复调度日志点击多次数据不变化的问题</li> <li>修复主题颜色在Drawer组件不会加载问题</li> <li>修复文件名包含特殊字符的文件无法下载问题</li> <li>修复table中更多按钮切换主题色未生效修复问题</li> <li>修复某些特性的环境生成代码变乱码TXT文件问题</li> <li>修复代码生成图片/文件/单选时选择必填无法校验问题</li> <li>修复某些特性的情况用户编辑对话框中角色和部门无法修改问题</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.4 - 2022-09-26"> <ol> <li>数据逻辑删除不进行唯一验证</li> <li>Excel注解支持导出对象的子列表方法</li> <li>Excel注解支持自定义隐藏属性列</li> <li>Excel注解支持backgroundColor属性设置背景色</li> <li>支持配置密码最大错误次数/锁定时间</li> <li>登录日志新增解锁账户功能</li> <li>通用下载方法新增config配置选项</li> <li>支持多权限字符匹配角色数据权限</li> <li>页面内嵌iframe切换tab不刷新数据</li> <li>操作日志记录支持排除敏感属性字段</li> <li>修复多文件上传报错出现的异常问题</li> <li>修复图片预览组件src属性为null值控制台报错问题</li> <li>升级oshi到最新版本6.2.2</li> <li>升级fastjson到最新版2.0.14</li> <li>升级pagehelper到最新版1.4.3</li> <li>升级core-js到最新版本3.25.2</li> <li>升级element-ui到最新版本2.15.10</li> <li>优化任务过期不执行调度</li> <li>优化字典数据使用store存取</li> <li>优化修改资料头像被覆盖的问题</li> <li>优化修改用户登录账号重复验证</li> <li>优化代码生成同步后值NULL问题</li> <li>优化定时任务支持执行父类方法</li> <li>优化用户个人信息接口防止修改部门</li> <li>优化布局设置使用el-drawer抽屉显示</li> <li>优化没有权限的用户编辑部门缺少数据</li> <li>优化日志注解记录限制请求地址的长度</li> <li>优化excel/scale属性导出单元格数值类型</li> <li>优化日志操作中重置按钮时重复查询的问题</li> <li>优化多个相同角色数据导致权限SQL重复问题</li> <li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.3 - 2022-06-27"> <ol> <li>新增缓存列表菜单功能</li> <li>代码生成树表新增(展开/折叠)</li> <li>Excel注解支持color字体颜色</li> <li>新增Anonymous匿名访问不鉴权注解</li> <li>用户头像上传限制只能为图片格式</li> <li>接口使用泛型使其看到响应属性字段</li> <li>检查定时任务bean所在包名是否为白名单配置</li> <li>添加页签openPage支持传递参数</li> <li>用户缓存信息添加部门ancestors祖级列表</li> <li>升级element-ui到最新版本2.15.8</li> <li>升级oshi到最新版本6.1.6</li> <li>升级druid到最新版本1.2.11</li> <li>升级fastjson到最新版2.0.8</li> <li>升级spring-boot到最新版本2.5.14</li> <li>降级jsencrypt版本兼容IE浏览器</li> <li>删除多余的salt字段</li> <li>新增获取不带后缀文件名称方法</li> <li>新增获取配置文件中的属性值方法</li> <li>新增内容编码/解码方便插件集成使用</li> <li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li> <li>优化设置分页参数默认值</li> <li>优化对空字符串参数处理的过滤</li> <li>优化显示顺序orderNum类型为整型</li> <li>优化表单构建按钮不显示正则校验</li> <li>优化字典数据回显样式下拉框显示值</li> <li>优化R响应成功状态码与全局保持一致</li> <li>优化druid开启wall过滤器出现的异常问题</li> <li>优化用户管理左侧树型组件增加选中高亮保持</li> <li>优化新增用户与角色信息&用户与岗位信息逻辑</li> <li>优化默认不启用压缩文件缓存防止node_modules过大</li> <li>修复字典数据显示不全问题</li> <li>修复操作日志查询类型条件为0时会查到所有数据</li> <li>修复Excel注解prompt/combo同时使用不生效问题</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.2 - 2022-04-01"> <ol> <li>前端支持设置是否需要防止数据重复提交</li> <li>开启TopNav没有子菜单情况隐藏侧边栏</li> <li>侧边栏菜单名称过长悬停显示标题</li> <li>用户访问控制时校验数据权限,防止越权</li> <li>导出Excel时屏蔽公式,防止CSV注入风险</li> <li>组件ImagePreview支持多图预览显示</li> <li>组件ImageUpload支持多图同时选择上传</li> <li>组件FileUpload支持多文件同时选择上传</li> <li>服务监控新增运行参数信息显示</li> <li>定时任务目标字符串过滤特殊字符</li> <li>定时任务目标字符串验证包名白名单</li> <li>代码生成列表图片支持预览</li> <li>代码生成编辑修改打开新页签</li> <li>代码生成新增Java类型Boolean</li> <li>代码生成子表支持日期/字典配置</li> <li>代码生成同步保留必填/类型选项</li> <li>升级oshi到最新版本6.1.2</li> <li>升级fastjson到最新版1.2.80</li> <li>升级pagehelper到最新版1.4.1</li> <li>升级spring-boot到最新版本2.5.11</li> <li>升级spring-boot-mybatis到最新版2.2.2</li> <li>添加遗漏的分页参数合理化属性</li> <li>修改npm即将过期的注册源地址</li> <li>修复分页组件请求两次问题</li> <li>修复通用文件下载接口跨域问题</li> <li>修复Xss注解字段值为空时的异常问题</li> <li>修复选项卡点击右键刷新丢失参数问题</li> <li>修复表单清除元素位置未垂直居中问题</li> <li>修复服务监控中运行参数显示条件错误</li> <li>修复导入Excel时字典字段类型为Long转义为空问题</li> <li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li> <li>优化加载字典缓存数据</li> <li>优化IP地址获取到多个的问题</li> <li>优化任务队列满时任务拒绝策略</li> <li>优化文件上传兼容Weblogic环境</li> <li>优化定时任务默认保存到内存中执行</li> <li>优化部门修改缩放后出现的错位问题</li> <li>优化Excel格式化不同类型的日期对象</li> <li>优化菜单表关键字导致的插件报错问题</li> <li>优化Oracle用户头像列为空时不显示问题</li> <li>优化页面若未匹配到字典标签则返回原字典值</li> <li>优化修复登录失效后多次请求提示多次弹窗问题</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.1 - 2022-01-01"> <ol> <li>新增Vue3前端代码生成模板</li> <li>新增图片预览组件</li> <li>新增压缩插件实现打包Gzip</li> <li>自定义xss校验注解实现</li> <li>自定义文字复制剪贴指令</li> <li>代码生成预览支持复制内容</li> <li>路由支持单独配置菜单或角色权限</li> <li>用户管理部门查询选择节点后分页参数初始</li> <li>修复用户分配角色属性错误</li> <li>修复打包后字体图标偶现的乱码问题</li> <li>修复菜单管理重置表单出现的错误</li> <li>修复版本差异导致的懒加载报错问题</li> <li>修复Cron组件中周回显问题</li> <li>修复定时任务多参数逗号分隔的问题</li> <li>修复根据ID查询列表可能出现的主键溢出问题</li> <li>修复tomcat配置参数已过期问题</li> <li>升级clipboard到最新版本2.0.8</li> <li>升级oshi到最新版本v5.8.6</li> <li>升级fastjson到最新版1.2.79</li> <li>升级spring-boot到最新版本2.5.8</li> <li>升级log4j2到2.17.1,防止漏洞风险</li> <li>优化下载解析blob异常提示</li> <li>优化代码生成字典组重复问题</li> <li>优化查询用户的角色组&岗位组代码</li> <li>优化定时任务cron表达式小时设置24</li> <li>优化用户导入提示溢出则显示滚动条</li> <li>优化防重复提交标识组合为(key+url+header)</li> <li>优化分页方法设置成通用方便灵活调用</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.8.0 - 2021-12-01"> <ol> <li>新增配套并同步的Vue3前端版本</li> <li>新增通用方法简化模态/缓存/下载/权限/页签使用</li> <li>优化导出数据/使用通用下载方法</li> <li>Excel注解支持自定义数据处理器</li> <li>Excel注解支持导入导出标题信息</li> <li>Excel导入支持@Excels注解</li> <li>新增组件data-dict,简化数据字典使用</li> <li>新增Jaxb依赖,防止jdk8以上出现的兼容错误</li> <li>生产环境使用路由懒加载提升页面响应速度</li> <li>修复五级以上菜单出现的404问题</li> <li>防重提交注解支持配置间隔时间/提示消息</li> <li>日志注解新增是否保存响应参数</li> <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li> <li>升级SpringBoot到最新版本2.5.6</li> <li>升级pagehelper到最新版1.4.0</li> <li>升级spring-boot-mybatis到最新版2.2.0</li> <li>升级oshi到最新版本v5.8.2</li> <li>升级druid到最新版1.2.8</li> <li>升级velocity到最新版本2.3</li> <li>升级fastjson到最新版1.2.78</li> <li>升级axios到最新版本0.24.0</li> <li>升级dart-sass到版本1.32.13</li> <li>升级core-js到最新版本3.19.1</li> <li>升级jsencrypt到最新版本3.2.1</li> <li>升级js-cookie到最新版本3.0.1</li> <li>升级file-saver到最新版本2.0.5</li> <li>升级sass-loader到最新版本10.1.1</li> <li>升级element-ui到最新版本2.15.6</li> <li>新增sendGet无参请求方法</li> <li>禁用el-tag组件的渐变动画</li> <li>代码生成点击预览重置激活tab</li> <li>AjaxResult重写put方法,以方便链式调用</li> <li>优化登录/验证码请求headers不设置token</li> <li>优化用户个人信息接口防止修改用户名</li> <li>优化Cron表达式生成器关闭时销毁避免缓存</li> <li>优化注册成功提示消息类型success</li> <li>优化aop语法,使用spring自动注入注解</li> <li>优化记录登录信息,移除不必要的修改</li> <li>优化mybatis全局默认的执行器</li> <li>优化Excel导入图片可能出现的异常</li> <li>修复代码生成模板主子表删除缺少事务</li> <li>修复日志记录可能出现的转换异常</li> <li>修复代码生成复选框字典遗漏问题</li> <li>修复关闭xss功能导致可重复读RepeatableFilter失效</li> <li>修复字符串无法被反转义问题</li> <li>修复后端主子表代码模板方法名生成错误问题</li> <li>修复xss过滤后格式出现的异常</li> <li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.7.0 - 2021-09-13"> <ol> <li>参数管理支持配置验证码开关</li> <li>新增是否开启用户注册功能</li> <li>定时任务支持在线生成cron表达式</li> <li>菜单管理支持配置路由参数</li> <li>支持自定义注解实现接口限流</li> <li>Excel注解支持Image图片导入</li> <li>自定义弹层溢出滚动样式</li> <li>自定义可拖动弹窗宽度指令</li> <li>自定义可拖动弹窗高度指令</li> <li>修复任意账户越权问题</li> <li>修改时检查用户数据权限范围</li> <li>修复保存配置主题颜色失效问题</li> <li>新增暗色菜单风格主题</li> <li>菜单&部门新增展开/折叠功能</li> <li>页签新增关闭左侧&添加图标</li> <li>顶部菜单排除隐藏的默认路由</li> <li>顶部菜单同步系统主题样式</li> <li>跳转路由高亮相对应的菜单栏</li> <li>代码生成主子表多选行数据</li> <li>日期范围支持添加多组</li> <li>升级element-ui到最新版本2.15.5</li> <li>升级oshi到最新版本v5.8.0</li> <li>升级commons.io到最新版本v2.11.0</li> <li>定时任务屏蔽ldap远程调用</li> <li>定时任务屏蔽http(s)远程调用</li> <li>补充定时任务表字段注释</li> <li>定时任务对检查异常进行事务回滚</li> <li>启用父部门状态排除顶级节点</li> <li>富文本新增上传文件大小限制</li> <li>默认首页使用keep-alive缓存</li> <li>修改代码生成字典回显样式</li> <li>自定义分页合理化传入参数</li> <li>修复字典组件值为整形不显示问题</li> <li>修复定时任务日志执行状态显示</li> <li>角色&菜单新增字段属性提示信息</li> <li>修复角色分配用户页面参数类型错误提醒</li> <li>优化布局设置动画特效</li> <li>优化异常处理信息</li> <li>优化错误token导致的解析异常</li> <li>密码框新增显示切换密码图标</li> <li>定时任务新增更多操作</li> <li>更多操作按钮添加权限控制</li> <li>导入用户样式优化</li> <li>提取通用方法到基类控制器</li> <li>优化使用权限工具获取用户信息</li> <li>优化用户不能删除自己</li> <li>优化XSS跨站脚本过滤</li> <li>优化代码生成模板</li> <li>验证码默认20s超时</li> <li>BLOB下载时清除URL对象引用</li> <li>代码生成导入表按创建时间排序</li> <li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li> <li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li> <li>多图上传组件移除多余的api地址&验证失败导致图片删除问题&无法删除相应图片修复</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.6.0 - 2021-07-12"> <ol> <li>角色管理新增分配用户功能</li> <li>用户管理新增分配角色功能</li> <li>日志列表支持排序操作</li> <li>优化参数&字典缓存操作</li> <li>系统布局配置支持动态标题开关</li> <li>菜单路由配置支持内链访问</li> <li>默认访问后端首页新增提示语</li> <li>富文本默认上传返回url类型</li> <li>新增自定义弹窗拖拽指令</li> <li>全局注册常用通用组件</li> <li>全局挂载字典标签组件</li> <li>ImageUpload组件支持多图片上传</li> <li>FileUpload组件支持多文件上传</li> <li>文件上传组件添加数量限制属性</li> <li>富文本编辑组件添加类型属性</li> <li>富文本组件工具栏配置视频</li> <li>封装通用iframe组件</li> <li>限制超级管理员不允许操作</li> <li>用户信息长度校验限制</li> <li>分页组件新增pagerCount属性</li> <li>添加bat脚本执行应用</li> <li>升级oshi到最新版本v5.7.4</li> <li>升级element-ui到最新版本2.15.2</li> <li>升级pagehelper到最新版1.3.1</li> <li>升级commons.io到最新版本v2.10.0</li> <li>升级commons.fileupload到最新版本v1.4</li> <li>升级swagger到最新版本v3.0.0</li> <li>修复关闭confirm提示框控制台报错问题</li> <li>修复存在的SQL注入漏洞问题</li> <li>定时任务屏蔽rmi远程调用</li> <li>修复用户搜索分页变量错误</li> <li>修复导出角色数据范围翻译缺少仅本人</li> <li>修复表单构建选择下拉选择控制台报错问题</li> <li>优化图片工具类读取文件</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.5.0 - 2021-05-25"> <ol> <li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li> <li>布局设置支持保存&重置配置</li> <li>修复树表数据显示不全&加载慢问题</li> <li>新增IE浏览器版本过低提示页面</li> <li>用户登录后记录最后登录IP&时间</li> <li>页面导出按钮点击之后添加遮罩</li> <li>富文本编辑器支持自定义上传地址</li> <li>富文本编辑组件新增readOnly属性</li> <li>页签TagsView新增关闭右侧功能</li> <li>显隐列组件加载初始默认隐藏列</li> <li>关闭头像上传窗口还原默认图片</li> <li>个人信息添加手机&邮箱重复验证</li> <li>代码生成模板导出按钮点击后添加遮罩</li> <li>代码生成模板树表操作列添加新增按钮</li> <li>代码生成模板修复主子表字段重名问题</li> <li>升级fastjson到最新版1.2.76</li> <li>升级druid到最新版本v1.2.6</li> <li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li> <li>升级oshi到最新版本v5.6.0</li> <li>velocity剔除commons-collections版本,防止3.2.1版本的反序列化漏洞</li> <li>数据监控页默认账户密码防止越权访问</li> <li>修复firefox下表单构建拖拽会新打卡一个选项卡</li> <li>修正后端导入表权限标识</li> <li>修正前端操作日志&登录日志权限标识</li> <li>设置Redis配置HashKey序列化</li> <li>删除操作日志记录信息</li> <li>上传媒体类型添加视频格式</li> <li>修复请求形参未传值记录日志异常问题</li> <li>优化xss校验json请求条件</li> <li>树级结构更新子节点使用replaceFirst</li> <li>优化ExcelUtil空值处理</li> <li>日志记录过滤BindingResult对象,防止异常</li> <li>修改主题后mini类型按钮无效问题</li> <li>优化通用下载完成后删除节点</li> <li>通用Controller添加响应返回消息</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.4.0 - 2021-02-22"> <ol> <li>代码生成模板支持主子表</li> <li>表格右侧工具栏组件支持显隐列</li> <li>图片组件添加预览&移除功能</li> <li>Excel注解支持Image图片导出</li> <li>操作按钮组调整为朴素按钮样式</li> <li>代码生成支持文件上传组件</li> <li>代码生成日期控件区分范围</li> <li>代码生成数据库文本类型生成表单文本域</li> <li>用户手机邮箱&菜单组件修改允许空字符串</li> <li>升级SpringBoot到最新版本2.2.13 提升启动速度</li> <li>升级druid到最新版本v1.2.4</li> <li>升级fastjson到最新版1.2.75</li> <li>升级element-ui到最新版本2.15.0</li> <li>修复IE11浏览器报错问题</li> <li>优化多级菜单之间切换无法缓存的问题</li> <li>修复四级菜单无法显示问题</li> <li>修正侧边栏静态路由丢失问题</li> <li>修复角色管理-编辑角色-功能权限显示异常</li> <li>配置文件新增redis数据库索引属性</li> <li>权限工具类增加admin判断</li> <li>角色非自定义权限范围清空选择值</li> <li>修复导入数据为负浮点数时丢失精度问题</li> <li>移除path-to-regexp正则匹配插件</li> <li>修复生成树表代码异常</li> <li>修改ip字段长度防止ipv6地址长度不够</li> <li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li> <li>登录后push添加catch防止出现检查错误</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.3.0 - 2020-12-14"> <ol> <li>新增缓存监控功能</li> <li>支持主题风格配置</li> <li>修复多级菜单之间切换无法缓存的问题</li> <li>多级菜单自动配置组件</li> <li>代码生成预览支持高亮显示</li> <li>支持Get请求映射Params参数</li> <li>删除用户和角色解绑关联</li> <li>去除用户手机邮箱部门必填验证</li> <li>Excel支持注解align对齐方式</li> <li>Excel支持导入Boolean型数据</li> <li>优化头像样式,鼠标移入悬停遮罩</li> <li>代码生成预览提供滚动机制</li> <li>代码生成删除多余的数字float类型</li> <li>修正转换字符串的目标字符集属性</li> <li>回显数据字典防止空值报错</li> <li>日志记录增加过滤多文件场景</li> <li>修改缓存Set方法可能导致嵌套的问题</li> <li>移除前端一些多余的依赖</li> <li>防止安全扫描YUI出现的风险提示</li> <li>修改node-sass为dart-sass</li> <li>升级SpringBoot到最新版本2.1.18</li> <li>升级poi到最新版本4.1.2</li> <li>升级oshi到最新版本v5.3.6</li> <li>升级bitwalker到最新版本1.21</li> <li>升级axios到最新版本0.21.0</li> <li>升级element-ui到最新版本2.14.1</li> <li>升级vue到最新版本2.6.12</li> <li>升级vuex到最新版本3.6.0</li> <li>升级vue-cli到版本4.5.9</li> <li>升级vue-router到最新版本3.4.9</li> <li>升级vue-cli到最新版本4.4.6</li> <li>升级vue-cropper到最新版本0.5.5</li> <li>升级clipboard到最新版本2.0.6</li> <li>升级core-js到最新版本3.8.1</li> <li>升级echarts到最新版本4.9.0</li> <li>升级file-saver到最新版本2.0.4</li> <li>升级fuse.js到最新版本6.4.3</li> <li>升级js-beautify到最新版本1.13.0</li> <li>升级js-cookie到最新版本2.2.1</li> <li>升级path-to-regexp到最新版本6.2.0</li> <li>升级quill到最新版本1.3.7</li> <li>升级screenfull到最新版本5.0.2</li> <li>升级sortablejs到最新版本1.10.2</li> <li>升级vuedraggable到最新版本2.24.3</li> <li>升级chalk到最新版本4.1.0</li> <li>升级eslint到最新版本7.15.0</li> <li>升级eslint-plugin-vue到最新版本7.2.0</li> <li>升级lint-staged到最新版本10.5.3</li> <li>升级runjs到最新版本4.4.2</li> <li>升级sass-loader到最新版本10.1.0</li> <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li> <li>升级svg-sprite-loader到最新版本5.1.1</li> <li>升级vue-template-compiler到最新版本2.6.12</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.2.1 - 2020-11-18"> <ol> <li>阻止任意文件下载漏洞</li> <li>代码生成支持上传控件</li> <li>新增图片上传组件</li> <li>调整默认首页</li> <li>升级druid到最新版本v1.2.2</li> <li>mapperLocations配置支持分隔符</li> <li>权限信息调整</li> <li>调整sql默认时间</li> <li>解决代码生成没有bit类型的问题</li> <li>升级pagehelper到最新版1.3.0</li> </ol> </el-collapse-item> <el-collapse-item title="v3.2.0 - 2020-10-10"> <ol> <li>升级springboot版本到2.1.17 提升安全性</li> <li>升级oshi到最新版本v5.2.5</li> <li>升级druid到最新版本v1.2.1</li> <li>升级jjwt到版本0.9.1</li> <li>升级fastjson到最新版1.2.74</li> <li>修改sass为node-sass,避免el-icon图标乱码</li> <li>代码生成支持同步数据库</li> <li>代码生成支持富文本控件</li> <li>代码生成页面时不忽略remark属性</li> <li>代码生成添加select必填选项</li> <li>Excel导出类型NUMERIC支持精度浮点类型</li> <li>Excel导出targetAttr优化获取值,防止get方法不规范</li> <li>Excel注解支持自动统计数据总和</li> <li>Excel注解支持设置BigDecimal精度&舍入规则</li> <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li> <li>允许用户分配到部门父节点</li> <li>菜单新增是否缓存keep-alive</li> <li>表格操作列间距调整</li> <li>限制系统内置参数不允许删除</li> <li>富文本组件优化,支持自定义高度&图片冲突问题</li> <li>富文本工具栏样式对齐</li> <li>导入excel整形值校验优化</li> <li>修复页签关闭所有时固定标签路由不刷新问题</li> <li>表单构建布局型组件新增按钮</li> <li>左侧菜单文字过长显示省略号</li> <li>修正根节点为子部门时,树状结构显示问题</li> <li>修正调用目标字符串最大长度</li> <li>修正菜单提示信息错误</li> <li>修正定时任务执行一次权限标识</li> <li>修正数据库字符串类型nvarchar</li> <li>优化递归子节点</li> <li>优化数据权限判断</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.1.0 - 2020-08-13"> <ol> <li>表格工具栏右侧添加刷新&显隐查询组件</li> <li>后端支持CORS跨域请求</li> <li>代码生成支持选择上级菜单</li> <li>代码生成支持自定义路径</li> <li>代码生成支持复选框</li> <li>Excel导出导入支持dictType字典类型</li> <li>Excel支持分割字符串组内容</li> <li>验证码类型支持(数组计算、字符验证)</li> <li>升级vue-cli版本到4.4.4</li> <li>修改 node-sass 为 dart-sass</li> <li>表单类型为Integer/Long设置整形默认值</li> <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li> <li>优化防重复提交拦截器</li> <li>优化上级菜单不能选择自己</li> <li>修复角色的权限分配后,未实时生效问题</li> <li>修复在线用户日志记录类型</li> <li>修复富文本空格和缩进保存后不生效问题</li> <li>修复在线用户判断逻辑</li> <li>唯一限制条件只返回单条数据</li> <li>添加获取当前的环境配置方法</li> <li>超时登录后页面跳转到首页</li> <li>全局异常状态汉化拦截处理</li> <li>HTML过滤器改为将html转义</li> <li>检查字符支持小数点&降级改成异常提醒</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v3.0.0 - 2020-07-20"> <ol> <li>单应用调整为多模块项目</li> <li>升级element-ui版本到2.13.2</li> <li>删除babel,提高编译速度。</li> <li>新增菜单默认主类目</li> <li>编码文件名修改为uuid方式</li> <li>定时任务cron表达式验证</li> <li>角色权限修改时已有权限未自动勾选异常修复</li> <li>防止切换权限用户后登录出现404</li> <li>Excel支持sort导出排序</li> <li>创建用户不允许选择超级管理员角色</li> <li>修复代码生成导入表结构出现异常页面不提醒问题</li> <li>修复代码生成点击多次表修改数据不变化的问题</li> <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li> <li>修复布局为small者mini用户表单显示错位问题</li> <li>修复热部署导致的强换异常问题</li> <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li> <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li> <li>生成domain 如果是浮点型 统一用BigDecimal</li> <li>定时任务调整label-width,防止部署出现错位</li> <li>调整表头固定列默认样式</li> <li>代码生成模板调整,字段为String并且必填则加空串条件</li> <li>代码生成字典Integer/Long使用parseInt</li> <li> 修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序 </li> <li>修正岗位导出权限注解</li> <li>禁止加密密文返回前端</li> <li>修复代码生成页面中的查询条件创建时间未生效的问题</li> <li>修复首页搜索菜单外链无法点击跳转问题</li> <li>修复菜单管理选择图标,backspace删除时不过滤数据</li> <li>用户管理部门分支节点不可检查&显示计数</li> <li>数据范围过滤属性调整</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v2.3.0 - 2020-06-01"> <ol> <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li> <li>dev启动默认打开浏览器</li> <li>vue-cli使用默认source-map</li> <li>slidebar eslint报错优化</li> <li>当tags-view滚动关闭右键菜单</li> <li>字典管理添加缓存读取</li> <li>参数管理支持缓存操作</li> <li>支持一级菜单(和主页同级)在main区域显示</li> <li>限制外链地址必须以http(s)开头</li> <li>tagview & sidebar 主题颜色与element ui(全局)同步</li> <li>修改数据源类型优先级,先根据方法,再根据类</li> <li>支持是否需要设置token属性,自定义返回码消息。</li> <li>swagger请求前缀加入配置。</li> <li>登录地点设置内容过长则隐藏显示</li> <li>修复定时任务执行一次按钮后不提示消息问题</li> <li>修改上级部门(选择项排除本身和下级)</li> <li>通用http发送方法增加参数 contentType 编码类型</li> <li>更换IP地址查询接口</li> <li>修复页签变量undefined</li> <li>添加校验部门包含未停用的子部门</li> <li>修改定时任务详情下次执行时间日期显示错误</li> <li>角色管理查询设置默认排序字段</li> <li>swagger添加enable参数控制是否启用</li> <li>只对json类型请求构建可重复读取inputStream的request</li> <li>修改代码生成字典字段int类型没有自动选中问题</li> <li>vuex用户名取值修正</li> <li>表格树模板去掉多余的)</li> <li>代码生成序号修正</li> <li>全屏情况下不调整上外边距</li> <li>代码生成Date字段添加默认格式</li> <li>用户管理角色选择权限控制</li> <li>修复路由懒加载报错问题</li> <li>模板sql.vm添加菜单状态</li> <li>设置用户名称不能修改</li> <li>dialog添加append-to-body属性,防止ie遮罩</li> <li>菜单区分状态和显示隐藏功能</li> <li>升级fastjson到最新版1.2.68 修复安全加固</li> <li>修复代码生成如果选择字典类型缺失逗号问题</li> <li>登录请求params更换为data,防止暴露url</li> <li>日志返回时间格式处理</li> <li>添加handle控制允许拖动的元素</li> <li>布局设置点击扩大范围</li> <li>代码生成列属性排序查询</li> <li>代码生成列支持拖动排序</li> <li>修复时间格式不支持ios问题</li> <li>表单构建添加父级class,防止冲突</li> <li>定时任务并发属性修正</li> <li>角色禁用&菜单隐藏不查询权限</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v2.2.0 - 2020-03-18"> <ol> <li>系统监控新增定时任务功能</li> <li>添加一个打包Web工程bat</li> <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li> <li>修复点击退出登录有时会无提示问题</li> <li>修复防重复提交注解无效问题</li> <li>修复通知公告批量删除异常问题</li> <li>添加菜单时路由地址必填限制</li> <li>代码生成字段描述可编辑</li> <li>修复用户修改个人信息导致缓存不过期问题</li> <li>个人信息创建时间获取正确属性值</li> <li>操作日志详细显示正确类型</li> <li>导入表单击行数据时选中对应的复选框</li> <li>批量替换表前缀逻辑调整</li> <li>固定重定向路径表达式</li> <li>升级element-ui版本到2.13.0</li> <li>操作日志排序调整</li> <li>修复charts切换侧边栏或者缩放窗口显示bug</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v2.1.0 - 2020-02-24"> <ol> <li>新增表单构建</li> <li>代码生成支持树表结构</li> <li>新增用户导入</li> <li>修复动态加载路由页面刷新问题</li> <li>修复地址开关无效问题</li> <li>汉化错误提示页面</li> <li>代码生成已知问题修改</li> <li>修复多数据源下配置关闭出现异常处理</li> <li>添加HTML过滤器,用于去除XSS漏洞隐患</li> <li>修复上传头像控制台出现异常</li> <li>修改用户管理分页不正确的问题</li> <li>修复验证码记录提示错误</li> <li>修复request.js缺少Message引用</li> <li>修复表格时间为空出现的异常</li> <li>添加Jackson日期反序列化时区配置</li> <li>调整根据用户权限加载菜单数据树形结构</li> <li>调整成功登录不恢复按钮,防止多次点击</li> <li>修改用户个人资料同步缓存信息</li> <li>修复页面同时出现el-upload和Editor不显示处理</li> <li>修复在角色管理页修改菜单权限偶尔未选中问题</li> <li>配置文件新增redis密码属性</li> <li>设置mybatis全局的配置文件</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v2.0.0 - 2019-12-02"> <ol> <li>新增代码生成</li> <li>新增@RepeatSubmit注解,防止重复提交</li> <li>新增菜单主目录添加/删除操作</li> <li>日志记录过滤特殊对象,防止转换异常</li> <li>修改代码生成路由脚本错误</li> <li>用户上传头像实时同步缓存,无需重新登录</li> <li>调整切换页签后不重新加载数据</li> <li>添加jsencrypt实现参数的前端加密</li> <li>系统退出删除用户缓存记录</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v1.1.0 - 2019-11-11"> <ol> <li>新增在线用户管理</li> <li>新增按钮组功能实现(批量删除、导出、清空)</li> <li>新增查询条件重置按钮</li> <li>新增Swagger全局Token配置</li> <li>新增后端参数校验</li> <li>修复字典管理页面的日期查询异常</li> <li>修改时间函数命名防止冲突</li> <li>去除菜单上级校验,默认为顶级</li> <li>修复用户密码无法修改问题</li> <li>修复菜单类型为按钮时不显示权限标识</li> <li>其他细节优化</li> </ol> </el-collapse-item> <el-collapse-item title="v1.0.0 - 2019-10-08"> <ol> <li>射洪项目前后端分离系统正式发布</li> </ol> </el-collapse-item> </el-collapse> </el-card> </el-col> <el-col :xs="24" :sm="24" :md="12" :lg="8"> <el-card class="update-log"> <div slot="header" class="clearfix"> <span>捐赠支持</span> </div> <div class="body"> <img src="@/assets/images/pay.png" alt="donate" width="100%" <div class="home"> <div class="overview"> <div class="overview-top"> <div class="title">项目总览</div> <div class="qurey"> <el-form ref="queryFormRef" :model="queryParams"> <div class="search_from"> <el-form-item label="日期"> <el-date-picker style="width: 300px" v-model="timeMerge" clearable end-placeholder="结束时间" format="YYYY-MM-DD" placeholder="请选择日期" size="default" start-placeholder="开始时间" type="daterange" value-format="YYYY-MM-DD" @change="dataPickerChange" /> <span style="display: inline-block; height: 30px; line-height: 30px" >你可以请作者喝杯咖啡表示鼓励</span </el-form-item> <el-form-item label="行政区划"> <el-select v-model="queryParams.area" clearable placeholder="请选择区划" style="width: 180px" > <el-option v-for="item in sys_administrative_divisions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item label="投资金额" style="margin-right: 50px" > <div class="from_input"> <el-input v-model="queryParams.start" clearable placeholder="请输入" style="width: 100px" type="number" /> 至 <el-input v-model="queryParams.end" clearable placeholder="请输入" style="width: 100px" type="number" /> </div> </el-form-item> <el-form-item style="margin-right: 20px"> <el-button icon="Search" type="primary" @click="handleQuery" >搜索</el-button > <el-button icon="Refresh" @click="resetQuery" >重置</el-button > </el-form-item> </div> </el-form> </div> </div> <!-- 统计情况 --> <ProjectOverview :calculation="calculation" :countExceptionProjectData="countExceptionProjectData" /> </div> <!-- 代办事项 --> <div class="flex"> <div class="flex_card"> <el-card> <NoticeTable style="height: 360px" /> </el-card> </div> <!-- 消息通知 --> <div class="flex_card"> <el-card> <TidingsTable style="height: 360px" /> </el-card> </div> <!-- 地图 --> </div> <div class="mt-[10px] min-w-[1600px]"> <el-card> <div> <div class="search-form"> <el-form :model="searchForm" inline> <el-form-item label=" "> <el-input v-model="searchForm.name" clearable placeholder="请输入项目名称或项目代码" style="width: 180px" /> </el-form-item> <el-form-item style="margin-right: 0px"> <el-button icon="Search" type="primary" @click="searchList" >搜索</el-button > <el-button icon="Refresh" @click="mapQuery" >重置</el-button > </el-form-item> </el-form> </div> <div class="flex w-full h-[500px] border border-[#DBDEEA]"> <!-- <Map id="DangerSourceId" ref="mapRef" :is-show-control="true" :list-type="true" :map-list="tableDatas" :map-type="true" class="w-full h-full border-r border-[#DBDEEA]" @label-click="showDetails" @mark-click="showDetails" @current-label-style-change="labelStyleChange" /> --> </div> </div> </el-card> </el-col> </el-row> </div> </div> </template> <script> import SvgIcon from '@/components/SvgIcon/index.vue'; import ProjectOverview from './components/projectOverview.vue'; import NoticeTable from './components/noticeTable.vue'; import TidingsTable from './components/tidingsTable.vue'; // import Map from './components/Map/index.vue'; export default { name: "Index", data() { return { // 版本号 version: "3.8.8" queryParams: {}, timeMerge: [], sys_administrative_divisions: [], calculation: [], countExceptionProjectData: {}, searchForm: {}, tableDatas: [] }; }, components: { SvgIcon, ProjectOverview, NoticeTable, TidingsTable }, methods: { goTarget(href) { window.open(href, "_blank"); dataPickerChange(val) { if (!val) { this.queryParams.startTime = ''; this.queryParams.endTime = ''; return; } } this.queryParams.startTime = timeMerge[0]; this.queryParams.endTime = timeMerge[1]; }, handleQuery() { console.log(queryParams); const obj = { startDate: queryParams.startTime, endDate: queryParams.endTime, areaCode: queryParams.area, minInvestment: queryParams.start, maxInvestment: queryParams.end }; this.getCalculatioln(obj).then((res) => { const arr = res.data.proPhaseCountVO?.concat(res.data.impTypeCountVO); const newArr = arr.map((item) => ({ text: item.text, mun: item.count, statistics: item.type, statisticsMun: item.amount })); // 创建一个对象,以便根据 text 属性快速查找 newArr 中的对象 const newArrLookup = newArr.reduce((lookup, item) => { lookup[item.text] = item; return lookup; }, {}); // 更新 calculation 数组,保持其原始顺序 calculation.value = calculation.value.map((item) => { const newItem = newArrLookup[item.text]; return newItem ? newItem : item; // 如果 newItem 存在,则返回 newItem,否则返回原始 item }); }); abnormalData(obj); }, // 获取异常数据 async abnormalData(obj) { const res = await getAbnormalData(obj); this.countExceptionProjectData = res.data; }, //地图详情 showDetails(row) { console.log(row); }, labelStyleChange(currentLabel) { if (lastLabel) { lastLabel.setBackgroundColor('#fff'); lastLabel.setFontColor('var(--el-color-primary)'); } currentLabel.setBackgroundColor('var(--el-color-primary)'); currentLabel.setFontColor('#fff'); lastLabel = currentLabel; }, resetQuery() { this.queryParams = { area: '', start: '', end: '', startTime: '', endTime: '' }; this.timeMerge = []; this.handleQuery(); }, // 地图搜索 async searchList() { // await search() this.mapRef.moveTo(105.37281, 30.87145); }, mapQuery() { } } } </script> <style scoped lang="scss"> .home { blockquote { padding: 10px 20px; margin: 0 0 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; padding: 10px; background-color: #f3f7fc; min-height: calc(100vh - 85px); overflow-x: auto; .overview { padding: 10px 0 0 10px; height: 280px; min-width: 1600px; background-color: #fff; border-radius: 6px; .overview-top { display: flex; justify-content: space-between; .title { font-size: 16px; } ul { padding: 0; margin: 0; } font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; color: #676a6c; overflow-x: hidden; ul { list-style-type: none; } h4 { margin-top: 0px; } h2 { margin-top: 10px; font-size: 26px; .qurey { font-size: 12px; font-weight: 100; } p { margin-top: 10px; b { font-weight: 700; } } .update-log { ol { display: block; list-style-type: decimal; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0; margin-inline-end: 0; padding-inline-start: 40px; .search-form { display: flex; justify-content: flex-end; } } // ::v-deep .el-form-item { // display: inline-block !important; // margin-right: 10px; // } ::v-deep .el-form-item--medium .el-form-item__content { display: inline-block !important; } ::v-deep .el-form-item__label { font-size: 12px; font-weight: 400; } ::v-deep .el-button { font-size: 12px; } ::v-deep.el-input__inner { font-size: 12px; height: 32px; } ::v-deep.el-range-input { font-size: 12px; } ::v-deep.el-select__placeholder { font-size: 12px; } ::v-deep input[type='number']::-webkit-inner-spin-button, input[type='number']::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } input[type='number'] { -moz-appearance: textfield; } .search_from { display: flex; justify-self: justify-end; gap: 10px; } .flex { display: flex; gap: 2%; } .flex_card { width: 49%; margin: 10px 0px; } .from_input { display: flex; gap: 10px; font-size: 12px; } </style> src/views/login.vue
@@ -52,7 +52,10 @@ type="text" > <template #prefix> <svg-icon class="el-input__icon input-icon" icon-class="user" /> <svg-icon class="el-input__icon input-icon" icon-class="user" /> </template> </el-input> </el-form-item> @@ -92,7 +95,11 @@ </template> </el-input> <div class="login-code"> <img :src="codeUrl" class="login-code-img" @click="getCode" /> <img :src="codeUrl" class="login-code-img" @click="getCode" /> </div> </el-form-item> <el-checkbox @@ -123,7 +130,7 @@ <div class="other-title"> <span style="color: #b3b8c1">其他登录方式:</span ><span style="color: #2d5eff; cursor: pointer"> <SvgIcon icon-class="phone" />手机验证码登录 <svg-icon icon-class="phone" />手机验证码登录 </span> </div> <div class="forget">忘记密码?</div> @@ -137,6 +144,7 @@ import { getCodeImg } from "@/api/login"; import Cookies from "js-cookie"; import { encrypt, decrypt } from "@/utils/jsencrypt"; import SvgIcon from '@/components/SvgIcon/index.vue'; export default { name: "Login", @@ -167,6 +175,9 @@ register: false, redirect: undefined, }; }, comments: { SvgIcon }, watch: { $route: { @@ -215,7 +226,6 @@ console.log(this.loginForm); }, handleLogin() { debugger this.$refs.loginRef.validate((valid) => { if (valid) { this.loading = true; @@ -271,7 +281,7 @@ align-items: center; gap: 100px; height: calc(100vh - 50px); background-image: url("../assets/images/login-background.png"); background-image: url('../assets/images/login-background.png'); background-size: cover; .left { @@ -285,7 +295,7 @@ } .img { background-image: url("../assets/images/login.png"); background-image: url('../assets/images/login.png'); background-size: cover; height: 295px; width: 366px;