Squashed commit of the following:

commit b39fec06efda601021c275acd670a93330921c9d
Author: sc <shencheng@heronshn.com>
Date:   Wed Sep 1 12:14:11 2021 +0800

    UP

commit 87181232d789605fa1a4a11a93fd6a0737b4009c
Author: sc <shencheng@heronshn.com>
Date:   Wed Sep 1 08:34:45 2021 +0800

    Update login.vue

commit 28154a7e19fc226399a64bd7e1e3a884c0900b61
Author: sakuya <81883387@qq.com>
Date:   Tue Aug 31 23:23:33 2021 +0800

    UP

commit 91c41d6de287b332e2270b3e73d63b36355dbacb
Author: sakuya <81883387@qq.com>
Date:   Tue Aug 31 22:30:59 2021 +0800

    up widgets

commit d21b65f77ca1ab9e41fcf5e9075a4b0f110965fe
Author: sc <shencheng@heronshn.com>
Date:   Tue Aug 31 17:26:51 2021 +0800

    UP widgets

commit 653c33359afb870516d979e9feeab1fdd3f62925
Author: sakuya <81883387@qq.com>
Date:   Sat Aug 28 21:14:05 2021 +0800

    FIX scTable 在关闭多标签时自适应高度失效

commit 2abbf2d7fa6142d6f81e481dd9b4275e95db7511
Author: sakuya <81883387@qq.com>
Date:   Sat Aug 28 20:30:20 2021 +0800

    Revert "UP"

    This reverts commit 4ac9af5c4fde0d98ecaca0841c78a0dffe28525a.

commit 4ac9af5c4fde0d98ecaca0841c78a0dffe28525a
Author: sc <shencheng@heronshn.com>
Date:   Sat Aug 28 14:03:13 2021 +0800

    UP

commit 52539ea6ed5524359a4fd35bffb71a78f045ab54
Author: sc <shencheng@heronshn.com>
Date:   Sat Aug 28 11:53:58 2021 +0800

    更改版本号 1.2.3

commit 7e6f7e7b4f868a246538e0047e8c505e2f517f53
Author: sc <shencheng@heronshn.com>
Date:   Sat Aug 28 11:53:17 2021 +0800

    ADD v-time directive

commit e5184083cae022b656748334bab14fa9f40b54a1
Author: sc <shencheng@heronshn.com>
Date:   Sat Aug 28 09:32:25 2021 +0800

    FIX

commit 13fc2cce5371b099a7936f787e40a5696acfe7cd
Author: sakuya <81883387@qq.com>
Date:   Sat Aug 28 00:21:18 2021 +0800

    scDialog & i18n

commit d722908dbccedcef6e4776d9a0a92298135f5ea3
Author: sc <shencheng@heronshn.com>
Date:   Fri Aug 27 16:49:43 2021 +0800

    scDialog demo

commit ec1bb4499070b7c0a92cc993fdb36a35c3aaf752
Author: sc <shencheng@heronshn.com>
Date:   Fri Aug 27 08:47:08 2021 +0800

    Update package.json

commit d2fc5a78bb44418b968a27430fc0c543a37a9fd1
Author: sc <shencheng@heronshn.com>
Date:   Thu Aug 26 14:13:30 2021 +0800

    UPD 部分依赖

    注意:这次 element-plus 1.1.0-beta 版本有很多破坏性更新

commit a2d45128f96d7df7d2f99249134d7fa5c1bb635d
Author: sc <shencheng@heronshn.com>
Date:   Thu Aug 26 14:01:41 2021 +0800

    FIX 图标选择器组件双向绑定失效
This commit is contained in:
sc 2021-09-01 12:15:20 +08:00
parent a2d6b50975
commit 72bdbd865e
37 changed files with 928 additions and 605 deletions

View File

