Compare commits

..

67 Commits

Author SHA1 Message Date
管理员 94f7d67452 . 3 months ago
管理员 5d5063a291 update 修改配置和脚本 4 months ago
管理员 f5a7b75f0a fix . 4 months ago
管理员 aebd46af2e update 重写ruoyi-mqtt模块 4 months ago
管理员 5c6a78a3bd update bi改动添加组件 5 months ago
管理员 e066d17483 fix . 5 months ago
管理员 8dcd0bea7e update apifox基础 7 months ago
管理员 adaac86f04 update 在线编辑器定义可配置的源文件source属性 8 months ago
管理员 7251f6a8e9 update 小改 8 months ago
管理员 423087ff59 update 组件 8 months ago
管理员 2fffc12f5c fix . 8 months ago
管理员 ad5db54094 update . 8 months ago
管理员 40e7e5aa96 update . 8 months ago
管理员 7090c6e4c7 update 重写管理端默认效果 8 months ago
管理员 e97bf21780 update . 8 months ago
管理员 38be2a9427 update 大屏进入加载效果 8 months ago
管理员 3a3e4e1786 fix 修复文件上传和图片上传组件max=1时的错误,并增加list属性控制是否显示列表 8 months ago
管理员 19ff36d040 fix . 8 months ago
管理员 7d9141bcb6 update . 8 months ago
管理员 605c0bc184 update . 9 months ago
管理员 3e1dd0d21b fix sse 10 months ago
管理员 d1fb3008a5 fix bug and WEcharts.vue 10 months ago
管理员 a4dd16682c update 单位换算 10 months ago
管理员 b264e46bdb update 单位换算 10 months ago
管理员 952ac01944 update public style 10 months ago
管理员 093ad26cc1 fix 修复sse连接断开后的异常输出 10 months ago
管理员 bfdde738d0 update 组件 10 months ago
管理员 fe7085da07 . 10 months ago
管理员 1b89eda79c update 每秒事件,动态配置工具类 10 months ago
管理员 5154a08a0e update . 10 months ago
管理员 4a7a2b7d15 feat 动态配置 10 months ago
管理员 3d4abe7a19 update 自定义飞线组件 10 months ago
管理员 4ac6bae1e2 fix test-enter 11 months ago
管理员 f1b889539a feat 新增基础工程对大屏的支持 11 months ago
管理员 a40fb073c0 fix 修复date_id长度问题 11 months ago
管理员 a82b2dbc79 update w-button 11 months ago
管理员 33ba845ddc update @Dev 12 months ago
管理员 4983d8d821 feat 新增SSE的支持,并编写示例代码 12 months ago
管理员 3259db4673 update 固定uniapp依赖版本 12 months ago
管理员 f2d2631ce9 update SSE支持添加根据条件发送的方法 12 months ago
管理员 92bee706ff fix delete console 12 months ago
管理员 32038b94db fix 修改实时日志显示 12 months ago
管理员 a3a418ad1b update 使用SSE重写实时定时任务日志输出 12 months ago
管理员 9ee30e5de3 update 带类型的SSE和带action的消息支持 12 months ago
管理员 6822f0a7a8 update 修改ES版本到ES2020 12 months ago
管理员 bf0a8ba598 feat 新增测试页面 12 months ago
管理员 4b38019237 update open:false,port:8888 12 months ago
管理员 9e0b455e8f update mjs 12 months ago
管理员 eb6f7880c0 update 升级前端部分版本 12 months ago
管理员 f32f2408f5 update px2rem 12 months ago
管理员 09e7fc82de feat WSwitch.vue 1 year ago
管理员 1edc1f4bd5 update . 1 year ago
管理员 95b658b4a0 update crypto 1 year ago
管理员 070ccc8610 update 修复多个小文件上传bug 1 year ago
管理员 cdc6544cc4 update . 1 year ago
管理员 854218aaad fix 文件上传 1 year ago
管理员 46f3f49e06 update db-backup.sh 1 year ago
管理员 b6102cfe45 update 1 year ago
管理员 294a85abc5 update 增强图片文件上传功能修复图片删除bug 1 year ago
管理员 96d38ce0a8 update 重写水印图片获取逻辑 1 year ago
管理员 42408657be fix 修复自定义mybaits-plus的主键生成器bug 1 year ago
管理员 c6d2dc78ac upload UploadController 1 year ago
管理员 b3e324f797 update 上传图片对象 1 year ago
管理员 ebd9fcfaba fix 修改设置前缀问题 1 year ago
管理员 bff4d692e5 update 上传组件小改,配置 1 year ago
管理员 8de5f162cd update 修改验证码字符为纯数字 1 year ago
管理员 516e479187 update 修改docker-compose配置 1 year ago

@ -1,6 +1,12 @@
# 页面标题
VITE_APP_TITLE = 某某系统
VITE_APP_TITLE = 管理中心
VITE_APP_COPY = Copyright © 2023 xxx.xxx.cn All Rights Reserved.
VITE_APP_COLOR = #257fbd
# 默认主题色,用户可用后台自行调节
VITE_APP_COLOR = "#20a0f1"
# 默认主题 light | dark
VITE_APP_THEME = "dark"
# 管理端暗黑主题色
VITE_APP_ADMIN_DARK = "#222"
# 管理端明亮主题色
VITE_APP_ADMIN_LIGHT = "#EfEfEf"

@ -14,34 +14,40 @@
"url": "https://gitee.com/JavaLionLi/RuoYi-Vue-Plus-UI.git"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@microsoft/fetch-event-source": "2.0.1",
"@element-plus/icons-vue": "2.3.1",
"@vueup/vue-quill": "1.1.0",
"@vueuse/core": "9.5.0",
"@vueuse/components": "^12.7.0",
"@vueuse/core": "^12.7.0",
"axios": "0.27.2",
"crypto-js": "4.2.0",
"echarts": "5.4.0",
"element-plus": "^2.8.4",
"element-plus": "2.9.2",
"file-saver": "2.0.5",
"fuse.js": "6.6.2",
"js-cookie": "3.0.1",
"highlight.js": "^11.11.1",
"jsencrypt": "3.3.1",
"mescroll.js": "^1.4.2",
"mitt": "^3.0.1",
"mescroll.js": "1.4.2",
"mitt": "3.0.1",
"normalize.css": "^8.0.1",
"nprogress": "0.2.0",
"pinia": "2.0.22",
"pinia-plugin-persist": "^1.0.0",
"spark-md5": "^3.0.2",
"vue": "3.2.45",
"pinia-plugin-persist": "1.0.0",
"spark-md5": "3.0.2",
"vue": "3.5.13",
"vue-cropper": "1.0.3",
"vue-router": "4.1.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "3.1.0",
"@vitejs/plugin-vue": "4.6.2",
"@vue/compiler-sfc": "3.2.45",
"postcss-plugin-px2rem": "0.8.1",
"sass": "1.56.1",
"unplugin-auto-import": "0.11.4",
"vite": "3.2.7",
"vite": "5.4.11",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-setup-extend": "0.4.0"
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,172 @@
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { getToken } from '@/utils/auth'
/**
* @description: 创建sse连接
*/
class ServerSentEvents {
static defaultConfig = {
base: import.meta.env.VITE_APP_BASE_API, // 基础地址
url: '/sse', // 地址
data: undefined, // 请求正文
params: undefined, // 请求参数
method: 'get', // 提交方式
auth: true, // 是否携带token
json: true, // 是否返回json
returnData: false, // json数据是否返回data属性
reconnect: true, //是否重连
headers: {
'Content-Type': 'application/json'
},
onopen: () => { },
onmessage: () => { },
onerror: () => { },
onclose: () => { }
}
constructor(config) {
if (config) {
this.setConfig(config)
this.init()
}
}
static get(url, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
return new ServerSentEvents(config)
}
static post(url, data, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
config.method = 'post'
config.data = data
return new ServerSentEvents(config)
}
setConfig(config) {
this.config = {
ctrl: new AbortController(),
...ServerSentEvents.defaultConfig,
...config
}
}
init() {
if (this.config.auth) {
this.config.headers.Authorization = 'Bearer ' + getToken()
}
let url = this.config.url
// 如果url不含协议
if (url.indexOf("//") == -1) {
url = this.config.base + url
}
if (this.config.params) {
if (url.indexOf("?") > -1) {
url += '&' + this.params(this.config.params)
} else {
url += '?' + this.params(this.config.params)
}
}
let body = undefined
if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
if (this.config.data.constructor == URLSearchParams) {
this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
body = this.params(this.config.data).toString()
} else if (this.config.data.constructor == FormData) {
this.config.headers['Content-Type'] = 'multipart/form-data'
body = this.config.data
} else {
body = JSON.stringify(body)
}
}
this.config._url = url
this.config._body = body
console.debug(this.config)
this.send()
}
send() {
fetchEventSource(this.config._url, {
method: this.config.method,
headers: this.config.headers,
body: this.config._body,
signal: this.config.ctrl.signal,
onopen: this.config.onopen,
onmessage: (msg) => {
if (this.config.json) {
let data = JSON.parse(msg.data)
if (this.config.returnData) {
data = data.data
}
this.config.onmessage(data)
} else {
this.config.onmessage(msg)
}
},
onclose: () => {
console.info('onclose')
this.abort()
this.config.onclose()
if (this.config.reconnect) {
this.send()
}
},
onerror: (err) => {
console.error(err)
this.abort()
this.config.onerror(err)
}
})
}
abort() {
if (this.config.ctrl && !this.config.reconnect) {
try {
this.config.ctrl.abort()
} catch (e) {
console.error(e)
}
}
}
close() {
this.abort()
}
params(param) {
if (param == null || param == "") {
return new URLSearchParams();
}
if (param.constructor == Array) {
let param1 = new URLSearchParams();
for (let obj of param) {
param1.append(obj.name, obj.value);
}
param = param1;
} else if (param.constructor == Object) {
let param1 = new URLSearchParams();
for (let name in param) {
param1.append(name, param[name]);
}
param = param1;
} else {
if (param.constructor == HTMLFormElement) {
param = new FormData(param);
}
if (param.constructor == FormData || param.constructor == String) {
param = new URLSearchParams(param);
}
}
return param;
}
}
export default ServerSentEvents

