| New file |
| | |
| | | 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 |
| | | }); |
| | | } |
| | |
| | | @import './variables.scss'; |
| | | @import './variables.module.scss'; |
| | | |
| | | @mixin colorBtn($color) { |
| | | background: $color; |
| | |
| | | } |
| | | |
| | | .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; |
| | |
| | | outline: 0; |
| | | margin: 0; |
| | | padding: 10px 15px; |
| | | font-size: 14px; |
| | | font-size: 12px; |
| | | border-radius: 4px; |
| | | } |
| | |
| | | // 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 { |
| | |
| | | } |
| | | |
| | | .el-upload { |
| | | input[type="file"] { |
| | | input[type='file'] { |
| | | display: none !important; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | // to fixed https://github.com/ElemeFE/element/issues/2461 |
| | | .el-dialog { |
| | | transform: none; |
| | | left: 0; |
| | | position: relative; |
| | | margin: 0 auto; |
| | | /*-------------Dialog-------------**/ |
| | | .el-overlay { |
| | | overflow: hidden; |
| | | |
| | | .el-overlay-dialog { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | .el-dialog { |
| | | 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 |
| | |
| | | // dropdown |
| | | .el-dropdown-menu { |
| | | a { |
| | | display: block |
| | | display: block; |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | @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 { |
| | |
| | | visibility: hidden; |
| | | display: block; |
| | | font-size: 0; |
| | | content: " "; |
| | | content: ' '; |
| | | clear: both; |
| | | height: 0; |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | .text-center { |
| | | text-align: center |
| | | text-align: center; |
| | | } |
| | | |
| | | .sub-navbar { |
| | |
| | | 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; |
| | | } |
| | |
| | | @mixin clearfix { |
| | | &:after { |
| | | content: ""; |
| | | content: ''; |
| | | display: table; |
| | | clear: both; |
| | | } |
| | |
| | | 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; |
| | |
| | | /** |
| | | * 通用css样式布局处理 |
| | | * Copyright (c) 2019 ruoyi |
| | | */ |
| | | * 通用css样式布局处理 |
| | | * Copyright (c) 2019 ruoyi |
| | | */ |
| | | |
| | | /** 基础通用 **/ |
| | | .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; |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .mt20 { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .mr20 { |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | .mb20 { |
| | | margin-bottom: 20px; |
| | | } |
| | | .ml20 { |
| | | margin-left: 20px; |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | .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) { |
| | |
| | | } |
| | | } |
| | | |
| | | .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 { |
| | | cursor: pointer; |
| | | margin-left: 5px; |
| | | .el-table .el-dropdown-link { |
| | | cursor: pointer; |
| | | color: #409eff; |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .el-table .el-dropdown, .el-icon-arrow-down { |
| | | .el-table .el-dropdown, |
| | | .el-icon-arrow-down { |
| | | font-size: 12px; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .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 { |
| | |
| | | /* 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 */ |
| | |
| | | } |
| | | |
| | | .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%; |
| | |
| | | |
| | | /* 拖拽列样式 */ |
| | | .sortable-ghost { |
| | | opacity: .8; |
| | | opacity: 0.8; |
| | | color: #fff !important; |
| | | background: #42b983 !important; |
| | | } |
| | | |
| | | /* 表格右侧工具栏样式 */ |
| | | .top-right-btn { |
| | | position: relative; |
| | | float: right; |
| | | margin-left: auto; |
| | | } |
| | |
| | | #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 { |
| | | margin-left: 0!important; |
| | | margin-left: 0 !important; |
| | | } |
| | | |
| | | .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; |
| | |
| | | } |
| | | |
| | | .el-scrollbar__bar.is-vertical { |
| | | right: 0px; |
| | | right: 0; |
| | | } |
| | | |
| | | .el-scrollbar { |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | .main-container { |
| | | margin-left: 54px; |
| | | padding-left: 54px; |
| | | } |
| | | |
| | | .submenu-title-noDropdown { |
| | | .sub-menu-title-noDropdown { |
| | | padding: 0 !important; |
| | | position: relative; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | .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 { |
| | | &>span { |
| | | .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; |
| | |
| | | } |
| | | } |
| | | |
| | | .el-menu--collapse .el-menu .el-submenu { |
| | | .el-menu--collapse .el-menu .el-sub-menu { |
| | | min-width: $base-sidebar-width !important; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .sidebar-container { |
| | | transition: transform .28s; |
| | | transition: transform 0.28s; |
| | | width: $base-sidebar-width !important; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .withoutAnimation { |
| | | |
| | | .main-container, |
| | | .sidebar-container { |
| | | transition: none; |
| | |
| | | |
| | | // when menu collapsed |
| | | .el-menu--vertical { |
| | | &>.el-menu { |
| | | & > .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; |
| | | } |
| | | } |
| | | } |
| | |
| | | .fade-transform--move, |
| | | .fade-transform-leave-active, |
| | | .fade-transform-enter-active { |
| | | transition: all .5s; |
| | | transition: all 0.5s; |
| | | } |
| | | |
| | | .fade-transform-enter { |
| | |
| | | /* breadcrumb transition */ |
| | | .breadcrumb-enter-active, |
| | | .breadcrumb-leave-active { |
| | | transition: all .5s; |
| | | transition: all 0.5s; |
| | | } |
| | | |
| | | .breadcrumb-enter, |
| | |
| | | } |
| | | |
| | | .breadcrumb-move { |
| | | transition: all .5s; |
| | | transition: all 0.5s; |
| | | } |
| | | |
| | | .breadcrumb-leave-active { |
| | |
| | | $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; |
| | | |
| | |
| | | $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; |
| | | |
| | |
| | | |
| | | .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 */ |
| | |
| | | <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" /> |
| | | </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> |
| | | |
| | | </template> |
| | | |
| | | <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> |
| | | <div class="avatar-wrapper"> |
| | | <img :src="avatar" class="user-avatar"> |
| | | <i class="el-icon-caret-bottom" /> |
| | | <div class="navbar"> |
| | | <div class="ruoyi-logo"> |
| | | <img src="@/assets/logo/logo.png" alt="" /> |
| | | <span>射洪项目管理系统</span> |
| | | </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 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"> |
| | | <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> |
| | | <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" /> |
| | | <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 divided @click.native="logout"> |
| | | <span>退出登录</span> |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | |
| | | 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 { |
| | | components: { |
| | | Breadcrumb, |
| | | TopNav, |
| | | Hamburger, |
| | | Screenfull, |
| | | SizeSelect, |
| | | Search, |
| | | RuoYiGit, |
| | | RuoYiDoc |
| | | }, |
| | | computed: { |
| | | ...mapGetters([ |
| | | 'sidebar', |
| | | 'avatar', |
| | | 'device' |
| | | ]), |
| | | setting: { |
| | | get() { |
| | | return this.$store.state.settings.showSettings |
| | | }, |
| | | set(val) { |
| | | this.$store.dispatch('settings/changeSetting', { |
| | | key: 'showSettings', |
| | | value: val |
| | | }) |
| | | } |
| | | data() { |
| | | return { |
| | | newNotice: 0 |
| | | } |
| | | }, |
| | | topNav: { |
| | | get() { |
| | | return this.$store.state.settings.topNav |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | toggleSideBar() { |
| | | this.$store.dispatch('app/toggleSideBar') |
| | | components: { |
| | | Breadcrumb, |
| | | TopNav, |
| | | Hamburger, |
| | | Screenfull, |
| | | SizeSelect, |
| | | Search, |
| | | RuoYiGit, |
| | | RuoYiDoc, |
| | | SearchMenu, |
| | | Notice |
| | | }, |
| | | async logout() { |
| | | this.$confirm('确定注销并退出系统吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.$store.dispatch('LogOut').then(() => { |
| | | location.href = '/index'; |
| | | }) |
| | | }).catch(() => {}); |
| | | computed: { |
| | | ...mapGetters([ |
| | | 'sidebar', |
| | | 'avatar', |
| | | 'device' |
| | | ]), |
| | | setting: { |
| | | get() { |
| | | return this.$store.state.settings.showSettings |
| | | }, |
| | | set(val) { |
| | | this.$store.dispatch('settings/changeSetting', { |
| | | key: 'showSettings', |
| | | value: val |
| | | }) |
| | | } |
| | | }, |
| | | topNav: { |
| | | get() { |
| | | return this.$store.state.settings.topNav |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | toggleSideBar() { |
| | | this.$store.dispatch('app/toggleSideBar') |
| | | }, |
| | | async logout() { |
| | | this.$confirm('确定注销并退出系统吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.$store.dispatch('LogOut').then(() => { |
| | | 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); |
| | | height: 50px; |
| | | overflow: hidden; |
| | | position: relative; |
| | | //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; |
| | | -webkit-tap-highlight-color:transparent; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, .025) |
| | | } |
| | | } |
| | | |
| | | .breadcrumb-container { |
| | | float: left; |
| | | } |
| | | |
| | | .topmenu-container { |
| | | position: absolute; |
| | | left: 50px; |
| | | } |
| | | |
| | | .errLog-container { |
| | | display: inline-block; |
| | | vertical-align: top; |
| | | } |
| | | |
| | | .right-menu { |
| | | float: right; |
| | | height: 100%; |
| | | line-height: 50px; |
| | | |
| | | &:focus { |
| | | outline: none; |
| | | } |
| | | |
| | | .right-menu-item { |
| | | display: inline-block; |
| | | padding: 0 8px; |
| | | height: 100%; |
| | | font-size: 18px; |
| | | color: #5a5e66; |
| | | vertical-align: text-bottom; |
| | | |
| | | &.hover-effect { |
| | | .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); |
| | | } |
| | | } |
| | | } |
| | | |
| | | .avatar-container { |
| | | margin-right: 30px; |
| | | |
| | | .avatar-wrapper { |
| | | margin-top: 5px; |
| | | position: relative; |
| | | |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .el-icon-caret-bottom { |
| | | cursor: pointer; |
| | | position: absolute; |
| | | right: -20px; |
| | | top: 25px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | .breadcrumb-container { |
| | | float: left; |
| | | } |
| | | } |
| | | |
| | | .topmenu-container { |
| | | position: absolute; |
| | | left: 50px; |
| | | } |
| | | |
| | | .errLog-container { |
| | | display: inline-block; |
| | | vertical-align: top; |
| | | } |
| | | |
| | | .right-menu { |
| | | float: right; |
| | | height: 100%; |
| | | line-height: 50px; |
| | | display: flex; |
| | | |
| | | &:focus { |
| | | outline: none; |
| | | } |
| | | |
| | | .right-menu-item { |
| | | display: inline-block; |
| | | padding: 0 8px; |
| | | height: 100%; |
| | | font-size: 18px; |
| | | color: #5a5e66; |
| | | vertical-align: text-bottom; |
| | | |
| | | &.hover-effect { |
| | | cursor: pointer; |
| | | transition: background 0.3s; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, 0.025); |
| | | } |
| | | } |
| | | } |
| | | |
| | | .avatar-container { |
| | | margin-right: 40px; |
| | | margin-top: 10px; |
| | | |
| | | .avatar-wrapper { |
| | | margin-top: 5px; |
| | | position: relative; |
| | | |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 10px; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | i { |
| | | cursor: pointer; |
| | | position: absolute; |
| | | right: -20px; |
| | | top: 25px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <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> |
| | |
| | | <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" |
| | |
| | | > |
| | | <sidebar-item |
| | | v-for="(route, index) in sidebarRouters" |
| | | :key="route.path + index" |
| | | :key="route.path + index" |
| | | :item="route" |
| | | :base-path="route.path" |
| | | /> |
| | |
| | | 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"]), |
| | |
| | | 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> |
| | |
| | | <template> |
| | | <div id="tags-view-container" class="tags-view-container"> |
| | | <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 }" |
| | | tag="span" |
| | | class="tags-view-item" |
| | | :style="activeStyle(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)" /> |
| | | </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> |
| | | </div> |
| | | <div id="tags-view-container" class="tags-view-container"> |
| | | <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 |
| | | }" |
| | | tag="span" |
| | | class="tags-view-item" |
| | | :style="activeStyle(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)" |
| | | /> |
| | | </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> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | |
| | | import path from 'path' |
| | | |
| | | export default { |
| | | components: { ScrollPane }, |
| | | data() { |
| | | return { |
| | | visible: false, |
| | | top: 0, |
| | | left: 0, |
| | | selectedTag: {}, |
| | | affixTags: [] |
| | | } |
| | | }, |
| | | computed: { |
| | | visitedViews() { |
| | | return this.$store.state.tagsView.visitedViews |
| | | }, |
| | | routes() { |
| | | return this.$store.state.permission.routes |
| | | }, |
| | | theme() { |
| | | return this.$store.state.settings.theme; |
| | | } |
| | | }, |
| | | watch: { |
| | | $route() { |
| | | this.addTags() |
| | | this.moveToCurrentTag() |
| | | }, |
| | | visible(value) { |
| | | if (value) { |
| | | document.body.addEventListener('click', this.closeMenu) |
| | | } else { |
| | | document.body.removeEventListener('click', this.closeMenu) |
| | | } |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.initTags() |
| | | this.addTags() |
| | | }, |
| | | methods: { |
| | | isActive(route) { |
| | | return route.path === this.$route.path |
| | | }, |
| | | activeStyle(tag) { |
| | | if (!this.isActive(tag)) return {}; |
| | | return { |
| | | "background-color": this.theme, |
| | | "border-color": this.theme |
| | | }; |
| | | }, |
| | | isAffix(tag) { |
| | | return tag.meta && tag.meta.affix |
| | | }, |
| | | isFirstView() { |
| | | try { |
| | | return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath |
| | | } catch (err) { |
| | | return false |
| | | } |
| | | }, |
| | | isLastView() { |
| | | try { |
| | | return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath |
| | | } catch (err) { |
| | | return false |
| | | } |
| | | }, |
| | | filterAffixTags(routes, basePath = '/') { |
| | | let tags = [] |
| | | routes.forEach(route => { |
| | | if (route.meta && route.meta.affix) { |
| | | const tagPath = path.resolve(basePath, route.path) |
| | | tags.push({ |
| | | fullPath: tagPath, |
| | | path: tagPath, |
| | | name: route.name, |
| | | meta: { ...route.meta } |
| | | }) |
| | | components: { ScrollPane }, |
| | | data() { |
| | | return { |
| | | visible: false, |
| | | top: 0, |
| | | left: 0, |
| | | selectedTag: {}, |
| | | affixTags: [] |
| | | } |
| | | if (route.children) { |
| | | const tempTags = this.filterAffixTags(route.children, route.path) |
| | | if (tempTags.length >= 1) { |
| | | tags = [...tags, ...tempTags] |
| | | } |
| | | } |
| | | }) |
| | | return tags |
| | | }, |
| | | initTags() { |
| | | const affixTags = this.affixTags = this.filterAffixTags(this.routes) |
| | | for (const tag of affixTags) { |
| | | // Must have tag name |
| | | if (tag.name) { |
| | | this.$store.dispatch('tagsView/addVisitedView', tag) |
| | | computed: { |
| | | visitedViews() { |
| | | return this.$store.state.tagsView.visitedViews |
| | | }, |
| | | routes() { |
| | | return this.$store.state.permission.routes |
| | | }, |
| | | theme() { |
| | | return this.$store.state.settings.theme; |
| | | } |
| | | } |
| | | }, |
| | | addTags() { |
| | | const { name } = this.$route |
| | | if (name) { |
| | | this.$store.dispatch('tagsView/addView', this.$route) |
| | | if (this.$route.meta.link) { |
| | | this.$store.dispatch('tagsView/addIframeView', this.$route) |
| | | } |
| | | } |
| | | return false |
| | | }, |
| | | moveToCurrentTag() { |
| | | const tags = this.$refs.tag |
| | | this.$nextTick(() => { |
| | | for (const tag of tags) { |
| | | if (tag.to.path === this.$route.path) { |
| | | this.$refs.scrollPane.moveToTarget(tag) |
| | | // when query is different then update |
| | | if (tag.to.fullPath !== this.$route.fullPath) { |
| | | this.$store.dispatch('tagsView/updateVisitedView', this.$route) |
| | | watch: { |
| | | $route() { |
| | | this.addTags() |
| | | this.moveToCurrentTag() |
| | | }, |
| | | visible(value) { |
| | | if (value) { |
| | | document.body.addEventListener('click', this.closeMenu) |
| | | } else { |
| | | document.body.removeEventListener('click', this.closeMenu) |
| | | } |
| | | break |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | refreshSelectedTag(view) { |
| | | this.$tab.refreshPage(view); |
| | | if (this.$route.meta.link) { |
| | | this.$store.dispatch('tagsView/delIframeView', this.$route) |
| | | } |
| | | mounted() { |
| | | this.initTags() |
| | | this.addTags() |
| | | }, |
| | | closeSelectedTag(view) { |
| | | this.$tab.closePage(view).then(({ visitedViews }) => { |
| | | if (this.isActive(view)) { |
| | | this.toLastView(visitedViews, view) |
| | | } |
| | | }) |
| | | }, |
| | | closeRightTags() { |
| | | this.$tab.closeRightPage(this.selectedTag).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { |
| | | this.toLastView(visitedViews) |
| | | } |
| | | }) |
| | | }, |
| | | closeLeftTags() { |
| | | this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { |
| | | this.toLastView(visitedViews) |
| | | } |
| | | }) |
| | | }, |
| | | closeOthersTags() { |
| | | this.$router.push(this.selectedTag.fullPath).catch(()=>{}); |
| | | this.$tab.closeOtherPage(this.selectedTag).then(() => { |
| | | this.moveToCurrentTag() |
| | | }) |
| | | }, |
| | | closeAllTags(view) { |
| | | this.$tab.closeAllPage().then(({ visitedViews }) => { |
| | | if (this.affixTags.some(tag => tag.path === this.$route.path)) { |
| | | return |
| | | } |
| | | this.toLastView(visitedViews, view) |
| | | }) |
| | | }, |
| | | toLastView(visitedViews, view) { |
| | | const latestView = visitedViews.slice(-1)[0] |
| | | if (latestView) { |
| | | this.$router.push(latestView.fullPath) |
| | | } else { |
| | | // now the default is to redirect to the home page if there is no tags-view, |
| | | // you can adjust it according to your needs. |
| | | if (view.name === 'Dashboard') { |
| | | // to reload home page |
| | | this.$router.replace({ path: '/redirect' + view.fullPath }) |
| | | } else { |
| | | this.$router.push('/') |
| | | } |
| | | } |
| | | }, |
| | | openMenu(tag, e) { |
| | | const menuMinWidth = 105 |
| | | const offsetLeft = this.$el.getBoundingClientRect().left // container margin left |
| | | const offsetWidth = this.$el.offsetWidth // container width |
| | | const maxLeft = offsetWidth - menuMinWidth // left boundary |
| | | const left = e.clientX - offsetLeft + 15 // 15: margin right |
| | | methods: { |
| | | isActive(route) { |
| | | return route.path === this.$route.path |
| | | }, |
| | | activeStyle(tag) { |
| | | if (!this.isActive(tag)) return {}; |
| | | return { |
| | | "background-color": this.theme, |
| | | "border-color": this.theme |
| | | }; |
| | | }, |
| | | isAffix(tag) { |
| | | return tag.meta && tag.meta.affix |
| | | }, |
| | | isFirstView() { |
| | | try { |
| | | return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath |
| | | } catch (err) { |
| | | return false |
| | | } |
| | | }, |
| | | isLastView() { |
| | | try { |
| | | return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath |
| | | } catch (err) { |
| | | return false |
| | | } |
| | | }, |
| | | filterAffixTags(routes, basePath = '/') { |
| | | let tags = [] |
| | | routes.forEach(route => { |
| | | if (route.meta && route.meta.affix) { |
| | | const tagPath = path.resolve(basePath, route.path) |
| | | tags.push({ |
| | | fullPath: tagPath, |
| | | path: tagPath, |
| | | name: route.name, |
| | | meta: { ...route.meta } |
| | | }) |
| | | } |
| | | if (route.children) { |
| | | const tempTags = this.filterAffixTags(route.children, route.path) |
| | | if (tempTags.length >= 1) { |
| | | tags = [...tags, ...tempTags] |
| | | } |
| | | } |
| | | }) |
| | | return tags |
| | | }, |
| | | initTags() { |
| | | const affixTags = this.affixTags = this.filterAffixTags(this.routes) |
| | | for (const tag of affixTags) { |
| | | // Must have tag name |
| | | if (tag.name) { |
| | | this.$store.dispatch('tagsView/addVisitedView', tag) |
| | | } |
| | | } |
| | | }, |
| | | addTags() { |
| | | const { name } = this.$route |
| | | if (name) { |
| | | this.$store.dispatch('tagsView/addView', this.$route) |
| | | if (this.$route.meta.link) { |
| | | this.$store.dispatch('tagsView/addIframeView', this.$route) |
| | | } |
| | | } |
| | | return false |
| | | }, |
| | | moveToCurrentTag() { |
| | | const tags = this.$refs.tag |
| | | this.$nextTick(() => { |
| | | for (const tag of tags) { |
| | | if (tag.to.path === this.$route.path) { |
| | | this.$refs.scrollPane.moveToTarget(tag) |
| | | // when query is different then update |
| | | if (tag.to.fullPath !== this.$route.fullPath) { |
| | | this.$store.dispatch('tagsView/updateVisitedView', this.$route) |
| | | } |
| | | break |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | refreshSelectedTag(view) { |
| | | this.$tab.refreshPage(view); |
| | | if (this.$route.meta.link) { |
| | | this.$store.dispatch('tagsView/delIframeView', this.$route) |
| | | } |
| | | }, |
| | | closeSelectedTag(view) { |
| | | this.$tab.closePage(view).then(({ visitedViews }) => { |
| | | if (this.isActive(view)) { |
| | | this.toLastView(visitedViews, view) |
| | | } |
| | | }) |
| | | }, |
| | | closeRightTags() { |
| | | this.$tab.closeRightPage(this.selectedTag).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { |
| | | this.toLastView(visitedViews) |
| | | } |
| | | }) |
| | | }, |
| | | closeLeftTags() { |
| | | this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { |
| | | this.toLastView(visitedViews) |
| | | } |
| | | }) |
| | | }, |
| | | closeOthersTags() { |
| | | this.$router.push(this.selectedTag.fullPath).catch(() => { }); |
| | | this.$tab.closeOtherPage(this.selectedTag).then(() => { |
| | | this.moveToCurrentTag() |
| | | }) |
| | | }, |
| | | closeAllTags(view) { |
| | | this.$tab.closeAllPage().then(({ visitedViews }) => { |
| | | if (this.affixTags.some(tag => tag.path === this.$route.path)) { |
| | | return |
| | | } |
| | | this.toLastView(visitedViews, view) |
| | | }) |
| | | }, |
| | | toLastView(visitedViews, view) { |
| | | const latestView = visitedViews.slice(-1)[0] |
| | | if (latestView) { |
| | | this.$router.push(latestView.fullPath) |
| | | } else { |
| | | // now the default is to redirect to the home page if there is no tags-view, |
| | | // you can adjust it according to your needs. |
| | | if (view.name === 'Dashboard') { |
| | | // to reload home page |
| | | this.$router.replace({ path: '/redirect' + view.fullPath }) |
| | | } else { |
| | | this.$router.push('/') |
| | | } |
| | | } |
| | | }, |
| | | openMenu(tag, e) { |
| | | const menuMinWidth = 105 |
| | | const offsetLeft = this.$el.getBoundingClientRect().left // container margin left |
| | | const offsetWidth = this.$el.offsetWidth // container width |
| | | const maxLeft = offsetWidth - menuMinWidth // left boundary |
| | | const left = e.clientX - offsetLeft + 15 // 15: margin right |
| | | |
| | | if (left > maxLeft) { |
| | | this.left = maxLeft |
| | | } else { |
| | | this.left = left |
| | | } |
| | | if (left > maxLeft) { |
| | | this.left = maxLeft |
| | | } else { |
| | | this.left = left |
| | | } |
| | | |
| | | this.top = e.clientY |
| | | this.visible = true |
| | | this.selectedTag = tag |
| | | }, |
| | | closeMenu() { |
| | | this.visible = false |
| | | }, |
| | | handleScroll() { |
| | | this.closeMenu() |
| | | this.top = e.clientY |
| | | this.visible = true |
| | | this.selectedTag = tag |
| | | }, |
| | | closeMenu() { |
| | | this.visible = false |
| | | }, |
| | | handleScroll() { |
| | | this.closeMenu() |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .tags-view-container { |
| | | height: 34px; |
| | | 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); |
| | | .tags-view-wrapper { |
| | | .tags-view-item { |
| | | display: inline-block; |
| | | position: relative; |
| | | cursor: pointer; |
| | | height: 26px; |
| | | line-height: 26px; |
| | | border: 1px solid #d8dce5; |
| | | color: #495060; |
| | | background: #fff; |
| | | padding: 0 8px; |
| | | font-size: 12px; |
| | | margin-left: 5px; |
| | | margin-top: 4px; |
| | | &:first-of-type { |
| | | margin-left: 15px; |
| | | } |
| | | &:last-of-type { |
| | | margin-right: 15px; |
| | | } |
| | | &.active { |
| | | background-color: #42b983; |
| | | color: #fff; |
| | | border-color: #42b983; |
| | | &::before { |
| | | content: ''; |
| | | background: #fff; |
| | | display: inline-block; |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | position: relative; |
| | | margin-right: 2px; |
| | | height: 44px; |
| | | width: 100%; |
| | | 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: 23px; |
| | | background-color: var(--el-bg-color); |
| | | border: 1px solid var(--el-border-color-light); |
| | | color: #495060; |
| | | padding: 0 8px; |
| | | font-size: 12px; |
| | | margin-left: 5px; |
| | | margin-top: 4px; |
| | | &:hover { |
| | | color: var(--el-color-primary); |
| | | } |
| | | &:first-of-type { |
| | | margin-left: 15px; |
| | | } |
| | | &:last-of-type { |
| | | margin-right: 15px; |
| | | } |
| | | &.active { |
| | | background-color: #42b983; |
| | | color: #fff; |
| | | border-color: #42b983; |
| | | &::before { |
| | | content: ''; |
| | | background: #fff; |
| | | display: inline-block; |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | position: relative; |
| | | margin-right: 5px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .contextmenu { |
| | | margin: 0; |
| | | background: #fff; |
| | | z-index: 3000; |
| | | position: absolute; |
| | | list-style-type: none; |
| | | padding: 5px 0; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | font-weight: 400; |
| | | color: #333; |
| | | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); |
| | | li { |
| | | margin: 0; |
| | | padding: 7px 16px; |
| | | cursor: pointer; |
| | | &:hover { |
| | | background: #eee; |
| | | } |
| | | .contextmenu { |
| | | margin: 0; |
| | | background: var(--el-bg-color); |
| | | z-index: 3000; |
| | | position: absolute; |
| | | list-style-type: none; |
| | | padding: 5px 0; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | font-weight: 400; |
| | | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); |
| | | li { |
| | | margin: 0; |
| | | padding: 7px 16px; |
| | | cursor: pointer; |
| | | &:hover { |
| | | background: #eee; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | |
| | | <style lang="scss"> |
| | | //reset element css of el-icon-close |
| | | .tags-view-wrapper { |
| | | .tags-view-item { |
| | | .el-icon-close { |
| | | width: 16px; |
| | | height: 16px; |
| | | vertical-align: 2px; |
| | | border-radius: 50%; |
| | | text-align: center; |
| | | transition: all .3s cubic-bezier(.645, .045, .355, 1); |
| | | transform-origin: 100% 50%; |
| | | &:before { |
| | | transform: scale(.6); |
| | | display: inline-block; |
| | | vertical-align: -3px; |
| | | } |
| | | &:hover { |
| | | background-color: #b4bccc; |
| | | color: #fff; |
| | | } |
| | | .tags-view-item { |
| | | .el-icon-close { |
| | | width: 16px; |
| | | height: 16px; |
| | | vertical-align: 2px; |
| | | border-radius: 50%; |
| | | text-align: center; |
| | | transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | transform-origin: 100% 50%; |
| | | &:before { |
| | | transform: scale(0.6); |
| | | display: inline-block; |
| | | vertical-align: -3px; |
| | | } |
| | | &:hover { |
| | | background-color: #b4bccc; |
| | | color: #fff; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <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> |
| | |
| | | <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="{'fixed-header':fixedHeader}"> |
| | | <navbar/> |
| | | <tags-view v-if="needTagsView"/> |
| | | </div> |
| | | <app-main/> |
| | | <right-panel> |
| | | <settings/> |
| | | </right-panel> |
| | | <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 ref="navbarRef" @setLayout="setLayout" /> |
| | | <tags-view v-if="needTagsView" /> |
| | | </div> |
| | | <app-main /> |
| | | <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> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | |
| | | 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', |
| | | components: { |
| | | AppMain, |
| | | Navbar, |
| | | RightPanel, |
| | | Settings, |
| | | Sidebar, |
| | | TagsView |
| | | }, |
| | | mixins: [ResizeMixin], |
| | | computed: { |
| | | ...mapState({ |
| | | theme: state => state.settings.theme, |
| | | sideTheme: state => state.settings.sideTheme, |
| | | sidebar: state => state.app.sidebar, |
| | | device: state => state.app.device, |
| | | needTagsView: state => state.settings.tagsView, |
| | | fixedHeader: state => state.settings.fixedHeader |
| | | }), |
| | | classObj() { |
| | | return { |
| | | hideSidebar: !this.sidebar.opened, |
| | | openSidebar: this.sidebar.opened, |
| | | withoutAnimation: this.sidebar.withoutAnimation, |
| | | mobile: this.device === 'mobile' |
| | | } |
| | | name: 'Layout', |
| | | components: { |
| | | AppMain, |
| | | Navbar, |
| | | RightPanel, |
| | | Settings, |
| | | Sidebar, |
| | | TagsView, |
| | | SideBar |
| | | }, |
| | | variables() { |
| | | return variables; |
| | | mixins: [ResizeMixin], |
| | | computed: { |
| | | ...mapState({ |
| | | theme: state => state.settings.theme, |
| | | sideTheme: state => state.settings.sideTheme, |
| | | sidebar: state => state.app.sidebar, |
| | | device: state => state.app.device, |
| | | needTagsView: state => state.settings.tagsView, |
| | | fixedHeader: state => state.settings.fixedHeader |
| | | }), |
| | | classObj() { |
| | | return { |
| | | hideSidebar: !this.sidebar.opened, |
| | | openSidebar: this.sidebar.opened, |
| | | withoutAnimation: this.sidebar.withoutAnimation, |
| | | mobile: this.device === 'mobile' |
| | | } |
| | | }, |
| | | variables() { |
| | | return variables; |
| | | } |
| | | }, |
| | | methods: { |
| | | setLayout() { |
| | | this.settingRef.value?.openSetting(); |
| | | }, |
| | | handleClickOutside() { |
| | | this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | handleClickOutside() { |
| | | this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
| | | } |
| | | } |
| | | } |
| | | </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 { |
| | | .app-wrapper { |
| | | @include clearfix; |
| | | position: relative; |
| | | height: 100%; |
| | | width: 100%; |
| | | |
| | | &.mobile.openSidebar { |
| | | position: fixed; |
| | | top: 0; |
| | | position: fixed; |
| | | top: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .drawer-bg { |
| | | .drawer-bg { |
| | | background: #000; |
| | | opacity: 0.3; |
| | | width: 100%; |
| | |
| | | height: 100%; |
| | | position: absolute; |
| | | z-index: 999; |
| | | } |
| | | } |
| | | |
| | | .fixed-header { |
| | | .fixed-header { |
| | | position: fixed; |
| | | top: 0; |
| | | right: 0; |
| | | z-index: 9; |
| | | width: calc(100% - #{$base-sidebar-width}); |
| | | transition: width 0.28s; |
| | | } |
| | | } |
| | | |
| | | .hideSidebar .fixed-header { |
| | | .hideSidebar .fixed-header { |
| | | width: calc(100% - 54px); |
| | | } |
| | | } |
| | | |
| | | .sidebarHide .fixed-header { |
| | | .sidebarHide .fixed-header { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | .mobile .fixed-header { |
| | | .mobile .fixed-header { |
| | | width: 100%; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | 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 |
| | |
| | | Vue.use(directive) |
| | | Vue.use(plugins) |
| | | Vue.use(VueMeta) |
| | | // Vue.use(HighLight); |
| | | // Vue.use(ElementIcons); |
| | | DictData.install() |
| | | |
| | | /** |
| | |
| | | /** |
| | | * 侧边栏主题 深色主题theme-dark,浅色主题theme-light |
| | | */ |
| | | sideTheme: 'theme-dark', |
| | | sideTheme: 'theme-light', |
| | | |
| | | /** |
| | | * 是否系统布局配置 |
| | |
| | | |
| | | |
| | | /** |
| | | * 通用js方法封装处理 |
| | | * Copyright (c) 2019 ruoyi |
| | |
| | | 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 |
| | | } |
| | |
| | | |
| | | // 回显数据字典(字符串、数组) |
| | | export function selectDictLabels(datas, value, separator) { |
| | | if (value === undefined || value.length ===0) { |
| | | if (value === undefined || value.length === 0) { |
| | | return ""; |
| | | } |
| | | if (Array.isArray(value)) { |
| | |
| | | |
| | | // 字符串格式化(%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') { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 参数处理 |
| | | * @param {*} params 参数 |
| | | */ |
| | | * 参数处理 |
| | | * @param {*} params 参数 |
| | | */ |
| | | export function tansParams(params) { |
| | | let result = '' |
| | | for (const propName of Object.keys(params)) { |
| | |
| | | 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; |
| | | } |
| | |
| | | } |
| | | return Array.isArray(arg) |
| | | } |
| | | |
| | | export function isHttp(url) { |
| | | return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1; |
| | | } |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| | |
| | | <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" |
| | | /> |
| | | </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" |
| | | /> |
| | | <span style="display: inline-block; height: 30px; line-height: 30px" |
| | | >你可以请作者喝杯咖啡表示鼓励</span |
| | | > |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </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> |
| | | </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" |
| | | }; |
| | | }, |
| | | methods: { |
| | | goTarget(href) { |
| | | window.open(href, "_blank"); |
| | | name: "Index", |
| | | data() { |
| | | return { |
| | | queryParams: {}, |
| | | timeMerge: [], |
| | | sys_administrative_divisions: [], |
| | | calculation: [], |
| | | countExceptionProjectData: {}, |
| | | searchForm: {}, |
| | | tableDatas: [] |
| | | }; |
| | | }, |
| | | components: { |
| | | SvgIcon, |
| | | ProjectOverview, |
| | | NoticeTable, |
| | | TidingsTable |
| | | }, |
| | | methods: { |
| | | |
| | | 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; |
| | | |
| | | ul { |
| | | padding: 0; |
| | | .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; |
| | | } |
| | | |
| | | .qurey { |
| | | font-size: 12px; |
| | | font-weight: 100; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .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; |
| | | } |
| | | |
| | | 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; |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | 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> |
| | | |
| | |
| | | <template> |
| | | <div class="login"> |
| | | <div class="nav"> |
| | | <img alt="" src="../assets/images/bj.png" /> |
| | | <div class="ml-[10px]">射洪市项目管理系统</div> |
| | | </div> |
| | | <div class="conter"> |
| | | <div class="left"> |
| | | <div class="title">射洪市项目管理系统</div> |
| | | <div> |
| | | 运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理 |
| | | <div class="login"> |
| | | <div class="nav"> |
| | | <img alt="" src="../assets/images/bj.png" /> |
| | | <div class="ml-[10px]">射洪市项目管理系统</div> |
| | | </div> |
| | | <div class="img"></div> |
| | | </div> |
| | | <div class="right"> |
| | | <div class="tab"> |
| | | <div |
| | | :class="{ active: currentTab === 'corporation' }" |
| | | class="login-corporation" |
| | | @click="currentClick('corporation')" |
| | | > |
| | | 法人登录 |
| | | </div> |
| | | <div |
| | | :class="{ active: currentTab === 'supervise' }" |
| | | class="login-supervise" |
| | | @click="superviseClick('supervise')" |
| | | > |
| | | 监管部门登录 |
| | | </div> |
| | | </div> |
| | | <el-form |
| | | ref="loginRef" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | class="login-form" |
| | | > |
| | | <!-- <el-form-item v-if="tenantEnabled" prop="tenantId"> |
| | | <div class="conter"> |
| | | <div class="left"> |
| | | <div class="title">射洪市项目管理系统</div> |
| | | <div> |
| | | 运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理 |
| | | </div> |
| | | <div class="img"></div> |
| | | </div> |
| | | <div class="right"> |
| | | <div class="tab"> |
| | | <div |
| | | :class="{ active: currentTab === 'corporation' }" |
| | | class="login-corporation" |
| | | @click="currentClick('corporation')" |
| | | > |
| | | 法人登录 |
| | | </div> |
| | | <div |
| | | :class="{ active: currentTab === 'supervise' }" |
| | | class="login-supervise" |
| | | @click="superviseClick('supervise')" |
| | | > |
| | | 监管部门登录 |
| | | </div> |
| | | </div> |
| | | <el-form |
| | | ref="loginRef" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | class="login-form" |
| | | > |
| | | <!-- <el-form-item v-if="tenantEnabled" prop="tenantId"> |
| | | <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> |
| | | <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" |
| | | :value="item.tenantId"></el-option> |
| | | <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> |
| | | </el-select> |
| | | </el-form-item> --> |
| | | <el-form-item prop="username"> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="请输入账号" |
| | | size="large" |
| | | type="text" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon class="el-input__icon input-icon" icon-class="user" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="password"> |
| | | <el-input |
| | | v-model="loginForm.password" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="请输入密码" |
| | | size="large" |
| | | type="password" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon |
| | | class="el-input__icon input-icon" |
| | | icon-class="password" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="captchaEnabled" prop="code"> |
| | | <el-input |
| | | v-model="loginForm.code" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="验证码" |
| | | size="large" |
| | | style="width: 167px" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon |
| | | class="el-input__icon input-icon" |
| | | icon-class="validCode" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | <div class="login-code"> |
| | | <img :src="codeUrl" class="login-code-img" @click="getCode" /> |
| | | <el-form-item prop="username"> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="请输入账号" |
| | | size="large" |
| | | type="text" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon |
| | | class="el-input__icon input-icon" |
| | | icon-class="user" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="password"> |
| | | <el-input |
| | | v-model="loginForm.password" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="请输入密码" |
| | | size="large" |
| | | type="password" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon |
| | | class="el-input__icon input-icon" |
| | | icon-class="password" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="captchaEnabled" prop="code"> |
| | | <el-input |
| | | v-model="loginForm.code" |
| | | auto-complete="off" |
| | | maxlength="20" |
| | | placeholder="验证码" |
| | | size="large" |
| | | style="width: 167px" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon |
| | | class="el-input__icon input-icon" |
| | | icon-class="validCode" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | <div class="login-code"> |
| | | <img |
| | | :src="codeUrl" |
| | | class="login-code-img" |
| | | @click="getCode" |
| | | /> |
| | | </div> |
| | | </el-form-item> |
| | | <el-checkbox |
| | | v-model="loginForm.rememberMe" |
| | | style="margin: 0 0 25px 0; color: #2d5eff" |
| | | >记住密码</el-checkbox |
| | | > |
| | | <div></div> |
| | | <el-form-item style="width: 100%"> |
| | | <el-button |
| | | :loading="loading" |
| | | size="large" |
| | | style="width: 100%" |
| | | type="primary" |
| | | @click.prevent="handleLogin" |
| | | > |
| | | <span v-if="!loading">登 录</span> |
| | | <span v-else>登 录 中...</span> |
| | | </el-button> |
| | | <div v-if="register" style="float: right"> |
| | | <router-link :to="'/register'" class="link-type" |
| | | >立即注册</router-link |
| | | > |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="other"> |
| | | <div class="other-title"> |
| | | <span style="color: #b3b8c1">其他登录方式:</span |
| | | ><span style="color: #2d5eff; cursor: pointer"> |
| | | <svg-icon icon-class="phone" />手机验证码登录 |
| | | </span> |
| | | </div> |
| | | <div class="forget">忘记密码?</div> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | <el-checkbox |
| | | v-model="loginForm.rememberMe" |
| | | style="margin: 0 0 25px 0; color: #2d5eff" |
| | | >记住密码</el-checkbox |
| | | > |
| | | <div></div> |
| | | <el-form-item style="width: 100%"> |
| | | <el-button |
| | | :loading="loading" |
| | | size="large" |
| | | style="width: 100%" |
| | | type="primary" |
| | | @click.prevent="handleLogin" |
| | | > |
| | | <span v-if="!loading">登 录</span> |
| | | <span v-else>登 录 中...</span> |
| | | </el-button> |
| | | <div v-if="register" style="float: right"> |
| | | <router-link :to="'/register'" class="link-type" |
| | | >立即注册</router-link |
| | | > |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="other"> |
| | | <div class="other-title"> |
| | | <span style="color: #b3b8c1">其他登录方式:</span |
| | | ><span style="color: #2d5eff; cursor: pointer"> |
| | | <SvgIcon icon-class="phone" />手机验证码登录 |
| | | </span> |
| | | </div> |
| | | <div class="forget">忘记密码?</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | 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", |
| | | data() { |
| | | return { |
| | | currentTab: "corporation", |
| | | codeUrl: "", |
| | | loginForm: { |
| | | username: "admin", |
| | | password: "admin123", |
| | | rememberMe: false, |
| | | code: "", |
| | | uuid: "", |
| | | }, |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请输入您的账号" }, |
| | | ], |
| | | password: [ |
| | | { required: true, trigger: "blur", message: "请输入您的密码" }, |
| | | ], |
| | | code: [{ required: true, trigger: "change", message: "请输入验证码" }], |
| | | }, |
| | | loading: false, |
| | | // 验证码开关 |
| | | captchaEnabled: true, |
| | | // 注册开关 |
| | | register: false, |
| | | redirect: undefined, |
| | | }; |
| | | }, |
| | | watch: { |
| | | $route: { |
| | | handler: function (route) { |
| | | this.redirect = route.query && route.query.redirect; |
| | | }, |
| | | immediate: true, |
| | | name: "Login", |
| | | data() { |
| | | return { |
| | | currentTab: "corporation", |
| | | codeUrl: "", |
| | | loginForm: { |
| | | username: "admin", |
| | | password: "admin123", |
| | | rememberMe: false, |
| | | code: "", |
| | | uuid: "", |
| | | }, |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请输入您的账号" }, |
| | | ], |
| | | password: [ |
| | | { required: true, trigger: "blur", message: "请输入您的密码" }, |
| | | ], |
| | | code: [{ required: true, trigger: "change", message: "请输入验证码" }], |
| | | }, |
| | | loading: false, |
| | | // 验证码开关 |
| | | captchaEnabled: true, |
| | | // 注册开关 |
| | | register: false, |
| | | redirect: undefined, |
| | | }; |
| | | }, |
| | | }, |
| | | created() { |
| | | this.getCode(); |
| | | this.getCookie(); |
| | | }, |
| | | methods: { |
| | | getCode() { |
| | | getCodeImg().then((res) => { |
| | | this.captchaEnabled = |
| | | res.captchaEnabled === undefined ? true : res.captchaEnabled; |
| | | if (this.captchaEnabled) { |
| | | this.codeUrl = "data:image/gif;base64," + res.img; |
| | | this.loginForm.uuid = res.uuid; |
| | | } |
| | | }); |
| | | comments: { |
| | | SvgIcon |
| | | }, |
| | | getCookie() { |
| | | const username = Cookies.get("username"); |
| | | const password = Cookies.get("password"); |
| | | const rememberMe = Cookies.get("rememberMe"); |
| | | this.loginForm = { |
| | | username: username === undefined ? this.loginForm.username : username, |
| | | password: |
| | | password === undefined ? this.loginForm.password : decrypt(password), |
| | | rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), |
| | | }; |
| | | watch: { |
| | | $route: { |
| | | handler: function (route) { |
| | | this.redirect = route.query && route.query.redirect; |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | }, |
| | | // 法人登录 |
| | | currentClick(tab) { |
| | | this.currentTab = tab; |
| | | this.loginForm.role = "2"; |
| | | console.log(this.loginForm); |
| | | created() { |
| | | this.getCode(); |
| | | this.getCookie(); |
| | | }, |
| | | // 监管部门登录 |
| | | superviseClick(tab) { |
| | | this.currentTab = tab; |
| | | this.loginForm.role = "1"; |
| | | console.log(this.loginForm); |
| | | }, |
| | | handleLogin() { |
| | | debugger |
| | | this.$refs.loginRef.validate((valid) => { |
| | | if (valid) { |
| | | this.loading = true; |
| | | if (this.loginForm.rememberMe) { |
| | | Cookies.set("username", this.loginForm.username, { expires: 30 }); |
| | | Cookies.set("password", encrypt(this.loginForm.password), { |
| | | expires: 30, |
| | | methods: { |
| | | getCode() { |
| | | getCodeImg().then((res) => { |
| | | this.captchaEnabled = |
| | | res.captchaEnabled === undefined ? true : res.captchaEnabled; |
| | | if (this.captchaEnabled) { |
| | | this.codeUrl = "data:image/gif;base64," + res.img; |
| | | this.loginForm.uuid = res.uuid; |
| | | } |
| | | }); |
| | | Cookies.set("rememberMe", this.loginForm.rememberMe, { |
| | | expires: 30, |
| | | }, |
| | | getCookie() { |
| | | const username = Cookies.get("username"); |
| | | const password = Cookies.get("password"); |
| | | const rememberMe = Cookies.get("rememberMe"); |
| | | this.loginForm = { |
| | | username: username === undefined ? this.loginForm.username : username, |
| | | password: |
| | | password === undefined ? this.loginForm.password : decrypt(password), |
| | | rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), |
| | | }; |
| | | }, |
| | | // 法人登录 |
| | | currentClick(tab) { |
| | | this.currentTab = tab; |
| | | this.loginForm.role = "2"; |
| | | console.log(this.loginForm); |
| | | }, |
| | | // 监管部门登录 |
| | | superviseClick(tab) { |
| | | this.currentTab = tab; |
| | | this.loginForm.role = "1"; |
| | | console.log(this.loginForm); |
| | | }, |
| | | handleLogin() { |
| | | this.$refs.loginRef.validate((valid) => { |
| | | if (valid) { |
| | | this.loading = true; |
| | | if (this.loginForm.rememberMe) { |
| | | Cookies.set("username", this.loginForm.username, { expires: 30 }); |
| | | Cookies.set("password", encrypt(this.loginForm.password), { |
| | | expires: 30, |
| | | }); |
| | | Cookies.set("rememberMe", this.loginForm.rememberMe, { |
| | | expires: 30, |
| | | }); |
| | | } else { |
| | | Cookies.remove("username"); |
| | | Cookies.remove("password"); |
| | | Cookies.remove("rememberMe"); |
| | | } |
| | | this.$store |
| | | .dispatch("Login", this.loginForm) |
| | | .then(() => { |
| | | this.$router.push({ path: this.redirect || "/" }).catch(() => { }); |
| | | }) |
| | | .catch(() => { |
| | | this.loading = false; |
| | | if (this.captchaEnabled) { |
| | | this.getCode(); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } else { |
| | | Cookies.remove("username"); |
| | | Cookies.remove("password"); |
| | | Cookies.remove("rememberMe"); |
| | | } |
| | | this.$store |
| | | .dispatch("Login", this.loginForm) |
| | | .then(() => { |
| | | this.$router.push({ path: this.redirect || "/" }).catch(() => {}); |
| | | }) |
| | | .catch(() => { |
| | | this.loading = false; |
| | | if (this.captchaEnabled) { |
| | | this.getCode(); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .login { |
| | | .nav { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 40px; |
| | | margin-left: 24px; |
| | | background-color: #fff; |
| | | font-family: PangMenZhengDao; |
| | | font-size: 20px; |
| | | font-style: italic; |
| | | color: #1e2538; |
| | | line-height: 40px; |
| | | } |
| | | |
| | | .conter { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | gap: 100px; |
| | | height: calc(100vh - 50px); |
| | | background-image: url("../assets/images/login-background.png"); |
| | | background-size: cover; |
| | | |
| | | .left { |
| | | width: 500px; |
| | | height: auto; |
| | | |
| | | .title { |
| | | font-size: 34px; |
| | | color: #1f2639; |
| | | line-height: 16px; |
| | | } |
| | | |
| | | .img { |
| | | background-image: url("../assets/images/login.png"); |
| | | background-size: cover; |
| | | height: 295px; |
| | | width: 366px; |
| | | margin: auto; |
| | | margin-top: 20px; |
| | | } |
| | | .nav { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 40px; |
| | | margin-left: 24px; |
| | | background-color: #fff; |
| | | font-family: PangMenZhengDao; |
| | | font-size: 20px; |
| | | font-style: italic; |
| | | color: #1e2538; |
| | | line-height: 40px; |
| | | } |
| | | |
| | | .right { |
| | | border-radius: 6px; |
| | | background: #ffffff; |
| | | width: 500px; |
| | | padding: 0px 25px 5px 25px; |
| | | |
| | | .tab { |
| | | margin: 20px 0; |
| | | .conter { |
| | | display: flex; |
| | | font-size: 24px; |
| | | line-height: 24px; |
| | | justify-content: center; |
| | | align-items: center; |
| | | gap: 100px; |
| | | height: calc(100vh - 50px); |
| | | background-image: url('../assets/images/login-background.png'); |
| | | background-size: cover; |
| | | |
| | | .login-corporation { |
| | | cursor: pointer; |
| | | .left { |
| | | width: 500px; |
| | | height: auto; |
| | | |
| | | .title { |
| | | font-size: 34px; |
| | | color: #1f2639; |
| | | line-height: 16px; |
| | | } |
| | | |
| | | .img { |
| | | background-image: url('../assets/images/login.png'); |
| | | background-size: cover; |
| | | height: 295px; |
| | | width: 366px; |
| | | margin: auto; |
| | | margin-top: 20px; |
| | | } |
| | | } |
| | | |
| | | .login-supervise { |
| | | cursor: pointer; |
| | | } |
| | | .right { |
| | | border-radius: 6px; |
| | | background: #ffffff; |
| | | width: 500px; |
| | | padding: 0px 25px 5px 25px; |
| | | |
| | | .active { |
| | | color: #2d5eff; |
| | | } |
| | | } |
| | | .tab { |
| | | margin: 20px 0; |
| | | display: flex; |
| | | font-size: 24px; |
| | | line-height: 24px; |
| | | gap: 100px; |
| | | |
| | | .other { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | font-size: 14px; |
| | | margin-bottom: 10px; |
| | | .login-corporation { |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .other-title { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | .login-supervise { |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .forget { |
| | | color: #2d5eff; |
| | | cursor: pointer; |
| | | .active { |
| | | color: #2d5eff; |
| | | } |
| | | } |
| | | |
| | | .other { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | font-size: 14px; |
| | | margin-bottom: 10px; |
| | | |
| | | .other-title { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .forget { |
| | | color: #2d5eff; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | margin: 0px auto 30px auto; |
| | | text-align: center; |
| | | color: #707070; |
| | | margin: 0px auto 30px auto; |
| | | text-align: center; |
| | | color: #707070; |
| | | } |
| | | |
| | | .login-form { |
| | | .el-input { |
| | | height: 40px; |
| | | .el-input { |
| | | height: 40px; |
| | | |
| | | input { |
| | | height: 40px; |
| | | input { |
| | | height: 40px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .input-icon { |
| | | height: 39px; |
| | | width: 14px; |
| | | margin-left: 0px; |
| | | } |
| | | .input-icon { |
| | | height: 39px; |
| | | width: 14px; |
| | | margin-left: 0px; |
| | | } |
| | | } |
| | | |
| | | .login-tip { |
| | | font-size: 13px; |
| | | text-align: center; |
| | | color: #bfbfbf; |
| | | font-size: 13px; |
| | | text-align: center; |
| | | color: #bfbfbf; |
| | | } |
| | | |
| | | .login-code { |
| | | width: 33%; |
| | | height: 40px; |
| | | float: right; |
| | | width: 33%; |
| | | height: 40px; |
| | | float: right; |
| | | |
| | | img { |
| | | cursor: pointer; |
| | | vertical-align: middle; |
| | | } |
| | | img { |
| | | cursor: pointer; |
| | | vertical-align: middle; |
| | | } |
| | | } |
| | | |
| | | .login-code-img { |
| | | height: 40px; |
| | | padding-left: 12px; |
| | | height: 40px; |
| | | padding-left: 12px; |
| | | } |
| | | </style> |