@ -1,6 +1,6 @@
{
"name": "scui",
"version": "1.2.2",
"version": "1.2.3",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@ -10,15 +10,15 @@
"dependencies": {
"@tinymce/tinymce-vue": "4.0.4",
"axios": "0.21.1",
"core-js": "3.16.1",
"core-js": "3.16.3",
"cropperjs": "1.5.12",
"crypto-js": "4.1.1",
"echarts": "5.1.2",
"element-plus": "1.0.2-beta.71",
"element-plus": "1.1.0-beta.8",
"nprogress": "0.2.0",
"sortablejs": "1.14.0",
"tinymce": "5.8.2",
"vue": "3.2.2",
"tinymce": "5.9.0",
"vue": "3.2.6",
"vue-i18n": "9.1.7",
"vue-router": "4.0.10",
"vuedraggable": "4.0.3",
@ -28,7 +28,7 @@
"@vue/cli-plugin-babel": "4.5.13",
"@vue/cli-plugin-eslint": "4.5.13",
"@vue/cli-service": "4.5.13",
"@vue/compiler-sfc": "3.2.2",
"@vue/compiler-sfc": "3.2.6",
"babel-eslint": "10.1.0",
"eslint": "6.8.0",
"eslint-plugin-vue": "7.12.1",

57
public/img/no-widgets.svg Normal file
View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 750 750" style="enable-background:new 0 0 750 750;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.35;fill:#B3B3B3;}
.st1{opacity:0.1;fill:#B3B3B3;}
.st2{opacity:0.3;fill:#B3B3B3;}
.st3{opacity:0.1;}
.st4{fill:#B3B3B3;}
</style>
<g>
<path class="st0" d="M465.1,261.4H264c-1.3,0-2.4,1.1-2.4,2.4v255.6c0,1.3,1.1,2.4,2.4,2.4h201.1c1.3,0,2.4-1.1,2.4-2.4V263.8
C467.5,262.4,466.4,261.4,465.1,261.4z M417.9,443c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4
h102c1.3,0,2.4,1.1,2.4,2.4V443z M417.9,397.2c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4h102
c1.3,0,2.4,1.1,2.4,2.4V397.2z M417.9,351.5c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4h102
c1.3,0,2.4,1.1,2.4,2.4V351.5z"/>
<g>
<path class="st1" d="M462.1,236.8L462.1,236.8C384.8,236.2,321,295.1,314,370.7c-18.5-19.1-44.4-31.1-73.1-31.3h0
c-56.8-0.4-103.2,45.3-103.6,102.1l-0.8,101.4l175.6,1.3l30.1,0.2l265.1,2l1.2-160.9C609.2,304,543.6,237.4,462.1,236.8z"/>
<path class="st2" d="M216.9,227.4c-3.4,0-6.5,1.1-9,2.9c0.2-1,0.3-2,0.3-3c0.1-8.3-6.6-15.1-15-15.2s-15.1,6.6-15.2,15
c0,0.3,0,0.6,0,0.9c-1.6-0.6-3.4-1-5.2-1c-8.3-0.1-15.1,6.6-15.2,15c-0.1,8.2,6.4,14.9,14.5,15.2l0,0l44.6,0.3
c8.3,0.1,15.1-6.6,15.2-15S225.2,227.5,216.9,227.4z"/>
<path class="st2" d="M596.4,194.2c-3.4,0-6.5,1.1-9,2.9c0.2-1,0.3-2,0.3-3c0.1-8.3-6.6-15.1-15-15.2s-15.1,6.6-15.2,15
c0,0.3,0,0.6,0,0.9c-1.6-0.6-3.4-1-5.2-1c-8.3-0.1-15.1,6.6-15.2,15c-0.1,8.2,6.4,14.9,14.5,15.2l0,0l44.6,0.3
c8.3,0.1,15.1-6.6,15.2-15S604.7,194.3,596.4,194.2z"/>
<g>
<g class="st3">
<path class="st4" d="M496.9,497.5c-2.1,0-3.7,1.6-3.7,3.7c0,1.5,0.8,2.7,2,3.3l-0.5,65.1l3.5,0l0.5-65.3
c1.1-0.6,1.8-1.8,1.8-3.1C500.6,499.1,499,497.6,496.9,497.5z"/>
<path class="st4" d="M572.3,501.7c0-1.9-1.6-3.6-3.7-3.7c-2.1,0-3.7,1.6-3.7,3.7c0,1.4,0.8,2.6,1.9,3.2l-0.5,65.2l3.5,0
l0.5-65.2C571.5,504.3,572.2,503.1,572.3,501.7z"/>
</g>
<rect x="522.7" y="472.2" transform="matrix(7.448311e-03 -1 1 7.448311e-03 8.6828 1045.4733)" class="st1" width="16.5" height="92.3"/>
<polygon class="st1" points="495.4,509.8 495.2,510.1 485.5,526.3 484.8,526.3 484.9,509.8 "/>
<polygon class="st1" points="518.7,510 508.8,526.5 496.3,526.4 500.2,519.8 506,509.9 "/>
<polygon class="st1" points="542,510.2 532.1,526.6 519.6,526.5 529.3,510.1 "/>
<polygon class="st1" points="565.3,510.4 555.5,526.8 542.9,526.7 552.7,510.3 "/>
<polygon class="st1" points="577.2,510.4 577.1,527 566.2,526.9 576,510.4 "/>
<rect x="522.5" y="497.7" transform="matrix(7.448311e-03 -1 1 7.448311e-03 -17.0149 1070.603)" class="st1" width="16.5" height="92.3"/>
<polygon class="st1" points="495.2,535.3 495,535.6 485.3,551.8 484.6,551.8 484.7,535.3 "/>
<polygon class="st1" points="518.5,535.5 508.6,552 496.1,551.9 500,545.3 505.8,535.4 "/>
<polygon class="st1" points="541.8,535.7 531.9,552.1 519.4,552 529.1,535.6 "/>
<polygon class="st1" points="565.1,535.9 555.4,552.3 542.7,552.2 552.5,535.8 "/>
<polygon class="st1" points="577,536 576.9,552.5 566,552.4 575.8,536 "/>
<path class="st1" d="M577.1,527c0,0,0-0.1,0-0.3l0-0.9c0-0.7,0-1.8,0-3.2c0-2.8,0.1-6.9,0.1-12.2l0.1,0.1l-92.3-0.5l0,0l0.1-0.1
c0,5.6-0.1,11.2-0.1,16.5l-0.1-0.1l65.8,0.6l19.5,0.1l5.3,0l0,0l-5.3,0l-19.5-0.1l-65.8-0.3l-0.3,0l0.1-16.8l0.1,0l92.3,0.8
l0.1,0l0,0.1c0,5.3-0.1,9.4-0.1,12.2c0,1.5,0,2.5,0,3.2l0,0.7C577.1,526.8,577.1,527,577.1,527z"/>
<path class="st1" d="M576.9,552.5c0,0,0-0.1,0-0.3l0-0.9c0-0.7,0-1.8,0-3.2c0-2.8,0.1-6.9,0.1-12.2l0.1,0.1l-92.3-0.5l0,0
l0.1-0.1c0,5.6-0.1,11.2-0.1,16.5l-0.1-0.1l65.8,0.6l19.5,0.1l5.3,0l0,0l-5.3,0l-19.5-0.1l-65.8-0.3l-0.3,0l0.1-16.7l0.1,0
l92.3,0.8l0.1,0l0,0.1c0,5.3-0.1,9.4-0.1,12.2c0,1.5,0,2.5,0,3.2l0,0.7C576.9,552.3,576.9,552.5,576.9,552.5z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,5 +1,5 @@
<template>
<el-config-provider :i18n="$i18n.t">
<el-config-provider :locale="$i18n.messages[$i18n.locale].el">
<router-view></router-view>
</el-config-provider>
</template>

View File

@ -0,0 +1,141 @@
<!--
* @Descripttion: 弹窗扩展组件
* @version: 1.0
* @Author: sakuya
* @Date: 2021年8月27日08:51:52
* @LastEditors:
* @LastEditTime:
-->
<template>
<div class="sc-dialog" ref="scDialog">
<el-dialog ref="dialog" v-model="dialogVisible" :fullscreen="isFullscreen" v-bind="$attrs" :show-close="false">
<template #title>
<slot name="title">
<span class="el-dialog__title">{{ title }}</span>
</slot>
<div class="sc-dialog__headerbtn">
<button v-if="showFullscreen" aria-label="fullscreen" type="button" @click="setFullscreen">
<i v-if="isFullscreen" class="el-dialog__close el-icon-bottom-left"></i>
<i v-else class="el-dialog__close el-icon el-icon-full-screen"></i>
</button>
<button v-if="showClose" aria-label="close" type="button" @click="closeDialog">
<i class="el-dialog__close el-icon el-icon-close"></i>
</button>
</div>
</template>
<div v-loading="loading">
<slot></slot>
</div>
<template #footer>
<slot name="footer"></slot>
</template>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
modelValue: { type: Boolean, default: false },
title: { type: String, default: "" },
showClose: { type: Boolean, default: true },
showFullscreen: { type: Boolean, default: true },
drag: { type: Boolean, default: true },
loading: { type: Boolean, default: false }
},
data() {
return {
dialogVisible: false,
isFullscreen: false
}
},
watch:{
modelValue(){
this.dialogVisible = this.modelValue
if(this.dialogVisible){
this.$refs.scDialog.querySelector('.el-dialog').style.top = '0px'
this.$refs.scDialog.querySelector('.el-dialog').style.left = '0px'
this.isFullscreen = false
}
}
},
mounted() {
this.dialogVisible = this.modelValue
this.drag && this.dialogdrag()
},
methods: {
//
closeDialog(){
this.dialogVisible = false
},
//
setFullscreen(){
this.isFullscreen = !this.isFullscreen
},
//
dialogdrag(){
const dialogHeaderEl = this.$refs.scDialog.querySelector('.el-dialog__header')
const dragDom = this.$refs.scDialog.querySelector('.el-dialog')
//dialogHeaderEl.style.cursor = 'move'
dialogHeaderEl.onmousedown = (e) => {
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const screenWidth = document.body.clientWidth
const screenHeight = document.documentElement.clientHeight
const dragDomWidth = dragDom.offsetWidth
const dragDomheight = dragDom.offsetHeight
let minDragDomLeft = -dragDom.offsetLeft
let maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
let minDragDomTop = -dragDom.offsetTop
let maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight
if(screenHeight < dragDomheight){
return false
}
dragDom.style.marginBottom = '0px'
let styL = getComputedStyle(dragDom).left
let styT = getComputedStyle(dragDom).top
if(styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace('%', '') / 100)
styT = +document.body.clientHeight * (+styT.replace('%', '') / 100)
}else {
styL = +styL.replace('px', '')
styT = +styT.replace('px', '')
}
document.onmousemove = function (e) {
let left = e.clientX - disX
let top = e.clientY - disY
if (left < minDragDomLeft) {
left = minDragDomLeft
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft
}
if (top < minDragDomTop) {
top = minDragDomTop
} else if (top > maxDragDomTop) {
top = maxDragDomTop
}
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
}
}
</script>
<style scoped>
.sc-dialog__headerbtn {position: absolute;top: var(--el-dialog-padding-primary);right: var(--el-dialog-padding-primary);}
.sc-dialog__headerbtn button {padding: 0;background: transparent;border: none;outline: none;cursor: pointer;font-size: var(--el-message-close-size,16px);margin-left: 15px;color: var(--el-color-info);}
.sc-dialog__headerbtn button:hover .el-dialog__close {color: var(--el-color-primary);}
.sc-dialog:deep(.el-dialog).is-fullscreen {display: flex;flex-direction: column;top:0px !important;left:0px !important;}
.sc-dialog:deep(.el-dialog).is-fullscreen .el-dialog__header {}
.sc-dialog:deep(.el-dialog).is-fullscreen .el-dialog__body {flex:1;overflow: auto;}
.sc-dialog:deep(.el-dialog).is-fullscreen .el-dialog__footer {padding-bottom: 10px;border-top: 1px solid var(--el-border-color-base);}
</style>

View File

@ -1,10 +1,10 @@
<!--
* @Descripttion: 图标选择器组件
* @version: 1.0
* @version: 1.1
* @Author: sakuya
* @Date: 2021年7月27日10:02:46
* @LastEditors:
* @LastEditTime:
* @LastEditors: sakuya
* @LastEditTime: 2021年8月26日13:59:51
-->
<template>
@ -61,6 +61,9 @@
watch:{
modelValue(val){
this.defaultValue = val
},
defaultValue(val){
this.$emit('update:modelValue', val)
}
},
mounted() {

View File

@ -88,11 +88,6 @@
userColumn: this.column
}
},
created() {
this.$nextTick(() => {
this.upTableHeight()
})
},
mounted() {
if(this.apiObj){
this.getData();
@ -100,6 +95,13 @@
this.tableData = this.data;
this.total = this.tableData.length
}
this.$nextTick(() => {
this.upTableHeight()
})
window.addEventListener("resize", this.upTableHeight, true)
},
unmounted(){
window.removeEventListener("resize", this.upTableHeight, true)
},
activated(){
this.$nextTick(() => {

View File

@ -3,16 +3,16 @@ const DEFAULT_CONFIG = {
APP_NAME: "SCUI",
//版本号
APP_VER: "1.2.2",
APP_VER: "1.2.3",
//内核版本号
CORE_VER: "1.2.2",
CORE_VER: "1.2.3",
//接口地址
API_URL: "/api",
//请求超时
TIMEOUT: 1000,
TIMEOUT: 10000,
//TokenName
TOKEN_NAME: "Authorization",
@ -45,12 +45,12 @@ const DEFAULT_CONFIG = {
//控制台首页默认布局
DEFAULT_GRID: {
//默认分栏数量和宽度 例如 [24] [18,6] [8,8,8] [6,12,6]
layout: [18, 6],
layout: [12, 6, 6],
//小组件分布com取值:views/home/components 文件名
copmsList: [
[{ title: "实时收入", com: 'C1' },{ title: "周收入对比", com: 'C3' }],
[{ title: "版本更新", com: 'C2' }],
[]
['welcome'],
['about', 'var'],
['time', 'progress']
]
}
}

75
src/directives/time.js Normal file
View File

@ -0,0 +1,75 @@
import tool from '@/utils/tool'
var Time = {
//获取当前时间戳
getUnix: function() {
var date = new Date();
return date.getTime();
},
//获取今天0点0分0秒的时间戳
getTodayUnix: function() {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
//获取今年1月1日0点0秒的时间戳
getYearUnix: function() {
var date = new Date();
date.setMonth(0);
date.setDate(1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
//获取标准年月日
getLastDate: function(time) {
var date = new Date(time);
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return date.getFullYear() + '-' + month + '-' + day;
},
//转换时间
getFormateTime: function(timestamp) {
timestamp = new Date(timestamp)
var now = this.getUnix();
var today = this.getTodayUnix();
//var year = this.getYearUnix();
var timer = (now - timestamp) / 1000;
var tip = '';
if (timer <= 0) {
tip = '刚刚';
} else if (Math.floor(timer / 60) <= 0) {
tip = '刚刚';
} else if (timer < 3600) {
tip = Math.floor(timer / 60) + '分钟前';
} else if (timer >= 3600 && (timestamp - today >= 0)) {
tip = Math.floor(timer / 3600) + '小时前';
} else if (timer / 86400 <= 31) {
tip = Math.ceil(timer / 86400) + '天前';
} else {
tip = this.getLastDate(timestamp);
}
return tip;
}
}
export default {
mounted(el, binding) {
const { value, modifiers} = binding
if (modifiers.tip) {
el.innerHTML = Time.getFormateTime(value)
el.__timeout__ = setInterval(() => {
el.innerHTML = Time.getFormateTime(value)
}, 60000)
} else {
const format = el.getAttribute('format') || undefined
el.innerHTML = tool.dateFormat(value, format)
}
}
};

View File

@ -10,13 +10,13 @@
<span>{{navMenu.meta.title}}</span>
</template>
</el-menu-item>
<el-submenu v-else :index="navMenu.path">
<el-sub-menu v-else :index="navMenu.path">
<template #title>
<i v-if="navMenu.meta&&navMenu.meta.icon" :class="navMenu.meta.icon || 'el-icon-menu'"></i>
<span>{{navMenu.meta.title}}</span>
</template>
<NavMenu :navMenus="navMenu.children"></NavMenu>
</el-submenu>
</el-sub-menu>
</template>
</template>

View File

@ -168,4 +168,8 @@
.msg-list__main h2 {font-size: 15px;font-weight: normal;color: #333;}
.msg-list__main p {font-size: 12px;color: #999;line-height: 1.8;margin-top: 5px;}
.msg-list__time {width: 100px;text-align: right;color: #999;}
[data-theme='dark'] .msg-list__main h2 {color: #d0d0d0;}
[data-theme='dark'] .msg-list li {border-top:1px solid #363636;}
[data-theme='dark'] .msg-list li a:hover {background: #383838;}
</style>

View File

@ -1,9 +1,9 @@
import sysConfig from "@/config"
import tool from '@/utils/tool'
import { createI18n } from 'vue-i18n'
import elementLocale_zh_cn from 'element-plus/lib/locale/lang/zh-cn'
import elementLocale_en from 'element-plus/lib/locale/lang/en'
import elementLocale_ja from 'element-plus/lib/locale/lang/ja'
import el_zh_cn from 'element-plus/lib/locale/lang/zh-cn'
import el_en from 'element-plus/lib/locale/lang/en'
import el_ja from 'element-plus/lib/locale/lang/ja'
import zh_cn from './lang/zh-cn.js'
import en from './lang/en.js'
@ -11,15 +11,15 @@ import ja from './lang/ja.js'
const messages = {
'zh-cn': {
el: elementLocale_zh_cn.el,
el: el_zh_cn,
...zh_cn
},
'en': {
el: elementLocale_en.el,
el: el_en,
...en
},
'ja': {
el: elementLocale_ja.el,
el: el_ja,
...ja
}
}

View File

@ -1,7 +1,7 @@
import ElementPlus from 'element-plus'
import i18n from './locales'
import 'element-plus/lib/theme-chalk/index.css'
import 'element-plus/lib/theme-chalk/display.css'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.css'
import { createApp } from 'vue'
import App from './App.vue'
import config from "./config"
@ -20,8 +20,10 @@ import scFormTable from './components/scFormTable'
import scTableSelect from './components/scTableSelect'
import scPageHeader from './components/scPageHeader'
import scSelect from './components/scSelect'
import scDialog from './components/scDialog'
import auth from './directives/auth'
import role from './directives/role'
import time from './directives/time'
const app = createApp(App);
@ -48,10 +50,12 @@ app.component('scFormTable', scFormTable);
app.component('scTableSelect', scTableSelect);
app.component('scPageHeader', scPageHeader);
app.component('scSelect', scSelect);
app.component('scDialog', scDialog);
//注册全局指令
app.directive('auth', auth)
app.directive('role', role)
app.directive('time', time)
//全局代码错误捕捉
app.config.errorHandler = errorHandler

View File

@ -14,7 +14,7 @@
.el-main.nopadding {padding:0;background: #fff;}
.el-drawer__body {overflow: auto;}
.el-popconfirm__main {margin: 14px 0;}
.el-card__header {border-bottom: 0;font-size: 17px;font-weight: bold;padding:15px 20px;}
.el-card__header {border-bottom: 0;font-size: 17px;font-weight: bold;padding:15px 20px 0px 20px;}
.el-dialog__title {font-size: 17px;font-weight: bold;}
.el-drawer__header>:first-child {font-size: 17px;font-weight: bold;}
.el-tree.menu .el-tree-node__content {height:36px;}

View File

@ -3,12 +3,13 @@
.el-form-item {display: block;}
.el-form-item__label {display: block;text-align: left;padding: 0 0 10px;}
.el-dialog {width: 90%!important;}
.el-dialog.is-fullscreen {width: 100%!important;}
.el-drawer.rtl {width: 90%!important;}
.el-form-item__content {margin-left: 0px!important;}
.adminui-main {
.el-container {display: block;height:auto;}
.el-aside {width: 100%!important;border: 0}
>.el-container {display: block;height:auto;}
>.el-container > .el-aside {width: 100%!important;border: 0}
}
.scTable {
.el-table,

View File

@ -106,7 +106,10 @@
.el-calendar {
--el-calendar-selected-background-color: #222225;
}
.el-dropdown__popper {
--el-dropdown-menuItem-hover-fill: #222225;
}
/* 布局 */
.adminui-header {background: $--background;}
.aminui-side-split {background: $--background;}

View File

@ -87,7 +87,7 @@ tool.objCopy = function (obj) {
}
/* 日期格式化 */
tool.dateFormat = function (date, fmt='yyyy-MM-dd') {
tool.dateFormat = function (date, fmt='yyyy-MM-dd hh:mm:ss') {
date = new Date(date)
var o = {
"M+" : date.getMonth()+1, //月份

View File

@ -10,19 +10,19 @@
</el-main>
</div>
<work v-if="dashboard=='1'" @on-mounted="onMounted"></work>
<stats v-else @on-mounted="onMounted"></stats>
<widgets v-else @on-mounted="onMounted"></widgets>
</template>
<script>
import { defineAsyncComponent } from 'vue';
const stats = defineAsyncComponent(() => import('./stats'));
const work = defineAsyncComponent(() => import('./work'));
const widgets = defineAsyncComponent(() => import('./widgets'));
export default {
name: "dashboard",
components: {
stats,
work
work,
widgets
},
data(){
return {

View File

@ -1,35 +0,0 @@
<template>
<div style="height: 248px;text-align: center;">
<img src="img/ver.svg" style="height:150px"/>
<h2 style="margin-top: 15px;">SCUI {{$CONFIG.CORE_VER}}</h2>
<p style="color: #999;margin-top: 10px;line-height: 2;">更新日志移到了gitee维护了点击下方更新日志按钮查看</p>
</div>
<div style="margin-top: 20px;">
<el-button type="primary" round @click="golog">更新日志</el-button>
<el-button type="primary" round @click="gogit">gitee</el-button>
</div>
</template>
<script>
export default {
title: "版本更新",
data() {
return {
}
},
mounted() {
},
methods: {
golog(){
window.open("https://gitee.com/lolicode/scui/releases")
},
gogit(){
window.open("https://gitee.com/lolicode/scui")
}
}
}
</script>

View File

@ -1,62 +0,0 @@
<template>
<div v-loading="loading">
<scEcharts height="220px" :option="option"></scEcharts>
</div>
</template>
<script>
import scEcharts from '@/components/scEcharts';
export default {
title:"周收入对比",
components: {
scEcharts
},
data() {
return {
loading: true,
option: {}
}
},
created() {
var _this = this;
setTimeout(function() {
_this.loading = false
}, 500);
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['支出', '收入'],
right: 13,
},
xAxis: {
data: ['周一', '周二', '周三', '周四', '周五'],
},
yAxis: [{
type: 'value',
name: '价格',
}, ],
series: [{
name: '支出',
barWidth: '15px',
type: 'bar',
data: [5, 20, 36, 10, 10],
},
{
name: '收入',
type: 'bar',
barWidth: '15px',
data: [15, 20, 16, 20, 30],
},
],
};
this.option = option;
}
}
</script>

View File

@ -1,15 +0,0 @@
<template>
<el-empty description="描述文字"></el-empty>
</template>
<script>
export default {
title:"模块4",
props: {
msg: String
},
mounted(){
console.log("加载C4");
}
}
</script>

View File

@ -1,305 +0,0 @@
<template>
<div class="diy-grid-setting" @click.stop="setting">
<i class="el-icon-setting"></i>
</div>
<div class="diy-grid-layout">
<el-row :gutter="15">
<el-col v-for="(item, index) in grid.layout" v-bind:key="index" :md="item" :xs="24">
<draggable v-model="grid.copmsList[index]" :disabled="!isDiy" animation="200" handle=".el-card__header" group="people" @end="end" item-key="com">
<template #item="{ element }">
<div>
<el-card shadow="hover" style="margin-bottom:15px;" :class="isDiy?'move':''">
<template #header>
<span>{{element.title}}</span>
<el-dropdown trigger="click" v-if="isDiy">
<span class="el-dropdown-link">
<i class="el-icon-menu"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="push()">添加组件</el-dropdown-item>
<el-dropdown-item @click="set()">分栏设置</el-dropdown-item>
<el-dropdown-item @click="backDefaul()">恢复默认</el-dropdown-item>
<el-dropdown-item @click="remove(element)" divided>移除</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<component :is="allComps[element.com]"></component>
</el-card>
</div>
</template>
</draggable>
</el-col>
</el-row>
</div>
<el-dialog title="添加组件" v-model="showPush" :width="400" :before-close="closePush" destroy-on-close :append-to-body='true'>
<el-alert title="添加的元素自动会添加至最左侧" type="info" show-icon style="margin-bottom:20px;"></el-alert>
<el-form :model="pushForm" ref="pushForm" :rules="rules" label-width="0">
<el-form-item prop="selectComps">
<el-select v-model="pushForm.selectComps" value-key="title" filterable clearable placeholder="请选择组件" style="width: 100%;">
<el-option v-for="item in allCompsList" :key="item.com" :label="item.title" :value="item" :disabled="item.disabled">
<span style="float: left">{{ item.title }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.com }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="closePush"> </el-button>
<el-button type="primary" @click="submitPush('pushForm')"> </el-button>
</template>
</el-dialog>
<el-dialog title="分栏设置" v-model="showSet" :width="500" destroy-on-close :append-to-body='true'>
<el-alert title="当出现设置的分栏数比现有少的情况,系统将自动移除多出的组件" type="info" show-icon style="margin-bottom:20px;"></el-alert>
<div class="diy-grid-layout-set">
<el-tooltip content="通栏">
<div :class="selectLayout.toString()==[24].toString()?'active col':'col'" @click="setLayout([24])">
<span></span>
<span></span>
<span></span>
</div>
</el-tooltip>
<el-tooltip content="左大右小布局">
<div :class="selectLayout.toString()==[18, 6].toString()?'active row':'row'" @click="setLayout([18, 6])">
<span style="width: 60%;"></span>
<span style="width: 30%;"></span>
</div>
</el-tooltip>
<el-tooltip content="等分布局">
<div :class="selectLayout.toString()==[8, 8, 8].toString()?'active row':'row'" @click="setLayout([8, 8, 8])">
<span></span>
<span></span>
<span></span>
</div>
</el-tooltip>
<el-tooltip content="左右辅助布局">
<div :class="selectLayout.toString()==[6, 12, 6].toString()?'active row':'row'" @click="setLayout([6, 12, 6])">
<span style="width: 25%;"></span>
<span style="width: 50%;"></span>
<span style="width: 25%;"></span>
</div>
</el-tooltip>
</div>
<template #footer>
<el-button @click="showSet=false"> </el-button>
<el-button type="primary" @click="submitSet()"> </el-button>
</template>
</el-dialog>
<el-drawer title="布局设置" v-model="settingDialog" :size="300" destroy-on-close>
<el-form ref="form" label-width="120px" label-position="left" style="padding:0 20px;">
<el-form-item label="自由拖拽">
<el-switch v-model="isDiy"></el-switch>
</el-form-item>
<el-divider></el-divider>
</el-form>
</el-drawer>
</template>
<script>
import draggable from 'vuedraggable'
import allComps from './components'
export default {
props: {
msg: String
},
components: {
draggable
},
data() {
return {
settingDialog: false,
isDiy: false,
allComps: allComps,
allCompsList: [],
showPush: false,
pushForm: {
selectComps: null
},
rules: {
selectComps: [
{ required: true, message: '请选择添加的组件', trigger: 'blur' }
]
},
showSet: false,
selectLayout: [],
defaultGrid: this.$CONFIG.DEFAULT_GRID,
grid: [],
}
},
created(){
var grid = this.$TOOL.data.get("grid");
this.grid = grid || JSON.parse(JSON.stringify(this.defaultGrid));
},
mounted(){
},
methods: {
//
setAllCompsList(){
var allCompsList = []
for(var key in allComps){
allCompsList.push({
title: allComps[key].title,
com: key
})
}
var nowCopmsList_arr = this.grid.copmsList.reduce(function(a, b){return a.concat(b)});
for(let comp of allCompsList){
const _item = nowCopmsList_arr.find((item)=>{return item.com === comp.com});
if(_item){
comp.disabled = true
}
}
this.allCompsList = allCompsList;
},
//
end(){
this.$TOOL.data.set("grid", this.grid);
},
//
set(){
this.showSet = true;
this.selectLayout = this.grid.layout;
},
//
push(){
this.setAllCompsList()
this.showPush = true;
},
submitPush(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
var formModel = this.$refs[formName].model;
this.grid.copmsList[0].unshift(formModel.selectComps);
this.$TOOL.data.set("grid", this.grid);
this.$refs[formName].resetFields();
this.showPush = false;
}else{
return false;
}
})
},
closePush(){
this.$refs.pushForm.resetFields();
this.showPush = false;
},
setLayout(value){
this.selectLayout = value;
},
submitSet(){
//
if(this.selectLayout.length == 1){
this.grid.copmsList[1] = []
this.grid.copmsList[2] = []
}
if(this.selectLayout.length == 2){
this.grid.copmsList[2] = []
}
this.showSet = false;
this.grid.layout = this.selectLayout;
this.$TOOL.data.set("grid", this.grid);
},
//
remove(item){
var newCopmsList = [...this.grid.copmsList];
newCopmsList.forEach((obj, index) => {
var newObj = obj.filter(o=>o.com!=item.com);
newCopmsList[index] = newObj;
})
var newCopmsList_arr = newCopmsList.reduce(function(a, b){return a.concat(b)});
if(newCopmsList_arr.length <= 0){
alert("至少留一个崽~")
return false;
}
this.grid.copmsList = newCopmsList;
this.$TOOL.data.set("grid", this.grid);
},
//
backDefaul(){
this.grid = JSON.parse(JSON.stringify(this.defaultGrid));
this.$TOOL.data.remove("grid");
},
//
setting(){
this.settingDialog = true;
}
}
}
</script>
<style>
.diy-grid-setting {position: fixed;width:40px;height:40px;border-radius: 3px 0 0 3px;bottom:40px;right:0px;z-index: 100;background: #409EFF;display: flex;flex-direction: column;align-items: center;justify-content: center;cursor: pointer;}
.diy-grid-setting i {font-size: 18px;color: #fff;}
.diy-grid-layout .el-card.move .el-card__header {cursor: move;}
.diy-grid-layout .el-card__header {
display: flex;
justify-content: space-between;
align-items: center;
}
.diy-grid-layout .el-card__header .el-dropdown-link {
color: #999;
border-radius: 3px;
cursor: pointer;
padding:3px 5px;
}
.diy-grid-layout .el-card__header .el-dropdown-link:hover {
color: #555;
background: #ecf5ff;
}
.diy-grid-layout .el-card__header .el-dropdown-link:focus {
color: #555;
background: #ecf5ff;
}
.diy-grid-layout .sortable-ghost {
opacity: 0.5;
background: #c8ebfb;
}
.diy-grid-layout-set {
display: flex;
justify-content: center
}
.diy-grid-layout-set div {
width:80px;
height:80px;
background: #ecf5ff;
margin:10px;
cursor: pointer;
}
.diy-grid-layout-set div span{
background: #d6efff;
}
.diy-grid-layout-set .col {
display: flex;
flex-direction: column;
align-content: space-between;
padding:0 5px 5px 5px;
}
.diy-grid-layout-set .col span {
height:20px;
width: 100%;
margin-top:5px;
}
.diy-grid-layout-set .row {
display: flex;
justify-content: flex-start;
padding:5px 5px 5px 0;
}
.diy-grid-layout-set .row span {
height: 70px;
width: 20px;
margin-left:5px;
}
.diy-grid-layout-set div.active {
background: #09f;
}
</style>

View File

@ -1,138 +0,0 @@
<template>
<el-main>
<el-row :gutter="15">
<el-col :span="24">
<el-card shadow="never" style="margin-bottom: 15px;">
<div class="welTop">
<div class="icon">
<el-avatar :size="60" src="img/avatar.jpg"></el-avatar>
</div>
<div class="main">
<h2>欢迎体验SCUI</h2>
<p>高性能 / 精致 / 优雅基于Vue3 + Element-Plus 的中后台前端解决方案如果喜欢就点个星星支持一下</p>
<p>
<a href='https://gitee.com/lolicode/scui' target="_blank">
<img src='https://gitee.com/lolicode/scui/badge/star.svg?theme=dark' alt='star' style="vertical-align: middle">
</a>
</p>
</div>
<div class="icons hidden-sm-and-down">
<div class="avatar-list">
<el-tooltip content="Sakuya" placement="top">
<el-avatar class="avatar" :size="30" src="img/avatar.jpg"></el-avatar>
</el-tooltip>
<el-tooltip content="Lolowan" placement="top">
<el-avatar class="avatar" :size="30" src="img/avatar2.gif"></el-avatar>
</el-tooltip>
<el-tooltip content="Ali" placement="top">
<el-avatar class="avatar" :size="30" src="img/avatar3.gif"></el-avatar>
</el-tooltip>
</div>
<p>Participants</p>
</div>
</div>
</el-card>
</el-col>
</el-row>
<div class="data-box">
<el-row :gutter="15">
<el-col :md="8" :xs="24">
<el-card shadow="never" class="item-background">
<div class="item">
<div class="main">
<h2>今日收入</h2>
<h4>¥1.9K</h4>
<p><span class="down"><i class="el-icon-bottom"></i>-18.9%</span> 比昨日</p>
</div>
<div class="icon">
<i class="el-icon-data-analysis"></i>
</div>
</div>
</el-card>
</el-col>
<el-col :md="8" :xs="24">
<el-card shadow="never">
<div class="item">
<div class="main">
<h2>会员总数</h2>
<h4>68</h4>
<p><span class="up"><i class="el-icon-top"></i>+1.9%</span> 比昨日</p>
</div>
<div class="icon">
<i class="el-icon-user"></i>
</div>
</div>
</el-card>
</el-col>
<el-col :md="8" :xs="24">
<el-card shadow="never">
<div class="item">
<div class="main">
<h2>今日访客</h2>
<h4>108</h4>
<p><span class="up"><i class="el-icon-top"></i>+7.7%</span> 比昨日</p>
</div>
<div class="icon">
<el-progress type="dashboard" :percentage="25" :width="50"></el-progress>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<gridLayout></gridLayout>
</el-main>
</template>
<script>
import gridLayout from './gridLayout'
export default {
components: {
gridLayout
},
data() {
return {}
},
mounted(){
this.$emit('on-mounted')
},
methods: {
}
}
</script>
<style scoped>
.el-row {}
.el-tag+.el-tag {margin-left: 10px;}
.welTop {display: flex;}
.welTop .main {margin-left:20px;}
.welTop .main h2 {font-size: 20px;color: #3c4a54;}
.welTop .main p {color: #999;margin-top:10px;line-height: 1.8;}
.welTop .icons {margin-left:auto;text-align: center;}
.welTop .icons p {font-size: 12px;}
.avatar-list .avatar {margin-left: -10px;border: 3px solid #fff;cursor: pointer;}
.data-box {}
.data-box .el-card {margin-bottom: 15px;}
.data-box .item-background {background: #409EFF;color: #fff;}
.data-box .item-background .item h2 {color: #fff;}
.data-box .item-background .item p {color: rgba(255, 255, 255, 0.5);}
.data-box .item-background .item .icon i {background: rgba(255, 255, 255, 0.2);}
.data-box .item {display: flex;}
.data-box .item h2 {font-size: 12px;color: #999;font-weight: normal;}
.data-box .item h4 {font-size: 25px;margin:5px 0 5px 0;}
.data-box .item p {font-size: 12px;color: #999;}
.data-box .item .icon {margin-left: auto;display: flex;align-items: center;margin-right: 10px;}
.data-box .item .icon i {font-size: 18px;background: #409EFF;color: #fff;border-radius: 50%;width:32px;height: 32px;display: flex;align-items: center;justify-content: center;}
.data-box .item p span.up {color: #F56C6C;}
.data-box .item p span.down {color: #67C23A;}
[data-theme='dark'] .welTop .main h2 {color: var(--el-text-color-regular);}
</style>

View File

@ -0,0 +1,27 @@
<template>
<el-card shadow="hover" header="关于项目" class="item-background">
<p>高性能 / 精致 / 优雅基于Vue3 + Element-Plus 的中后台前端解决方案如果喜欢就点个星星支持一下</p>
<p>
<a href='https://gitee.com/lolicode/scui' target="_blank">
<img src='https://gitee.com/lolicode/scui/badge/star.svg?theme=dark' alt='star' style="vertical-align: middle">
</a>
</p>
</el-card>
</template>
<script>
export default {
title: "关于项目",
icon: "el-icon-s-tools",
description: "点个星星支持一下",
data() {
return {
}
}
}
</script>
<style scoped>
.item-background p {color: #999;margin-top:10px;line-height: 1.8;}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div v-loading="loading">
<el-card shadow="hover" header="实时收入" v-loading="loading">
<scEcharts ref="c1" height="300px" :option="option"></scEcharts>
</div>
</el-card>
</template>
<script>
@ -9,6 +9,8 @@
export default {
title: "实时收入",
icon: "el-icon-data-line",
description: "Echarts组件演示",
components: {
scEcharts
},

View File

@ -0,0 +1,32 @@
<template>
<el-card shadow="hover" header="进度环">
<div class="progress">
<el-progress type="dashboard" :percentage="85.5" :width="160">
<template #default="{ percentage }">
<div class="percentage-value">{{ percentage }}%</div>
<div class="percentage-label">当前进度</div>
</template>
</el-progress>
</div>
</el-card>
</template>
<script>
export default {
title: "进度环",
icon: "el-icon-odometer",
description: "进度环原子组件演示",
data() {
return {
}
}
}
</script>
<style scoped>
.progress {text-align: center;}
.progress .percentage-value {font-size: 28px;}
.progress .percentage-label {font-size: 12px;margin-top: 10px;}
</style>

View File

@ -0,0 +1,40 @@
<template>
<el-card shadow="hover" header="时钟" class="item-background">
<div class="time">
<h2>{{ time }}</h2>
<p>{{ day }}</p>
</div>
</el-card>
</template>
<script>
export default {
title: "时钟",
icon: "el-icon-time",
description: "演示部件效果",
data() {
return {
time: '',
day: ''
}
},
mounted() {
this.showTime()
setInterval(()=>{
this.showTime()
},1000)
},
methods: {
showTime(){
this.time = this.$TOOL.dateFormat(new Date(), 'hh:mm:ss')
this.day = this.$TOOL.dateFormat(new Date(), 'yyyy年MM月dd日')
}
}
}
</script>
<style scoped>
.item-background {background: linear-gradient(to right, #8E54E9, #4776E6);color: #fff;}
.time h2 {font-size: 40px;}
.time p {font-size: 14px;margin-top: 13px;opacity: 0.7;}
</style>

View File

@ -0,0 +1,33 @@
<template>
<el-card shadow="hover" header="版本信息">
<div style="height: 210px;text-align: center;">
<img src="img/ver.svg" style="height:140px"/>
<h2 style="margin-top: 15px;">SCUI {{$CONFIG.CORE_VER}}</h2>
</div>
<div style="margin-top: 20px;">
<el-button type="primary" plain round @click="golog">更新日志</el-button>
<el-button type="primary" plain round @click="gogit">gitee</el-button>
</div>
</el-card>
</template>
<script>
export default {
title: "版本信息",
icon: "el-icon-monitor",
description: "当前项目版本信息",
data() {
return {
}
},
methods: {
golog(){
window.open("https://gitee.com/lolicode/scui/releases")
},
gogit(){
window.open("https://gitee.com/lolicode/scui")
}
}
}
</script>

View File

@ -0,0 +1,59 @@
<template>
<el-card shadow="hover" header="欢迎">
<div class="welcome">
<div class="logo">
<img src="img/logo.png">
<h2>欢迎体验 SCUI</h2>
</div>
<div class="tips">
<div class="tips-item">
<div class="tips-item-icon"><i class="el-icon-menu"></i></div>
<div class="tips-item-message">这里是项目控制台你可以点击右上方的自定义按钮来添加移除或者移动部件</div>
</div>
<div class="tips-item">
<div class="tips-item-icon"><i class="el-icon-s-promotion"></i></div>
<div class="tips-item-message">在提高前端算力减少带宽请求和代码执行力上多次优化并且持续着</div>
</div>
<div class="tips-item">
<div class="tips-item-icon"><i class="el-icon-milk-tea"></i></div>
<div class="tips-item-message">项目目的让前端工作更快乐</div>
</div>
</div>
<div class="actions">
<el-button type="primary" icon="el-icon-check" size="medium" @click="godoc">文档</el-button>
</div>
</div>
</el-card>
</template>
<script>
export default {
title: "欢迎",
icon: "el-icon-present",
description: "项目特色以及文档链接",
data() {
return {
}
},
methods: {
godoc(){
window.open("https://lolicode.gitee.io/scui-doc/")
}
}
}
</script>
<style scoped>
.welcome {}
.welcome .logo {text-align: center;}
.welcome .logo img {vertical-align: bottom;width: 100px;height: 100px;margin-bottom: 20px;}
.welcome .logo h2 {font-size: 30px;font-weight: normal;display: flex;align-items: center;justify-content: center;}
.tips {margin-top: 20px;padding:0 40px;}
.tips-item {display: flex;align-items: center;justify-content: center;padding:7.5px 0;}
.tips-item-icon {width: 40px;height:40px;display: flex;align-items: center;justify-content: center;border-radius: 50%;font-size: 18px;margin-right: 20px;color: var(--el-color-primary);background: rgba(180,180,180,0.1);}
.tips-item-message {flex: 1;font-size: 14px;}
.actions {text-align: center;margin: 40px 0 20px 0;}
</style>

View File

@ -0,0 +1,214 @@
<template>
<div :class="['widgets-home', customizing?'customizing':'']" ref="main">
<div class="widgets-content">
<div class="widgets-top">
<div class="widgets-top-title">
控制台
</div>
<div class="widgets-top-actions">
<el-button v-if="customizing" type="primary" icon="el-icon-check" round @click="save">完成</el-button>
<el-button v-else type="primary" icon="el-icon-edit" round @click="custom">自定义</el-button>
</div>
</div>
<div class="widgets" ref="widgets">
<div class="widgets-wrapper">
<div v-if="nowCompsList.length<=0" class="no-widgets">
<el-empty image="img/no-widgets.svg" description="没有部件啦" :image-size="280"></el-empty>
</div>
<el-row :gutter="15">
<el-col v-for="(item, index) in grid.layout" v-bind:key="index" :md="item" :xs="24">
<draggable v-model="grid.copmsList[index]" animation="200" handle=".customize-overlay" group="people" item-key="com" dragClass="aaaaa" force-fallback fallbackOnBody class="draggable-box">
<template #item="{ element }">
<div class="widgets-item">
<component :is="allComps[element]"></component>
<div v-if="customizing" class="customize-overlay">
<el-button class="close" type="danger" plain icon="el-icon-close" size="small" @click="remove(element)"></el-button>
<label><i :class="allComps[element].icon"></i>{{ allComps[element].title }}</label>
</div>
</div>
</template>
</draggable>
</el-col>
</el-row>
</div>
</div>
</div>
<div v-if="customizing" class="widgets-aside">
<el-container>
<el-header style="border: 0;">
<div class="widgets-aside-title"><i class="el-icon-circle-plus"></i>添加部件</div>
<div class="widgets-aside-close" @click="close()"><i class="el-icon-close"></i></div>
</el-header>
<el-main class="nopadding">
<div class="widgets-list">
<div v-if="myCompsList.length<=0" class="widgets-list-nodata">
<el-empty description="没有部件啦" :image-size="60"></el-empty>
</div>
<div v-for="item in myCompsList" :key="item.title" class="widgets-list-item">
<div class="item-logo"><i :class="item.icon"></i></div>
<div class="item-info">
<h2>{{ item.title }}</h2>
<p>{{ item.description }}</p>
</div>
<div class="item-actions">
<el-button type="primary" icon="el-icon-plus" size="small" @click="push(item)"></el-button>
</div>
</div>
</div>
</el-main>
<el-footer style="height:51px;">
<el-button size="mini" @click="backDefaul()">恢复默认</el-button>
</el-footer>
</el-container>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import allComps from './components'
export default {
components: {
draggable
},
data() {
return {
customizing: false,
allComps: allComps,
selectLayout: [],
defaultGrid: this.$CONFIG.DEFAULT_GRID,
grid: []
}
},
created(){
this.grid = this.$TOOL.data.get("grid") || JSON.parse(JSON.stringify(this.defaultGrid))
},
mounted() {
this.$emit('on-mounted')
},
computed: {
allCompsList(){
var allCompsList = []
for(var key in this.allComps){
allCompsList.push({
key: key,
title: allComps[key].title,
icon: allComps[key].icon,
description: allComps[key].description
})
}
var myCopmsList = this.grid.copmsList.reduce(function(a, b){return a.concat(b)})
for(let comp of allCompsList){
const _item = myCopmsList.find((item)=>{return item === comp.key})
if(_item){
comp.disabled = true
}
}
return allCompsList
},
myCompsList(){
return this.allCompsList.filter(item => !item.disabled )
},
nowCompsList(){
return this.grid.copmsList.reduce(function(a, b){return a.concat(b)})
}
},
methods: {
//
custom(){
this.customizing = true
const oldWidth = this.$refs.widgets.offsetWidth
this.$nextTick(() => {
const scale = this.$refs.widgets.offsetWidth / oldWidth
this.$refs.widgets.style.setProperty('transform', `scale(${scale})`)
})
},
//
push(item){
let target = this.grid.copmsList[0]
if(this.grid.copmsList[0].length == 0){
target = this.grid.copmsList[0]
}else if(this.grid.copmsList[1].length == 0){
target = this.grid.copmsList[1]
}else if(this.grid.copmsList[2].length == 0){
target = this.grid.copmsList[2]
}
target.push(item.key)
},
//
remove(item){
var newCopmsList = this.grid.copmsList
newCopmsList.forEach((obj, index) => {
var newObj = obj.filter(o=>o!=item)
newCopmsList[index] = newObj;
})
},
//
save(){
this.customizing = false
this.$refs.widgets.style.removeProperty('transform')
this.$TOOL.data.set("grid", this.grid)
},
//
backDefaul(){
this.customizing = false
this.$refs.widgets.style.removeProperty('transform')
this.grid = JSON.parse(JSON.stringify(this.defaultGrid))
this.$TOOL.data.remove("grid")
},
//
close(){
this.customizing = false
this.$refs.widgets.style.removeProperty('transform')
}
}
}
</script>
<style scoped lang="scss">
.widgets-home {display: flex;flex-direction: row;flex: 1;height: 100%;}
.widgets-content {flex: 1;overflow: auto;overflow-x:hidden;padding:15px;}
.widgets-aside {width: 360px;background: #fff;box-shadow: 0 0 10px rgba(0,0,0,.1);position: relative;overflow: auto;}
.widgets-aside-title {font-size: 14px;display: flex;align-items: center;justify-content: center;}
.widgets-aside-title i {margin-right: 10px;font-size: 18px;}
.widgets-aside-close {font-size: 18px;width:30px;height: 30px;display: flex;align-items: center;justify-content: center;border-radius: 3px;cursor: pointer;}
.widgets-aside-close:hover {background: rgba(180,180,180,0.1);}
.widgets-top {margin-bottom: 15px;display: flex;justify-content: space-between;align-items: center;}
.widgets-top-title {font-size: 18px;font-weight: bold;}
.widgets {transform-origin: top left;transition: transform .15s;}
.draggable-box {height: 100%;}
.customizing .widgets-wrapper {margin-right:-360px}
.customizing .widgets-item {position: relative;margin-bottom: 15px;}
.customize-overlay {position: absolute;top:0;right:0;bottom:0;left:0;z-index: 1;display: flex;flex-direction: column;align-items: center;justify-content: center;background: rgba(255,255,255,0.9);cursor: move;}
.customize-overlay label {background: var(--el-color-primary);color: #fff;height:40px;padding:0 30px;border-radius: 40px;font-size: 18px;display: flex;align-items: center;justify-content: center;cursor: move;}
.customize-overlay label i {margin-right: 15px;font-size: 24px;}
.customize-overlay .close {position: absolute;top:15px;right:15px;}
.customize-overlay .close:focus, .customize-overlay .close:hover {background: var(--el-button-hover-color);}
.widgets-list {}
.widgets-list-item {display: flex;flex-direction: row;padding:15px;align-items: center;}
.widgets-list-item .item-logo {width: 40px;height: 40px;border-radius: 50%;background: rgba(180,180,180,0.1);display: flex;align-items: center;justify-content: center;font-size: 18px;margin-right: 15px;color: #6a8bad;}
.widgets-list-item .item-info {flex: 1;}
.widgets-list-item .item-info h2 {font-size: 16px;font-weight: normal;cursor: default;}
.widgets-list-item .item-info p {font-size: 12px;color: #999;cursor: default;}
.widgets-list-item:hover {background: rgba(180,180,180,0.1);}
.widgets-wrapper .sortable-ghost {opacity: 0.5;}
[data-theme=dark] {
.widgets-aside {background: #2b2b2b;}
.customize-overlay {background: rgba(43,43,43,0.9);}
}
@media (max-width: 992px){
.customizing .widgets {transform: scale(1) !important;}
.customizing .widgets-aside {width: 100%;position: absolute;top:50%;right:0;bottom:0;}
.customizing .widgets-wrapper {margin-right:0;}
}
</style>

View File

@ -11,6 +11,9 @@
<el-tab-pane label="user">
<pre class="code">{{json.user}}</pre>
</el-tab-pane>
<el-tab-pane label="token">
<pre class="code">{{json.token}}</pre>
</el-tab-pane>
<el-tab-pane label="grid">
<pre class="code">{{json.grid}}</pre>
</el-tab-pane>
@ -34,6 +37,7 @@
title: "CMD",
json: {
user: null,
token: null,
grid: null,
config: null,
api: null,
@ -41,7 +45,8 @@
}
},
created() {
this.json.user = this.$TOOL.data.get("user");
this.json.user = this.$TOOL.data.get("USER_INFO");
this.json.token = this.$TOOL.data.get("TOKEN");
this.json.grid = this.$TOOL.data.get("grid")||'null';
this.json.config = this.$CONFIG;
this.json.api = this.$API;

View File

@ -1,17 +1,30 @@
<template>
<el-main>
<el-card shadow="never">
<h2 style="margin-bottom: 20px;">v-auth 高精度权限控制</h2>
<el-card shadow="never" header="v-auth 高精度权限控制">
<el-button v-auth="'user.add'" type="primary">v-auth="'user.add'"</el-button>
<el-button v-auth="['user.no','user.add']" type="primary">v-auth="['user.no','user.add']"</el-button>
<el-alert title="v-auth指令 是$AUTH的语法糖, 原先需要使用v-if来判断是否有权限, 使用指令将减少代码冗余. 并且支持传入数组,有一项满足就判断有权限" style="margin-top: 20px;"></el-alert>
</el-card>
<el-card shadow="never" style="margin-top: 15px;">
<h2 style="margin-bottom: 20px;">v-role 角色权限控制</h2>
<el-card shadow="never" header="v-role 角色权限控制" style="margin-top: 15px;">
<el-button v-role="'admin'" type="primary">v-role="'admin'"</el-button>
<el-button v-role="['SA','admin']" type="primary">v-role="['SA','admin']"</el-button>
<el-alert title="v-role指令 是$ROLE的语法糖, 原理是判断是否含有用户所在的角色别名" style="margin-top: 20px;"></el-alert>
</el-card>
<el-card shadow="never" header="v-time 时间转换" style="margin-top: 15px;">
<p>
<el-tag v-time="1630117968295" format="yyyy-MM-dd hh:mm:ss"></el-tag>
</p>
<p style="margin-top: 15px;">
<el-tag v-time.tip="time1"></el-tag>
</p>
<p style="margin-top: 15px;">
<el-tag v-time.tip="time2"></el-tag>
</p>
<p style="margin-top: 15px;">
<el-tag v-time.tip="time3"></el-tag>
</p>
<el-alert title="指令方式日期时间转换,如设置'tip'修饰符将会转换成相对时间,并且每60秒自动更新" style="margin-top: 20px;"></el-alert>
</el-card>
</el-main>
</template>
@ -19,7 +32,11 @@
export default {
name: 'directive',
data() {
return {}
return {
time1: new Date(),
time2: new Date().setMinutes(new Date().getMinutes()-1),
time3: new Date().setMinutes(new Date().getMinutes()-120)
}
},
created() {

View File

@ -42,7 +42,8 @@
},
data() {
return {
mapLoading: false
mapLoading: false,
option: {}
}
},
mounted() {

View File

@ -97,6 +97,7 @@
this.$TOOL.data.remove("USER_INFO")
this.$TOOL.data.remove("MENU")
this.$TOOL.data.remove("PERMISSIONS")
this.$TOOL.data.remove("grid")
this.$store.commit("clearViewTags")
this.$store.commit("clearKeepLive")
this.$store.commit("clearIframeList")

View File

@ -0,0 +1,28 @@
<template>
<sc-dialog v-model="visible" title="提示" @closed="$emit('closed')">
内容1
<template #footer>
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="visible = false"> </el-button>
</template>
</sc-dialog>
</template>
<script>
export default {
data() {
return {
visible: true
}
},
mounted() {
console.log("加载./dialog1组件完成")
},
methods: {
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,28 @@
<template>
<sc-dialog v-model="visible" title="提示" @closed="$emit('closed')">
内容2
<template #footer>
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="visible = false"> </el-button>
</template>
</sc-dialog>
</template>
<script>
export default {
data() {
return {
visible: true
}
},
mounted() {
console.log("加载./dialog2组件完成")
},
methods: {
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,101 @@
<!--
* @Descripttion: scDialog 弹窗扩展演示文件
* @version: 1.0
* @Author: sakuya
* @Date: 2021年8月27日08:56:30
* @LastEditors:
* @LastEditTime:
-->
<template>
<el-main>
<el-alert title="二次封装el-dialog,加入拖拽/加载中/最大化." type="success" style="margin:0 0 20px 0;"></el-alert>
<el-card shadow="never" header="内置">
<el-button type="primary" @click="open1">默认</el-button>
<el-button type="primary" @click="open2">加载</el-button>
<el-button type="primary" @click="open3">禁止拖拽最大化和关闭</el-button>
</el-card>
<el-card shadow="never" header="异步" style="margin-top: 15px;">
<el-button type="primary" @click="asyn1">异步加载1</el-button>
<el-button type="primary" @click="asyn2">异步加载2</el-button>
<el-alert title="适用于页面有很多弹窗操作,利用异步组件按需加载,加快首屏的加载速度和打包体积" style="margin-top: 20px;"></el-alert>
</el-card>
</el-main>
<sc-dialog v-model="dialog1" title="提示">
内容
<template #footer>
<el-button @click="dialog1 = false"> </el-button>
<el-button type="primary" @click="dialog1 = false"> </el-button>
</template>
</sc-dialog>
<sc-dialog v-model="dialog2" title="模拟加载" :width="400" :loading="dialog2Loading">
<el-empty description="NO Data" :image-size="80"></el-empty>
<template #footer>
<el-button @click="dialog2 = false"> </el-button>
<el-button type="primary" @click="dialog2 = false" :loading="dialog2Loading"> </el-button>
</template>
</sc-dialog>
<sc-dialog v-model="dialog3" title="禁用拖拽" :drag="false" :show-fullscreen="false" :show-close="false">
内容
<template #footer>
<el-button @click="dialog3 = false"> </el-button>
<el-button type="primary" @click="dialog3 = false"> </el-button>
</template>
</sc-dialog>
<dialog1 v-if="asynDialog1" @closed="asynDialog1 = false"></dialog1>
<dialog2 v-if="asynDialog2" @closed="asynDialog2 = false"></dialog2>
</template>
<script>
import { defineAsyncComponent } from 'vue'
export default {
name: 'dialogExtend',
components: {
dialog1: defineAsyncComponent(() => import("./dialog1")),
dialog2: defineAsyncComponent(() => import("./dialog2"))
},
data() {
return {
dialog1: false,
dialog2: false,
dialog3: false,
dialog2Loading: false,
asynDialog1: false,
asynDialog2: false,
}
},
mounted() {
},
methods: {
open1(){
this.dialog1 = true
},
open2(){
this.dialog2 = true
this.dialog2Loading = true
setTimeout(()=>{
this.dialog2Loading = false
}, 1000)
},
open3(){
this.dialog3 = true
},
asyn1(){
this.asynDialog1 = true
},
asyn2(){
this.asynDialog2 = true
}
}
}
</script>
<style>
</style>