@ -11,7 +11,7 @@ body {
--left-img: url(../images/login.png);
background-color: var(--bg);
background-image: linear-gradient(-25deg, #FFF0 30%, #FFF2 50%, #FFF0 70%), linear-gradient(to top, var(--bg),var(--bg));
width: 100%;
height: 100%;
font-size: var(--size);
@ -19,6 +19,17 @@ body {
justify-content: center;
align-items: center;
overflow: hidden;
position: relative;
&::before {
content: '';
position: absolute;
inset: 0;
background-image: radial-gradient(circle, #0001 .1em, #0000 1em,#0000 100%);
background-size: 2em 2em;
filter: url(#WEffectNoiseBgFilter);
transform: scale(2);
}
&>.w-login-outer {
position: relative;
@ -34,13 +45,24 @@ body {
box-shadow: 0 0 1em #0003;
&> :first-child {
background-image: var(--left-img), linear-gradient(to bottom,var(--el-color-primary-light-9) 15%, var(--el-color-primary-light-8) 50%, var(--el-color-primary-light-3));
background-size: 70% auto, 100% 100%;
background-position: center center;
background-repeat: no-repeat;
position: relative;
box-shadow: -.3em 0 .6em #0001 inset;
background-image: radial-gradient(circle, #FFFFFF16 1px, #FFF0 1px,#FFF0 100%) ,linear-gradient(to bottom, var(--el-color-primary-light-9) 15%, var(--el-color-primary-light-8) 50%, var(--el-color-primary-light-3));
background-size: 5px 5px, auto;
overflow: hidden;
opacity: .85;
&::after {
position: absolute;
inset: 0;
content:'';
background-image: var(--left-img);
background-size: 70% auto;
background-position: center;
background-repeat: no-repeat;
z-index: 2;
}
&::before {
position: absolute;
@ -49,12 +71,21 @@ body {
top: calc(50% - 2em);
box-shadow: -.3em .3em .6em #0001;
transform: scaleX(.8) rotate(45deg);
z-index: 3;
width: 4em;
height: 4em;
content: '';
}
&>div {
position: absolute;
inset: 0;
z-index: 1;
background-color: #0000;
background-image: radial-gradient(circle, #FFFFFF16 1px, #FFF0 1px,#FFF0 100%);
background-size: 5px 5px;
}
}
.w-login-form {
@ -134,54 +165,24 @@ body {
}
&>.h2 {
margin-top: 0.6em;
margin-top: 0.7em;
display: flex;
justify-content: space-between;
align-items: center;
color: var(--primary-color);
& label:has(input[type="checkbox"]) {
margin-top: .3em;
font-size: .9em;
--color: #aaa;
color: var(--color);
display: flex;
justify-content: flex-start;
align-items: center;
cursor: pointer;
font-weight: normal;
&::before {
content: "";
background-color: var(--color);
border: .13em solid var(--color);
box-sizing: border-box;
padding: .17em;
background-clip: content-box;
height: 1em;
width: 1em;
margin-right: .3em;
border-radius: 2em;
}
&>input[type="checkbox"] {
display: none;
}
* {
font-size: .8rem;
}
& label:has(input[type="checkbox"]:checked) {
--color: var(--primary-color);
}
& label:hover {
filter: brightness(0.8);
}
& a {
color: var(--primary-color);
&>div>div, a {
text-decoration: none;
&:hover {
filter: brightness(0.7);
filter: brightness(1.1);
}
&:active {
filter: brightness(.9);
}
}
}

@ -0,0 +1 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M156.608 487.86c1.156-1.138 2.649-1.623 3.919-2.56l306.667-301.569c13.195-12.97 34.586-12.97 47.78 0a32.836 32.836 0 010 46.988L263.303 478.21h579.204c18.978 0 34.362 15.129 34.362 33.79 0 18.662-15.384 33.793-34.362 33.793H263.302L514.974 793.28a32.832 32.832 0 010 46.985c-13.195 12.974-34.587 12.974-47.781 0L160.526 538.703c-1.27-.94-2.763-1.422-3.92-2.562-6.334-6.23-9.24-14.34-9.476-22.503.237-11.437 3.143-19.547 9.478-25.779zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 563 B

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569915748289" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3062" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M768.35456 416a256 256 0 1 0-512 0 192 192 0 1 0 0 384v64a256 256 0 0 1-58.88-505.216 320.128 320.128 0 0 1 629.76 0A256.128 256.128 0 0 1 768.35456 864v-64a192 192 0 0 0 0-384z m-512 384h64v64H256.35456v-64z m448 0h64v64h-64v-64z" fill="#333333" p-id="3063"></path><path d="M539.04256 845.248V512.192a32.448 32.448 0 0 0-32-32.192c-17.664 0-32 14.912-32 32.192v333.056l-36.096-36.096a32.192 32.192 0 0 0-45.056 0.192 31.616 31.616 0 0 0-0.192 45.056l90.88 90.944a31.36 31.36 0 0 0 22.528 9.088 30.08 30.08 0 0 0 22.4-9.088l90.88-90.88a32.192 32.192 0 0 0-0.192-45.12 31.616 31.616 0 0 0-45.056-0.192l-36.096 36.096z" fill="#333333" p-id="3064"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569915748289" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3062" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M768.35456 416a256 256 0 1 0-512 0 192 192 0 1 0 0 384v64a256 256 0 0 1-58.88-505.216 320.128 320.128 0 0 1 629.76 0A256.128 256.128 0 0 1 768.35456 864v-64a192 192 0 0 0 0-384z m-512 384h64v64H256.35456v-64z m448 0h64v64h-64v-64z" p-id="3063"></path><path d="M539.04256 845.248V512.192a32.448 32.448 0 0 0-32-32.192c-17.664 0-32 14.912-32 32.192v333.056l-36.096-36.096a32.192 32.192 0 0 0-45.056 0.192 31.616 31.616 0 0 0-0.192 45.056l90.88 90.944a31.36 31.36 0 0 0 22.528 9.088 30.08 30.08 0 0 0 22.4-9.088l90.88-90.88a32.192 32.192 0 0 0-0.192-45.12 31.616 31.616 0 0 0-45.056-0.192l-36.096 36.096z" p-id="3064"></path></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1005 B

@ -0,0 +1 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M576 192v128h64V160a32 32 0 00-32-32H96a32 32 0 00-32 32v704a32 32 0 0032 32h512a32 32 0 0032-32V704h-64v128H128V192h448z"/><path d="M718.848 336.256L862.528 480H384v64h478.528l-143.68 143.744 45.248 45.248 198.336-198.4a32 32 0 000-45.248l-198.4-198.336-45.184 45.248z"/></svg>

After

Width:  |  Height:  |  Size: 395 B

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1738984125918" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4325" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 0a512 512 0 1 0 512 512A512.602869 512.602869 0 0 0 512 0zM93.170627 512A419.541854 419.541854 0 0 1 512 93.170627v837.877971A419.541854 419.541854 0 0 1 93.170627 512z" p-id="4326"></path></svg>

After

Width:  |  Height:  |  Size: 533 B

@ -1 +1,11 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802846045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.593046 403.832442c-30.081109-28.844955-70.037123-44.753273-112.624057-44.753273L265.949606 359.079168c-42.554188 0-82.510202 15.908318-112.469538 44.690852-30.236652 28.782533-46.857191 67.222007-46.857191 108.198258l0 294.079782c0 40.977273 16.619516 79.414701 46.702672 108.136859 29.959336 28.844955 70.069869 44.814672 112.624057 44.814672l490.019383 0c42.585911 0 82.696444-15.969717 112.624057-44.814672 30.082132-28.844955 46.579875-67.222007 46.579875-108.136859L915.172921 511.968278C915.171897 471.053426 898.675178 432.677397 868.593046 403.832442zM841.821309 806.049083c0 22.098297-8.882298 42.772152-25.099654 58.306964-16.154935 15.661701-37.81935 24.203238-60.752666 24.203238L265.949606 888.559285c-22.934339 0-44.567032-8.54256-60.877509-24.264637-16.186657-15.474436-25.067932-36.148291-25.067932-58.246589L180.004165 511.968278c0-22.035876 8.881274-42.772152 25.192775-58.307987 16.186657-15.536858 37.81935-24.139793 60.753689-24.139793l490.019383 0c22.933315 0 44.597731 8.602935 60.752666 24.139793 16.21838 15.535835 25.099654 36.272112 25.099654 58.307987L841.822332 806.049083zM510.974136 135.440715c114.914216 0 208.318536 89.75214 208.318536 200.055338l73.350588 0c0-149.113109-126.366036-270.496667-281.669124-270.496667-155.333788 0-281.699824 121.383558-281.699824 270.496667l73.350588 0C302.623877 225.193879 396.059919 135.440715 510.974136 135.440715zM474.299865 747.244792l73.350588 0L547.650453 629.576859l-73.350588 0L474.299865 747.244792z" p-id="2751"></path></svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802846045"
class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750"
xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path
d="M868.593046 403.832442c-30.081109-28.844955-70.037123-44.753273-112.624057-44.753273L265.949606 359.079168c-42.554188 0-82.510202 15.908318-112.469538 44.690852-30.236652 28.782533-46.857191 67.222007-46.857191 108.198258l0 294.079782c0 40.977273 16.619516 79.414701 46.702672 108.136859 29.959336 28.844955 70.069869 44.814672 112.624057 44.814672l490.019383 0c42.585911 0 82.696444-15.969717 112.624057-44.814672 30.082132-28.844955 46.579875-67.222007 46.579875-108.136859L915.172921 511.968278C915.171897 471.053426 898.675178 432.677397 868.593046 403.832442zM841.821309 806.049083c0 22.098297-8.882298 42.772152-25.099654 58.306964-16.154935 15.661701-37.81935 24.203238-60.752666 24.203238L265.949606 888.559285c-22.934339 0-44.567032-8.54256-60.877509-24.264637-16.186657-15.474436-25.067932-36.148291-25.067932-58.246589L180.004165 511.968278c0-22.035876 8.881274-42.772152 25.192775-58.307987 16.186657-15.536858 37.81935-24.139793 60.753689-24.139793l490.019383 0c22.933315 0 44.597731 8.602935 60.752666 24.139793 16.21838 15.535835 25.099654 36.272112 25.099654 58.307987L841.822332 806.049083zM510.974136 135.440715c114.914216 0 208.318536 89.75214 208.318536 200.055338l73.350588 0c0-149.113109-126.366036-270.496667-281.669124-270.496667-155.333788 0-281.699824 121.383558-281.699824 270.496667l73.350588 0C302.623877 225.193879 396.059919 135.440715 510.974136 135.440715zM474.299865 747.244792l73.350588 0L547.650453 629.576859l-73.350588 0L474.299865 747.244792z"
p-id="2751"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M965.829 166.057l-64.458 50.4C813.486 104.114 676.8 32 523.314 32 258.286 32 43.771 246.286 43.43 511.429 43.086 776.8 258.057 992 523.314 992c207.2 0 383.772-131.429 450.972-315.543 1.714-4.8-.8-10.171-5.6-11.771l-64.8-22.286a9.143 9.143 0 00-11.543 5.486c-2.057 5.714-4.343 11.428-6.743 17.028-19.771 46.857-48.114 88.915-84.229 125.029a394.023 394.023 0 01-124.914 84.343c-48.343 20.457-99.886 30.857-152.914 30.857-53.143 0-104.572-10.4-152.914-30.857a390.286 390.286 0 01-124.915-84.343 391.04 391.04 0 01-84.228-125.029c-20.457-48.457-30.857-99.885-30.857-153.028s10.4-104.572 30.857-153.029C181.257 312 209.6 269.943 245.714 233.83c36.115-36.115 78.172-64.458 124.915-84.343 48.342-20.457 99.885-30.857 152.914-30.857 53.143 0 104.571 10.4 152.914 30.857a390.286 390.286 0 01124.914 84.343 393.912 393.912 0 0131.772 35.885l-68.8 53.715a9.143 9.143 0 003.428 16.114l200.686 49.143c5.714 1.371 11.314-2.972 11.314-8.8l.915-206.743c-.115-7.543-8.915-11.772-14.857-7.086z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M692.315 1023.925c-5.353-.768-10.712-1.562-16.065-2.305-24.26-3.385-45.779-12.973-65.03-28.089-22.698-17.82-38.17-40.475-47.108-67.84-4.485-13.729-6.652-27.833-6.677-42.13-.163-106.23-.088-212.458-.088-318.687v-7.533h7.215c107.778 0 215.562-.337 323.34.219 29.376.15 56.166 10.044 79.895 27.901 17.751 13.355 31.48 29.982 41.33 49.676 7.946 15.897 13.124 32.75 13.686 50.75.031.988.725 1.956 1.112 2.936v202.458c-.387 1.174-.918 2.317-1.143 3.517-1.886 10.23-2.83 20.737-5.74 30.662-8.208 27.958-24.754 50.47-47.503 68.458-18.994 15.022-40.5 24.342-64.535 27.702-5.353.75-10.7 1.537-16.053 2.305H692.315zM1023.931 333.94c-.774 4.772-1.586 9.544-2.317 14.322-3.698 24.192-13.348 45.71-28.539 64.88-12.192 15.39-27.008 27.714-44.254 36.77-14.291 7.503-29.57 13.037-45.853 14.236-13.255.974-26.584 1.218-39.882 1.23-99.452.094-198.904.05-298.362.05h-7.377v-6.79c0-107.209-.324-214.418.2-321.622.156-31.674 10.931-60.238 31.044-85.154 22.436-27.795 51.693-43.655 86.266-50.607 2.323-.468 4.666-.837 6.996-1.249h217.586c.78.388 1.524.906 2.348 1.137 12.549 3.435 25.535 5.747 37.577 10.475 23.648 9.288 42.605 25.147 57.521 45.728 13.011 17.952 21.537 37.796 24.741 59.826.7 4.785 1.537 9.544 2.312 14.316-.007 67.478-.007 134.962-.007 202.452zM0 683.008c1.537-7.12 2.873-14.291 4.66-21.343 4.915-19.432 13.872-36.803 26.533-52.406 17.583-21.668 39.633-36.621 66.085-45.203 13.686-4.441 27.758-6.684 42.143-6.69 105.842-.031 211.683-.019 317.525-.019h8.489v6.265c0 110.302.243 220.603-.219 330.898-.081 19.926-6.852 38.59-16.521 56.228-7.758 14.148-17.527 26.547-29.42 37.172-18.463 16.49-39.82 27.758-64.28 32.442-7.276 1.393-14.778 1.624-22.167 2.467-.818.094-1.574.731-2.361 1.112H134.993c-1.175-.387-2.336-1.099-3.517-1.112-19.182-.28-37.184-5.446-54.11-14.016-17.134-8.676-32.219-20.069-44.58-35.122-13.117-15.966-22.76-33.58-28.039-53.505-2.005-7.577-3.173-15.378-4.722-23.074C0 825.734 0 754.371 0 683.008M139.59 605.1zM340.923-.006c7.314 1.549 14.71 2.78 21.924 4.71 19.926 5.334 37.565 14.94 53.524 28.101 16.908 13.941 29.076 31.237 37.89 50.969 6.701 15.01 11.105 30.8 11.117 47.39.088 108.952.044 217.91.044 326.863v7.395h-6.196c-109.927 0-219.847.244-329.774-.212-21.38-.088-41.593-7.127-59.838-18.308-10-6.134-19.894-13.054-28.14-21.318-14.034-14.06-25.309-30.319-32.242-49.301-4.198-11.48-7.583-23.061-8.208-35.335-.018-.412-.662-.8-1.018-1.193V125.661c.388-.781.95-1.524 1.125-2.349 2.123-9.981 3.179-20.325 6.458-29.907 8.932-26.09 24.922-47.452 46.653-64.385C68.102 18.22 83.28 9.8 100.539 5.634c7.976-1.924 15.977-3.76 23.966-5.64h216.418m-13.03 46.815zm89.658 77.74z"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569580729849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M513.3 958.5c-142.2 0-397.9-222.1-401.6-440.5V268c1.7-39.6 31.7-72.3 71.1-77.3 49-4.6 97.1-16.5 142.7-35.3 47.8-14 91.9-38.3 129.4-71.1 30.3-24.4 72.9-26.3 105.3-4.6 39.9 30.7 83.8 55.9 130.5 74.6 48.6 14.7 98.2 25.9 148.4 33.7 38.5 7.6 67.1 40.3 69.5 79.5 3.3 84.9 2.5 169.9-2.6 254.7-33.7 281.6-253.7 436.4-392.7 436.3z m-0.1-813.7c-7.2-0.2-14.3 2-20 6.4-39.7 35.2-86.8 61.1-137.7 75.7-46.8 19.2-96.2 31-146.6 35.2-11 3.2-18.8 13-19.5 24.4v230.1c3.5 180.3 223.3 361 323.9 361s287.3-120.2 317.6-360.5c7.3-142.7 0-228.6 0-229.6-1.3-13.3-11-24.3-24-27.3-49.6-7.7-98.6-19-146.5-33.7-46.3-19.5-89.7-45.3-129-76.7-5.8-3.8-12.7-5.5-19.5-4.9l1.3-0.1z" fill="#C6CCDA" p-id="1940"></path><path d="M750.1 428L490.7 673.2c-11.7 11.1-29.5 12.9-43.1 4.2l-6.8-5.8-141.2-149.4c-9.3-9.3-12.7-22.9-9-35.5 3.8-12.6 14.1-22.1 27-24.8 12.9-2.7 26.1 1.9 34.6 11.9L469 597.5l233.7-221c14.6-12.8 36.8-11.6 49.9 2.7 13.2 14.2 11.5 35.3-2.5 48.8" fill="#C6CCDA" p-id="1941"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569580729849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M513.3 958.5c-142.2 0-397.9-222.1-401.6-440.5V268c1.7-39.6 31.7-72.3 71.1-77.3 49-4.6 97.1-16.5 142.7-35.3 47.8-14 91.9-38.3 129.4-71.1 30.3-24.4 72.9-26.3 105.3-4.6 39.9 30.7 83.8 55.9 130.5 74.6 48.6 14.7 98.2 25.9 148.4 33.7 38.5 7.6 67.1 40.3 69.5 79.5 3.3 84.9 2.5 169.9-2.6 254.7-33.7 281.6-253.7 436.4-392.7 436.3z m-0.1-813.7c-7.2-0.2-14.3 2-20 6.4-39.7 35.2-86.8 61.1-137.7 75.7-46.8 19.2-96.2 31-146.6 35.2-11 3.2-18.8 13-19.5 24.4v230.1c3.5 180.3 223.3 361 323.9 361s287.3-120.2 317.6-360.5c7.3-142.7 0-228.6 0-229.6-1.3-13.3-11-24.3-24-27.3-49.6-7.7-98.6-19-146.5-33.7-46.3-19.5-89.7-45.3-129-76.7-5.8-3.8-12.7-5.5-19.5-4.9l1.3-0.1z" p-id="1940"></path><path d="M750.1 428L490.7 673.2c-11.7 11.1-29.5 12.9-43.1 4.2l-6.8-5.8-141.2-149.4c-9.3-9.3-12.7-22.9-9-35.5 3.8-12.6 14.1-22.1 27-24.8 12.9-2.7 26.1 1.9 34.6 11.9L469 597.5l233.7-221c14.6-12.8 36.8-11.6 49.9 2.7 13.2 14.2 11.5 35.3-2.5 48.8" p-id="1941"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -20,10 +20,16 @@ label {
}
html {
font-size: 1vw;
height: 100%;
box-sizing: border-box;
}
@media screen and (max-width:1400px) {
html {
font-size: 14px;
}
}
#app {
height: 100%;
}
@ -202,87 +208,288 @@ fieldset {
border: var(--el-border-color) 1px solid;
}
@layer {
.w-abs {
position: absolute;
inset: 0;
}
.w-lines {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.w-flex {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
position: relative;
}
.w-flex-column {
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.w-lines {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.w-flex {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
position: relative;
}
.w-loading {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 1em;
border: .2em solid currentColor;
border-top-color: #0000;
animation: w-am-loading 1s infinite;
}
.w-flex-column {
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
@keyframes w-am-loading {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* 印章效果 */
.w-seal {
position: absolute;
display: flex;
line-height: 1;
justify-content: center;
align-items: center;
box-sizing: border-box;
width: 6em;
height: 6em;
border-radius: 10em;
border: .25em solid currentColor;
background-color: #FFF;
z-index: 1;
transform: rotate(-25deg);
padding: 0;
&>div {
border: .13em solid currentColor;
padding: .3em 0;
width: 4.3em;
text-align: center;
font-weight: bold;
}
.w-radio,
.w-checkbox {
--btn-color-inner: var(--btn-color,currentColor);
--opacity: .6;
transition: all .3s;
cursor: pointer;
&::before {
content: '';
font-size: var(--btn-size,inherit);
width: 1em;
height: 1em;
opacity: var(--opacity);
box-sizing: border-box;
border: solid 1px var(--btn-color-inner);
margin-right: .2em;
border-radius: .2em;
background-color: var(--btn-bg-color-inner,#0000);
background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNzA5NzA3MjQ5OTg3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQyODUiIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiI+PHBhdGggZD0iTTg0My42OTM5NTkgMjkzLjYwOTA2MSA0MjUuMjU1ODY5IDcxMi4wNTYzNjIgMTg2LjE0NTAyNiA0NzIuOTQ3NTY2IDY2LjU3OTg4MyA1OTIuNTA0NTIyIDQyNS4yNTU4NjkgOTUxLjE2NTE1OCA5NjMuMjYwMTI2IDQxMy4xNzQyMDRaIiBwLWlkPSI0Mjg2IiBmaWxsPSIjZmZmZmZmIj48L3BhdGg+PC9zdmc+");
background-size: .65em .65em;
background-repeat: no-repeat;
background-position: var(--background-position-inner,center -1em);
transition: all .3s;
overflow: hidden;
}
&.selected {
--btn-color-inner: var(--selected-btn-color, var(--w-main));
--opacity: 1;
--btn-bg-color-inner: var(--selected-btn-color, var(--w-main));
--background-position-inner: center .1em;
color: var(--selected-text-color, currentColor);
}
&::before {
content: "";
position: absolute;
width: 5em;
height: 5em;
border: .15em solid currentColor;
border-radius: 10em;
}
}
.w-radio::before {
border-radius: 1em;
}
&::after {
content: "";
position: absolute;
width: 3.5em;
height: 3.5em;
border: .15em solid currentColor;
border-color: currentColor #0000 currentColor #0000;
border-radius: 10em;
}
}
.w-loading {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 1em;
border: solid .2em currentColor;
mask-image: conic-gradient(from 0deg, #0000 0%, #000 75%, #000 83%, #0000 85%);
animation: w-am-loading 1s ease infinite;
}
.w-inner-loading {
pointer-events: none;
user-select: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
&::before {
content: '';
position: absolute;
inset: 0;
background-color: var(--bg-color, #0003);
backdrop-filter: blur(.1em);
}
&::after {
position: absolute;
content: '';
font-size: var(--size, 1em);
display: block;
width: 1em;
height: 1em;
border-radius: 1em;
border: solid .2em var(--loading-color, currentColor);
mask-image: conic-gradient(from 0deg, #0000 0%, #000 75%, #000 83%, #0000 85%);
animation: w-am-loading 1s ease infinite;
}
}
@keyframes w-am-loading {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@property --border-gradient-angle {
syntax: "<angle>";
inherits: true;
initial-value: 0turn;
}
.w-border-light,
.w-border-light-1,
.w-border-light-2,
.w-border-light-3 {
position: relative;
border: none !important;
animation-play-state: inherit;
--border: .1em solid #0000;
--border-light-color: #FFF9;
--time: 5s;
&::before {
content: '';
pointer-events: none;
position: absolute;
inset: 0;
border: var(--border);
border-radius: inherit;
}
&::after {
content: '';
pointer-events: none;
position: absolute;
inset: 0;
border: var(--border);
border-color: var(--border-light-color);
border-radius: inherit;
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000, #000 10%, #0000 11%, #0000 50%, #000 60%, #0000 61%);
animation: am-frame var(--time) infinite linear;
animation-play-state: inherit;
}
}
.w-border-light-1::after {
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000, #000 10%, #0000 11%);
}
.w-border-light-3::after {
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000,#0000 23%, #000 33%, #0000 34%,#0000 56%,#000 66%,#0000 67%, #0000 89%, #000 99%, #0000 100%);
}
@keyframes am-frame {
0% {
--border-gradient-angle: 0turn;
}
100% {
--border-gradient-angle: 1turn;
}
}
.w-part-hide {
--top: 1em;
--bottom: 1em;
mask-image: linear-gradient(to bottom,#0000 0%,#000 var(--top),#000 calc(100% - var(--bottom)), #0000 100%);
}
.w-radio,
.w-checkbox {
--btn-color-inner: var(--btn-color, currentColor);
--opacity: .6;
transition: all .3s;
cursor: pointer;
display: flex;
align-items: center;
&::before {
content: '';
font-size: var(--btn-size, inherit);
width: 1.5em;
height: 1.5em;
opacity: var(--opacity);
box-sizing: border-box;
border: solid .1em var(--btn-color-inner);
margin-right: .2em;
border-radius: .2em;
background-color: var(--btn-bg-color-inner, #0000);
background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNzA5NzA3MjQ5OTg3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQyODUiIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiI+PHBhdGggZD0iTTg0My42OTM5NTkgMjkzLjYwOTA2MSA0MjUuMjU1ODY5IDcxMi4wNTYzNjIgMTg2LjE0NTAyNiA0NzIuOTQ3NTY2IDY2LjU3OTg4MyA1OTIuNTA0NTIyIDQyNS4yNTU4NjkgOTUxLjE2NTE1OCA5NjMuMjYwMTI2IDQxMy4xNzQyMDRaIiBwLWlkPSI0Mjg2IiBmaWxsPSIjZmZmZmZmIj48L3BhdGg+PC9zdmc+");
background-size: 1em 1em;
background-repeat: no-repeat;
background-position: var(--background-position-inner, center -1em);
transition: all .3s;
overflow: hidden;
transform: scale(.8);
}
&.selected {
--btn-color-inner: var(--selected-btn-color, var(--el-color-primary));
--opacity: 1;
--btn-bg-color-inner: var(--selected-btn-color, var(--el-color-primary));
--background-position-inner: center 0.1em;
color: var(--selected-text-color, currentColor);
}
}
.w-radio::before {
border-radius: 1em;
}
@property --data-num {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
.w-breathing {
--filter: brightness(110%);
--transform: scale(1.1);
--time: 1.3s;
--data-num: 0;
--data-num-to: 1;
animation: w-am-breathing var(--time) infinite linear;
animation-play-state: inherit;
}
@keyframes w-am-breathing {
0% {
filter: none;
transform: none;
}
45% {
filter: var(--filter);
transform: var(--transform);
--data-num: var(--data-num-to);
}
90% {
filter: none;
transform: none;
}
}
}

@ -8,7 +8,7 @@
}
.sidebarHide {
margin-left: 0!important;
margin-left: 0 !important;
}
.sidebar-container {
@ -24,9 +24,39 @@
left: 0;
z-index: 1001;
overflow: hidden;
text-shadow: .1em .1em 0 #000;
&.theme-light {
text-shadow: .1em .1em 0 #FFF;
li {
&::before {
background-color: #FFF5;
}
}
}
// -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
// box-shadow: 2px 0 6px rgba(0,21,41,.35);
&::before {
content: '';
position: absolute;
inset: 0;
// background-color: red;
background-image: radial-gradient(circle, var(--noise-color, #FFFFFF06) .5rem, #0000 1rem, #0000 100%);
background-size: 2rem 2rem;
filter: url(#WEffectNoiseBgFilter);
transform: scale(2);
}
&.theme-light::before {
--noise-color: #00000006;
}
// 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;
@ -70,7 +100,8 @@
width: 100% !important;
}
.el-menu-item, .menu-title {
.el-menu-item,
.menu-title {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
@ -88,10 +119,15 @@
}
}
& .theme-dark .is-active > .el-sub-menu__title {
& .theme-dark .is-active>.el-sub-menu__title {
color: $base-menu-color-active !important;
}
// .el-menu-item.is-active {
// --el-menu-active-color: #FFF;
// }
& .nest-menu .el-sub-menu>.el-sub-menu__title,
& .el-sub-menu .el-menu-item {
min-width: $base-sidebar-width !important;
@ -101,14 +137,51 @@
}
}
& .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
& .theme-dark .el-sub-menu .el-menu-item {
& .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title:not(.is-active),
& .theme-dark .el-sub-menu .el-menu-item:not(.is-active) {
background-color: $base-sub-menu-background !important;
&:hover {
background-color: $base-sub-menu-hover !important;
}
}
.router-link-active.router-link-exact-active {
position: relative;
background-color: var(--el-menu-active-color);
&::before {
content: '';
position: absolute;
inset: 0;
background-image: linear-gradient(to bottom, #0000 50%, #0003);
}
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
border: solid .5rem #0000;
border-right-color: #f7f7f7;
top: 50%;
transform: translateY(-50%);
right: 0;
}
.el-menu-item.is-active {
position: relative;
color: var(--my-menu-active-color, #FFF);
background-color: none !important;
&:hover {
background-color: none !important;
}
}
}
}
.hideSidebar {
@ -147,6 +220,7 @@
}
.el-menu--collapse {
.el-sub-menu {
&>.el-sub-menu__title {
&>span {
@ -156,6 +230,7 @@
visibility: hidden;
display: inline-block;
}
&>i {
height: 0;
width: 0;
@ -222,6 +297,7 @@
max-height: 100vh;
overflow-y: auto;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
@ -235,4 +311,7 @@
border-radius: 20px;
}
}
}
}

@ -9,17 +9,20 @@ $yellow: #FEC171;
$panGreen: #30B08F;
//
$base-menu-color: #bfcbd9;
$base-menu-color-active: #f4f4f5;
$base-menu-background: hsl(210, 63%, 30%);
$base-logo-title-color: #ffffff;
$base-menu-color: #FFFC;
$base-menu-color-active: #FFFE;
// $base-menu-background: hsl(210, 63%, 30%);
// $base-menu-background: #222;
$base-menu-background: #0000;
$base-logo-title-color: #FFFE;
$base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529;
$base-menu-light-color: #0009;
// $base-menu-light-background: #F1F1F1;
$base-menu-light-background: #0000;
$base-logo-light-title-color: #000C;
$base-sub-menu-background: hsl(210, 63%, 25%);
$base-sub-menu-hover: hsl(210, 63%, 20%);
$base-sub-menu-background: #0006;
$base-sub-menu-hover: #0001;
//
/**

@ -0,0 +1,228 @@
<template>
<div class="w-code">
<w-icon icon-class="clipboard" @click="copy" />
<pre><code ref="codeRef" :class="props.language?['language-'+props.language]:[]"><slot></slot></code></pre>
</div>
</template>
<script setup>
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import { ElMessage } from 'element-plus'
import { onMounted } from 'vue';
const props = defineProps({
language: {
type: String,
default: ''
}
})
const codeRef = ref(null);
const copy = () => {
navigator.clipboard.writeText(codeRef.value.textContent).then(() => {
ElMessage.success('复制成功');
})
}
onMounted(() => {
hljs.highlightElement(codeRef.value);
})
const getCode = () => {
return codeRef.value.textContent;
}
const setCode = (code) => {
if(props.language){
codeRef.value.innerHTML = hljs.highlight(code, { language: props.language }).value;
}else{
codeRef.value.innerHTML = hljs.highlightAuto(code).value;
}
}
defineExpose({
copy,
getCode,
setCode,
})
</script>
<style lang="scss">
.w-code {
background-color: #0001;
margin: 1em;
padding: 0em;
border: solid 1px #0002;
border-radius: .5em;
position: relative;
&>:first-child {
position: absolute;
right: .5em;
top: .5em;
cursor: pointer;
opacity: 0;
transition: all .3s;
}
&:hover>:first-child {
opacity: 0.7;
&:hover {
opacity: 1;
}
&:active {
opacity: .85;
}
}
.hljs {
background: #0000 !important;
}
}
.dark {
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em
}
code.hljs {
padding: 3px 5px
}
/*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/
.hljs {
color: #c9d1d9;
background: #0d1117
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #ff7b72
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #d2a8ff
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #79c0ff
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #a5d6ff
}
.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #ffa657
}
.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #8b949e
}
.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #7ee787
}
.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #c9d1d9
}
.hljs-section {
/* prettylights-syntax-markup-heading */
color: #1f6feb;
font-weight: bold
}
.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #f2cc60
}
.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #c9d1d9;
font-style: italic
}
.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #c9d1d9;
font-weight: bold
}
.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #aff5b4;
background-color: #033a16
}
.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #ffdcd7;
background-color: #67060c
}
.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}
}
</style>

@ -6,7 +6,7 @@
</div>
<input ref="fileInputRef" v-if="!props.disabled" :accept="props.accept" @change="fileInputChange" type="file"
style="position: absolute; top:-100vh;" :multiple="props.max != 1" />
<div class="list">
<div class="list" v-if="props.list">
<slot :list="list">
<div v-for="(item, index) in data" :key="index" class="item"
:class="{ error: item.error, abort: item.abort, border: props.border }"
@ -16,7 +16,7 @@
<a v-else :href="baseUrl + base + 'download?' + request.params({ url: item.url, key: uploadKey }).toString()"
target="_blank">{{ item.name }}</a>
<div v-if="item.uploading && !item.abort" class="btn" @click="item.uploading.abort()"></div>
<div v-if="item.url && !props.disabled" @click="item.remove()" class="btn"></div>
<div v-if="item.url && !props.disabled" @click="remove(item)" class="btn"></div>
</div>
</slot>
</div>
@ -55,10 +55,14 @@ const props = defineProps({
getUploadKey: {
type: Function,
default: async () => {
let r = await request.get("/file/upload/getUploadKey")
let r = await request.get("/uploadKey")
return r.data
}
},
before: {
type: Function,
default: (file) => { return true }
},
/**
* 上传路径前缀
*/
@ -131,6 +135,10 @@ const props = defineProps({
border: {
type: Boolean,
default: true
},
list: {
type: Boolean,
default: true
}
})
@ -147,6 +155,21 @@ const mv = computed({
emit("change", value)
}
})
watch(mv, () => {
if (props.max == 1) {
data.value = []
if (mv.value) {
data.value = [{ url: mv.value ,ext: getExt(mv.value), name: getName(mv.value) }]
}
} else {
data.value = []
if (mv.value) {
data.value = mv.value.map(a => ({ url: a ,ext: getExt(a), name: getName(a)}))
}
}
})
const uploading = computed({
get() {
return props.uploading
@ -181,11 +204,7 @@ onMounted(async () => {
data.value = mv.value.map(a => ({ url: a, ext: getExt(a), name: getName(a) }))
}
}
for (let one of data.value) {
one.remove = () => {
remove(one)
}
}
})
const remove = (one) => {
@ -241,6 +260,9 @@ const fileInputChange = () => {
}
const addUploadFile = async (file) => {
if (!props.before(file)) {
return
}
if (props.max > 1 && props.max == data.value.length) {
ElMessage.error('最多只允许上传' + props.max + '个文件')
return
@ -287,7 +309,12 @@ const uploadFiles = async () => {
for (let i = 0; i < props.threadNum; i++) {
a.push(doOne())
}
Promise.all(a).then(() => {
Promise.all(a).then((r) => {
if (props.max == 1) {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)[0]
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
}).finally(() => {
data.value = data.value.filter(a => !a.error && !a.abort)
doing.value = false
@ -323,9 +350,6 @@ const uploadFile = async (index, retry = 0) => {
}
}
one.remove = () => {
remove(one)
}
if (one.raw.size <= props.chunksize) {
@ -351,11 +375,7 @@ const uploadFile = async (index, retry = 0) => {
delete one.raw
delete one.uploading
one.url = r.data
if (props.max == 1) {
mv.value = r.data
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
} else {
delete one.uploading
await uploadFile(index, retry)
@ -397,11 +417,7 @@ const uploadFileBig = async (one) => {
delete one.raw
delete one.uploading
one.url = r.data
if (props.max == 1) {
mv.value = r.data
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
} else {
one.error = true
request.post(base + 'multipartUploadAbort?uploadId=' + one.uploading.uploadId)
@ -427,7 +443,7 @@ const uploadChunk = async (one, chunksList, index, uploadId, retry = 0) => {
one.uploading.loaded = props.chunksize * index + event.loaded
}
try {
let r = await request.post(base + "multipartUpload?r="+index+''+ Math.random(), formData, {
let r = await request.post(base + "multipartUpload?r=" + index + '' + Math.random(), formData, {
onUploadProgress,
timeout: 600000,
showLoading: false,
@ -460,7 +476,7 @@ const chunkFile = (file, chunksize) => {
return chunksList;
}
defineExpose({ open, reloadUploadKey })
defineExpose({ open, reloadUploadKey,addUploadFile })
</script>
<style lang="scss" scoped>
.doing {
@ -545,6 +561,8 @@ defineExpose({ open, reloadUploadKey })
background-position: -14em center;
font-size: .4em;
margin-right: .5em;
flex-flow: 1;
flex-shrink: 1;
&.icon-dir {
background-position: 0 center;

@ -0,0 +1,53 @@
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName" :fill="color" />
</svg>
</template>
<script>
export default defineComponent({
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
},
setup(props) {
return {
iconName: computed(() => `#icon-${props.iconClass}`),
svgClass: computed(() => {
if (props.className) {
return `svg-icon ${props.className}`
}
return 'svg-icon'
})
}
}
})
</script>
<style scope lang="scss">
.sub-el-icon,
.nav-icon {
display: inline-block;
font-size: 15px;
margin-right: 12px;
position: relative;
}
.svg-icon {
width: 1em;
height: 1em;
position: relative;
fill: currentColor;
vertical-align: -2px;
}
</style>

@ -6,7 +6,7 @@
</div>
<input ref="fileInputRef" v-if="!props.disabled" accept="image/*" @change="fileInputChange" type="file"
style="position: absolute; top:-100vh;" :multiple="props.max != 1" />
<div class="list">
<div class="list" :class="{ noEffect: props.noEffect }" v-if="props.list">
<slot :list="data">
<div v-for="(item, index) in data" :key="index" class="item" :class="{ error: item.error, abort: item.abort }"
:style="{ '--ps': item.uploading ? (item.uploading?.loaded || 0) * 100 / (item.uploading?.total || 1) + '%' : '100%' }"
@ -38,7 +38,7 @@
</svg>
</div>
<div v-if="item.url && !props.disabled" @click.stop="item.remove()" class="btn">
<div v-if="item.url && !props.disabled" @click.stop="remove(item)" class="btn">
<svg t="1729755512665" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="2491" width="200" height="200">
<path
@ -55,7 +55,7 @@
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, getCurrentInstance } from 'vue'
import { ref, onMounted, onUnmounted, computed, getCurrentInstance, watch } from 'vue'
import { request } from '@/utils'
import { ElMessage } from 'element-plus'
@ -95,10 +95,14 @@ const props = defineProps({
getUploadKey: {
type: Function,
default: async () => {
let r = await request.get("/file/upload/getUploadKey")
let r = await request.get("/uploadKey")
return r.data
}
},
before: {
type: Function,
default: (file) => { return true }
},
/**
* 上传路径前缀
*/
@ -157,6 +161,14 @@ const props = defineProps({
watermark: {
type: Boolean,
default: true
},
noEffect: {
type: Boolean,
default: false
},
list: {
type: Boolean,
default: true
}
@ -209,12 +221,21 @@ onMounted(async () => {
data.value = mv.value.map(a => ({ url: a }))
}
}
for (let one of data.value) {
one.remove = () => {
remove(one)
console.debug(proxy.$refs.imgRef)
})
watch(mv, () => {
if (props.max == 1) {
data.value = []
if (mv.value) {
data.value = [{ url: mv.value }]
}
} else {
data.value = []
if (mv.value) {
data.value = mv.value.map(a => ({ url: a }))
}
}
console.debug(proxy.$refs.imgRef)
})
const remove = (one) => {
@ -272,7 +293,10 @@ const fileInputChange = () => {
}
const addUploadFile = async (file) => {
console.debug(file)
if (!props.before(file)) {
return
}
if (props.max > 1 && props.max == data.value.length) {
ElMessage.error('最多只允许上传' + props.max + '个文件')
return
@ -320,7 +344,7 @@ const uploadFiles = async () => {
console.debug('end')
}).finally(() => {
data.value = data.value.filter(a => !a.error && !a.abort)
console.debug('finally')
console.debug('finally', data.value)
doing.value = false
uploading.value = false
})
@ -352,10 +376,6 @@ const uploadFile = async (index, retry = 0) => {
one.uploading.controller.abort()
}
one.remove = () => {
remove(one)
}
let formData = new FormData()
@ -399,7 +419,7 @@ const uploadFile = async (index, retry = 0) => {
}
defineExpose({ open, reloadUploadKey })
defineExpose({ open, reloadUploadKey, addUploadFile })
</script>
<style lang="scss" scoped>
.doing {
@ -422,6 +442,14 @@ defineExpose({ open, reloadUploadKey })
display: flex;
flex-wrap: wrap;
&.noEffect {
--image-border-radius: 0;
--image-margin: 0;
--image-border: none;
--image-box-shadow: none;
}
.item {
width: var(--image-size, 10em);
@ -429,16 +457,15 @@ defineExpose({ open, reloadUploadKey })
position: relative;
overflow: hidden;
border-radius: .4em;
margin-top: .5em;
margin-right: .5em;
border-radius: var(--image-border-radius, .4em);
margin: var(--image-margin, .5em .5em 0 0);
padding: 0;
border: #FFF solid 2px;
box-shadow: 0 0 .2em #0005;
border: var(--image-border, #FFF solid 2px);
box-shadow: var(--image-box-shadow, 0 0 .2em #0005);
cursor: pointer;
img {
object-fit: cover;
object-fit: var(--image-fit, cover);
width: 100%;
height: 100%;
object-position: center;
@ -524,4 +551,4 @@ defineExpose({ open, reloadUploadKey })
}
}
</style>
</style>

@ -1,5 +1,5 @@
<template>
<el-image-viewer v-if="imgShow" @close="imgShow=false" ref="imgRef" :url-list="[img]" />
<el-image-viewer v-if="imgShow" @close="imgShow=false" ref="imgRef" :url-list="img" />
</template>
<script setup>
@ -7,13 +7,18 @@ import { ref, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance();
const img = ref("");
const img = ref([]);
const imgShow = ref(false);
const open = async (src) => {
img.value = src;
if(Array.isArray(src)){
img.value = src;
}else{
img.value = [src];
}
imgShow.value = true
await proxy.$nextTick();
}

@ -0,0 +1,77 @@
<template>
<div class="w-tags-input">
<el-tag v-for="(tag, index) in model" :key="index" closable :disable-transitions="false" :type="props.type"
@close="handleClose(index)">
{{ index }} : {{ tag }}
</el-tag>
<el-input v-if="inputVisible" ref="inputRef" v-model="inputValue" :style="{ width: props.placeholder.length * 2 + 1 + 'em' }"
size="small" placeholder="key : value" @keyup.enter="handleInputConfirm" @blur="handleInputConfirm" />
<el-button v-else class="button-new-tag" size="small" @click="showInput">
{{ props.placeholder }}
</el-button>
</div>
</template>
<script setup>
import { ElMessage } from 'element-plus';
import { nextTick, ref } from 'vue'
const model = defineModel({
type: Object,
required: true
});
const props = defineProps({
/**
* 输入提示
*/
placeholder: {
type: String,
default: "新增配置项",
},
type: {
type: String,
default: 'primary'
}
});
const inputValue = ref('')
const inputVisible = ref(false);
const inputRef = ref(undefined);
const handleClose = (index) => {
delete model.value[index];
};
const showInput = () => {
inputVisible.value = true
nextTick(() => {
inputRef.value?.input?.focus();
})
}
const handleInputConfirm = () => {
if (inputValue.value) {
if (inputValue.value.indexOf(":")>0) {
model.value[inputValue.value.split(':')[0].trim()] = inputValue.value.split(':')[1].trim();
} else {
ElMessage.error('输入格式错误');
}
}
inputVisible.value = false
inputValue.value = ''
}
</script>
<style lang="scss" scoped>
.w-tags-input {
display: flex;
flex-wrap: wrap;
&>* {
margin: 0 1em 1em 0;
}
}
</style>

@ -0,0 +1,136 @@
<template>
<div class="w-switch" :class="{ 'w-switch-on': props.modelValue, 'disabled': props.disabled }" @click="handleChange">
<div>
<slot name="off">{{ props.offText }}</slot>
</div>
<div>
<slot name="on">{{ props.onText }}</slot>
</div>
<div></div>
</div>
</template>
<script setup>
const props = defineProps({
modelValue: {
type: Boolean,
required: true
},
onText: {
type: String,
default: 'ON'
},
offText: {
type: String,
default: "OFF"
},
disabled: {
type: Boolean,
default: false
}
})
const emit = defineEmits(["change", "update:modelValue"])
const handleChange = () => {
if (props.disabled) {
return;
}
let d = !props.modelValue;
emit("update:modelValue", d);
emit("change", d);
}
</script>
<style lang="scss" scoped>
.w-switch {
position: relative;
min-width: 5em;
line-height: 1;
display: flex;
box-sizing: border-box;
overflow: hidden;
border-radius: 2em;
height: 2em;
color: #FFF;
--off-color: #ccc;
--on-color: #13ce66;
&.disabled {
filter: grayscale(.5);
&::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
cursor: not-allowed;
}
}
&>div {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 2em;
background-color: var(--off-color);
display: flex;
justify-content: center;
align-items: center;
padding: 0 .5em;
transition: all .5s;
&:nth-child(1) {
padding-left: 2em;
}
&:nth-child(2) {
background-color: var(--on-color);
padding-right: 2em;
opacity: 0;
}
&:nth-child(3) {
left: 0;
top: 0;
width: 2em;
height: 2em;
background-color: #FFF;
padding: .3em;
background-clip: content-box;
border-radius: 2em;
}
}
&.w-switch-on>div {
&:nth-child(1) {
opacity: 0;
}
&:nth-child(2) {
opacity: 1;
}
&:nth-child(3) {
left: calc(100% - 2em);
}
}
}
</style>

@ -0,0 +1,83 @@
<template>
<div class="w-tags-input">
<el-tag
v-for="(tag, index) in model"
:key="index"
closable
:disable-transitions="false"
:type="props.type"
@close="handleClose(index)"
>
{{ tag }}
</el-tag>
<el-input
v-if="inputVisible"
ref="inputRef"
v-model="inputValue"
:style="{width:props.placeholder.length+1+'em'}"
size="small"
@keyup.enter="handleInputConfirm"
@blur="handleInputConfirm"
/>
<el-button v-else class="button-new-tag" size="small" @click="showInput">
{{ props.placeholder }}
</el-button>
</div>
</template>
<script setup>
import { nextTick, ref } from 'vue'
const model = defineModel({
type: Array,
required: true
});
const props = defineProps({
/**
* 输入提示
*/
placeholder: {
type: String,
default: "新增分组",
},
type:{
type:String,
default:'primary'
}
});
const inputValue = ref('')
const inputVisible = ref(false);
const inputRef = ref(undefined);
const handleClose = (index) => {
model.value.splice(index, 1);
};
const showInput = () => {
inputVisible.value = true
nextTick(() => {
inputRef.value?.input?.focus();
})
}
const handleInputConfirm = () => {
if (inputValue.value) {
model.value.push(inputValue.value)
}
inputVisible.value = false
inputValue.value = ''
}
</script>
<style lang="scss" scoped>
.w-tags-input {
display: flex;
flex-wrap: wrap;
& > * {
margin: 0 1em 1em 0;
}
}
</style>

@ -1,36 +1,51 @@
<template>
<div>
<el-upload
:action="uploadUrl"
:before-upload="handleBeforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
class="editor-img-uploader"
name="file"
:show-file-list="false"
:headers="headers"
style="display: none"
ref="uploadRef"
v-if="type == 'url'"
>
<div style="width: 100%;">
<el-upload :action="uploadUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess"
:on-error="handleUploadError" class="editor-img-uploader" name="file" :show-file-list="false" :headers="headers"
style="display: none" ref="uploadRef" v-if="type == 'url'">
</el-upload>
<div class="editor">
<quill-editor
ref="myQuillEditor"
v-model:content="content"
contentType="html"
@textChange="(e) => $emit('update:modelValue', content)"
:options="options"
:style="styles"
/>
<div v-if="!source">
<quill-editor ref="myQuillEditor" v-model:content="content" contentType="html"
@textChange="(e) => $emit('update:modelValue', content)" :options="options" :style="styles" />
</div>
<el-input v-if="source" class="source-textarea" :style="{ height: height + 'px',width:'100%' }" type="textarea"
v-model="content" />
<div style="padding-top: .2em; display: flex; justify-content: flex-end;">
<el-radio-group v-model="source" @change="changeSource">
<el-radio-button label="编辑视图" :value="false" />
<el-radio-button label="源码视图" :value="true" />
</el-radio-group>
</div>
</div>
</div>
</template>
<script setup>
import { QuillEditor, Quill } from '@vueup/vue-quill';
// import ImageResize from 'quill-image-resize-module';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { getToken } from "@/utils/auth";
import { ref, computed, onMounted, getCurrentInstance } from 'vue'
// Quill.register(ImageResize)
onMounted(async () => {
await proxy.$nextTick()
height.value = myQuillEditor.value.editor.clientHeight + 42;
})
const changeSource = () => {
if (!source.value) {
console.debug(myQuillEditor.value.editor.clientHeight);
}
}
const props = defineProps({
/* 编辑器的内容 */
@ -61,12 +76,23 @@ const props = defineProps({
type: {
type: String,
default: "url",
},
server: {
type: String,
default: "/system/oss/upload"
},
source: {
type: Boolean,
default: false,
}
});
const source = ref(props.source);
const height = ref(props.height || props.minHeight || 100);
const { proxy } = getCurrentInstance();
//
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/system/oss/upload");
const uploadUrl = computed(() => import.meta.env.VITE_APP_BASE_API + props.server);
const headers = ref({ Authorization: "Bearer " + getToken() });
const myQuillEditor = ref();
@ -80,14 +106,14 @@ const options = ref({
container: [
["bold", "italic", "underline", "strike"], // 线 线
["blockquote", "code-block"], //
[{ list: "ordered" }, { list: "bullet"} ], //
[{ list: "ordered" }, { list: "bullet" }], //
[{ indent: "-1" }, { indent: "+1" }], //
[{ size: ["small", false, "large", "huge"] }], //
[{ header: [1, 2, 3, 4, 5, 6, false] }], //
[{ color: [] }, { background: [] }], //
[{ align: [] }], //
["clean"], //
["link", "image", "video"] //
["link", "image"] //
],
handlers: {
image: function (value) {
@ -132,7 +158,7 @@ function handleUploadSuccess(res, file) {
//
let length = quill.selection.savedRange.index;
// res
quill.insertEmbed(length, "image", res.data.url);
quill.insertEmbed(length, "image", res.data);
//
quill.setSelection(length + 1);
proxy.$modal.closeLoading();
@ -164,16 +190,20 @@ function handleUploadError(err) {
</script>
<style>
.editor, .ql-toolbar {
.editor,
.ql-toolbar {
white-space: pre-wrap !important;
line-height: normal !important;
}
.quill-img {
display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: "保存";
@ -188,14 +218,17 @@ function handleUploadError(err) {
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
@ -205,26 +238,32 @@ function handleUploadError(err) {
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
@ -234,12 +273,21 @@ function handleUploadError(err) {
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
.source-textarea textarea.el-textarea__inner {
resize: none;
height: 100%;
width: 100%;
}
</style>

@ -1,13 +1,11 @@
<template>
<div>
<svg-icon icon-class="github" @click="goto" />
<div v-if="env == 'development'">
<svg-icon icon-class="bug" @click="router.push({ path: '/test/index' })" />
</div>
</template>
<script setup>
const url = ref('https://gitee.com/JavaLionLi/RuoYi-Vue-Plus');
function goto() {
window.open(url.value)
}
import { useRouter } from "vue-router";
const router = useRouter();
const env = import.meta.env.VITE_APP_ENV;
</script>

@ -15,6 +15,9 @@
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip> -->
<el-tooltip content="示例代码" effect="dark" placement="bottom">
<ruo-yi-git class="right-menu-item hover-effect" />
</el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
@ -107,7 +110,7 @@ function setLayout() {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
background: #0000;
// box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {

@ -80,7 +80,7 @@
<script setup>
import variables from '@/assets/styles/variables.module.scss'
import originElementPlus from 'element-plus/theme-chalk/index.css'
import 'element-plus/theme-chalk/index.css'
import axios from 'axios'
import { ElLoading, ElMessage } from 'element-plus'
import { useDynamicTitle } from '@/utils/dynamicTitle'

@ -44,8 +44,8 @@ const sideTheme = computed(() => settingsStore.sideTheme);
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
height: 4.5rem;
line-height: 4.5rem;
background: #2b2f3a;
text-align: center;
overflow: hidden;

@ -1,15 +1,27 @@
<template>
<div style="box-shadow: 0 0 .5rem #0001;" :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<div style="box-shadow: 0 0 .5rem #0001;" :class="[showLogo?'has-logo':'no-logo',sideTheme]"
:style="{ backgroundColor: sideTheme === 'theme-dark' ? `var(--admin-menu-bg-dark,${adminDark})` : `var(--admin-menu-bg-light,${adminlight})` }">
<svg style="display: none;">
<defs>
<filter id="WEffectNoiseBgFilter" color-interpolation-filters="linearRGB" filterUnits="objectBoundingBox"
primitiveUnits="userSpaceOnUse">
<feTurbulence type="turbulence" baseFrequency="1 1" numOctaves="100" seed="100" stitchTiles="stitch"
x="-100%" y="-100%" width="300%" height="300%" result="turbulence" />
<feDisplacementMap in="SourceGraphic" in2="turbulence" scale="200" xChannelSelector="R" yChannelSelector="A"
x="-100%" y="-100%" width="300%" height="300%" result="displacementMap" />
</filter>
</defs>
</svg>
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
:background-color="sideTheme === 'theme-dark' && isCollapse?`var(--admin-menu-bg-dark,${adminDark})`:'#0000'"
:text-color="sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
:unique-opened="true"
:active-text-color="theme"
:collapse-transition="false"
:collapse-transition="true"
mode="vertical"
>
<sidebar-item
@ -42,6 +54,10 @@ const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened);
const adminDark = import.meta.env.VITE_APP_ADMIN_DARK;
const adminlight = import.meta.env.VITE_APP_ADMIN_LIGHT;
const activeMenu = computed(() => {
const { meta, path } = route;
// if set path, the sidebar will highlight the path you set

@ -245,7 +245,7 @@ function handleScroll() {
.tags-view-container {
height: 34px;
width: 100%;
background: #fff;
background: #0000;
border-bottom: 1px solid #d8dce5;
// 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 {
@ -276,9 +276,8 @@ function handleScroll() {
height: 39px;
padding-top: 3px;
font-size: 13px;
background-color: #42b983;
color: #fff;
border-color: #42b983;
&::before {
content: "";
background: #fff;

@ -3,7 +3,7 @@
<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 }">
<div :class="{ 'fixed-header': fixedHeader }" style="background-image: linear-gradient(to top, #EEE, #FFF 70%);">
<navbar @setLayout="setLayout" />
<tags-view v-if="needTagsView" />
</div>

@ -6,7 +6,7 @@ import ElementPlus from 'element-plus'
// import locale from 'element-plus/lib/locale/lang/zh-cn' // 中文语言
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import 'normalize.css' // CSS重置样式
import '@/assets/styles/index.scss' // global css
import App from './App'
import { store, useSettingsStore } from './store'

@ -1,4 +1,4 @@
import { createWebHistory,createWebHashHistory, createRouter } from 'vue-router'
import { createWebHistory, createWebHashHistory, createRouter } from 'vue-router'
/* Layout */
import Layout from '@/layout'
@ -24,6 +24,17 @@ import Layout from '@/layout'
}
*/
const env = import.meta.env.VITE_APP_ENV;
const children = []
if (env == 'development') {
const files = import.meta.glob('@/views/test/*.vue');//异步导入
for (let fileName in files) {
let moduleName = fileName.replace(/^.*\/(\w+)\.vue$/, "$1");
children.push({ path: moduleName, component: files[fileName] })
}
}
console.debug(children)
// 公共路由
export const constantRoutes = [
{
@ -83,9 +94,20 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' }
}
]
}, {
path: '/test',
component: () => import('@/views/test'),
hidden: true,
redirect: '/test/index',
children
}
]
// 动态路由,基于用户权限动态去加载
export const dynamicRoutes = [
{
@ -129,20 +151,6 @@ export const dynamicRoutes = [
meta: { title: '字典数据', activeMenu: '/system/dict' }
}
]
},
{
path: '/system/oss-config',
component: Layout,
hidden: true,
permissions: ['monitor:job:list'],
children: [
{
path: 'index',
component: () => import('@/views/system/oss/config'),
name: 'OssConfig',
meta: { title: '配置管理', activeMenu: '/system/oss'}
}
]
}
]

@ -6,7 +6,7 @@ export default {
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-light',
sideTheme: 'theme-'+import.meta.env.VITE_APP_THEME,
/**
* 是否系统布局配置
*/

@ -0,0 +1,60 @@
import CryptoJS from 'crypto-js/crypto-js'
const bufferChunkSize = 1024 * 1024 * 5;
export const fileHash = (file, config={}) => {
config = {
algo: 'MD5',
enc: 'Hex',
onProgress: (a,b)=>{console.debug(a,b)}
,...config
}
return new Promise((resolve, reject) => {
if(file==null || file.size==0){
resolve(null)
return
}
const hash = CryptoJS.algo[config.algo].create()
let count = 0;
const reader = new FileReader()
// 以流的方式读取文件
function readChunk(start, end) {
const slice = file.slice(start, end)
reader.readAsArrayBuffer(slice);
}
// 递归读取文件的每个分块
function processChunk(offset) {
const start = offset;
const end = Math.min(start + bufferChunkSize, file.size)
count = end
readChunk(start, end)
}
// 当读取完整个文件后,计算哈希值并返回
reader.onloadend = function () {
const arrayBuffer = reader.result
const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)
// 更新哈希对象
hash.update(wordArray)
config.onProgress(count,file.size)
if (count < file.size) {
// 继续处理下一个分块
processChunk(count)
}
else {
// 计算哈希值并返回
const ret = hash.finalize()
resolve(ret.toString(CryptoJS.enc.Hex))
}
}
config.onProgress(count,file.size)
// 开始处理文件内容分块
processChunk(0)
})
}

@ -0,0 +1,75 @@
export { fileHash } from './fileHash'
import CryptoJS from 'crypto-js/crypto-js'
import { encrypt, decrypt } from '../jsencrypt'
const AESKey = "d34xsfljkwSD}2cv32$#%dfdgvcJH{PIOPeopir1KSHD"
/**
* Base64编码
* @param {String} str
* @returns
*/
const Base64Encode = (str) => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str))
/**
* Base64解码
* @param {String} str
* @returns
*/
const Base64Decode = (str) => CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(str))
/**
* 消息摘要md5加密
* @param {String} str
* @returns
*/
const md5 = (str) => CryptoJS.enc.Hex.stringify(CryptoJS.MD5(str))
/**
* 消息摘要sha256加密
* @param {String} str
* @returns
*/
const sha256 = (str) => CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(str))
/**
* 对称加密AES
* @param {String} str
* @returns
*/
const aesEncrypt = (str) => CryptoJS.AES.encrypt(str, AESKey).toString()
/**
* 对称解密AES
* @param {String} str
* @returns
*/
const aesDecrypt = (str) => CryptoJS.AES.decrypt(str, AESKey).toString(CryptoJS.enc.Utf8)
export { CryptoJS, Base64Encode, Base64Decode, md5, sha256, encrypt, decrypt, aesEncrypt, aesDecrypt }
// let str = "https://evoai.cn"
// let strEncode = Base64Encode(str)
// console.debug("Base64Encode", strEncode)
// console.debug("Base64Decode", Base64Decode(strEncode))
// console.debug("md5", md5(str))
// console.debug("sha256", sha256(str))
// strEncode = encrypt(str);
// console.debug("encrypt", strEncode)
// console.debug("decrypt", decrypt(strEncode))
// strEncode = aesEncrypt(str)
// console.debug("aesEncrypt", strEncode)
// console.debug("aesDecrypt", aesDecrypt(strEncode))
// console.debug("Hex.stringify",Hex.stringify(str));
// console.debug("Hex.parse",Hex.parse(Hex.stringify(str)));
// var words = CryptoJS.enc.Base64.parse("SGVsbG8sIFdvcmxkIQ==");
// console.debug(words)

@ -36,7 +36,12 @@ const getUploadKey =async () => {
<li>属性saveSrc是否保存图片原文件如果true则下载时下载原图zip文件否则下载大图片默认false </li>
<li>属性saveMin是否保存缩略图如果true则列表时显示缩略图否则显示大图默认true </li>
<li>属性watermark是否添加水印默认true </li>
<li>属性noEffect是否无效果本质设置css属性默认false </li>
<li>css属性--image-size图片显示大小默认 10em </li>
<li>css属性--image-border-radius图片显示圆角默认 .4em</li>
<li>css属性--image-margin图片外边距默认 .5em .5em 0 0</li>
<li>css属性--image-border图片边框默认 #FFF solid 2px </li>
<li>css属性--image-box-shadow图片阴影默认 0 0 .2em #0005</li>
<li>插槽button上传按钮插槽</li>
<li>插槽default图片列表插槽作用域list不建议定义</li>
<li>事件changemodelValue发送了变化</li>
@ -146,7 +151,7 @@ const { proxy } = getCurrentInstance()
const data = ref(['/files/default/2024/10/24/2nhdirb2ujey/5mb.txt'])
const uploading = ref(false)
const imgs = ref(['/files/default/2024/10/24/f99pkzpyc0bt.webp'])
const imgs = ref(['/files/default/2024/10/24/d0wt3m3j4tud.webp'])
const imging = ref(false)
</script>
<style lang="scss" scoped>

@ -1,8 +1,20 @@
<template>
<div class="w-login-content">
<svg style="display: none;">
<defs>
<filter id="WEffectNoiseBgFilter" color-interpolation-filters="linearRGB" filterUnits="objectBoundingBox"
primitiveUnits="userSpaceOnUse">
<feTurbulence type="turbulence" baseFrequency=".1 .1" numOctaves="100" seed="100" stitchTiles="stitch"
x="-100%" y="-100%" width="300%" height="300%" result="turbulence" />
<feDisplacementMap in="SourceGraphic" in2="turbulence" scale="200" xChannelSelector="R" yChannelSelector="A"
x="-100%" y="-100%" width="300%" height="300%" result="displacementMap" />
</filter>
</defs>
</svg>
<div class="w-login-outer">
<div></div>
<div>
</div>
<div class="w-login-form">
<div>你好!<br />欢迎登录{{ title }}</div>
<div><input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号" /></div>
@ -15,8 +27,8 @@
<img :src="codeUrl" @click="getCode" />
</div>
<div class="h2">
<div><label><input type="checkbox" v-model="loginForm.rememberMe" />记住我</label></div>
<div v-if="false"><a href="javascript:void(0);" @click="ElMessageBox.alert('请联系管理员');">?</a></div>
<div><div :class="{selected:loginForm.rememberMe}" @click="loginForm.rememberMe=!loginForm.rememberMe;" class="w-checkbox">记住密码</div></div>
<div ><a href="javascript:void(0);" @click="ElMessageBox.alert('请联系管理员');">?</a></div>
</div>
<el-button :loading="loading" class="btn" size="large" type="primary" @click.prevent="handleLogin">
<span v-if="!loading"> </span>
@ -25,6 +37,7 @@
<div class="copy">{{ copy }} </div>
</div>
</div>
</div>
</template>
@ -43,6 +56,7 @@ import { ElMessage, ElMessageBox } from "element-plus";
const title = import.meta.env.VITE_APP_TITLE;
const copy = import.meta.env.VITE_APP_COPY;
const color = import.meta.env.VITE_APP_COLOR;
console.debug("login", title, copy, color);
onMounted(() => {
useSettingsStore().title = "登录"
@ -96,16 +110,16 @@ function login() {
}
function handleLogin() {
if(!loginForm.value.username){
if (!loginForm.value.username) {
ElMessage.error("请输入帐号");
return;
}
if(!loginForm.value.password){
if (!loginForm.value.password) {
ElMessage.error("请输入帐号");
return;
}
if(captchaEnabled.value){
if(!loginForm.value.code) {
if (captchaEnabled.value) {
if (!loginForm.value.code) {
ElMessage.error("请输入验证码");
return;
}

@ -29,10 +29,10 @@
<el-switch v-model="row.enabled" @change="handleEnabled(row)" />
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200" align="center">
<el-table-column label="操作" fixed="right" width="220" align="center">
<template #default="{ row }">
<el-button-group>
<el-button type="default" link @click="proxy.$refs.runRef.open(taskList, row);">运行</el-button>
<el-button type="success" link @click="proxy.$refs.runRef.open(taskList, row);">手动运行</el-button>
<el-button type="default" link @click="subCron(row);"></el-button>
<el-button type="primary" link @click="proxy.$refs.editRef.open(taskList, row);">修改</el-button>
<el-button type="danger" link @click="handleDelete(row)"></el-button>

@ -1,4 +1,5 @@
import request from '@/utils/request'
import SSE from '@/api/SSE'
const base = '/system/cron/'
@ -17,4 +18,6 @@ export const logPage = (params) => request.get(base + 'log-page', { params })
export const current = (group = 0) => request.get(base + 'current-' + group)
export const start = (cronId, taskId, paramEls) => request.post(base + "/start", request.params({ cronId, taskId, paramEls }))
export const start = (cronId, taskId, paramEls) => request.post(base + "/start", request.params({ cronId, taskId, paramEls }))
export const doSSE = (groupId = 0, callback) => SSE.post(base + 'sse-' + groupId, {}, callback, { returnData: false })

@ -1,26 +1,61 @@
<template>
<div class="xf-root">
<div class="search-form">
<el-select v-model="search.taskId" style="width: 10em; display: block;" clearable placeholder="任务">
<el-option v-for="item in taskList" :key="item.id" :label="item.name" :value="item.id" />
<el-select
v-model="search.taskId"
style="width: 10em; display: block"
clearable
placeholder="任务"
>
<el-option
v-for="item in taskList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-select v-model="search.ok" style="width: 6em; display: block;" clearable placeholder="成败">
<el-select
v-model="search.ok"
style="width: 6em; display: block"
clearable
placeholder="成败"
>
<el-option label="成功" :value="true" />
<el-option label="失败" :value="false" />
</el-select>
<div style="width: 20em;"><el-date-picker v-model="daterange" value-format="YYYY-MM-DD" type="daterange"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" /></div>
<div style="width: 20em">
<el-date-picker
v-model="daterange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</div>
<el-button type="default" @click="handleSearch"></el-button>
<el-badge :value="cList.length" style="margin-left: auto; margin-right: 1em;">
<el-button :disabled="cList.length == 0" type="primary" plain @click="cShow = true">运行中</el-button>
<el-badge
:value="cList.length"
style="margin-left: auto; margin-right: 1em"
>
<el-button
:disabled="cList.length == 0"
type="primary"
plain
@click="cShow = true"
>运行中</el-button
>
</el-badge>
<el-button type="primary" @click="proxy.$refs.cronListRef.open(taskList, query.groupId);">定时任务</el-button>
<el-button
type="primary"
@click="proxy.$refs.cronListRef.open(taskList, query.groupId)"
>定时任务</el-button
>
</div>
<el-table :data="list" border stripe height="100%" v-loading="loading">
<el-table-column label="任务名称" align="left">
<template #default="{ row }">
{{ taskList.find(a => a.id == row.taskId)?.name || '未知任务' }}
{{ taskList.find((a) => a.id == row.taskId)?.name || "未知任务" }}
</template>
</el-table-column>
<el-table-column label="执行结果" align="left">
@ -30,7 +65,7 @@
<template #reference>
<el-button type="success" link>执行成功</el-button>
</template>
<div style="width: 100%; height: 400px; overflow: auto;">
<div style="width: 100%; height: 400px; overflow: auto">
<pre>{{ row.ex }}</pre>
</div>
</el-popover>
@ -38,9 +73,11 @@
<template v-else>
<el-popover placement="bottom" :width="800" trigger="hover">
<template #reference>
<el-button type="danger" link>{{ row.msg || '未知异常' }}</el-button>
<el-button type="danger" link>{{
row.msg || "未知异常"
}}</el-button>
</template>
<div style="width: 100%; height: 400px; overflow: auto;">
<div style="width: 100%; height: 400px; overflow: auto">
<pre>{{ row.ex }}</pre>
</div>
</el-popover>
@ -49,15 +86,13 @@
</el-table-column>
<el-table-column label="参数" align="center" width="100">
<template #default="{ row }">
<template v-if="!row.params">
</template>
<template v-if="!row.params"> </template>
<template v-else>
<el-popover placement="bottom" :width="300" trigger="hover">
<template #reference>
{{ JSON.parse(row.params).length }}个参数
</template>
<div style="width: 100%; height: 200px; overflow: auto;">
<div style="width: 100%; height: 200px; overflow: auto">
<pre>{{ JSON.stringify(JSON.parse(row.params), null, 2) }}</pre>
</div>
</el-popover>
@ -65,36 +100,70 @@
</template>
</el-table-column>
<el-table-column label="启动时间" align="center" width="170" prop="startTime" />
<el-table-column
label="启动时间"
align="center"
width="170"
prop="startTime"
/>
<el-table-column label="耗时" align="center" width="100">
<template #default="{ row }">
{{ times(row) }}
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :page-sizes="[10, 20, 50]" :total="total" v-model:page="query.current"
v-model:limit="query.size" @pagination="loadPage" />
<pagination
v-show="total > 0"
:page-sizes="[10, 20, 50]"
:total="total"
v-model:page="query.current"
v-model:limit="query.size"
@pagination="loadPage"
/>
<w-cron-list ref="cronListRef" />
<el-drawer direction="rtl" size="40%" title="正在运行的任务" v-model="cShow">
<el-drawer
direction="rtl"
size="40%"
title="正在运行的任务"
v-model="cShow"
>
<el-collapse :modelValue="0" accordion>
<el-collapse-item v-for="row in cList" :key="row.id">
<template #title>
<div style="display: grid; width: 100%; grid-template-columns: 2fr 1fr 1fr; ">
<div style="font-weight: bold; text-align: left;"> {{ taskList.find(a => a.id == row.taskId)?.name ||
'未知任务' }}</div>
<div>{{ row.startTime.toDate("yyyy-MM-dd HH:mm:ss").format("HH:mm:ss") }}</div>
<div style="display: flex; align-items: center; justify-content: center;">
<div class="w-loading" style="margin-right: .5em;"></div> 运行中
<div
style="
display: grid;
width: 100%;
grid-template-columns: 2fr 1fr 1fr;
"
>
<div style="font-weight: bold; text-align: left">
{{
taskList.find((a) => a.id == row.taskId)?.name || "未知任务"
}}
</div>
<div>
{{
row.startTime.toDate("yyyy-MM-dd HH:mm:ss").format("HH:mm:ss")
}}
</div>
<div
style="
display: flex;
align-items: center;
justify-content: center;
"
>
<div class="w-loading" style="margin-right: 0.5em"></div>
运行中
</div>
</div>
</template>
<div style="width: 100%; height: 400px; overflow: auto;">
<div style="width: 100%; height: 400px; overflow: auto">
<pre>{{ row.ex }}</pre>
</div>
</el-collapse-item>
@ -103,15 +172,23 @@
</div>
</template>
<script setup>
import WCronList from './components/WCronList.vue'
import { ref, getCurrentInstance, watch, onMounted, computed, onUnmounted } from 'vue'
import { ElLoading, ElMessage } from 'element-plus'
import * as api from './cron'
import WCronList from "./components/WCronList.vue";
import {
ref,
getCurrentInstance,
watch,
onMounted,
computed,
onUnmounted,
} from "vue";
import { ElLoading, ElMessage } from "element-plus";
import * as api from "./cron";
const daterange = computed({
get() {
return search.value.beginDate ? [search.value.beginDate, search.value.endDate] : []
return search.value.beginDate
? [search.value.beginDate, search.value.endDate]
: [];
},
set(value) {
if (value && value[0]) {
@ -121,13 +198,17 @@ const daterange = computed({
search.value.beginDate = "";
search.value.endDate = "";
}
}
})
},
});
const { proxy } = getCurrentInstance()
const { proxy } = getCurrentInstance();
const times = (a) => ((a.endTime.toDate("yyyy-MM-dd HH:mm:ss") - a.startTime.toDate("yyyy-MM-dd HH:mm:ss")) / 1000).toTime()
const times = (a) =>
(
(a.endTime.toDate("yyyy-MM-dd HH:mm:ss") -
a.startTime.toDate("yyyy-MM-dd HH:mm:ss")) /
1000
).toTime();
//
const search = ref({});
@ -135,7 +216,7 @@ const search = ref({});
const query = ref({
current: 1,
size: 10,
orderBy: 'endTime desc'
orderBy: "endTime desc",
});
//
@ -153,57 +234,64 @@ const loadPage = async () => {
list.value = r.data?.records || [];
total.value = Number(r.data?.total || 0);
loading.value = false;
}
};
//
const handleSearch = () => {
query.value = { ...query.value, ...search.value };
query.value.current = 1;
loadPage();
}
};
const taskList = ref([])
const taskList = ref([]);
const init = async () => {
let r = await api.list(proxy.$route.query.group || 0)
taskList.value = r.data
query.value.groupId = proxy.$route.query.group || 0
handleSearch()
}
let r = await api.list(proxy.$route.query.group || 0);
taskList.value = r.data;
query.value.groupId = proxy.$route.query.group || 0;
handleSearch();
};
const cList = ref([])
const cShow = ref(false)
const cList = ref([]);
const cShow = ref(false);
watch(
() => cList.value.length, () => {
() => cList.value.length,
() => {
handleSearch();
if (cList.value.length == 0) {
cShow.value = false;
}
}
)
);
let timer = null;
let sse = null;
onMounted(async () => {
await proxy.$nextTick()
await init()
timer = window.setInterval(async () => {
let r = await api.current(query.value.groupId)
cList.value = r.data
}, 500);
})
await proxy.$nextTick();
await init();
let r = await api.current(query.value.groupId);
cList.value = r.data;
sse = api.doSSE(query.value.groupId, (data) => {
if (data.action == "list") {
cList.value = data.data;
} else if (data.action == "log") {
let item = cList.value.find((item) => item.id == data.data.logId);
if (item) {
if (item.ex) {
item.ex += "\n" + (data.data.ex || "");
} else {
item.ex = data.data.ex || "";
}
}
}
});
});
onUnmounted(() => {
window.clearInterval(timer)
})
sse.close();
});
</script>
<style lang="scss" scoped>
.xf-root {
@ -213,11 +301,11 @@ onUnmounted(() => {
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 0 0 .3rem 0;
padding: 0 0 0.3rem 0;
position: relative;
&>* {
margin: 0 .5rem .5rem 0;
& > * {
margin: 0 0.5rem 0.5rem 0;
display: flex;
align-items: center;
}

@ -1,382 +0,0 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="配置key" prop="configKey">
<el-input
v-model="queryParams.configKey"
placeholder="配置key"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input
v-model="queryParams.bucketName"
placeholder="请输入桶名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="是否默认" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
<el-option key="0" label="是" value="0"/>
<el-option key="1" label="否" value="1"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:oss:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:oss:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:oss:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible"/>
<el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
<el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
<el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
<el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
<el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
<el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
<el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible" >
<template #default="scope">
<el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
<el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
<el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
</template>
</el-table-column>
<el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']"></el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改对象存储配置对话框 -->
<el-dialog :title="title" v-model="open" width="800px" append-to-body>
<el-form ref="ossConfigRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="form.configKey" placeholder="请输入配置key" />
</el-form-item>
<el-form-item label="访问站点" prop="endpoint">
<el-input v-model="form.endpoint" placeholder="请输入访问站点" />
</el-form-item>
<el-form-item label="自定义域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入自定义域名" />
</el-form-item>
<el-form-item label="accessKey" prop="accessKey">
<el-input v-model="form.accessKey" placeholder="请输入accessKey" />
</el-form-item>
<el-form-item label="secretKey" prop="secretKey">
<el-input v-model="form.secretKey" placeholder="请输入秘钥" show-password />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="form.bucketName" placeholder="请输入桶名称" />
</el-form-item>
<el-form-item label="前缀" prop="prefix">
<el-input v-model="form.prefix" placeholder="请输入前缀" />
</el-form-item>
<el-form-item label="是否HTTPS">
<el-radio-group v-model="form.isHttps">
<el-radio
v-for="dict in sys_yes_no"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="桶权限类型">
<el-radio-group v-model="form.accessPolicy">
<el-radio label="0">private</el-radio>
<el-radio label="1">public</el-radio>
<el-radio label="2">custom</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="域" prop="region">
<el-input v-model="form.region" placeholder="请输入域" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="OssConfig">
import {
listOssConfig,
getOssConfig,
delOssConfig,
addOssConfig,
updateOssConfig,
changeOssConfigStatus
} from "@/api/system/ossConfig";
const { proxy } = getCurrentInstance();
const { sys_yes_no } = proxy.useDict("sys_yes_no");
const ossConfigList = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
//
const columns = ref([
{ key: 0, label: `主建`, visible: true },
{ key: 1, label: `配置key`, visible: false },
{ key: 2, label: `访问站点`, visible: true },
{ key: 3, label: `自定义域名`, visible: true },
{ key: 4, label: `桶名称`, visible: true },
{ key: 5, label: `前缀`, visible: true },
{ key: 6, label: ``, visible: true },
{ key: 7, label: `桶权限类型`, visible: true },
{ key: 8, label: `状态`, visible: true }
]);
const data = reactive({
form: {},
//
queryParams: {
pageNum: 1,
pageSize: 10,
configKey: undefined,
bucketName: undefined,
status: undefined,
},
rules: {
configKey: [
{ required: true, message: "configKey不能为空", trigger: "blur" },
],
accessKey: [
{ required: true, message: "accessKey不能为空", trigger: "blur" },
{
min: 2,
max: 200,
message: "accessKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
secretKey: [
{ required: true, message: "secretKey不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "secretKey长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
bucketName: [
{ required: true, message: "bucketName不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "bucketName长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
endpoint: [
{ required: true, message: "endpoint不能为空", trigger: "blur" },
{
min: 2,
max: 100,
message: "endpoint名称长度必须介于 2 和 100 之间",
trigger: "blur",
},
],
accessPolicy:[
{ required: true, message: "accessPolicy不能为空", trigger: "blur" }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询对象存储配置列表 */
function getList() {
loading.value = true;
listOssConfig(queryParams.value).then((response) => {
ossConfigList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
ossConfigId: undefined,
configKey: undefined,
accessKey: undefined,
secretKey: undefined,
bucketName: undefined,
prefix: undefined,
endpoint: undefined,
domain: undefined,
isHttps: "N",
accessPolicy: "1",
region: undefined,
status: "1",
remark: undefined,
};
proxy.resetForm("ossConfigRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.ossConfigId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加对象存储配置";
}
/** 修改按钮操作 */
function handleUpdate(row) {
loading.value = true;
reset();
const ossConfigId = row.ossConfigId || ids.value;
getOssConfig(ossConfigId).then((response) => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改对象存储配置";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["ossConfigRef"].validate(valid => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId != null) {
updateOssConfig(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addOssConfig(this.form).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
}
}
});
}
/** 用户状态修改 */
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?').then(() => {
return changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
}).then(() => {
getList()
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
row.status = row.status === "0" ? "1" : "0";
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const ossConfigIds = row.ossConfigId || ids.value;
proxy.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?').then(() => {
loading.value = true;
return delOssConfig(ossConfigIds);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
}
getList();
</script>

@ -1,374 +0,0 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="文件名" prop="fileName">
<el-input
v-model="queryParams.fileName"
placeholder="请输入文件名"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="原名" prop="originalName">
<el-input
v-model="queryParams.originalName"
placeholder="请输入原名"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="文件后缀" prop="fileSuffix">
<el-input
v-model="queryParams.fileSuffix"
placeholder="请输入文件后缀"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item label="上传人" prop="createBy">
<el-input
v-model="queryParams.createBy"
placeholder="请输入上传人"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="服务商" prop="service">
<el-input
v-model="queryParams.service"
placeholder="请输入服务商"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleFile"
v-hasPermi="['system:oss:upload']"
>上传文件</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleImage"
v-hasPermi="['system:oss:upload']"
>上传图片</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:oss:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
:type="previewListResource ? 'danger' : 'warning'"
plain
@click="handlePreviewListResource(!previewListResource)"
v-hasPermi="['system:oss:edit']"
>预览开关 : {{previewListResource ? "禁用" : "启用"}}</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Operation"
@click="handleOssConfig"
v-hasPermi="['system:oss:list']"
>配置管理</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="ossList" @selection-change="handleSelectionChange"
:header-cell-class-name="handleHeaderClass"
@header-click="handleHeaderCLick"
v-if="showTable">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false"/>
<el-table-column label="文件名" align="center" prop="fileName" />
<el-table-column label="原名" align="center" prop="originalName" />
<el-table-column label="文件后缀" align="center" prop="fileSuffix" />
<el-table-column label="文件展示" align="center" prop="url">
<template #default="scope">
<ImagePreview
v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
:width="100" :height="100"
:src="scope.row.url"
:preview-src-list="[scope.row.url]"/>
<span v-text="scope.row.url"
v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
<template #default="scope">
<span>{{ scope.row.createTime}}</span>
</template>
</el-table-column>
<el-table-column label="上传人" align="center" prop="createBy" />
<el-table-column label="服务商" align="center" prop="service" sortable="custom"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改OSS对象存储对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="ossRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件名">
<fileUpload v-model="form.file" v-if="type === 0"/>
<imageUpload v-model="form.file" v-if="type === 1"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Oss">
import { listOss, delOss } from "@/api/system/oss";
import ImagePreview from "@/components/ImagePreview/index.vue";
const router = useRouter();
const { proxy } = getCurrentInstance();
const ossList = ref([]);
const open = ref(false);
const showTable = ref(true);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const type = ref(0);
const previewListResource = ref(true);
const daterangeCreateTime = ref([]);
//
const defaultSort = ref({prop: 'createTime', order: 'desc'});
const data = reactive({
form: {},
//
queryParams: {
pageNum: 1,
pageSize: 10,
fileName: undefined,
originalName: undefined,
fileSuffix: undefined,
url: undefined,
createTime: undefined,
createBy: undefined,
service: undefined
},
rules: {
file: [
{ required: true, message: "文件不能为空", trigger: "blur" }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询OSS对象存储列表 */
function getList() {
loading.value = true;
proxy.getConfigKey("sys.oss.previewListResource").then(response => {
previewListResource.value = response.msg === undefined ? true : response.msg === 'true';
});
listOss(proxy.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(response => {
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
});
}
function checkFileSuffix(fileSuffix) {
let arr = ["png", "jpg", "jpeg","webp","gif"];
return arr.some(type => {
return fileSuffix.indexOf(type) > -1;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
file: undefined,
};
proxy.resetForm("ossRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
showTable.value = false;
daterangeCreateTime.value = [];
proxy.resetForm("queryRef");
queryParams.value.orderByColumn = defaultSort.value.prop;
queryParams.value.isAsc = defaultSort.value.order;
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
//
function handleHeaderClass({column}) {
column.order = column.multiOrder
}
//
function handleHeaderCLick(column) {
if (column.sortable !== 'custom') {
return
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder)
}
function handleOrderChange(prop, order) {
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
let propIndex = orderByArr.indexOf(prop)
if (propIndex !== -1) {
if (order) {
//
isAscArr[propIndex] = order;
} else {
//ordernull
isAscArr.splice(propIndex, 1);//
orderByArr.splice(propIndex, 1);//
}
} else {
//
orderByArr.push(prop);
isAscArr.push(order);
}
//
queryParams.value.orderByColumn = orderByArr.join(",");
queryParams.value.isAsc = isAscArr.join(",");
getList();
}
/** 任务日志列表查询 */
function handleOssConfig() {
router.push('/system/oss-config/index')
}
/** 文件按钮操作 */
function handleFile() {
reset();
open.value = true;
title.value = "上传文件";
type.value = 0;
}
/** 图片按钮操作 */
function handleImage() {
reset();
open.value = true;
title.value = "上传图片";
type.value = 1;
}
/** 提交按钮 */
function submitForm() {
open.value = false;
getList();
}
/** 下载按钮操作 */
function handleDownload(row) {
proxy.$download.oss(row.ossId)
}
/** 用户状态修改 */
function handlePreviewListResource(previewListResource) {
let text = previewListResource ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?').then(() => {
return proxy.updateConfigByKey("sys.oss.previewListResource", previewListResource);
}).then(() => {
getList()
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
previewListResource.value = previewListResource.value !== true;
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const ossIds = row.ossId || ids.value;
proxy.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?').then(() => {
loading.value = true;
return delOss(ossIds);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
}
getList();
</script>

@ -0,0 +1,103 @@
<template>
<div class="w-test">
<div>
<div>
<router-link to="/">系统首页</router-link>
<router-link v-for="(path,index) in list" :to="'./'+path" :key="index">{{ path }}</router-link>
</div>
</div>
<div>
<div>
<router-view />
</div>
</div>
</div>
</template>
<script setup>
const list = ref([]);
let files = import.meta.glob("./test/*.vue");
for (let fileName in files) {
let moduleName = fileName.replace(/^.*\/(\w+)\.vue$/, "$1");
if (moduleName == "index") {
continue;
}
list.value.push(moduleName);
}
list.value.sort((a, b) => a.localeCompare(b));
list.value.unshift("index");
</script>
<style lang="scss" scoped>
.w-test {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 10rem 1fr;
gap: 2rem;
& > div {
position: relative;
& > div {
position: absolute;
width: 100%;
height: 100%;
}
&:last-child > div {
overflow: auto;
}
&:first-child {
background-image: linear-gradient(to right, #fff 70%, #0001);
& > div {
padding: 1rem 0;
& > a {
display: flex;
font-size: 0.9rem;
position: relative;
height: 2rem;
align-items: center;
justify-content: center;
transition: all 0.5s;
margin: 0.3rem 0;
color: var(--el-color-primary-dark-2);
border: solid 0.1rem #0000;
&:not(.router-link-exact-active):hover {
background-color: #fff;
color: var(--el-color-primary-dark-3);
border: solid 0.1rem var(--el-color-primary-dark-3);
transform: scale(0.95);
}
&::after {
content: "";
position: absolute;
box-sizing: border-box;
right: 0rem;
width: 1rem;
height: 2rem;
border: solid 1rem #0000;
border-right-width: 0;
border-left-color: var(--c, #0000);
transition: all 0.5s;
}
&.router-link-exact-active {
--c: var(--el-color-primary-dark-2);
background-color: var(--c);
color: #fff;
transform: scale(1.05);
&:hover {
--c: var(--el-color-primary-dark-3);
}
&::after {
right: -1rem;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,51 @@
<template>
<div style="font-size: .7rem;">
<h1>图标</h1>
<w-code language="html">{{ `<w-icon icon-class="404" />
<w-icon icon-class="404" class-name="icon-test" color="var(--el-color-error)" style="font-size: 10em; color: var(--el-color-primary);" />
.icon-test {
color: var(--el-color-success);
font-size: 5em;
}
` }}</w-code>
<w-icon icon-class="404" />
<w-icon icon-class="404" class-name="icon-test" color="var(--el-color-error)" style="font-size: 10em; color: var(--el-color-primary);" />
<h2>使用说明</h2>
<ol style="margin: 1em 2em;">
<li>icon-class: 必填图片类别自定义的图片请放入/src/assets/icons/目录下</li>
<li>color: 图标颜色,优先级高本质定义svg的fill属性</li>
<li>class-name: 使用的css类名可以定义颜色和字体大小</li>
<li>style: 可以定义定义颜色和字体大小</li>
</ol>
<div class="w-flex icons">
<div v-for="item in icons" :key="item" class="w-flex-column">
<w-icon :icon-class="item" />
{{ item }}
</div>
</div>
</div>
</template>
<script setup>
import icons from "@/components/IconSelect/requireIcons";
</script>
<style lang="scss" scoped>
.icon-test {
color: var(--el-color-success);
font-size: 5em;
}
.icons {
flex-wrap: wrap;
justify-content: flex-start;
padding: 2em;
& > div {
padding: 2em;
svg {
width: 5em;
height: 5em;
margin-bottom: 0.5em;
color: var(--w-main);
}
}
}
</style>

@ -0,0 +1,11 @@
<template>
<div>
<h1>示例首页</h1>
<div>直接在@/views/test/下创建vue文件</div>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,9 @@
<template>
<div></div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,168 @@
<template>
<div style="margin: 1rem;">
<el-tabs type="border-card">
<el-tab-pane label="图片上传组件">
<div style="padding: 1rem;">
<div>
图片上传组件说明
<ol style="font-size: .8rem; line-height: 1.8;">
<li>基础用法 &lt;w-image-uploader v-model="value" :getUploadKey="getUploadKey" max="1"
v-model:uploading="uploading" /&gt;</li>
<li>属性getUploadKey获取上传凭证的方法需要使用者提供开发模式下提供:<br />
前端示例<br />
<pre class="code">
const getUploadKey =async () => {
let r = await request.get("/file/upload/getUploadKey")
return r.data
} </pre>
后端示例<br />
<pre class="code"> @GetMapping("getUploadKey")
public R getUploadKey() {
return R.ok().setData(FileUtils.getUploadKey());
}</pre>
</li>
<li>属性v-model双向绑定上传的文件URL,max=1是类型为String,否则为Array</li>
<li>属性v-model:uploading双向绑定是否上传中,PS: 上传完成后才允许业务表单提交</li>
<li>属性max允许上传的文件数量0表示没有限制,默认0</li>
<li>属性prefix上传路径前缀默认default</li>
<li>属性disabled禁止上传图片预览模式 默认false</li>
<li>属性text按钮文字默认上传图片</li>
<li>属性maxSize允许上传的文件最大大小,0表示不限制默认0</li>
<li>属性threadNum并行上传数量默认2</li>
<li>属性retry重试次数默认3 </li>
<li>属性saveSrc是否保存图片原文件如果true则下载时下载原图zip文件否则下载大图片默认false </li>
<li>属性saveMin是否保存缩略图如果true则列表时显示缩略图否则显示大图默认true </li>
<li>属性watermark是否添加水印默认true </li>
<li>属性noEffect是否无效果本质设置css属性默认false </li>
<li>属性list是否显示列表默认true</li>
<li>属性before文件添加之前的方法返回true则继续</li>
<li>css属性--image-size图片显示大小默认 10em </li>
<li>css属性--image-border-radius图片显示圆角默认 .4em</li>
<li>css属性--image-margin图片外边距默认 .5em .5em 0 0</li>
<li>css属性--image-border图片边框默认 #FFF solid 2px </li>
<li>css属性--image-box-shadow图片阴影默认 0 0 .2em #0005</li>
<li>插槽button上传按钮插槽</li>
<li>插槽default图片列表插槽作用域list不建议定义</li>
<li>事件changemodelValue发送了变化</li>
</ol>
</div>
<el-divider>单图片上传</el-divider>
<w-image-uploader v-model="imgs[0]" saveSrc max="1" v-model:uploading="imging" />
<pre>绑定值{{ imgs[0] }}</pre>
<div>{{ imging ? '上传中' : '没有上传' }}
<w-image-view ref="imgView" />
<el-button @click="proxy.$refs.imgView.open(imgs[0])"></el-button>
</div>
<el-divider>9张图片上传</el-divider>
<div style="width: 50em;"><w-image-uploader v-model="imgs[1]" saveSrc max="9" text="9张图片上传"
style="--image-size:15em;" /></div>
<pre>绑定值{{ imgs[1] }}</pre>
<el-divider>预览模式</el-divider>
<w-image-uploader style="width: 35em;" disabled :modelValue="[
'/files/default/2024/10/24/d0wt3m3j4tud.webp',
'/files/default/2024/10/24/4x53htt9v8j1.webp',
'/files/default/2024/10/24/1trnacdjxeoju.webp',
'/files/default/2024/10/24/742tvr5pq526.webp',
'/files/default/2024/10/24/1dg74ibgi0xbj.webp',
'/files/default/2024/10/24/1bgesfnixpfvt.webp',
'/files/default/2024/10/24/h1legy4o8tko.webp',
'/files/default/2024/10/24/9xe6yyoed9dj.webp'
]" />
</div>
</el-tab-pane>
<el-tab-pane label="文件上传组件">
<div style="padding: 1rem;">
<div>
文件上传组件说明
<ol style="font-size: .8rem; line-height: 1.8;">
<li>基础用法 &lt;w-file-uploader v-model="value" :getUploadKey="getUploadKey" max="1"
v-model:uploading="uploading" /&gt;</li>
<li>大小大于chunksize的大文件上传会自动分片上传</li>
<li>属性getUploadKey获取上传凭证的方法需要使用者提供开发模式下提供:<br />
前端示例<br />
<pre class="code">
const getUploadKey =async () => {
let r = await request.get("/file/upload/getUploadKey")
return r.data
} </pre>
后端示例<br />
<pre class="code"> @GetMapping("getUploadKey")
public R getUploadKey() {
return R.ok().setData(FileUtils.getUploadKey());
}</pre>
</li>
<li>属性v-model双向绑定上传的文件URL,max=1是类型为String,否则为Array</li>
<li>属性v-model:uploading双向绑定是否上传中,PS: 上传完成后才允许业务表单提交</li>
<li>属性max允许上传的文件数量0表示没有限制,默认0</li>
<li>属性prefix上传路径前缀默认default</li>
<li>属性keepFilename是否保留文件名, 默认true</li>
<li>属性disabled禁止上传文件预览模式 默认false</li>
<li>属性text按钮文字默认上传文件</li>
<li>属性accept允许上传的文件扩展名列表默认'' ,office:'.doc,.docx,.ppt,.pptx,.xls,.xlsx'</li>
<li>属性maxSize允许上传的文件最大大小,0表示不限制默认0</li>
<li>属性threadNum并行上传数量默认2</li>
<li>属性retry重试次数默认3 </li>
<li>属性chunksize分片大小默认5Mb不建议修改</li>
<li>属性list是否显示列表默认true</li>
<li>属性border文件项是否显示边框默认true</li>
<li>属性before文件添加之前的方法返回true则继续</li>
<li>插槽button上传按钮插槽</li>
<li>插槽default文件列表作用域list不建议定义</li>
<li>事件changemodelValue发送了变化</li>
</ol>
</div>
<el-divider>单文件上传</el-divider>
<w-file-uploader v-model="data[0]" max="1" v-model:uploading="uploading" />
<pre>绑定值{{ data[0] }}</pre>
<div>{{ uploading ? '上传中' : '没有上传' }}</div>
<el-divider>预览模式</el-divider>
<w-file-uploader v-model="data[0]" max="1" :border="false" disabled />
<el-divider>单word文件小于10kb上传</el-divider>
<w-file-uploader v-model="data[1]" max="1" accept=".docx,.doc" text="单word文件小于10kb上传" :max-size="10240" />
<pre>绑定值{{ data[1] }}</pre>
<el-divider>多文件上传</el-divider>
<w-file-uploader v-model="data[2]" max="2" />
<pre>绑定值{{ data[2] }}</pre>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
const data = ref(['/files/default/2024/10/24/2nhdirb2ujey/5mb.txt'])
const uploading = ref(false)
const imgs = ref(['/files/default/2024/10/24/d0wt3m3j4tud.webp'])
const imging = ref(false)
</script>
<style lang="scss" scoped>
.code {
border: solid 1px #0001;
margin: .5rem;
padding: .5rem;
border-radius: .3rem;
}
</style>

@ -1,11 +1,20 @@
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
import px2rem from 'postcss-plugin-px2rem'
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd())
return {
build: {
target: 'es2020',
},
optimizeDeps: {
esbuildOptions: {
target: 'es2020',
},
},
// 部署生产环境和开发环境下的URL。
// 默认情况下vite 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
@ -25,9 +34,9 @@ export default defineConfig(({ mode, command }) => {
// vite 相关配置
server: {
hmr: true,
port: 80,
port: 8888,
host: true,
open: true,
open: false,
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
@ -40,7 +49,7 @@ export default defineConfig(({ mode, command }) => {
changeOrigin: true
},
'/files': {
target: 'http://192.168.3.222:9000',
target: 'http://192.168.3.56:9000',
changeOrigin: true
}
}
@ -49,6 +58,18 @@ export default defineConfig(({ mode, command }) => {
css: {
postcss: {
plugins: [
px2rem({
rootValue: 19.2, //换算基数, 默认100 ,也就是1440px 这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多少px了
unitPrecision: 5, //允许REM单位增长到的十进制数字其实就是精度控制
// propWhiteList: [], // 默认值是一个空数组,这意味着禁用白名单并启用所有属性。
// propBlackList: [], // 黑名单
// exclude:false, //默认false可以reg利用正则表达式排除某些文件夹的方法例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem请把此属性设为默认值
// selectorBlackList: [], //要忽略并保留为px的选择器
// ignoreIdentifier: false, //boolean/string忽略单个属性的方法启用ignoreidentifier后replace将自动设置为true。
// replace: true, // 布尔值替换包含REM的规则而不是添加回退。
mediaQuery: false, //布尔值允许在媒体查询中转换px
minPixelValue: 0 //设置要替换的最小像素值(3px会被转rem)。 默认 0
}),
{
postcssPlugin: 'internal:charset-removal',
AtRule: {

@ -0,0 +1,34 @@
# Dependencies
node_modules/
# Logs
logs/
*.log
# Environment files
.env*
# IDE files
.vscode/
.idea/
# OS generated files
.DS_Store
Thumbs.db
# Build outputs
dist/
build/
# PM2 logs
.pm2/
# Docker
.dockerignore
# pnpm
pnpm-lock.yaml
# Temporary files
*.tmp
*.temp

@ -0,0 +1,35 @@
# Use the official Node.js image as the base image
FROM node:22.16.0 AS builder
# Set the working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json (if available) to the working directory
COPY package*.json ./
# Install the application dependencies
RUN npm install
# Copy the rest of the application code to the working directory
COPY . .
# Production stage
FROM node:22.16.0-alpine AS production
# Set the working directory inside the container
WORKDIR /app
# Copy dependencies from builder stage
COPY --from=builder /app/node_modules ./node_modules
# Copy application code from builder stage
COPY --from=builder /app/. .
# Install pm2 globally
RUN npm install -g pm2
# Expose the port that the application listens on
EXPOSE 3000
# Define the command to run the application in production mode with pm2.json config
CMD ["pm2", "start", "pm2.json", "--no-daemon"]

@ -0,0 +1,3 @@
# 内部授权服务器
为内部第三方提供授权restful-api,如:emqx,zlmediakit

@ -0,0 +1,27 @@
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const username = process.env.AUTH_USERNAME || 'admin';
const password = process.env.AUTH_PASSWORD || '3.1415926'
const authUrl = process.env.AUTH_URL || 'http://127.0.0.1:8080'
// Middleware to parse JSON bodies
app.use(express.json());
app.use(express.urlencoded({extended: true}));
// RESTful routes
app.get('/', (req, res) => {
res.json({message: 'Welcome to the auth-inner-server API'});
});
app.post('/emqx-login', (req, res) => {
if (req.body.username === username && req.body.password === password) {
res.json({is_superuser: true, result: 'allow'});
} else {
res.json({is_superuser: false, result: 'deny'});
}
})
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});

@ -0,0 +1,24 @@
{
"name": "auth-inner-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"prod": "pm2 start index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.21.2",
"pm2": "^6.0.8"
},
"devDependencies": {
"nodemon": "^3.1.10"
},
"engines": {
"node": "22.16.0"
}
}

@ -0,0 +1,25 @@
{
"apps": [
{
"name": "auth-inner-server",
"script": "index.js",
"watch": [
"app"
],
"ignore_watch": [
"app/public"
],
"log_date_format": "YYYY-MM-DD HH:mm Z",
"error_file": "./logs/pm2-err.log",
"out_file": "./logs/pm2-out.log",
"merge_logs": true,
"exec_mode": "fork",
"max_memory_restart": "200M",
"autorestart": true,
"env": {
"NODE_ENV": "prd"
},
"instances": 1
}
]
}

File diff suppressed because one or more lines are too long

24
bi-ui/.gitignore vendored

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,3 @@
# 铁建智慧园区大屏
vite + vue3 + vue-router + pinia + axios + element-plus

5
bi-ui/env/.env vendored

@ -0,0 +1,5 @@
VITE_BASE_API='/api'
VITE_APP_NAME='智慧能源综合管控平台'
VITE_APP_CONTEXT_PATH="/bi/"
VITE_DEFAULT_USER="bi"
VITE_DEFAULT_PASSWORD="w8N9m8qQ+Z+skmrpPDl11TyJGTLX9hdwiA8DaeGxrS5peXwzcIwLiUUyzGJKUy/+BGZaSF40Y7fzUpjkAHvhwF9a7uZyzZlOhO+XSUUTgyj7bFNQCaYXFqb+ZAFpBWczopm95i/krFDfgiS4AmRv2Bb0wkegV5z071EjiCfOuPA="

@ -0,0 +1,2 @@
VITE_BASE_API='https://mock.apifox.cn/m1/2563668-0-default'
VITE_APP_NAME='测试大屏'

@ -0,0 +1,2 @@
VITE_BASE_API='http://127.0.0.1:4523/m1/2563668-0-default'
VITE_APP_NAME='铁建大屏'

@ -0,0 +1,144 @@
<!DOCTYPE html>
<html class="dark">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title></title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
html,
body,
#app {
min-height: 100vh;
background-color: #FFF;
margin: 0;
padding: 0;
user-select: none;
overflow: hidden;
border: none;
}
.loader {
width: 20em;
height: 20em;
font-size: 1.5vmin;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.loader .face {
position: absolute;
border-radius: 50%;
border-style: solid;
animation: animate 3s linear infinite;
}
.loader .face:nth-child(1) {
width: 100%;
height: 100%;
color: #0d9be0;
border-color: currentColor transparent transparent currentColor;
border-width: 0.2em 0.2em 0em .2em;
--deg: -45deg;
animation-direction: normal;
}
.loader .face:nth-child(2) {
width: 90%;
height: 90%;
color: #7bc528;
border-color: currentColor currentColor transparent transparent;
border-width: 0.2em 0em 0em 0.2em;
--deg: -135deg;
animation-direction: reverse;
}
.loader .face .circle {
position: absolute;
width: 50%;
height: 0.1em;
top: 50%;
left: 50%;
background-color: #0000;
transform: rotate(var(--deg));
transform-origin: left;
}
.loader .face .circle::before {
position: absolute;
top: -.5em;
right: -0.45em;
content: '';
width: .6em;
height: .6em;
background-color: currentColor;
border-radius: 50%;
box-shadow: 0 0 .5em .15em currentColor;
}
@keyframes animate {
to {
transform: rotate(1turn);
}
}
.loader-root {
position: absolute;
inset: 0;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: #00000001;
background-image: radial-gradient(#FFF, #ccc);
}
.loader-title {
margin: 4vmin 0 10vmin;
font-size: 3vmin;
color: #666;
text-shadow: .2vmin .2vmin 0 #fff;
letter-spacing: .3vmin;
}
.loader .logo img {
width: 13vmin;
height: 13vmin;
}
.loader .logo {
background-image: linear-gradient(to bottom, #FFF, #aaa);
padding: 3vmin;
border-radius: 50%;
box-shadow: 0 0 .5vmin #fff inset, 0 0 2vmin #0006;
}
</style>
</head>
<body style="margin:0;padding:0;user-select: none; overflow: hidden; border:none;">
<div id="app">
<div class="loader-root">
<div class="loader">
<div class="face">
<div class="circle"></div>
</div>
<div class="face">
<div class="circle"></div>
</div>
<div class="logo"><img src="/logo.png" loading="lazy"></div>
</div>
<div class="loader-title">正在加载系统资源,请耐心等待...</div>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

@ -0,0 +1,15 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
// 使@vscode
"@/*": ["src/*"]
},
// prettier
"experimentalDecorators": true,
// .jsx
"jsx": "preserve"
},
// IDE
"exclude": ["node_modules", "dist", "build"]
}

@ -0,0 +1,50 @@
{
"name": "large-screen-energylab",
"private": true,
"version": "0.0.1",
"scripts": {
"run:prop": "vite --mode prop",
"run:dev": "vite --mode dev",
"run:mock": "vite --mode mock",
"run:cloud": "vite --mode cloud",
"build:dev": "vite build --mode dev",
"build:cloud": "vite build --mode cloud",
"build:prop": "vite build --mode prop",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@microsoft/fetch-event-source": "2.0.1",
"@vueuse/components": "^12.7.0",
"@vueuse/core": "^12.7.0",
"axios": "0.27.2",
"crypto-js": "4.2.0",
"echarts": "5.4.2",
"element-plus": "2.9.2",
"file-saver": "2.0.5",
"highlight.js": "^11.11.1",
"jsencrypt": "^3.3.2",
"mescroll.js": "1.4.2",
"mitt": "3.0.1",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"pinia": "2.0.22",
"pinia-plugin-persist": "1.0.0",
"spark-md5": "3.0.2",
"swiper": "9.4.1",
"vue": "3.5.13",
"vue-cropper": "1.0.3",
"vue-router": "4.2.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "4.6.2",
"@vue/compiler-sfc": "3.2.45",
"postcss-plugin-px2rem": "0.8.1",
"sass": "1.84.0",
"unplugin-auto-import": "0.11.4",
"vite": "5.4.11",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-setup-extend": "0.4.0"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

@ -0,0 +1,28 @@
<script setup>
import { onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
//
(parent || window).postMessage("loading.hide", "*");
</script>
<template>
<div>
<Transition name="fade" mode="out-in">
<router-view></router-view>
</Transition>
</div>
</template>
<style lang="scss" scoped>
.loading {
position: fixed;
width: 100vw;
height: 100vh;
background: #000;
top: 0;
left: 0;
z-index: 9999;
}
</style>

@ -0,0 +1,9 @@
import mitt from 'mitt';
/**
* 穿件全局事件总线
* @type {Emitter<Record<EventType, unknown>>}
*/
const emitter = mitt();
export default emitter;

@ -0,0 +1,7 @@
import { request,params } from "@/api";
export const doLogin = (username,password)=>request.post("/login-pwd",params({username,password}),{
showLoading:true,
token:false
})

@ -0,0 +1,169 @@
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { useAuthStore } from '@/store'
/**
* @description: 创建sse连接
*/
class ServerSentEvents {
static defaultConfig = {
base: import.meta.env.VITE_BASE_API, // 基础地址
url: '/sse', // 地址
data: undefined, // 请求正文
params: undefined, // 请求参数
method: 'get', // 提交方式
auth: true, // 是否携带token
json: true, // 是否返回json
returnData: false, // json数据是否返回data属性
reconnect: true, //是否重连
headers: {
'Content-Type': 'application/json'
},
onopen: () => { },
onmessage: () => { },
onerror: () => { },
onclose: () => { }
}
constructor(config) {
if (config) {
this.setConfig(config)
this.init()
}
}
static get(url, onmessage = () => { }, config = {}) {
config.onmessage = onmessage
config.url = url
return new ServerSentEvents(config)
}
static post(url, data, onmessage = () => { }, config = {}) {
config.onmessage = onmessage
config.url = url
config.method = 'post'
config.data = data
return new ServerSentEvents(config)
}
setConfig(config) {
this.config = {
ctrl: new AbortController(),
...ServerSentEvents.defaultConfig,
...config
}
}
init() {
if (this.config.auth) {
this.config.headers.Authorization = 'Bearer ' + useAuthStore().token
}
let url = this.config.url
// 如果url不含协议
if (url.indexOf("//") == -1) {
url = this.config.base + url
}
if (this.config.params) {
if (url.indexOf("?") > -1) {
url += '&' + this.params(this.config.params)
} else {
url += '?' + this.params(this.config.params)
}
}
let body = undefined
if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
if (this.config.data.constructor == URLSearchParams) {
this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
body = this.params(this.config.data).toString()
} else if (this.config.data.constructor == FormData) {
this.config.headers['Content-Type'] = 'multipart/form-data'
body = this.config.data
} else {
body = JSON.stringify(body)
}
}
this.config._url = url
this.config._body = body
console.debug(this.config)
this.send()
}
send() {
fetchEventSource(this.config._url, {
method: this.config.method,
headers: this.config.headers,
body: this.config._body,
signal: this.config.ctrl.signal,
onopen: this.config.onopen,
onmessage: (msg) => {
if (this.config.json) {
let data = JSON.parse(msg.data)
if (this.config.returnData) {
data = data.data
}
this.config.onmessage(data)
} else {
this.config.onmessage(msg)
}
},
onclose: () => {
console.info('onclose')
this.abort()
this.config.onclose()
if (this.config.reconnect) {
this.send()
}
},
onerror: (err) => {
console.error(err)
this.abort()
this.config.onerror(err)
}
})
}
abort() {
if (this.config.ctrl && !this.config.reconnect) {
try {
this.config.ctrl.abort()
} catch (e) {
console.error(e)
}
}
}
params(param) {
if (param == null || param == "") {
return new URLSearchParams();
}
if (param.constructor == Array) {
let param1 = new URLSearchParams();
for (let obj of param) {
param1.append(obj.name, obj.value);
}
param = param1;
} else if (param.constructor == Object) {
let param1 = new URLSearchParams();
for (let name in param) {
param1.append(name, param[name]);
}
param = param1;
} else {
if (param.constructor == HTMLFormElement) {
param = new FormData(param);
}
if (param.constructor == FormData || param.constructor == String) {
param = new URLSearchParams(param);
}
}
return param;
}
}
export default ServerSentEvents

@ -0,0 +1,4 @@
export { request, params, formData } from './request'
export { doLogin } from './AuthApi'
import SSE from './SSE'
export { SSE }

@ -0,0 +1,153 @@
import { ElLoading, ElMessage } from 'element-plus'
import axios from 'axios'
import { useAuthStore } from '@/store';//导入用户仓库
const env = import.meta.env
import { useRouter,useRoute } from 'vue-router';
console.debug('env',env,env.VITE_BASE_API)
const instance = axios.create({
baseURL: env.VITE_BASE_API,
timeout: 30000,
showLoading: false,
showError: true,
token: true,//控制是否需要携带请求头令牌
returnData: true,//返回
});
let loading = null;
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
//如果需要携带请求头令牌,则从用户仓库中获取token设置请求头x-token中
if (config.token) {
let authStore = useAuthStore();
if (authStore.isLogin) {
config.headers["Authorization"] = "Bearer "+authStore.token;
}
}
if (config.showLoading) {
loading = ElLoading.service({
fullscreen: true,
lock: true,
text: 'Loading',
background: 'rgba(0, 0, 0, 0.1)',
});
}
// 在发送请求之前做些什么
return config;
}, function (error) {
if (loading != null) {
loading.close();
loading = null;
}
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
if (loading != null) {
loading.close();
loading = null;
}
// console.debug(response);
//对错误信息进行全局提示
if (response.config.showError) {
if ("code" in response.data) {
// if (!response.data.ok) {
// ElMessage.error(response.data.message);
// }
if (response.data.code != 200) {
ElMessage.error(response.data.msg || response.data.message);
if(response.data.code == 401) {
let authStore = useAuthStore();
authStore.logout();
useRouter().push({path:'/login', query: { to: encodeURIComponent(useRoute().fullPath) }});
}
}
}
}
// console.debug(response)
if (response.config.returnData) {
return response.data;
} else {
return response;
}
}, function (error) {
if (loading != null) {
loading.close();
loading = null;
}
// 对响应错误做点什么
ElMessage.error("响应错误:" + error.message);
return Promise.reject(error);
});
/**
* 格式化参数成URLSearchParams
* @param {String|Array|Object|HTMLFormElement|FormData|URLSearchParams} param
* @return {URLSearchParams}
*/
instance.params = function (param) {
if (param == null || param == "") {
return new URLSearchParams();
}
if (param.constructor == Array) {
let param1 = new URLSearchParams();
for (let obj of param) {
param1.append(obj.name, obj.value);
}
param = param1;
} else if (param.constructor == Object) {
let param1 = new URLSearchParams();
for (let name in param) {
param1.append(name, param[name]);
}
param = param1;
} else {
if (param.constructor == HTMLFormElement) {
param = new FormData(param);
}
if (param.constructor == FormData || param.constructor == String) {
param = new URLSearchParams(param);
}
}
return param;
}
instance.formData = function (param) {
if (param == null || param == "") {
return new FormData();
}
if (param.constructor == Array) {
let param1 = new FormData();
for (let obj of param) {
param1.append(obj.name, obj.value);
}
return param1;
}
if (param.constructor == Object) {
let param1 = new FormData();
for (let name in param) {
param1.append(name, param[name]);
}
return param1;
}
if (param.constructor == HTMLFormElement) {
return new FormData(param);
}
return new FormData();
}
export const request = instance;
export const params = instance.params;
export const formData = instance.formData;

@ -0,0 +1,5 @@
:root,
html,
html.dark {
@include varELColor($el-colors, -$w-step);
}

@ -0,0 +1,3 @@
:root,html {
@include varELColor($el-colors, $w-step);
}

@ -0,0 +1,110 @@
@use "sass:color";
@use "sass:map";
/*
*/
$w-size: .85vw;
/**
:
1. 使css,2:
1.1. /,()css
1.2. css,virtualHost
2. $css:$w-z-index -> --w-z-index
3. ,$colorsmain,
3.1. --w-main:
3.2. --w-main-light: + $w-step
3.3. --w-main-light-1: + $w-step * 2
3.4. --w-main-light-2: + $w-step * 3
3.5. --w-main-dark: - $w-step
3.6. --w-main-dark-1: - $w-step * 2
3.7. --w-main-dark-2: - $w-step * 3
3.8. --w-main-h:
3.9. --w-main-s:
3.10. --w-main-l:
3.11. $w-step--w-step,
4.:
4.1. 使csshsl: hsl(var(--w-main-h),var(--w-main-s),calc(var(--w-main-l) + 50%))
4.2. 使csshsla: hsl(var(--w-main-h),var(--w-main-s),var(--w-main-l),.5)
4.3. 使css,scss,使
4.4. ,\\\,
*/
//
$w-step: 5;
// z
$w-z-index: 100;
// z
$w-z-index-top: 1000;
$colors: (
"main": hsl(185, 80%, 50%),
"text": hsl(185, 80%, 5%),
"bg": #F8F8F8,
"primary": #3c9cff,
"warn": #eaa339,
"success": #5ac725,
"info": #999,
"error": #f56c6c,
"danger": #f56c6c
);
$dark-colors: (
"main": map.get($colors, "main"),
"text": map.get($colors, "bg"),
"bg": map.get($colors, "text"),
"primary": map.get($colors, "primary"),
"warn": map.get($colors, "warn"),
"success": map.get($colors, "success"),
"info": map.get($colors, "info"),
"error": map.get($colors, "error"),
"danger": map.get($colors, "danger")
);
$el-colors: (
"primary":"main",
"warn": "warn",
"success": "success",
"info": "info",
"error": "error",
"danger": "danger"
);
@mixin varColor($map, $step) {
@each $name , $value in $map {
$s: color.channel($value, "saturation", $space: hsl);
$h: color.channel($value, "hue", $space: hsl);
$l: color.channel($value, "lightness", $space: hsl);
--w-#{$name}-h: #{$h};
--w-#{$name}-s: #{$s};
--w-#{$name}-l: #{$l};
--w-#{$name}: hsl(var(--w-#{$name}-h), var(--w-#{$name}-s), var(--w-#{$name}-l));
//
@for $n from 1 through 6 {
@if $n == 1 {
--w-#{$name}-light: hsl(var(--w-#{$name}-h), var(--w-#{$name}-s), calc(var(--w-#{$name}-l) + #{$n} * var(--w-step) * 1%));
--w-#{$name}-dark: hsl(var(--w-#{$name}-h), var(--w-#{$name}-s), calc(var(--w-#{$name}-l) - #{$n} * var(--w-step) * 1%));
} @else {
--w-#{$name}-light-#{$n - 1}: hsl(var(--w-#{$name}-h), var(--w-#{$name}-s), calc(var(--w-#{$name}-l) + #{$n} * var(--w-step) * 1%));
--w-#{$name}-dark-#{$n - 1}: hsl(var(--w-#{$name}-h), var(--w-#{$name}-s), calc(var(--w-#{$name}-l) - #{$n} * var(--w-step) * 1%));
}
}
}
}
@mixin varELColor($map, $step) {
@each $name , $value in $map {
--el-color-#{$name}: hsl(var(--w-#{$value}-h), var(--w-#{$value}-s), var(--w-#{$value}-l));
@for $n from 1 through 9 {
--el-color-#{$name}-light-#{$n}: hsl(var(--w-#{$value}-h), var(--w-#{$value}-s), calc(var(--w-#{$value}-l) + #{$n} * var(--w-step) * 1%));
--el-color-#{$name}-dark-#{$n}: hsl(var(--w-#{$value}-h), var(--w-#{$value}-s), calc(var(--w-#{$value}-l) - #{$n} * var(--w-step) * 1%));
}
}
}

@ -0,0 +1,333 @@
/*
main.js
*/
@font-face {
font-family: led;
src: url(../fonts/led.ttf);
}
@font-face {
font-family: num;
src: url(../fonts/num.ttf);
}
@layer {
:root,
.w-var {
--w-step: #{$w-step};
--w-z-index: #{$w-z-index};
--w-z-index-top: #{$w-z-index-top};
--w-size: #{$w-size};
@include varColor($colors, $w-step);
}
.dark {
--w-step: #{-$w-step};
@include varColor($dark-colors, -$w-step);
}
* {
font-family: Segoe UI, Segoe UI Midlevel, Segoe WP, Arial, sans-serif;
box-sizing: border-box;
padding: 0;
margin: 0;
border: none;
outline: none;
color: inherit;
}
html {
font-size: var(--w-size);
color: var(--w-text);
background-color: var(--w-bg);
}
.w-abs {
position: absolute;
}
.w-lines {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.w-flex {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
position: relative;
}
.w-flex-column {
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
/* 印章效果 */
.w-seal {
position: absolute;
display: flex;
line-height: 1;
justify-content: center;
align-items: center;
box-sizing: border-box;
width: 6em;
height: 6em;
border-radius: 10em;
border: .25em solid currentColor;
background-color: #FFF;
z-index: 1;
transform: rotate(-25deg);
padding: 0;
&>div {
border: .13em solid currentColor;
padding: .3em 0;
width: 4.3em;
text-align: center;
font-weight: bold;
}
&::before {
content: "";
position: absolute;
width: 5em;
height: 5em;
border: .15em solid currentColor;
border-radius: 10em;
}
&::after {
content: "";
position: absolute;
width: 3.5em;
height: 3.5em;
border: .15em solid currentColor;
border-color: currentColor #0000 currentColor #0000;
border-radius: 10em;
}
}
.w-loading {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 1em;
border: solid .2em currentColor;
mask-image: conic-gradient(from 0deg, #0000 0%, #000 75%, #000 83%, #0000 85%);
animation: w-am-loading 1s ease infinite;
}
.w-inner-loading {
pointer-events: none;
user-select: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
&::before {
content: '';
position: absolute;
inset: 0;
background-color: var(--bg-color, #0003);
backdrop-filter: blur(.1em);
}
&::after {
position: absolute;
content: '';
font-size: var(--size, 1em);
display: block;
width: 1em;
height: 1em;
border-radius: 1em;
border: solid .2em var(--loading-color, currentColor);
mask-image: conic-gradient(from 0deg, #0000 0%, #000 75%, #000 83%, #0000 85%);
animation: w-am-loading 1s ease infinite;
}
}
@keyframes w-am-loading {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@property --border-gradient-angle {
syntax: "<angle>";
inherits: true;
initial-value: 0turn;
}
.w-border-light,
.w-border-light-1,
.w-border-light-2,
.w-border-light-3 {
position: relative;
border: none !important;
animation-play-state: inherit;
--border: .2em solid var(--w-main-dark-3);
--border-light-color: #FFF9;
--time: 5s;
&::before {
content: '';
pointer-events: none;
position: absolute;
inset: 0;
border: var(--border);
border-radius: inherit;
}
&::after {
content: '';
pointer-events: none;
position: absolute;
inset: 0;
border: var(--border);
border-color: var(--border-light-color);
border-radius: inherit;
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000, #000 10%, #0000 11%, #0000 50%, #000 60%, #0000 61%);
animation: am-frame var(--time) infinite linear;
animation-play-state: inherit;
}
}
.w-border-light-1::after {
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000, #000 10%, #0000 11%);
}
.w-border-light-3::after {
mask-image: conic-gradient(from var(--border-gradient-angle) at 50% 50%, #0000,#0000 23%, #000 33%, #0000 34%,#0000 56%,#000 66%,#0000 67%, #0000 89%, #000 99%, #0000 100%);
}
@keyframes am-frame {
0% {
--border-gradient-angle: 0turn;
}
100% {
--border-gradient-angle: 1turn;
}
}
.w-part-hide {
--top: 1em;
--bottom: 1em;
mask-image: linear-gradient(to bottom,#0000 0%,#000 var(--top),#000 calc(100% - var(--bottom)), #0000 100%);
}
.w-radio,
.w-checkbox {
--btn-color-inner: var(--btn-color, currentColor);
--opacity: .6;
transition: all .3s;
cursor: pointer;
&::before {
content: '';
display: inline-block;
font-size: var(--btn-size, inherit);
width: 1em;
height: 1em;
opacity: var(--opacity);
box-sizing: border-box;
border: solid 1px var(--btn-color-inner);
margin-right: .2em;
border-radius: .2em;
background-color: var(--btn-bg-color-inner, #0000);
background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNzA5NzA3MjQ5OTg3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQyODUiIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiI+PHBhdGggZD0iTTg0My42OTM5NTkgMjkzLjYwOTA2MSA0MjUuMjU1ODY5IDcxMi4wNTYzNjIgMTg2LjE0NTAyNiA0NzIuOTQ3NTY2IDY2LjU3OTg4MyA1OTIuNTA0NTIyIDQyNS4yNTU4NjkgOTUxLjE2NTE1OCA5NjMuMjYwMTI2IDQxMy4xNzQyMDRaIiBwLWlkPSI0Mjg2IiBmaWxsPSIjZmZmZmZmIj48L3BhdGg+PC9zdmc+");
background-size: .65em .65em;
background-repeat: no-repeat;
background-position: var(--background-position-inner, center -1em);
transition: all .3s;
overflow: hidden;
}
&.selected {
--btn-color-inner: var(--selected-btn-color, var(--w-main));
--opacity: 1;
--btn-bg-color-inner: var(--selected-btn-color, var(--w-main));
--background-position-inner: center .1em;
color: var(--selected-text-color, currentColor);
}
}
.w-radio::before {
border-radius: 1em;
}
@property --data-num {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
.w-breathing {
--filter: brightness(110%);
--transform: scale(1.1);
--time: 1.3s;
--data-num: 0;
--data-num-to: 1;
animation: w-am-breathing var(--time) infinite linear;
animation-play-state: inherit;
}
@keyframes w-am-breathing {
0% {
filter: none;
transform: none;
}
45% {
filter: var(--filter);
transform: var(--transform);
--data-num: var(--data-num-to);
}
90% {
filter: none;
transform: none;
}
}
}

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M156.608 487.86c1.156-1.138 2.649-1.623 3.919-2.56l306.667-301.569c13.195-12.97 34.586-12.97 47.78 0a32.836 32.836 0 010 46.988L263.303 478.21h579.204c18.978 0 34.362 15.129 34.362 33.79 0 18.662-15.384 33.793-34.362 33.793H263.302L514.974 793.28a32.832 32.832 0 010 46.985c-13.195 12.974-34.587 12.974-47.781 0L160.526 538.703c-1.27-.94-2.763-1.422-3.92-2.562-6.334-6.23-9.24-14.34-9.476-22.503.237-11.437 3.143-19.547 9.478-25.779zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 563 B

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>

After

Width:  |  Height:  |  Size: 954 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></path></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>

After

Width:  |  Height:  |  Size: 179 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575982282951" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="902" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M828.40625 90.125H195.59375C137.375 90.125 90.125 137.375 90.125 195.59375v632.8125c0 58.21875 47.25 105.46875 105.46875 105.46875h632.8125c58.21875 0 105.46875-47.25 105.46875-105.46875V195.59375c0-58.21875-47.25-105.46875-105.46875-105.46875z m52.734375 738.28125c0 29.16-23.57015625 52.734375-52.734375 52.734375H195.59375c-29.109375 0-52.734375-23.574375-52.734375-52.734375V195.59375c0-29.109375 23.625-52.734375 52.734375-52.734375h632.8125c29.16 0 52.734375 23.625 52.734375 52.734375v632.8125z" p-id="903"></path><path d="M421.52890625 709.55984375a36.28125 36.28125 0 0 1-27.55265625-12.66890625L205.17453125 476.613125a36.28546875 36.28546875 0 0 1 55.10109375-47.22890625l164.986875 192.4846875 342.16171875-298.48078125a36.2896875 36.2896875 0 0 1 47.70984375 54.68765625L445.3859375 700.6203125a36.3234375 36.3234375 0 0 1-23.85703125 8.93953125z" p-id="904"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>

After

Width:  |  Height:  |  Size: 971 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1546567861908" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2422" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M318.577778 819.2L17.066667 512l301.511111-307.2 45.511111 45.511111L96.711111 512l267.377778 261.688889zM705.422222 819.2l-45.511111-45.511111L927.288889 512l-267.377778-261.688889 45.511111-45.511111L1006.933333 512zM540.785778 221.866667l55.751111 11.150222L483.157333 802.133333l-55.751111-11.093333z" p-id="2423"></path></svg>

After

Width:  |  Height:  |  Size: 717 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577252187056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2508" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M747.59340925 691.12859384c11.51396329 0.25305413 22.43746719-0.21087818 40.74171707-1.51832482 29.35428085-2.10878421 35.84933734-2.36183835 46.47761114-0.8856895 24.71495444 3.37405491 41.12129828 21.76265671 32.47528161 47.95376084-85.57447632 258.19957947-442.00123984 249.76444099-628.67084683 50.73735554-153.47733892-159.33976008-153.09775772-414.41833795 0.92786545-573.42069196 159.71934128-162.67163983 424.03439521-166.59397897 565.78689185 0.63263534 80.38686649 94.81095318 108.34934958 169.16669549 89.11723508 230.57450162-15.01454608 47.99593598-50.61082928 77.68762207-119.77896259 114.63352789-4.89237973 2.65706845-29.35428085 15.52065436-35.84933652 19.02123633-46.94154346 25.30541465-63.51659033 41.20565021-62.20914449 58.45550757 2.95229856 39.13904114 24.16667102 52.7196135 70.98168823 53.81618115z m44.41100207 50.10472101c-19.82257471 1.43397372-32.05352527 1.940082-45.63409763 1.6448519-70.34905207-1.60267593-115.98314969-30.91478165-121.38163769-101.64341492-3.45840683-46.05585397 24.7571304-73.13264758 89.24376132-107.96976837 6.7902866-3.66928501 31.37871396-16.57504688 36.06021551-19.06341229 57.69634516-30.83042972 85.15271997-53.73183005 94.76877722-84.47790866 12.77923398-40.78389304-9.10994898-98.94417051-79.24812286-181.6507002-121.17075953-142.97559219-350.14258521-139.60153647-489.2380134 2.06660824-134.49827774 138.84237405-134.79350784 362.12048163-0.42175717 501.637667 158.53842169 168.99799328 451.9968783 181.18676788 534.57688175-11.80919339-4.68150156 0.2952301-10.71262573 0.67481131-18.72600705 1.26527069z" p-id="2509"></path><path d="M346.03865637 637.18588562a78.82636652 78.82636652 0 0 0 78.32025825-79.29029883c0-43.69401562-35.005823-79.29029883-78.32025825-79.29029882a78.82636652 78.82636652 0 0 0-78.36243338 79.29029882c0 43.69401562 35.005823 79.29029883 78.36243338 79.29029883z m0-51.7495729a27.07679361 27.07679361 0 0 1-26.5706845-27.54072593c0-15.30977536 11.97789643-27.54072593 26.5706845-27.54072592 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072592a27.07679361 27.07679361 0 0 1-26.57068533 27.54072593zM475.7289063 807.11174353a78.82636652 78.82636652 0 0 0 78.3624334-79.29029882c0-43.69401562-34.96364785-79.29029883-78.32025825-79.29029883a78.82636652 78.82636652 0 0 0-78.32025742 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029882z m0-51.74957208a27.07679361 27.07679361 0 0 1-26.57068532-27.54072674c0-15.30977536 12.06224753-27.54072593 26.57068532-27.54072593 14.59278892 0 26.57068533 12.23095057 26.57068453 27.54072593a27.07679361 27.07679361 0 0 1-26.57068453 27.54072674zM601.24376214 377.21492718a78.82636652 78.82636652 0 0 0 78.32025742-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025742-79.29029882a78.82636652 78.82636652 0 0 0-78.32025823 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025824 79.29029883z m1e-8-51.74957208a27.07679361 27.07679361 0 0 1-26.57068534-27.54072675c0-15.30977536 11.97789643-27.54072593 26.57068534-27.54072591 14.55061295 0 26.57068533 12.23095057 26.57068451 27.54072592a27.07679361 27.07679361 0 0 1-26.57068451 27.54072674zM378.80916809 433.85687983a78.82636652 78.82636652 0 0 0 78.32025824-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025824-79.29029802a78.82636652 78.82636652 0 0 0-78.32025742 79.29029802c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029883z m0-51.74957209a27.07679361 27.07679361 0 0 1-26.57068451-27.54072674c0-15.30977536 11.97789643-27.54072593 26.57068451-27.54072593 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072593a27.07679361 27.07679361 0 0 1-26.57068533 27.54072674z" p-id="2510"></path></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575804206892" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3145" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M826.56 470.016c-32.896 0-64.384 12.288-89.984 35.52l0-104.96c0-62.208-50.496-112.832-112.64-113.088L623.936 287.04 519.552 287.104C541.824 262.72 554.56 230.72 554.56 197.12c0-73.536-59.904-133.44-133.504-133.44-73.472 0-133.376 59.904-133.376 133.44 0 32.896 12.224 64.256 35.52 89.984L175.232 287.104l0 0.576C113.728 288.704 64 338.88 64 400.576l0.32 0 0.32 116.48C60.864 544.896 70.592 577.728 100.8 588.48c12.736 4.608 37.632 7.488 60.864-25.28 12.992-18.368 34.24-29.248 56.64-29.248 38.336 0 69.504 31.104 69.504 69.312 0 38.4-31.168 69.504-69.504 69.504-22.656 0-44.032-11.264-57.344-30.4C138.688 610.112 112.576 615.36 102.464 619.136c-29.824 10.752-39.104 43.776-38.144 67.392l0 160.384L64 846.912C64 909.248 114.752 960 177.216 960l446.272 0c62.4 0 113.152-50.752 113.152-113.152l0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.536 0 133.44-59.904 133.44-133.504C960 529.92 900.096 470.016 826.56 470.016zM826.56 672.896c-22.72 0-44.032-11.264-57.344-30.4-22.272-32.384-48.448-27.136-58.56-23.36-29.824 10.752-39.04 43.776-38.08 67.392l0 160.384c0 27.136-22.016 49.152-49.152 49.152L177.216 896.064C150.08 896 128 873.984 128 846.848l0.32 0 0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.6 0 133.504-59.904 133.504-133.504 0-73.472-59.904-133.376-133.504-133.376-32.896 0-64.32 12.288-89.984 35.52l0-104.96L128 400.512c0-27.072 22.08-49.152 49.216-49.152L177.216 351.04 334.656 350.72c3.776 0.512 7.616 0.832 11.52 0.832 24.896 0 50.752-10.816 60.032-37.056 4.544-12.736 7.424-37.568-25.344-60.736C362.624 240.768 351.68 219.52 351.68 197.12c0-38.272 31.104-69.44 69.376-69.44 38.336 0 69.504 31.168 69.504 69.44 0 22.72-11.264 44.032-30.528 57.472C427.968 276.736 433.088 302.784 436.8 313.024c10.752 29.888 43.072 39.232 67.392 38.08l119.232 0 0 0.384c27.136 0 49.152 22.08 49.152 49.152l0.256 116.48c-3.776 27.84 6.016 60.736 36.224 71.488 12.736 4.608 37.632 7.488 60.8-25.28 13.056-18.368 34.24-29.248 56.704-29.248C864.832 534.016 896 565.12 896 603.392 896 641.728 864.832 672.896 826.56 672.896z" p-id="3146"></path></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1 @@
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774833889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1376" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M887.466667 192.853333h-100.693334V119.466667c0-10.24-6.826667-17.066667-17.066666-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H303.786667V119.466667c0-10.24-6.826667-17.066667-17.066667-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H168.96c-46.08 0-85.333333 37.546667-85.333333 85.333334V836.266667c0 46.08 37.546667 85.333333 85.333333 85.333333H887.466667c46.08 0 85.333333-37.546667 85.333333-85.333333V278.186667c0-47.786667-37.546667-85.333333-85.333333-85.333334z m-718.506667 34.133334h100.693333v66.56c0 10.24 6.826667 17.066667 17.066667 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56h450.56v66.56c0 10.24 6.826667 17.066667 17.066666 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56H887.466667c27.306667 0 51.2 22.186667 51.2 51.2v88.746666H117.76v-88.746666c0-29.013333 22.186667-51.2 51.2-51.2zM887.466667 887.466667H168.96c-27.306667 0-51.2-22.186667-51.2-51.2V401.066667H938.666667V836.266667c0 27.306667-22.186667 51.2-51.2 51.2z" p-id="1377"></path><path d="M858.453333 493.226667H327.68c-10.24 0-17.066667 6.826667-17.066667 17.066666v114.346667h-116.053333c-10.24 0-17.066667 6.826667-17.066667 17.066667v133.12c0 10.24 6.826667 17.066667 17.066667 17.066666H460.8c10.24 0 17.066667-6.826667 17.066667-17.066666v-114.346667h380.586666c10.24 0 17.066667-6.826667 17.066667-17.066667v-133.12c0-10.24-6.826667-17.066667-17.066667-17.066666z m-413.013333 34.133333v97.28h-98.986667v-97.28h98.986667z m-230.4 131.413333h98.986667v98.986667h-98.986667v-98.986667z m131.413333 97.28v-97.28h98.986667v97.28h-98.986667z m133.12-228.693333h97.28v98.986667h-97.28v-98.986667z m131.413334 0h98.986666v98.986667h-98.986666v-98.986667z m230.4 97.28h-98.986667v-98.986667h98.986667v98.986667z" p-id="1378"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577186573535" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1068" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M479.85714249 608.42857168h64.28571502c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285751s-12.85714249-32.14285751-32.14285664-32.14285664h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285662s12.85714249 32.14285751 32.14285664 32.14285753z m-2e-8 122.14285665h64.28571504c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285665s-12.85714249-32.14285751-32.14285664-32.14285751h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285751s12.85714249 32.14285751 32.14285664 32.14285664z m353.57142921-559.28571416h-128.57142921v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285664-32.14285753s-32.14285751 12.85714249-32.14285751 32.14285753v32.14285664h-257.14285665v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285752-32.14285753s-32.14285751 12.85714249-32.14285664 32.14285753v32.14285664h-128.57142919c-70.71428585 0-128.57142832 57.85714249-128.57142832 122.14285751v501.42857081c0 70.71428585 57.85714249 128.57142832 128.57142832 122.14285751h642.85714335c70.71428585 0 128.57142832-57.85714249 128.57142833-122.14285751v-501.42857081c0-70.71428585-57.85714249-122.14285753-128.57142833-122.14285751z m64.28571415 623.57142832c0 32.14285751-32.14285751 64.28571415-64.28571416 64.28571504h-642.85714335c-32.14285751 0-64.28571415-25.71428583-64.28571417-64.28571504v-372.85714249h771.42857168v372.85714249z m0-437.14285664h-771.42857168v-64.28571417c0-32.14285751 32.14285751-64.28571415 64.28571417-64.28571415h128.57142919v32.14285664c0 19.28571417 12.85714249 32.14285751 32.14285664 32.14285751s32.14285751-12.85714249 32.14285753-32.14285751v-32.14285664h257.14285665v32.14285664c0 19.28571417 12.85714249 32.14285751 32.1428575 32.14285751s32.14285751-12.85714249 32.14285664-32.14285751v-32.14285664h128.57142921c32.14285751 0 64.28571415 25.71428583 64.28571415 64.28571415v64.28571417z m-610.71428583 372.85714247h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285664s-12.85714249-32.14285751-32.14285753-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285751s12.85714249 32.14285751 32.14285751 32.14285665z m385.71428583-122.14285664h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285751s-12.85714249-32.14285751-32.14285751-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285664s12.85714249 32.14285751 32.14285753 32.14285751z m-385.71428583 0h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285751s-12.85714249-32.14285751-32.14285753-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285664s12.85714249 32.14285751 32.14285751 32.14285751z m385.71428583 122.14285665h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285665s-12.85714249-32.14285751-32.14285751-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285751s12.85714249 32.14285751 32.14285753 32.14285665z" p-id="1069"></path></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035680909" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3601" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1002.0848 744.672l-33.568 10.368c0.96 7.264 2.144 14.304 2.144 21.76 0 7.328-1.184 14.432-2.368 21.568l33.792 10.56c7.936 2.24 14.496 7.616 18.336 14.752 3.84 7.328 4.672 15.808 1.952 23.552-5.376 16-23.168 24.672-39.936 19.68l-34.176-10.624c-7.136 12.8-15.776 24.672-26.208 35.2l20.8 27.488a28.96 28.96 0 0 1 5.824 22.816 29.696 29.696 0 0 1-12.704 19.616 32.544 32.544 0 0 1-44.416-6.752l-20.8-27.552c-13.696 6.56-28.192 11.2-43.008 13.888v33.632c0 16.736-14.112 30.432-31.648 30.432-17.6 0-31.872-13.696-31.872-30.432v-33.632a167.616 167.616 0 0 1-42.88-13.888l-20.928 27.552c-10.72 13.76-30.08 16.64-44.288 6.752a29.632 29.632 0 0 1-12.704-19.616 29.28 29.28 0 0 1 5.696-22.816l20.896-27.808a166.72 166.72 0 0 1-27.008-34.688l-33.376 10.432c-16.8 5.184-34.56-3.552-39.936-19.616a29.824 29.824 0 0 1 20.224-38.24l33.472-10.432c-0.8-7.264-2.016-14.304-2.016-21.824 0-7.36 1.184-14.496 2.304-21.632l-33.792-10.368c-16.672-5.376-25.632-22.496-20.224-38.432 5.376-16 23.136-24.672 39.936-19.68l34.016 10.752c7.328-12.672 15.84-24.8 26.336-35.328l-20.8-27.552a29.44 29.44 0 0 1 6.944-42.432 32.704 32.704 0 0 1 44.384 6.752l20.832 27.616c13.696-6.432 28.224-11.2 43.104-13.952v-33.568c0-16.736 14.048-30.432 31.648-30.432 17.536 0 31.808 13.568 31.808 30.432v33.504c15.072 2.688 29.344 7.808 42.848 14.016l20.992-27.616a32.48 32.48 0 0 1 44.224-6.752 29.568 29.568 0 0 1 7.136 42.432l-21.024 27.808c10.432 10.432 19.872 21.888 27.04 34.752l33.376-10.432c16.768-5.12 34.56 3.68 39.936 19.68 5.536 15.936-3.712 33.056-20.32 38.304z m-206.016-74.432c-61.344 0-111.136 47.808-111.136 106.56 0 58.88 49.792 106.496 111.136 106.496 61.312 0 111.104-47.616 111.104-106.496 0-58.752-49.792-106.56-111.104-106.56z" p-id="3602"></path><path d="M802.7888 57.152h-76.448c0-22.08-21.024-38.24-42.848-38.24H39.3968a39.68 39.68 0 0 0-39.36 40.032v795.616s41.888 120.192 110.752 120.192H673.2848a227.488 227.488 0 0 1-107.04-97.44H117.6368s-40.608-13.696-40.608-41.248l470.304-0.256 1.664 3.36a227.68 227.68 0 0 1-12.64-73.632c0-60.576 24-118.624 66.88-161.44a228.352 228.352 0 0 1 123.552-63.392l-3.2 0.288 2.144-424.672h38.208l0.576 421.024c27.04 0 52.672 4.8 76.64 13.344V101.536c0.032 0-6.304-44.384-38.368-44.384zM149.7648 514.336H72.3888v-77.408H149.7648v77.408z m0-144.32H72.3888v-77.44H149.7648v77.44z m0-137.248H72.3888v-77.44H149.7648v77.44z m501.856 281.568H206.0848v-77.408h445.536v77.408z m0-144.32H206.0848v-77.44h445.536v77.44z m0-137.248H206.0848v-77.44h445.536v77.44z" p-id="3603"></path></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>

After

Width:  |  Height:  |  Size: 418 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save