提交代码

This commit is contained in:
guanj
2025-09-25 11:34:55 +08:00
commit 448b8df85b
188 changed files with 21433 additions and 0 deletions

10
src/App.vue Normal file
View File

@@ -0,0 +1,10 @@
<script setup lang="ts">
import loadSvg from '@/utils/loadSvg'
loadSvg()
</script>
<template>
<router-view></router-view>
</template>
<style scoped></style>

87
src/api/index.ts Normal file
View File

@@ -0,0 +1,87 @@
import http from '@/utils/request'
//查询图元
export function find() {
return http.request({
url: '/cs-system-boot/csElement/find',
method: 'POST'
})
}
// 获取svg文件
export function download(params: any) {
return http.request({
url: '/system-boot/file/download',
method: 'get',
params
})
}
// 新增图元
export function addElement(params: any) {
return http.request({
url: '/cs-system-boot/csElement/add',
method: 'post',
data: params
})
}
// 删除图元
export function deleteElement(params: any) {
return http.request({
url: '/cs-system-boot/csElement/delete',
method: 'post',
params: params
})
}
// 查询左侧图纸列表
export function queryPage(params: any) {
return http.request({
url: '/cs-harmonic-boot/cspage/queryPage',
method: 'post',
data: params
})
}
// 总的画布的保存
export function addCanvas(params: any) {
return http.request({
url: '/cs-harmonic-boot/cspage/add',
method: 'post',
data: params
})
}
// 截图
export function audit(params: any) {
return http.request({
url: '/cs-harmonic-boot/csconfiguration/audit',
method: 'post',
data: params
})
}
// 监测点列表
export function lineTree(params: any) {
return http.request({
url: '/cs-device-boot/csLedger/lineTree',
method: 'post',
data: params
})
}
// 指标列表
export function targetList(params: any) {
return http.request({
url: '/cs-harmonic-boot/lineTarget/target',
method: 'post',
params: params
})
}
// 无锡指标列表
export function eleEpdChooseTree_wx() {
return http.request({
url: '/csDictData/eleEpdChooseTree',
method: 'get'
})
}

10
src/api/index_wx.ts Normal file
View File

@@ -0,0 +1,10 @@
import http from '@/utils/request'
// 监测点树
export function lineTree_wx(params: any) {
return http.request({
url: '/terminalTree/tree',
method: 'get',
params: params
})
}

91
src/assets/css-vars.css Normal file
View File

@@ -0,0 +1,91 @@
#mt-edit.dark {
color-scheme: dark;
--el-color-primary: #409eff;
--el-color-primary-light-3: #3375b9;
--el-color-primary-light-5: #2a598a;
--el-color-primary-light-7: #213d5b;
--el-color-primary-light-8: #1d3043;
--el-color-primary-light-9: #18222c;
--el-color-primary-dark-2: #66b1ff;
--el-color-success: #67c23a;
--el-color-success-light-3: #4e8e2f;
--el-color-success-light-5: #3e6b27;
--el-color-success-light-7: #2d481f;
--el-color-success-light-8: #25371c;
--el-color-success-light-9: #1c2518;
--el-color-success-dark-2: #85ce61;
--el-color-warning: #e6a23c;
--el-color-warning-light-3: #a77730;
--el-color-warning-light-5: #7d5b28;
--el-color-warning-light-7: #533f20;
--el-color-warning-light-8: #3e301c;
--el-color-warning-light-9: #292218;
--el-color-warning-dark-2: #ebb563;
--el-color-danger: #f56c6c;
--el-color-danger-light-3: #b25252;
--el-color-danger-light-5: #854040;
--el-color-danger-light-7: #582e2e;
--el-color-danger-light-8: #412626;
--el-color-danger-light-9: #2b1d1d;
--el-color-danger-dark-2: #f78989;
--el-color-error: #f56c6c;
--el-color-error-light-3: #b25252;
--el-color-error-light-5: #854040;
--el-color-error-light-7: #582e2e;
--el-color-error-light-8: #412626;
--el-color-error-light-9: #2b1d1d;
--el-color-error-dark-2: #f78989;
--el-color-info: #909399;
--el-color-info-light-3: #6b6d71;
--el-color-info-light-5: #525457;
--el-color-info-light-7: #393a3c;
--el-color-info-light-8: #2d2d2f;
--el-color-info-light-9: #202121;
--el-color-info-dark-2: #a6a9ad;
--el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72);
--el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72);
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72);
--el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000, 0px 8px 16px -8px #000000;
--el-bg-color-page: #0a0a0a;
--el-bg-color: #141414;
--el-bg-color-overlay: #1d1e1f;
--el-text-color-primary: #e5eaf3;
--el-text-color-regular: #cfd3dc;
--el-text-color-secondary: #a3a6ad;
--el-text-color-placeholder: #8d9095;
--el-text-color-disabled: #6c6e72;
--el-border-color-darker: #636466;
--el-border-color-dark: #58585b;
--el-border-color: #4c4d4f;
--el-border-color-light: #414243;
--el-border-color-lighter: #363637;
--el-border-color-extra-light: #2b2b2c;
--el-fill-color-darker: #424243;
--el-fill-color-dark: #39393a;
--el-fill-color: #303030;
--el-fill-color-light: #262727;
--el-fill-color-lighter: #1d1d1d;
--el-fill-color-extra-light: #191919;
--el-fill-color-blank: transparent;
--el-mask-color: rgba(0, 0, 0, 0.8);
--el-mask-color-extra-light: rgba(0, 0, 0, 0.3);
transition: all 5s;
}
#mt-edit.dark .el-button {
--el-button-disabled-text-color: rgba(255, 255, 255, 0.5);
}
#mt-edit.dark .el-card {
--el-card-bg-color: var(--el-bg-color-overlay);
}
#mt-edit.dark .el-empty {
--el-empty-fill-color-0: var(--el-color-black);
--el-empty-fill-color-1: #4b4b52;
--el-empty-fill-color-2: #36383d;
--el-empty-fill-color-3: #1e1e20;
--el-empty-fill-color-4: #262629;
--el-empty-fill-color-5: #202124;
--el-empty-fill-color-6: #212224;
--el-empty-fill-color-7: #1b1c1f;
--el-empty-fill-color-8: #1c1d1f;
--el-empty-fill-color-9: #18181a;
}

6
src/assets/icons/add.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<path
d="M801.171 483.589H544V226.418c0-17.673-14.327-32-32-32s-32 14.327-32 32v257.171H222.83c-17.673 0-32 14.327-32 32s14.327 32 32 32H480v257.17c0 17.673 14.327 32 32 32s32-14.327 32-32v-257.17h257.171c17.673 0 32-14.327 32-32s-14.327-32-32-32z"
fill=""></path>
</svg>

After

Width:  |  Height:  |  Size: 412 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M228 216a12 12 0 0 1-12 12H40a12 12 0 0 1 0-24h176a12 12 0 0 1 12 12m-92-48V80a20 20 0 0 1 20-20h36a20 20 0 0 1 20 20v88a20 20 0 0 1-20 20h-36a20 20 0 0 1-20-20m24-4h28V84h-28Zm-116 4V40a20 20 0 0 1 20-20h36a20 20 0 0 1 20 20v128a20 20 0 0 1-20 20H64a20 20 0 0 1-20-20m24-4h28V44H68Z"/></svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M208 136h-68v-16h44a20 20 0 0 0 20-20V60a20 20 0 0 0-20-20h-44v-8a12 12 0 0 0-24 0v8H72a20 20 0 0 0-20 20v40a20 20 0 0 0 20 20h44v16H48a20 20 0 0 0-20 20v40a20 20 0 0 0 20 20h68v8a12 12 0 0 0 24 0v-8h68a20 20 0 0 0 20-20v-40a20 20 0 0 0-20-20M76 64h104v32H76Zm128 128H52v-32h152Z"/></svg>

After

Width:  |  Height:  |  Size: 404 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M52 40v176a12 12 0 0 1-24 0V40a12 12 0 0 1 24 0m16 60V64a20 20 0 0 1 20-20h88a20 20 0 0 1 20 20v36a20 20 0 0 1-20 20H88a20 20 0 0 1-20-20m24-4h80V68H92Zm144 60v36a20 20 0 0 1-20 20H88a20 20 0 0 1-20-20v-36a20 20 0 0 1 20-20h128a20 20 0 0 1 20 20m-24 4H92v28h120Z"/></svg>

After

Width:  |  Height:  |  Size: 387 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M228 40v176a12 12 0 0 1-24 0V40a12 12 0 0 1 24 0m-40 24v36a20 20 0 0 1-20 20H80a20 20 0 0 1-20-20V64a20 20 0 0 1 20-20h88a20 20 0 0 1 20 20m-24 4H84v28h80Zm24 88v36a20 20 0 0 1-20 20H40a20 20 0 0 1-20-20v-36a20 20 0 0 1 20-20h128a20 20 0 0 1 20 20m-24 4H44v28h120Z"/></svg>

After

Width:  |  Height:  |  Size: 389 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M228 40a12 12 0 0 1-12 12H40a12 12 0 0 1 0-24h176a12 12 0 0 1 12 12m-16 48v88a20 20 0 0 1-20 20h-36a20 20 0 0 1-20-20V88a20 20 0 0 1 20-20h36a20 20 0 0 1 20 20m-24 4h-28v80h28Zm-68-4v128a20 20 0 0 1-20 20H64a20 20 0 0 1-20-20V88a20 20 0 0 1 20-20h36a20 20 0 0 1 20 20m-24 4H68v120h28Z"/></svg>

After

Width:  |  Height:  |  Size: 409 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><path fill="currentColor" d="M224 116h-8V72a20 20 0 0 0-20-20h-40a20 20 0 0 0-20 20v44h-16V48a20 20 0 0 0-20-20H60a20 20 0 0 0-20 20v68h-8a12 12 0 0 0 0 24h8v68a20 20 0 0 0 20 20h40a20 20 0 0 0 20-20v-68h16v44a20 20 0 0 0 20 20h40a20 20 0 0 0 20-20v-44h8a12 12 0 0 0 0-24M96 204H64V52h32Zm96-24h-32V76h32Z"/></svg>

After

Width:  |  Height:  |  Size: 401 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 15 15">
<path fill="currentColor" fill-rule="evenodd"
d="M3.5 14.9a.4.4 0 0 0 .4-.4v-4.034l1.317 1.317a.4.4 0 0 0 .565-.566l-2-2a.4.4 0 0 0-.565 0l-2 2a.4.4 0 0 0 .565.566L3.1 10.466V14.5c0 .22.18.4.4.4ZM8 10.5a.5.5 0 0 0 .5.5h6a.5.5 0 1 0 0-1h-6a.5.5 0 0 0-.5.5Zm0-3a.5.5 0 0 0 .5.5h6a.5.5 0 0 0 0-1h-6a.5.5 0 0 0-.5.5ZM8.5 5a.5.5 0 1 1 0-1h6a.5.5 0 0 1 0 1h-6ZM3.9.5a.4.4 0 0 0-.8 0v4.034L1.781 3.217a.4.4 0 0 0-.565.566l2 2a.4.4 0 0 0 .565 0l2-2a.4.4 0 0 0-.565-.566L3.899 4.534V.5Z"
clip-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 614 B

View File

@@ -0,0 +1,6 @@
<svg viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200">
<path
d="M513.173333 128A255.061333 255.061333 0 0 0 448 298.666667c0 141.376 114.624 256 256 256a255.36 255.36 0 0 0 189.802667-84.202667c1.450667 13.653333 2.197333 27.498667 2.197333 41.536 0 212.074667-171.925333 384-384 384S128 724.074667 128 512c0-209.706667 168.106667-380.16 376.96-383.936L513.152 128z m-117.824 85.930667l-3.52 1.408C274.645333 262.826667 192 377.770667 192 512c0 176.725333 143.274667 320 320 320 145.408 0 268.16-96.981333 307.114667-229.802667l1.536-5.504-1.6 0.64a319.509333 319.509333 0 0 1-106.496 21.226667L704 618.666667c-176.725333 0-320-143.274667-320-320 0-28.48 3.754667-56.405333 10.944-83.2l0.405333-1.536z"></path>
</svg>

After

Width:  |  Height:  |  Size: 829 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M7.5 1h9v3H22v2h-2.029l-.5 17H4.529l-.5-17H2V4h5.5V1Zm2 3h5V3h-5v1ZM6.03 6l.441 15h11.058l.441-15H6.03ZM13 8v11h-2V8h2Z"/></svg>

After

Width:  |  Height:  |  Size: 242 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 15 15">
<path fill="currentColor" fill-rule="evenodd"
d="M5.5 2a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1 0-1H5V2.5a.5.5 0 0 1 .5-.5Zm4 0a.5.5 0 0 1 .5.5V5h2.5a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5v-3a.5.5 0 0 1 .5-.5ZM2 9.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-1 0V10H2.5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1H10v2.5a.5.5 0 0 1-1 0v-3Z"
clip-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 497 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M3 1h12.414L21 6.586V12h-2V9h-6V3H5v18h6v2H3V1Zm12 2.414V7h3.586L15 3.414Zm4.05 10.674l4.858 4.914l-4.858 4.914l-1.422-1.406l2.48-2.508h-7.11v-2h7.11l-2.48-2.508l1.422-1.406Z"/></svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 2048 2048">
<path fill="currentColor"
d="M1664 1664v-384h128v512h-512v-128h384zM1280 256h512v512h-128V384h-384V256zM256 768V256h512v128H384v384H256zm128 512v384h384v128H256v-512h128z" />
</svg>

After

Width:  |  Height:  |  Size: 283 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024"><path fill="currentColor" d="M912 820.1V203.9c28-9.9 48-36.6 48-67.9c0-39.8-32.2-72-72-72c-31.3 0-58 20-67.9 48H203.9C194 84 167.3 64 136 64c-39.8 0-72 32.2-72 72c0 31.3 20 58 48 67.9v616.2C84 830 64 856.7 64 888c0 39.8 32.2 72 72 72c31.3 0 58-20 67.9-48h616.2c9.9 28 36.6 48 67.9 48c39.8 0 72-32.2 72-72c0-31.3-20-58-48-67.9zM888 112c13.3 0 24 10.7 24 24s-10.7 24-24 24s-24-10.7-24-24s10.7-24 24-24zM136 912c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24zm0-752c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24zm704 680H184V184h656v656zm48 72c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/><path fill="currentColor" d="M288 474h448c8.8 0 16-7.2 16-16V282c0-8.8-7.2-16-16-16H288c-8.8 0-16 7.2-16 16v176c0 8.8 7.2 16 16 16zm56-136h336v64H344v-64zm-56 420h448c8.8 0 16-7.2 16-16V566c0-8.8-7.2-16-16-16H288c-8.8 0-16 7.2-16 16v176c0 8.8 7.2 16 16 16zm56-136h336v64H344v-64z"/></svg>

After

Width:  |  Height:  |  Size: 1023 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M12 21a9 9 0 1 0 0-18a9 9 0 0 0 0 18m11-9c0 6.075-4.925 11-11 11S1 18.075 1 12S5.925 1 12 1s11 4.925 11 11m-9.996 6.254H11V16.25h2.004zM11 15.25V14c0-.867.39-1.573.826-2.11c.432-.53.974-.974 1.41-1.318a2 2 0 1 0-3.123-2.24l-.333.944l-1.885-.666l.333-.943a4.001 4.001 0 1 1 6.246 4.476c-.431.34-.817.666-1.096 1.009c-.274.338-.378.61-.378.848v1.25z"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20"><path fill="currentColor" d="M3.5 18a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 1 0v15a.5.5 0 0 1-.5.5m12.5-.5a.5.5 0 0 0 1 0v-15a.5.5 0 0 0-1 0zM9 4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 295 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M3 1h12.414L21 6.586V23h-9v-2h7V9h-6V3H5v10H3V1Zm12 2.414V7h3.586L15 3.414ZM7.05 14.088l4.858 4.914l-4.858 4.914l-1.422-1.406l2.48-2.508H.997v-2h7.11l-2.48-2.508l1.422-1.406Z"/></svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@@ -0,0 +1,7 @@
<svg viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200">
<path
d="M522.88 874.666667a21.333333 21.333333 0 0 1 21.333333 21.333333v85.333333a21.333333 21.333333 0 0 1-21.333333 21.333334h-21.333333a21.333333 21.333333 0 0 1-21.333334-21.333334v-85.333333a21.333333 21.333333 0 0 1 21.333334-21.333333h21.333333z m268.416-107.52l60.352 60.352a21.333333 21.333333 0 0 1 0 30.165333l-15.082667 15.082667a21.333333 21.333333 0 0 1-30.186666 0l-60.330667-60.352a21.333333 21.333333 0 0 1 0-30.165334l15.082667-15.082666a21.333333 21.333333 0 0 1 30.165333 0z m-527.957333 0l15.082666 15.082666a21.333333 21.333333 0 0 1 0 30.165334l-60.352 60.352a21.333333 21.333333 0 0 1-30.165333 0l-15.082667-15.082667a21.333333 21.333333 0 0 1 0-30.165333l60.330667-60.352a21.333333 21.333333 0 0 1 30.186667 0zM512 277.333333c141.376 0 256 114.624 256 256s-114.624 256-256 256-256-114.624-256-256 114.624-256 256-256z m0 64a192 192 0 1 0 0 384 192 192 0 0 0 0-384z m448.213333 160a21.333333 21.333333 0 0 1 21.333334 21.333334v21.333333a21.333333 21.333333 0 0 1-21.333334 21.333333h-85.333333a21.333333 21.333333 0 0 1-21.333333-21.333333v-21.333333a21.333333 21.333333 0 0 1 21.333333-21.333334h85.333333z m-810.666666 0a21.333333 21.333333 0 0 1 21.333333 21.333334v21.333333a21.333333 21.333333 0 0 1-21.333333 21.333333h-85.333334a21.333333 21.333333 0 0 1-21.333333-21.333333v-21.333333a21.333333 21.333333 0 0 1 21.333333-21.333334h85.333334zM836.586667 193.92l15.082666 15.082667a21.333333 21.333333 0 0 1 0 30.165333l-60.352 60.352a21.333333 21.333333 0 0 1-30.165333 0l-15.082667-15.082667a21.333333 21.333333 0 0 1 0-30.165333l60.330667-60.352a21.333333 21.333333 0 0 1 30.186667 0z m-618.496 0l60.352 60.352a21.333333 21.333333 0 0 1 0 30.165333l-15.082667 15.082667a21.333333 21.333333 0 0 1-30.186667 0L172.821333 239.146667a21.333333 21.333333 0 0 1 0-30.165334l15.082667-15.082666a21.333333 21.333333 0 0 1 30.165333 0zM522.901333 64a21.333333 21.333333 0 0 1 21.333334 21.333333v85.333334a21.333333 21.333333 0 0 1-21.333334 21.333333h-21.333333a21.333333 21.333333 0 0 1-21.333333-21.333333V85.333333a21.333333 21.333333 0 0 1 21.333333-21.333333h21.333333z"
></path>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -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="1676518938084" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2193" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M893.60324 384c-54.7 1-101.1 36.4-118.4 85.4-2.2 6.4-8.3 10.6-15 10.6H263.80324c-6.7 0-12.8-4.2-15-10.6-17.3-49.1-63.6-84.4-118.4-85.4C59.90324 382.7 0.50324 440.6 0.00324 511.1-0.49676 582.2 57.00324 640 128.00324 640c55.7 0 103.1-35.6 120.7-85.3 2.3-6.4 8.3-10.7 15.1-10.7h496.4c6.8 0 12.8 4.3 15.1 10.7 17.6 49.7 65 85.3 120.7 85.3 71 0 128.5-57.8 128-128.9-0.5-70.5-59.9-128.4-130.4-127.1zM128.00324 576c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z m768 0c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z" p-id="2194"></path></svg>

After

Width:  |  Height:  |  Size: 904 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 36 36"><path fill="currentColor" d="M18.09 20.59A2.41 2.41 0 0 0 17 25.14V28h2v-2.77a2.41 2.41 0 0 0-.91-4.64" class="clr-i-outline clr-i-outline-path-1"/><path fill="currentColor" d="M26 15v-4.28a8.2 8.2 0 0 0-8-8.36a8.2 8.2 0 0 0-8 8.36V15H7v17a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V15Zm-14-4.28a6.2 6.2 0 0 1 6-6.36a6.2 6.2 0 0 1 6 6.36V15H12ZM9 32V17h18v15Z" class="clr-i-outline clr-i-outline-path-2"/><path fill="none" d="M0 0h36v36H0z"/></svg>

After

Width:  |  Height:  |  Size: 521 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M2 4h20v2H2V4Zm20 5.57v4.86L18.113 12L22 9.57ZM2 13v-2h15v2H2Zm0 7v-2h20v2H2Z"/></svg>

After

Width:  |  Height:  |  Size: 200 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M2 4h20v2H2V4Zm0 5.57L5.887 12L2 14.43V9.57ZM7 11h15v2H7v-2Zm-5 7h20v2H2v-2Z"/></svg>

After

Width:  |  Height:  |  Size: 199 B

View File

@@ -0,0 +1,6 @@
<svg width="256" height="256" xmlns="http://www.w3.org/2000/svg">
<g>
<path d="m227.32,73.37l-44.69,-44.68a16,16 0 0 0 -22.63,0l-123.31,123.31a15.86,15.86 0 0 0 -4.69,11.31l0,44.69a16,16 0 0 0 16,16l44.69,0a15.86,15.86 0 0 0 11.31,-4.69l83.67,-83.66l3.48,13.9l-36.8,36.79a8,8 0 0 0 11.31,11.32l40,-40a8,8 0 0 0 2.11,-7.6l-6.9,-27.61l26.45,-26.45a16,16 0 0 0 0,-22.63m-179.32,105.94l28.69,28.69l-28.69,0l0,-28.69zm48,25.38l-44.69,-44.69l84.69,-84.69l44.69,44.69l-84.69,84.69zm96,-96l-44.68,-44.69l24,-24l44.68,44.69l-24,24z" fill="currentColor"/>
<line stroke-width="10" y2="234" x2="245" y1="234" x1="47" stroke="#000" fill="none"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 650 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18ZM1 12C1 5.925 5.925 1 12 1s11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12Zm7.5-5.63L18.25 12L8.5 17.63V6.37Zm2 3.465v4.33L14.25 12L10.5 9.835Z"/></svg>

After

Width:  |  Height:  |  Size: 299 B

View File

@@ -0,0 +1,10 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200"
height="200">
<path
d="M512 65.984C266.08 65.984 65.984 266.08 65.984 512c0 245.952 200.064 446.016 446.016 446.016 245.952 0 446.016-200.064 446.016-446.016C958.016 266.08 757.952 65.984 512 65.984zM512 894.016C301.344 894.016 129.984 722.624 129.984 512 129.984 301.344 301.344 129.984 512 129.984c210.624 0 382.016 171.36 382.016 382.016C894.016 722.624 722.624 894.016 512 894.016z"
fill="#5C636E"></path>
<path
d="M512 255.2c-77.216 0-140.032 62.272-140.032 138.816 0 17.664 14.336 32 32 32s32-14.336 32-32c0-41.952 33.376-74.816 76.032-74.816 41.952 0 76.032 34.368 76.032 76.64 0 15.968-22.848 38.784-43.008 58.944C514.56 485.216 480 519.744 480 566.016l0 45.696c0 17.696 14.336 32 32 32s32-14.304 32-32l0-45.696c0-19.744 23.52-43.264 46.272-65.984 28.928-28.928 61.76-61.728 61.76-104.192C652.032 318.272 589.216 255.2 512 255.2z"
fill="#5C636E"></path>
<path d="M512 753.92m-48 0a1.5 1.5 0 1 0 96 0 1.5 1.5 0 1 0-96 0Z" fill="#5C636E"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="-1 -2 24 24"><path fill="currentColor" d="m19.347 7.24l.847-1.266a.984.984 0 0 1 1.375-.259c.456.31.58.93.277 1.383L19.65 10.38a.984.984 0 0 1-1.375.259L14.97 8.393a1.002 1.002 0 0 1-.277-1.382a.984.984 0 0 1 1.375-.26l1.344.915C16.428 4.386 13.42 2 9.863 2c-4.357 0-7.89 3.582-7.89 8s3.533 8 7.89 8c.545 0 .987.448.987 1s-.442 1-.987 1C4.416 20 0 15.523 0 10S4.416 0 9.863 0c4.504 0 8.302 3.06 9.484 7.24z"/></svg>

After

Width:  |  Height:  |  Size: 489 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 2048 2048"><path fill="currentColor" d="M1792 1152H475l466 467l-90 90l-621-621l621-621l90 90l-466 467h1189V384h128v768z"/></svg>

After

Width:  |  Height:  |  Size: 206 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44C30.9566 44 37.0836 40.4483 40.6667 35.0593" stroke="#333" stroke-width="4" stroke-linecap="round"/><path d="M44 24H30" stroke="#333" stroke-width="4" stroke-linecap="round"/><circle cx="24" cy="24" r="6" fill="#333" stroke="#333" stroke-width="4"/></svg>

After

Width:  |  Height:  |  Size: 481 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 2048 2048"><path fill="currentColor" d="M1792 128q27 0 50 10t40 27t28 41t10 50v1664H357l-229-230V256q0-27 10-50t27-40t41-28t50-10h1536zM512 896h1024V256H512v640zm768 512H640v384h128v-256h128v256h384v-384zm512-1152h-128v768H384V256H256v1381l154 155h102v-512h896v512h384V256z"/></svg>

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024"><path fill="currentColor" d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1c-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"/></svg>

After

Width:  |  Height:  |  Size: 644 B

View File

@@ -0,0 +1,6 @@
<svg viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<path
d="M919.6 405.6l-57.2-8c-12.7-1.8-23-10.4-28-22.1-11.3-26.7-25.7-51.7-42.9-74.5-7.7-10.2-10-23.5-5.2-35.3l21.7-53.5c6.7-16.4 0.2-35.3-15.2-44.1L669.1 96.6c-15.4-8.9-34.9-5.1-45.8 8.9l-35.4 45.3c-7.9 10.2-20.7 14.9-33.5 13.3-14-1.8-28.3-2.8-42.8-2.8-14.5 0-28.8 1-42.8 2.8-12.8 1.6-25.6-3.1-33.5-13.3l-35.4-45.3c-10.9-14-30.4-17.8-45.8-8.9L230.4 168c-15.4 8.9-21.8 27.7-15.2 44.1l21.7 53.5c4.8 11.9 2.5 25.1-5.2 35.3-17.2 22.8-31.7 47.8-42.9 74.5-5 11.8-15.3 20.4-28 22.1l-57.2 8C86 408 72.9 423 72.9 440.8v142.9c0 17.7 13.1 32.7 30.6 35.2l57.2 8c12.7 1.8 23 10.4 28 22.1 11.3 26.7 25.7 51.7 42.9 74.5 7.7 10.2 10 23.5 5.2 35.3l-21.7 53.5c-6.7 16.4-0.2 35.3 15.2 44.1L354 927.8c15.4 8.9 34.9 5.1 45.8-8.9l35.4-45.3c7.9-10.2 20.7-14.9 33.5-13.3 14 1.8 28.3 2.8 42.8 2.8 14.5 0 28.8-1 42.8-2.8 12.8-1.6 25.6 3.1 33.5 13.3l35.4 45.3c10.9 14 30.4 17.8 45.8 8.9l123.7-71.4c15.4-8.9 21.8-27.7 15.2-44.1l-21.7-53.5c-4.8-11.8-2.5-25.1 5.2-35.3 17.2-22.8 31.7-47.8 42.9-74.5 5-11.8 15.3-20.4 28-22.1l57.2-8c17.6-2.5 30.6-17.5 30.6-35.2V440.8c0.2-17.8-12.9-32.8-30.5-35.2z m-408 245.5c-76.7 0-138.9-62.2-138.9-138.9s62.2-138.9 138.9-138.9 138.9 62.2 138.9 138.9-62.2 138.9-138.9 138.9z"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20"><path fill="currentColor" d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path fill="currentColor" d="M17 4H3v10h14zM5 12l2.5-3l2 2L12 8l3 4zm-1 3h12v1H4z"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M6 22a4 4 0 0 1-1-7.874V9.874A4.002 4.002 0 0 1 6 2a4 4 0 0 1 1 7.874v4.252A4.002 4.002 0 0 1 6 22Zm-2-4a2 2 0 1 0 4 0a2 2 0 0 0-4 0ZM4 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0Zm8 12h7v2h-7v-2Zm0-7h10v2H12v-2Zm0-7h7v2h-7V4Z"/></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="-0.5 -2 24 24"><path fill="currentColor" d="m5.308 7.612l1.352-.923a.981.981 0 0 1 1.372.27a1.008 1.008 0 0 1-.266 1.388l-3.277 2.237a.981.981 0 0 1-1.372-.27L.907 6.998a1.007 1.007 0 0 1 .266-1.389a.981.981 0 0 1 1.372.27l.839 1.259C4.6 3.01 8.38 0 12.855 0c5.458 0 9.882 4.477 9.882 10s-4.424 10-9.882 10a.994.994 0 0 1-.988-1c0-.552.443-1 .988-1c4.366 0 7.906-3.582 7.906-8s-3.54-8-7.906-8C9.311 2 6.312 4.36 5.308 7.612z"/></svg>

After

Width:  |  Height:  |  Size: 507 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024"><path fill="currentColor" d="M736 550H288c-8.8 0-16 7.2-16 16v176c0 8.8 7.2 16 16 16h448c8.8 0 16-7.2 16-16V566c0-8.8-7.2-16-16-16zm-56 136H344v-64h336v64zm208 130c-39.8 0-72 32.2-72 72s32.2 72 72 72s72-32.2 72-72s-32.2-72-72-72zm0 96c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24zM736 266H288c-8.8 0-16 7.2-16 16v176c0 8.8 7.2 16 16 16h448c8.8 0 16-7.2 16-16V282c0-8.8-7.2-16-16-16zm-56 136H344v-64h336v64zm208-194c39.8 0 72-32.2 72-72s-32.2-72-72-72s-72 32.2-72 72s32.2 72 72 72zm0-96c13.3 0 24 10.7 24 24s-10.7 24-24 24s-24-10.7-24-24s10.7-24 24-24zM136 64c-39.8 0-72 32.2-72 72s32.2 72 72 72s72-32.2 72-72s-32.2-72-72-72zm0 96c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24zm0 656c-39.8 0-72 32.2-72 72s32.2 72 72 72s72-32.2 72-72s-32.2-72-72-72zm0 96c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg>

After

Width:  |  Height:  |  Size: 956 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 36 36"><path fill="currentColor" d="M12 25.14V28h2v-2.77a2.42 2.42 0 1 0-2-.09" class="clr-i-outline clr-i-outline-path-1"/><path fill="currentColor" d="M26 2a8.2 8.2 0 0 0-8 8.36V15H2v17a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V15h-4v-4.64A6.2 6.2 0 0 1 26 4a6.2 6.2 0 0 1 6 6.36v6.83a1 1 0 0 0 2 0v-6.83A8.2 8.2 0 0 0 26 2m-4 15v15H4V17Z" class="clr-i-outline clr-i-outline-path-2"/><path fill="none" d="M0 0h36v36H0z"/></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2M7 9l5-5l5 5m-5-5v12"/></svg>

After

Width:  |  Height:  |  Size: 262 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20"><path fill="currentColor" d="M2.5 3a.5.5 0 0 0 0 1h15a.5.5 0 0 0 0-1zM2 16.5a.5.5 0 0 1 .5-.5h15a.5.5 0 0 1 0 1h-15a.5.5 0 0 1-.5-.5M6 7a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 293 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20"><path fill="currentColor" d="m12.81 4.36l-1.77 1.78a4 4 0 0 0-4.9 4.9l-2.76 2.75C2.06 12.79.96 11.49.2 10a11 11 0 0 1 12.6-5.64zm3.8 1.85c1.33 1 2.43 2.3 3.2 3.79a11 11 0 0 1-12.62 5.64l1.77-1.78a4 4 0 0 0 4.9-4.9l2.76-2.75zm-.25-3.99l1.42 1.42L3.64 17.78l-1.42-1.42z"/></svg>

After

Width:  |  Height:  |  Size: 361 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20"><path fill="currentColor" d="M.2 10a11 11 0 0 1 19.6 0A11 11 0 0 1 .2 10m9.8 4a4 4 0 1 0 0-8a4 4 0 0 0 0 8m0-2a2 2 0 1 1 0-4a2 2 0 0 1 0 4"/></svg>

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

4
src/assets/main.css Normal file
View File

@@ -0,0 +1,4 @@
body {
margin: 0;
padding: 0;
}

View File

@@ -0,0 +1,5 @@
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 454 488.5">
<path d="m134.5,20c30.58,0,59.34,11.91,80.96,33.54,21.63,21.63,33.54,50.38,33.54,80.96s-11.91,59.34-33.54,80.96c-21.63,21.63-50.38,33.54-80.96,33.54s-59.34-11.91-80.96-33.54c-21.63-21.63-33.54-50.38-33.54-80.96s11.91-59.34,33.54-80.96c21.63-21.63,50.38-33.54,80.96-33.54m0-20C60.22,0,0,60.22,0,134.5s60.22,134.5,134.5,134.5,134.5-60.22,134.5-134.5S208.78,0,134.5,0h0Z"/>
<path d="m134.5,240c30.58,0,59.34,11.91,80.96,33.54,21.63,21.63,33.54,50.38,33.54,80.96s-11.91,59.34-33.54,80.96c-21.63,21.63-50.38,33.54-80.96,33.54s-59.34-11.91-80.96-33.54c-21.63-21.63-33.54-50.38-33.54-80.96s11.91-59.34,33.54-80.96c21.63-21.63,50.38-33.54,80.96-33.54m0-20C60.22,220,0,280.22,0,354.5s60.22,134.5,134.5,134.5,134.5-60.22,134.5-134.5-60.22-134.5-134.5-134.5h0Z"/>
<path d="m319.5,129.75c30.58,0,59.34,11.91,80.96,33.54,21.63,21.63,33.54,50.38,33.54,80.96s-11.91,59.34-33.54,80.96c-21.63,21.63-50.38,33.54-80.96,33.54s-59.34-11.91-80.96-33.54c-21.63-21.63-33.54-50.38-33.54-80.96s11.91-59.34,33.54-80.96c21.63-21.63,50.38-33.54,80.96-33.54m0-20c-74.28,0-134.5,60.22-134.5,134.5s60.22,134.5,134.5,134.5,134.5-60.22,134.5-134.5-60.22-134.5-134.5-134.5h0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<path d="m250,20c31.06,0,61.18,6.08,89.52,18.07,27.39,11.58,51.99,28.17,73.11,49.3,21.13,21.13,37.72,45.73,49.3,73.11,11.99,28.34,18.07,58.46,18.07,89.52s-6.08,61.18-18.07,89.52c-11.58,27.39-28.17,51.99-49.3,73.11s-45.73,37.72-73.11,49.3c-28.34,11.99-58.46,18.07-89.52,18.07s-61.18-6.08-89.52-18.07c-27.39-11.58-51.99-28.17-73.11-49.3-21.13-21.13-37.72-45.73-49.3-73.11-11.99-28.34-18.07-58.46-18.07-89.52s6.08-61.18,18.07-89.52c11.58-27.39,28.17-51.99,49.3-73.11,21.13-21.13,45.73-37.72,73.11-49.3,28.34-11.99,58.46-18.07,89.52-18.07m0-20C111.93,0,0,111.93,0,250s111.93,250,250,250,250-111.93,250-250S388.07,0,250,0h0Z"/>
<text transform="translate(193.93 213.75) scale(1.35 1)" style="font-family: SimHei, SimHei; font-size: 161.58px;"><tspan x="0" y="0">G</tspan></text>
<text transform="translate(145.34 570.94) scale(1.24 1)" style="font-family: SimHei, SimHei; font-size: 327.63px;"><tspan x="0" y="0">~</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 278 500">
<path d="m139,21c31.79,0,61.67,12.38,84.15,34.85,22.48,22.48,34.85,52.36,34.85,84.15s-12.38,61.67-34.85,84.15c-22.48,22.48-52.36,34.85-84.15,34.85s-61.67-12.38-84.15-34.85c-22.48-22.48-34.85-52.36-34.85-84.15s12.38-61.67,34.85-84.15c22.48-22.48,52.36-34.85,84.15-34.85m0-20C62.23,1,0,63.23,0,140s62.23,139,139,139,139-62.23,139-139S215.77,1,139,1h0Z"/>
<path d="m139,242c31.79,0,61.67,12.38,84.15,34.85,22.48,22.48,34.85,52.36,34.85,84.15s-12.38,61.67-34.85,84.15c-22.48,22.48-52.36,34.85-84.15,34.85s-61.67-12.38-84.15-34.85c-22.48-22.48-34.85-52.36-34.85-84.15s12.38-61.67,34.85-84.15c22.48-22.48,52.36-34.85,84.15-34.85m0-20C62.23,222,0,284.23,0,361s62.23,139,139,139,139-62.23,139-139-62.23-139-139-139h0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 861 B

View File

@@ -0,0 +1,16 @@
<?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
id="_图层_12" data-name="图层 12"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2803"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="200"
height="200"
>
<path
d="M959.800889 318.762667a30.364444 30.364444 0 0 1-11.377778 41.543111l-98.133333 56.632889-30.222222-52.864 94.435555-56.632889a47.872 47.872 0 0 1 22.641778-3.783111 34.688 34.688 0 0 1 22.656 15.104z m-898.844445 0c4.48-6.968889 11.107556-12.273778 18.887112-15.104a24.974222 24.974222 0 0 1 22.656 3.783111l94.435555 56.632889-30.222222 52.864-94.421333-56.632889a30.364444 30.364444 0 0 1-11.377778-41.543111h0.042666zM249.799111 129.962667a47.900444 47.900444 0 0 1 22.656-3.783111 37.688889 37.688889 0 0 1 18.887111 15.104l56.661334 94.407111-52.878223 30.208-56.647111-94.407111a30.364444 30.364444 0 0 1 11.377778-41.528889h-0.056889zM513.848889 56.888889a37.105778 37.105778 0 0 1 36.636444 31.530667v109.511111h-70.570666v-109.511111C476.131556 73.315556 494.961778 56.888889 513.848889 56.888889z m253.383111 73.073778a30.364444 30.364444 0 0 1 11.377778 41.528889l-56.647111 94.407111-52.878223-30.208 56.647112-94.407111a66.304 66.304 0 0 1 18.887111-15.104c7.552 0 18.887111 0 22.656 3.783111h-0.042667zM533.020444 409.329778L378.168889 665.614222h124.629333l-30.222222 181.902222 162.247111-252.387555h-132.024889l30.222222-185.799111z m-271.928888 483.100444h-64.782223V594.360889c1.521778-172.103111 141.952-310.556444 314.055111-309.632A308.48 308.48 0 0 1 819.868444 594.346667v298.069333H261.091556z m-169.955556 0H933.404444a37.12 37.12 0 0 1 33.991112 37.603556 33.877333 33.877333 0 0 1-33.991112 33.991111H91.164444a33.848889 33.848889 0 0 1-33.991111-33.991111 37.12 37.12 0 0 1 33.991111-37.603556"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180">
<rect y="0" width="180" height="180" rx="18.7" ry="18.7"/>
</svg>

After

Width:  |  Height:  |  Size: 205 B

View File

@@ -0,0 +1,22 @@
<?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="1689212544735"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2636"
width="48"
height="48"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<path
d="M866.816 588.8c17.92 11.264 45.056 11.264 61.44 0 16.384-12.288 16.384-31.232 0-41.984l-379.904-322.56c-9.728-5.632-20.992-8.704-33.792-7.68-12.8-1.024-24.064 1.024-33.792 7.68l-382.464 322.56c-16.384 12.288-16.384 31.232 0 41.984 17.92 11.264 45.056 11.264 61.44 0l354.816-303.616 352.256 303.616z"
p-id="2637"
></path>
<path
d="M873.984 836.608c17.92 11.264 45.056 11.264 61.44 0 16.384-12.288 16.384-31.232 0-41.984l-379.904-322.56c-9.728-5.632-20.992-8.704-33.792-7.68-12.8-1.024-24.064 1.024-33.792 7.68l-382.464 322.56c-16.384 12.288-16.384 31.232 0 41.984 17.92 11.264 45.056 11.264 61.44 0l354.816-303.616 352.256 303.616z"
p-id="2638"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 218 364">
<line x1="210.89" y1="6.61" x2="63.11" y2="154.39"
style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;" />
<line x1="56" y1="157" x2="201" y2="157"
style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;" />
<line x1="208.45" y1="154.2" x2="60.66" y2="301.98"
style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;" />
<polygon points="2.42 360.3 94.44 307.69 55.03 268.28 2.42 360.3" />
</svg>

After

Width:  |  Height:  |  Size: 641 B

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 492">
<polygon points="28.14 226 56 123.72 .27 123.72 28.14 226" stroke="none"/>
<line x1="28.14" y1=".6" x2="28.14" y2="126.7" style="stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<polygon points="28.38 266.54 .51 368.81 56.24 368.81 28.38 266.54" stroke="none"/>
<line x1="28.38" y1="491.94" x2="28.38" y2="365.83" style="stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
</svg>

After

Width:  |  Height:  |  Size: 559 B

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 259 158">
<rect x="10" y="50" width="239" height="99" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<text transform="translate(114.5 40.88)" style="font-size: 60px;">R</text>
</svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 134 337" style="enable-background:new 0 0 134 337;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<polygon points="67,227 92.72,124 41.28,124 " fill="none"/>
<line class="st3" x1="67" y1="0" x2="67" y2="127"/>
<line class="st3" x1="67" y1="243" x2="67" y2="337.05"/>
<rect x="8" y="83" class="st3" width="118" height="163"/>
</svg>

After

Width:  |  Height:  |  Size: 935 B

View File

@@ -0,0 +1,5 @@
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 258 499">
<circle cx="129.5" cy="370" r="119" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<circle cx="129.5" cy="179" r="119" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<path d="m248.5,180c0-93.19-52.48-168.86-117.53-169.99-.69.68-2.08,1.07-2.77,1.75" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 158 286">
<polyline points="6.88 87 79 14.88 151.12 87" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<polyline points="6.6 155.52 78.73 83.39 150.85 155.52" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="79" y1="94" x2="79" y2="286" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 552 B

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 210 392">
<line y1="284" x2="210" y2="284" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="25" y1="333" x2="185" y2="333" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="45" y1="382" x2="165" y2="382" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="105" x2="105" y2="275" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 648 B

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 125.5 318" style="enable-background:new 0 0 125.5 318;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<line class="st0" x1="111" y1="0" x2="111" y2="76"/>
<line class="st0" x1="111" y1="242" x2="111" y2="318"/>
<line class="st1" x1="96" y1="74" x2="124" y2="102"/>
<line class="st1" x1="96" y1="102" x2="124" y2="74"/>
<line class="st0" x1="110.5" y1="251.47" x2="9.5" y2="76.53"/>
</svg>

After

Width:  |  Height:  |  Size: 992 B

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 146 648">
<path d="m66,78c37,0,67,30,67,67s-30,67-67,67" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<path d="m65.91,211.53c37,0,67,30,67,67s-30,67-67,67" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<path d="m65.91,345.53c37,0,67,30,67,67s-30,67-67,67" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<line x1="62" y1=".5" x2="62" y2="86.5" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<line x1="74" y1="474" x2="74" y2="560" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 16px;"/>
<line x1=".14" y1="570" x2="145.86" y2="570" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="17.49" y1="604" x2="128.51" y2="604" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="33" y1="638" x2="113" y2="638" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 190 469">
<rect
x="10"
y="98.5"
width="170"
height="272"
style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px"
/>
<line
x1="95"
y1="1"
x2="95"
y2="469"
style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px"
/>
</svg>

After

Width:  |  Height:  |  Size: 452 B

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 465.5 465">
<circle cx="233" cy="233" r="222" stroke="currentColor" style="fill: none; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 269 B

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 345 151">
<line y1="74" x2="129" y2="74" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="135" x2="135" y2="151" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="345" y1="77" x2="216" y2="77" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
<line x1="210" y1="151" x2="210" y2="0" style="fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 644 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 120 282" style="enable-background:new 0 0 120 282;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke-width:16;stroke-miterlimit:10;}
</style>
<path class="st0" d="M60,215c-28.17,0-51-22.83-51-51s22.83-51,51-51s51,22.83,51,51"/>
<line class="st0" x1="60" y1="0" x2="60" y2="159"/>
<line class="st0" x1="60" y1="205" x2="60" y2="283"/>
<line class="st0" x1="120" y1="163" x2="50" y2="163"/>
</svg>

After

Width:  |  Height:  |  Size: 915 B

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 222 336" style="enable-background:new 0 0 222 336;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<line class="st0" x1="111" y1="0" x2="111" y2="336"/>
<polygon class="st0" points="111,269 204.92,106.33 17.08,106.33 "/>
</svg>

After

Width:  |  Height:  |  Size: 830 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 160 318" style="enable-background:new 0 0 160 318;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<line class="st0" x1="149.81" y1="-0.48" x2="149.81" y2="75.52"/>
<line class="st0" x1="149.81" y1="241.52" x2="149.81" y2="317.52"/>
<line class="st0" x1="149.31" y1="250.99" x2="48.31" y2="76.05"/>
<line class="st2" x1="50" y1="185" x2="108" y2="185"/>
</svg>

After

Width:  |  Height:  |  Size: 963 B

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 179 319" style="enable-background:new 0 0 179 319;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<line class="st0" x1="168.6" y1="0.58" x2="168.6" y2="76.58"/>
<line class="st0" x1="168.6" y1="242.58" x2="168.6" y2="318.58"/>
<line class="st0" x1="168.1" y1="252.05" x2="67.1" y2="77.11"/>
<rect x="82" y="107" transform="matrix(0.866 -0.5 0.5 0.866 -64.4769 78.3689)" class="st3" width="64" height="105"/>
<line class="st2" x1="45.05" y1="190.18" x2="87" y2="169"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: $$$/GeneralStr/196=Adobe Illustrator 27.6.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 133 318" style="enable-background:new 0 0 133 318;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:currentColor;stroke-width:20;stroke-miterlimit:10;}
.st1{fill:none;stroke:currentColor;stroke-width:4;stroke-miterlimit:10;}
.st2{fill:none;stroke:currentColor;stroke-width:10;stroke-miterlimit:10;}
.st3{fill:none;stroke:currentColor;stroke-width:16;stroke-miterlimit:10;}
</style>
<line class="st0" x1="109.27" y1="0.58" x2="109.27" y2="76.58"/>
<line class="st0" x1="109.27" y1="242.58" x2="109.27" y2="318.58"/>
<line class="st0" x1="108.77" y1="252.05" x2="7.77" y2="77.11"/>
<line class="st0" x1="82" y1="79" x2="133" y2="79"/>
</svg>

After

Width:  |  Height:  |  Size: 959 B

View File

@@ -0,0 +1,39 @@
<template>
<p
class="break-words w-1/1 h-1/1"
:class="props.vertical ? 'text-vertical' : ''"
:style="{ fontFamily: props.fontFamily, fontSize: props.fontSize + 'px', color: props.fill }"
>
{{ props.text }}
</p>
</template>
<script setup lang="ts">
const props = defineProps({
fontFamily: {
type: String,
default: ''
},
fontSize: {
type: Number,
default: 15
},
text: {
type: String,
default: ''
},
fill: {
type: String,
default: ''
},
vertical: {
type: Boolean,
default: false
}
})
</script>
<style scoped>
.text-vertical {
writing-mode: tb;
letter-spacing: 5px;
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<p
class="break-words w-1/1 h-1/1"
:class="props.vertical ? 'text-vertical' : ''"
:style="{ fontFamily: props.fontFamily, fontSize: props.fontSize + 'px', color: props.fill }"
>
{{ props.text }}
</p>
</template>
<script setup lang="ts">
const props = defineProps({
fontFamily: {
type: String,
default: ''
},
fontSize: {
type: Number,
default: 15
},
text: {
type: String,
default: ''
},
fill: {
type: String,
default: ''
},
vertical: {
type: Boolean,
default: false
}
})
</script>
<style scoped>
.text-vertical {
writing-mode: tb;
letter-spacing: 5px;
}
</style>

View File

@@ -0,0 +1,39 @@
<!-- eslint-disable vue/html-indent -->
<template>
<div class="w-1/1 h-1/1 flex justify-center items-center custom-card">
<el-card
class="w-95/100 h-95/100"
:shadow="props.shadow as any"
:style="{
'background-color': props.backGroundColor
}"
></el-card>
</div>
</template>
<script setup lang="ts">
import { ElCard } from 'element-plus'
const props = defineProps({
shadow: {
type: String,
default: ''
},
backGroundColor: {
type: String,
default: '#ffffff'
},
boxShadow: {
type: String,
default: '#ffffff'
}
})
</script>
<style lang="less">
.custom-card {
.el-card.is-always-shadow {
box-shadow: v-bind('`0px 0px 12px ${$props.boxShadow}`') !important;
}
.el-card.is-hover-shadow:hover {
box-shadow: v-bind('`0px 0px 12px ${$props.boxShadow}`') !important;
}
}
</style>

View File

@@ -0,0 +1,71 @@
<template>
<table class="w-1/1 h-1/1 kvTable">
<tbody>
<tr>
<td class="kvKey kvKeyValue" colspan="1">{{ props.label }}</td>
<td class="kvValue kvKeyValue" colspan="1">{{ props.value }}</td>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
import { ElDescriptions, ElDescriptionsItem } from 'element-plus'
import type { PropType } from 'vue'
const props = defineProps({
fontFamily: {
type: String,
default: ''
},
fontSize: {
type: Number,
default: 15
},
label: {
type: String,
default: ''
},
labelWidth: {
type: Number,
default: 50
},
value: {
type: String,
default: ''
},
valueWidth: {
type: Number,
default: 50
},
color: {
type: String,
default: ''
},
border: {
type: Boolean,
default: true
},
borderColor: {
type: String,
default: ''
}
})
</script>
<style scroped>
.kvTable {
border: v-bind('`${props.border?1:0}px solid ${props.borderColor}`');
}
.kvKeyValue {
font-size: v-bind('`${props.fontSize}px`');
font-family: v-bind('`${props.fontFamily}`');
color: v-bind('`${props.color}`');
}
.kvKey {
width: v-bind('`${props.labelWidth}px`');
border-right-width: v-bind('`${props.border?1:0}px`');
border-right-style: solid;
border-right-color: v-bind('`${props.borderColor}`') !important;
}
.kvValue {
width: v-bind('`${props.valueWidth}px`');
}
</style>

View File

@@ -0,0 +1,72 @@
<!-- eslint-disable vue/html-indent -->
<template>
<div>
<div class="flex">
<div class="font-bold" :style="{ color: props.fontColor, fontSize: `${props.dateSize}px` }">
{{ date }}
</div>
<div class="font-bold ml-5px" :style="{ color: props.fontColor, fontSize: `${props.weekSize}px ` }">
{{ week }}
</div>
</div>
<div class="font-bold mt-5px ml-5px" :style="{ color: props.fontColor, fontSize: `${props.timeSize}px ` }">
{{ time }}
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, onUnmounted } from 'vue'
const props = defineProps({
fontColor: {
type: String,
default: '#000000'
},
dateSize: {
type: Number,
default: 12
},
weekSize: {
type: Number,
default: 12
},
timeSize: {
type: Number,
default: 24
}
})
const now_date = ref(new Date())
const timer = ref()
const date = computed(() => {
const year = now_date.value.getFullYear()
const month = now_date.value.getMonth() + 1
const day = now_date.value.getDate()
const time = year.toString() + '年' + month.toString() + '月' + day.toString() + '日'
return time
})
const week = computed(() => {
const d = now_date.value.getDay()
const weekday = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
const time = weekday[d]
return time
})
const time = computed(() => {
const hour = now_date.value.getHours()
const minute = now_date.value.getMinutes()
const second = now_date.value.getSeconds()
const time =
(hour < 10 ? '0' + hour.toString() : hour.toString()) +
':' +
(minute < 10 ? '0' + minute.toString() : minute.toString()) +
':' +
(second < 10 ? '0' + second.toString() : second.toString())
return time
})
onMounted(() => {
timer.value = setInterval(() => {
now_date.value = new Date() // 修改数据date
}, 500)
})
onUnmounted(() => {
clearInterval(timer.value)
})
</script>

View File

@@ -0,0 +1,48 @@
<template>
<div style="width: 100%; height: 100%">
<button class="w-1/1 h-1/1" :style="getStyle(props.type, props.round)">
<el-text>{{ props.text }}</el-text>
</button>
</div>
</template>
<script setup lang="ts">
import { ElText } from 'element-plus'
import type { PropType } from 'vue'
type ButtonType = '' | 'default' | 'success' | 'warning' | 'info' | 'primary' | 'danger'
const props = defineProps({
text: {
type: String,
default: '按钮文本'
},
type: {
type: String as PropType<ButtonType>,
default: ''
},
round: {
type: Boolean,
default: false
}
})
const getStyle = (type: ButtonType, round: boolean) => {
let bg_color = ''
let border_radius = '4px'
if (type == 'primary') {
bg_color = '#409eff'
} else if (type == 'success') {
bg_color = '#67c23a'
} else if (type == 'warning') {
bg_color = '#e6a23c'
} else if (type == 'danger') {
bg_color = '#f56c6c'
} else if (type == 'info') {
bg_color = '#909399'
}
if (round) {
border_radius = '20px'
}
return {
backgroundColor: bg_color,
borderRadius: border_radius
}
}
</script>

View File

@@ -0,0 +1,39 @@
<template>
<p
class="break-words w-1/1 h-1/1"
:class="props.vertical ? 'text-vertical' : ''"
:style="{ fontFamily: props.fontFamily, fontSize: props.fontSize + 'px', color: props.fill }"
>
{{ props.text }}
</p>
</template>
<script setup lang="ts">
const props = defineProps({
fontFamily: {
type: String,
default: ''
},
fontSize: {
type: Number,
default: 15
},
text: {
type: String,
default: ''
},
fill: {
type: String,
default: ''
},
vertical: {
type: Boolean,
default: false
}
})
</script>
<style scoped>
.text-vertical {
writing-mode: tb;
letter-spacing: 5px;
}
</style>

View File

@@ -0,0 +1,11 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HelloWorld from '../index.vue'
describe('HelloWorld', () => {
it('renders properly', () => {
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
expect(wrapper.text()).toContain('Hello Vitest')
})
})

View File

@@ -0,0 +1,5 @@
<template>
<div class="w-1/1 h-1/1 select-none">
<slot></slot>
</div>
</template>

View File

@@ -0,0 +1,190 @@
<template>
<div>
<div
v-for="(item, key) in points"
:key="key"
:id="`resize_${key}`"
:style="item"
class="mt-dzr-resize mt-dzr-resize-point touch-none"
@mousedown="e => onMouseDown(e, key)"
@touchstart.passive="e => onMouseDown(e, key)"
></div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { IDzrPropsModelValue } from '../types'
import { dzrStore } from '../store'
import {
autoDestroyMouseMove,
calcGrid,
centerToTL,
degToRadian,
formatData,
getLength,
getNewStyle,
getXY
} from '../utils'
import type { MouseTouchEvent } from '../utils/types'
type ResizeProps = {
itemInfo: IDzrPropsModelValue
targetDom: HTMLElement | null
scaleRatio: number
gridAlignSize: number
genId: string
useProportionalScaling?: boolean
}
const resizeProps = withDefaults(defineProps<ResizeProps>(), {
scaleRatio: 1,
gridAlignSize: 1,
useProportionalScaling: false
})
const points = computed(() => {
return {
tl: {
left: '0px',
top: '0px',
cursor: getCursor(0)
},
tc: {
left: resizeProps.itemInfo.width / 2 + 'px',
top: '0px',
cursor: getCursor(45)
},
tr: {
left: resizeProps.itemInfo.width + 'px',
top: '0px',
cursor: getCursor(90)
},
l: {
left: '0px',
top: resizeProps.itemInfo.height / 2 + 'px',
cursor: getCursor(315)
},
r: {
left: resizeProps.itemInfo.width + 'px',
top: resizeProps.itemInfo.height / 2 + 'px',
cursor: getCursor(135)
},
bl: {
left: '0px',
top: resizeProps.itemInfo.height + 'px',
cursor: getCursor(270)
},
bc: {
left: resizeProps.itemInfo.width / 2 + 'px',
top: resizeProps.itemInfo.height + 'px',
cursor: getCursor(225)
},
br: {
left: resizeProps.itemInfo.width + 'px',
top: resizeProps.itemInfo.height + 'px',
cursor: getCursor(180)
}
}
})
const angle_to_cursor = [
{ start: 338, end: 23, cursor: 'nw' },
{ start: 23, end: 68, cursor: 'n' },
{ start: 68, end: 113, cursor: 'ne' },
{ start: 293, end: 338, cursor: 'w' },
{ start: 113, end: 158, cursor: 'e' },
{ start: 248, end: 293, cursor: 'sw' },
{ start: 203, end: 248, cursor: 's' },
{ start: 158, end: 203, cursor: 'se' }
]
/**
* 获取旋转之后的光标样式
* @param init_angle 初始角度 360/8=45
*/
const getCursor = (init_angle: number) => {
const now_init_angle = (init_angle + resizeProps.itemInfo.angle) % 360
const find_cursor = angle_to_cursor.find(f => f.start <= now_init_angle && f.end > now_init_angle)
if (!find_cursor) {
return 'nw-resize'
}
return find_cursor.cursor + '-resize'
}
const emits = defineEmits(['update:itemInfo', 'onResizeDone', 'onResizeMove'])
//记录原始位置
const dzr_copy_info_value = ref({ ...resizeProps.itemInfo })
const onMouseDown = (de: MouseTouchEvent, type: 'tl' | 'tc' | 'tr' | 'l' | 'r' | 'bl' | 'bc' | 'br') => {
de.stopPropagation()
dzr_copy_info_value.value = { ...resizeProps.itemInfo }
const { clientX: de_client_x, clientY: de_client_y } = getXY(de)
//计算组件中心点
const { width, height, left, top } = resizeProps.itemInfo
const centerX = left + width / 2
const centerY = top + height / 2
//记录原始信息和中心点
const rect = {
width,
height,
centerX,
centerY,
rotateAngle: resizeProps.itemInfo.angle
}
const onMouseMove = (me: MouseTouchEvent) => {
me.preventDefault()
dzrStore.showDzrCopy({ ...dzr_copy_info_value.value }, resizeProps.genId)
const { clientX: me_client_x, clientY: me_client_y } = getXY(me)
// 距离 网格对齐
const delta_x = (me_client_x - de_client_x) / resizeProps.scaleRatio
const delta_y = (me_client_y - de_client_y) / resizeProps.scaleRatio
const alpha = Math.atan2(delta_y, delta_x)
const delta_l = getLength(delta_x, delta_y)
const beta = alpha - degToRadian(rect.rotateAngle)
const deltaW = delta_l * Math.cos(beta)
const deltaH = delta_l * Math.sin(beta)
// 如果按shift键则等比缩放
const ratio = resizeProps.useProportionalScaling || me.shiftKey ? rect.width / rect.height : undefined
const {
position: { centerX, centerY },
size: { width, height }
} = getNewStyle(type, { ...rect, rotateAngle: rect.rotateAngle }, deltaW, deltaH, ratio, 1, 1)
const pData = centerToTL({
centerX,
centerY,
width,
height,
angle: resizeProps.itemInfo.angle
})
const format_data = formatData(pData, centerX, centerY)
const new_width = calcGrid(format_data.width, resizeProps.gridAlignSize)
const new_height = calcGrid(format_data.height, resizeProps.gridAlignSize)
emits('update:itemInfo', {
...resizeProps.itemInfo,
...format_data,
left: calcGrid(format_data.left, resizeProps.gridAlignSize),
top: calcGrid(format_data.top, resizeProps.gridAlignSize),
width: new_width,
height: new_height
})
emits('onResizeMove', {
width: new_width,
height: new_height
})
}
autoDestroyMouseMove(onMouseMove, () => {
dzrStore.hideDzrCopy()
emits('onResizeDone')
})
}
</script>
<style scoped lang="less">
.mt-dzr-resize {
position: absolute;
}
.mt-dzr-resize-point {
position: absolute;
background: #fff;
border: 1px solid #59c7f9;
width: 8px;
height: 8px;
margin-left: -4px;
margin-top: -4px;
border-radius: 50%;
z-index: 1;
}
</style>

View File

@@ -0,0 +1,86 @@
<template>
<div class="mt-dzr-rotate touch-none" @mousedown="onMouseDown" @touchstart.passive="onMouseDown">
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path
d="M929 849a30 30 0 0 1-30-30v-83.137a447.514 447.514 0 0 1-70.921 92.209C722.935 933.225 578.442 975.008 442 953.482a444.917 444.917 0 0 1-241.139-120.591 30 30 0 1 1 37.258-47.01l0.231-0.231A385.175 385.175 0 0 0 442 892.625v-0.006c120.855 22.123 250.206-13.519 343.656-106.975a386.646 386.646 0 0 0 70.6-96.653h-87.247a30 30 0 0 1 0-60H929a30 30 0 0 1 30 30V819a30 30 0 0 1-30 30zM512 392a120 120 0 1 1-120 120 120 120 0 0 1 120-120z m293.005-147.025a29.87 29.87 0 0 1-19.117-6.882l-0.232 0.231A386.5 386.5 0 0 0 689.478 168h-0.011c-145.646-75.182-329.021-51.747-451.117 70.35a386.615 386.615 0 0 0-70.6 96.65H255a30 30 0 0 1 0 60H95a30 30 0 0 1-30-30V205a30 30 0 0 1 60 0v83.129a447.534 447.534 0 0 1 70.923-92.206C317.981 73.866 493.048 37.2 647 85.836v-0.045a444.883 444.883 0 0 1 176.143 105.291 30 30 0 0 1-18.138 53.893z"
fill="#06B7FF"
></path>
</svg>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { dzrStore } from '../store'
import type { IDzrPropsModelValue } from '../types'
import { alignToGrid, autoDestroyMouseMove, getXY } from '../utils'
import type { MouseTouchEvent } from '../utils/types'
type RotateProps = {
itemInfo: IDzrPropsModelValue
targetDom: HTMLElement | null
genId: string
}
const rotateProps = withDefaults(defineProps<RotateProps>(), {})
const emits = defineEmits(['update:itemInfo', 'onRotateDone', 'onRotateMove'])
//记录原始位置
const dzr_copy_info_value = ref({ ...rotateProps.itemInfo })
const is_mouse_down = ref(false)
const onMouseDown = (de: MouseTouchEvent) => {
de.stopPropagation()
if (!rotateProps.targetDom) {
console.error('target_dom is null')
return
}
const target_dom_rect = rotateProps.targetDom.getBoundingClientRect()
if (!target_dom_rect) {
console.error('boundingClientRect is null')
return
}
const { clientX: de_client_x, clientY: de_client_y } = getXY(de)
dzr_copy_info_value.value = { ...rotateProps.itemInfo }
dzrStore.hideDzrCopy()
//记录旋转前的初始值
const init_angle = rotateProps.itemInfo.angle
//计算组件中心点位置
const center_x = target_dom_rect.left + target_dom_rect.width / 2
const center_y = target_dom_rect.top + target_dom_rect.height / 2
is_mouse_down.value = true
const onMouseMove = (me: MouseTouchEvent) => {
if (!is_mouse_down.value) {
return
}
const { clientX: me_client_x, clientY: me_client_y } = getXY(me)
dzrStore.showDzrCopy({ ...dzr_copy_info_value.value }, rotateProps.genId)
// 旋转前的角度
const rotate_before = Math.atan2(de_client_y - center_y, de_client_x - center_x) / (Math.PI / 180)
// 旋转后的角度
const rotate_after = Math.atan2(me_client_y - center_y, me_client_x - center_x) / (Math.PI / 180)
const new_angle = alignToGrid(init_angle + rotate_after - rotate_before)
emits('update:itemInfo', {
...rotateProps.itemInfo,
left: alignToGrid(rotateProps.itemInfo.left),
top: alignToGrid(rotateProps.itemInfo.top),
angle: new_angle
})
emits('onRotateMove', {
angle: new_angle
})
}
autoDestroyMouseMove(onMouseMove, () => {
dzrStore.hideDzrCopy()
is_mouse_down.value = false
emits('onRotateDone')
})
}
</script>
<style scoped lang="less">
.mt-dzr-rotate {
position: absolute;
cursor: grab;
left: 50%;
top: 0;
transform: translate(-50%, -160%);
width: 16px;
height: 16px;
font-size: 20px;
}
</style>

View File

@@ -0,0 +1,3 @@
import MtDzr from './index.vue'
export default MtDzr

View File

@@ -0,0 +1,276 @@
<template>
<div
class="absolute select-none opacity-30"
v-if="dzrStore.dzr_copy_info.show && dzrStore.dzr_copy_info.gen_id == gen_id && MtDzrProps.showGhostDom"
style="outline: 1px solid #06b7ff"
:style="getStyle(dzrStore.dzr_copy_info.value)"
>
<render-item>
<slot></slot>
</render-item>
</div>
<div
v-if="!MtDzrProps.hide"
:id="MtDzrProps.id"
ref="dzrRef"
:class="`${MtDzrProps.class} absolute select-none touch-none ${MtDzrProps.lock ? 'opacity-50' : ''} ${
MtDzrProps.active && MtDzrProps.modelValue.width != 0 && MtDzrProps.modelValue.height != 0
? 'dzr-active'
: ''
}`"
@mousedown="onMouseDown"
@touchstart.passive="onMouseDown"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
@click.right.prevent="onRightClick"
:style="getStyle(drag_data_info)"
>
<render-item>
<slot></slot>
</render-item>
<div v-if="MtDzrProps.resize && !MtDzrProps.lock && MtDzrProps.active && !MtDzrProps.disabled">
<resize-handle
v-model:item-info="mt_dzr_vmodel"
:target-dom="dzrRef"
:scale-ratio="MtDzrProps.scaleRatio"
:grid-align-size="grid_align_size"
:gen-id="gen_id"
:use-proportional-scaling="MtDzrProps.useProportionalScaling"
@on-resize-done="onResizeDone"
@on-resize-move="val => onResizeMove(val)"
></resize-handle>
</div>
<rotate-handle
v-if="MtDzrProps.rotate && !MtDzrProps.lock && MtDzrProps.active && !MtDzrProps.disabled"
v-model:item-info="mt_dzr_vmodel"
:target-dom="dzrRef"
:gen-id="gen_id"
@on-rotate-done="onRotateDone"
@on-rotate-move="val => onRotateMove(val)"
></rotate-handle>
</div>
</template>
<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue'
import { type IDzrProps, type IDzrPropsModelValue } from './types'
import { alignToGrid, autoDestroyMouseMove, getXY, randomString } from './utils/index'
import ResizeHandle from './components/resize-handle.vue'
import RotateHandle from './components/rotate-handle.vue'
import renderItem from './components/render-item.vue'
import { dzrStore } from './store/index'
import type { MouseTouchEvent } from './utils/types'
const MtDzrProps = withDefaults(defineProps<IDzrProps>(), {
id: randomString(16),
modelValue: () => {
return {
left: 0,
top: 0,
width: 0,
height: 0,
angle: 0
}
},
scaleRatio: 1,
grid: () => {
return {
enabled: false,
align: false,
size: 10
}
},
resize: true,
rotate: true,
lock: false,
active: false,
useProportionalScaling: false,
showGhostDom: true,
hide: false,
disabled: false,
adsorp_diff: () => {
return {
x: 0,
y: 0
}
}
})
const MtDzrEmits = defineEmits([
'update:modelValue',
'mousedown',
'onItemMove',
'moveMouseUp',
'onMouseEnter',
'onMouseLeave',
'onResizeMove',
'onResizeDone',
'onRotateDone',
'onRightClick',
'onRotateMove'
])
const dzrRef = ref()
//
const gen_id = randomString(16)
//记录原始位置
const dzr_copy_info_value = ref({ ...MtDzrProps.modelValue })
// 拖拽数据
const drag_data_info = ref({
...MtDzrProps.modelValue
})
const getStyle = (data: IDzrPropsModelValue) => {
const { width, height, left, top, angle } = data
return {
width: width + 'px',
height: height + 'px',
left: left + 'px',
top: top + 'px',
transform: `rotate(${angle}deg)`
}
}
//如果网格关闭或者没有开启网格对齐网格大小为1
const grid_align_size = computed(() => (!MtDzrProps.grid.align || !MtDzrProps.grid.enabled ? 1 : MtDzrProps.grid.size))
const mt_dzr_vmodel = computed({
get: () => drag_data_info.value,
set: value => {
drag_data_info.value = value
MtDzrEmits('update:modelValue', value)
}
})
const onMouseDown = (de: MouseTouchEvent) => {
MtDzrEmits('mousedown', de)
if (MtDzrProps.lock || MtDzrProps.disabled) {
return
}
//记录最开始点击时鼠标位置和组件的位置
const { clientX: de_client_x, clientY: de_client_y } = getXY(de)
dzr_copy_info_value.value = { ...MtDzrProps.modelValue }
drag_data_info.value = {
...MtDzrProps.modelValue
}
dzrStore.hideDzrCopy()
const { left: init_x, top: init_y } = MtDzrProps.modelValue
//计算xy轴最小坐标和最大坐标不要超出父元素
const { clientWidth, clientHeight } = dzrRef.value.parentElement
const min_left = 0
const min_top = 0
const max_left = clientWidth - MtDzrProps.modelValue.width
const max_top = clientHeight - MtDzrProps.modelValue.height
let set_new_left = init_x
let set_new_top = init_y
const onMouseMove = (me: MouseTouchEvent) => {
dzrStore.showDzrCopy({ ...dzr_copy_info_value.value }, gen_id)
const { clientX: me_client_x, clientY: me_client_y } = getXY(me)
const move_x = (me_client_x - de_client_x) / MtDzrProps.scaleRatio
const move_y = (me_client_y - de_client_y) / MtDzrProps.scaleRatio
const new_left = alignToGrid(init_x + move_x, grid_align_size.value)
const new_top = alignToGrid(init_y + move_y, grid_align_size.value)
set_new_left = new_left < min_left ? min_left : new_left > max_left ? max_left : new_left
set_new_top = new_top < min_top ? min_top : new_top > max_top ? max_top : new_top
drag_data_info.value = {
...drag_data_info.value,
left: set_new_left,
top: set_new_top
}
MtDzrEmits('onItemMove', {
move_length: {
x: new_left - init_x,
y: new_top - init_y
},
new_lt: {
left: set_new_left,
top: set_new_top
},
// 因为是鼠标松开的时候才更新组件数据所以这里需要把组件的实时binfo返回回去
move_binfo: {
id: MtDzrProps.id,
left: set_new_left,
top: set_new_top,
width: drag_data_info.value.width,
height: drag_data_info.value.height,
angle: drag_data_info.value.angle
}
})
nextTick(() => {
const adsorp_diff_x = MtDzrProps.adsorp_diff?.x ?? 0
const adsorp_diff_y = MtDzrProps.adsorp_diff?.y ?? 0
// 当视图渲染之后 根据需要吸附的距离更新数据
if (adsorp_diff_x == 0 && adsorp_diff_y == 0) {
return
}
set_new_left += adsorp_diff_x
set_new_top += adsorp_diff_y
drag_data_info.value = {
...drag_data_info.value,
left: set_new_left,
top: set_new_top
}
MtDzrEmits('onItemMove', {
new_lt: {
left: set_new_left,
top: set_new_top
},
// 因为是鼠标松开的时候才更新组件数据所以这里需要把组件的实时binfo返回回去
move_binfo: {
id: MtDzrProps.id,
left: set_new_left,
top: set_new_top,
width: drag_data_info.value.width,
height: drag_data_info.value.height,
angle: drag_data_info.value.angle
}
})
})
}
autoDestroyMouseMove(onMouseMove, () => {
nextTick(() => {
dzrStore.hideDzrCopy()
MtDzrEmits('moveMouseUp')
MtDzrEmits('update:modelValue', {
...MtDzrProps.modelValue,
left: set_new_left,
top: set_new_top
})
})
})
}
const onMouseEnter = (e: MouseEvent) => {
MtDzrEmits('onMouseEnter', e)
}
const onMouseLeave = (e: MouseEvent) => {
MtDzrEmits('onMouseLeave', e)
}
const onResizeMove = (val: any) => {
MtDzrEmits('onResizeMove', val)
}
const onResizeDone = () => {
MtDzrEmits('onResizeDone')
}
const onRotateDone = () => {
MtDzrEmits('onRotateDone')
}
const onRotateMove = (val: any) => {
MtDzrEmits('onRotateMove', val)
}
const onRightClick = (e: MouseEvent) => {
MtDzrEmits('onRightClick', e)
}
watch(
() => MtDzrProps.modelValue,
value => {
drag_data_info.value = value
},
{
deep: true
}
)
</script>
<style scoped>
.dzr {
position: absolute;
user-select: none;
}
.dzr-active {
outline: 1px solid #06b7ff;
}
</style>

View File

@@ -0,0 +1,34 @@
import { reactive } from 'vue'
import type { IDzrCopyInfo, IDzrStore } from './types'
import type { IDzrPropsModelValue } from '../types'
export const dzrStore: IDzrStore = reactive({
dzr_copy_info: {
gen_id: '',
show: false,
value: {
left: 0,
top: 0,
width: 0,
height: 0,
angle: 0
}
},
setDzrCopyInfo: (value: IDzrCopyInfo) => {
dzrStore.dzr_copy_info = value
},
showDzrCopy: (value: IDzrPropsModelValue, gen_id: string) => {
dzrStore.setDzrCopyInfo({
...dzrStore.dzr_copy_info,
show: true,
value,
gen_id
})
},
hideDzrCopy: () => {
dzrStore.setDzrCopyInfo({
...dzrStore.dzr_copy_info,
show: false
})
}
})

View File

@@ -0,0 +1,13 @@
import type { IDzrPropsModelValue } from '../types'
export interface IDzrStore {
dzr_copy_info: IDzrCopyInfo
setDzrCopyInfo: (value: IDzrCopyInfo) => void
showDzrCopy: (value: IDzrPropsModelValue, gen_id: string) => void
hideDzrCopy: () => void
}
export interface IDzrCopyInfo {
gen_id: string
show: boolean
value: IDzrPropsModelValue
}

View File

@@ -0,0 +1,31 @@
export interface IDzrProps {
id: string
modelValue: IDzrPropsModelValue //位置和大小
scaleRatio?: number //画布缩放倍数
hide: boolean //隐藏
grid?: IDzrPropsGrid //网格配置
resize?: boolean //开启缩放
rotate?: boolean //开启旋转
lock?: boolean //锁定
active?: boolean //激活
useProportionalScaling?: boolean //开启等比例缩放
showGhostDom?: boolean //是否显示幽灵dom
class?: string //
disabled: boolean //是否禁用
adsorp_diff?: {
x: number
y: number
}
}
export interface IDzrPropsModelValue {
left: number
top: number
width: number
height: number
angle: number
}
export interface IDzrPropsGrid {
enabled: boolean //开启网格
align: boolean //对齐到网格
size: number //网格大小
}

View File

@@ -0,0 +1,349 @@
import type { IDzrPropsModelValue } from '../types'
import type { MouseTouchEvent } from './types'
/**
* 会自动销毁的鼠标移动事件
* @param onMousemove
*/
export const autoDestroyMouseMove = (onMousemove: (e: MouseTouchEvent) => void, mouseUpCallBack?: () => void) => {
const onMouseup = () => {
document.removeEventListener('mousemove', onMousemove)
document.removeEventListener('touchmove', onMousemove)
document.removeEventListener('mouseup', onMouseup)
document.removeEventListener('touchend', onMouseup)
document.removeEventListener('mouseleave', onMouseup)
if (mouseUpCallBack) {
mouseUpCallBack()
}
}
document.addEventListener('mousemove', onMousemove)
document.addEventListener('touchmove', onMousemove)
document.addEventListener('mouseup', onMouseup)
document.addEventListener('touchend', onMouseup)
document.addEventListener('mouseleave', onMouseup)
}
/**
* 根据坐标对齐到网格
* @param position 当前坐标
* @param grid 网格大小
* @returns 对应网格的坐标
*/
export const alignToGrid = (position: number, grid = 1) => {
const integerPart = Math.floor(position / grid)
const fractionalPart = position % grid
if (fractionalPart >= grid / 2) {
return (integerPart + 1) * grid
} else {
return integerPart * grid
}
}
/** 根据移动的距离对齐到网格
* @param diff 移动的距离
* @param grid 网格大小
*/
export const calcGrid = (diff: number, grid = 1) => {
// 得到每次缩放的余数
const r = Math.abs(diff) % grid
// 正负grid
const mulGrid = diff > 0 ? grid : -grid
let result = 0
// 余数大于grid的1/2
if (r > grid / 2) {
result = mulGrid * Math.ceil(Math.abs(diff) / grid)
} else {
result = mulGrid * Math.floor(Math.abs(diff) / grid)
}
return result
}
/**
* 获取当前点击坐标 根据pc端和移动端获取
* @param e
* @returns
*/
export function getXY(e: MouseTouchEvent) {
let clientX = 0,
clientY = 0
if (isTouchEvent(e)) {
const touch = e.targetTouches[0]
clientX = touch.pageX
clientY = touch.pageY
} else {
clientX = e.clientX
clientY = e.clientY
}
return { clientX, clientY }
}
function isTouchEvent(val: unknown): val is TouchEvent {
const typeStr = Object.prototype.toString.call(val)
return typeStr.substring(8, typeStr.length - 1) === 'TouchEvent'
}
export const getLength = (x: number, y: number) => Math.sqrt(x * x + y * y)
export const degToRadian = (deg: number) => (deg * Math.PI) / 180
const cos = (deg: number) => Math.cos(degToRadian(deg))
const sin = (deg: number) => Math.sin(degToRadian(deg))
/**
* 计算并返回给定类型变换的新样式。
*
* @param {string} type - 变换的类型。
* @param {any} rect - 矩形对象。
* @param {number} deltaW - 宽度变化。
* @param {number} deltaH - 高度变化。
* @param {number | undefined} ratio - 比例。
* @param {number} minWidth - 最小宽度。
* @param {number} minHeight - 最小高度。
* @returns {Object} 矩形的新位置和大小。
*/
export const getNewStyle = (
type: string,
rect: any,
deltaW: number,
deltaH: number,
ratio: number | undefined,
minWidth: number,
minHeight: number
) => {
// eslint-disable-next-line prefer-const
let { width, height, centerX, centerY, rotateAngle } = rect
const widthFlag = width < 0 ? -1 : 1
const heightFlag = height < 0 ? -1 : 1
width = Math.abs(width)
height = Math.abs(height)
switch (type) {
case 'r': {
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
if (ratio) {
deltaH = deltaW / ratio
height = width / ratio
// 左上角固定
centerX += (deltaW / 2) * cos(rotateAngle) - (deltaH / 2) * sin(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle) + (deltaH / 2) * cos(rotateAngle)
} else {
// 左边固定
centerX += (deltaW / 2) * cos(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle)
}
break
}
case 'tr': {
deltaH = -deltaH
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
deltaW = deltaH * ratio
width = height * ratio
}
centerX += (deltaW / 2) * cos(rotateAngle) + (deltaH / 2) * sin(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle) - (deltaH / 2) * cos(rotateAngle)
break
}
case 'br': {
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
deltaW = deltaH * ratio
width = height * ratio
}
centerX += (deltaW / 2) * cos(rotateAngle) - (deltaH / 2) * sin(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle) + (deltaH / 2) * cos(rotateAngle)
break
}
case 'bc': {
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
deltaW = deltaH * ratio
width = height * ratio
// 左上角固定
centerX += (deltaW / 2) * cos(rotateAngle) - (deltaH / 2) * sin(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle) + (deltaH / 2) * cos(rotateAngle)
} else {
// 上边固定
centerX -= (deltaH / 2) * sin(rotateAngle)
centerY += (deltaH / 2) * cos(rotateAngle)
}
break
}
case 'bl': {
deltaW = -deltaW
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
height = width / ratio
deltaH = deltaW / ratio
}
centerX -= (deltaW / 2) * cos(rotateAngle) + (deltaH / 2) * sin(rotateAngle)
centerY -= (deltaW / 2) * sin(rotateAngle) - (deltaH / 2) * cos(rotateAngle)
break
}
case 'l': {
deltaW = -deltaW
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
if (ratio) {
height = width / ratio
deltaH = deltaW / ratio
// 右上角固定
centerX -= (deltaW / 2) * cos(rotateAngle) + (deltaH / 2) * sin(rotateAngle)
centerY -= (deltaW / 2) * sin(rotateAngle) - (deltaH / 2) * cos(rotateAngle)
} else {
// 右边固定
centerX -= (deltaW / 2) * cos(rotateAngle)
centerY -= (deltaW / 2) * sin(rotateAngle)
}
break
}
case 'tl': {
deltaW = -deltaW
deltaH = -deltaH
const widthAndDeltaW = setWidthAndDeltaW(width, deltaW, minWidth)
width = widthAndDeltaW.width
deltaW = widthAndDeltaW.deltaW
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
width = height * ratio
deltaW = deltaH * ratio
}
centerX -= (deltaW / 2) * cos(rotateAngle) - (deltaH / 2) * sin(rotateAngle)
centerY -= (deltaW / 2) * sin(rotateAngle) + (deltaH / 2) * cos(rotateAngle)
break
}
case 'tc': {
deltaH = -deltaH
const heightAndDeltaH = setHeightAndDeltaH(height, deltaH, minHeight)
height = heightAndDeltaH.height
deltaH = heightAndDeltaH.deltaH
if (ratio) {
width = height * ratio
deltaW = deltaH * ratio
// 左下角固定
centerX += (deltaW / 2) * cos(rotateAngle) + (deltaH / 2) * sin(rotateAngle)
centerY += (deltaW / 2) * sin(rotateAngle) - (deltaH / 2) * cos(rotateAngle)
} else {
centerX += (deltaH / 2) * sin(rotateAngle)
centerY -= (deltaH / 2) * cos(rotateAngle)
}
break
}
}
return {
position: {
centerX,
centerY
},
size: {
width: width * widthFlag,
height: height * heightFlag
}
}
}
/**
* 根据给定的参数设置高度和 deltaH 值。
*
* @param {number} height - 当前的高度值。
* @param {number} deltaH - 高度变化值。
* @param {number} minHeight - 最小高度值。
* @return {object} - 包含更新后的高度和 deltaH 值的对象。
*/
const setHeightAndDeltaH = (height: number, deltaH: number, minHeight: number) => {
const expectedHeight = height + deltaH
if (expectedHeight > minHeight) {
height = expectedHeight
} else {
deltaH = minHeight - height
height = minHeight
}
return { height, deltaH }
}
/**
* 设置元素的宽度和deltaW值。
*
* @param {number} width - 元素的当前宽度。
* @param {number} deltaW - 元素宽度的变化量。
* @param {number} minWidth - 元素的最小宽度。
* @return {Object} - 包含更新后的宽度和deltaW值的对象。
*/
const setWidthAndDeltaW = (width: number, deltaW: number, minWidth: number) => {
const expectedWidth = width + deltaW
if (expectedWidth > minWidth) {
width = expectedWidth
} else {
deltaW = minWidth - width
width = minWidth
}
return { width, deltaW }
}
/**
* 根据矩形的中心坐标、尺寸和角度计算左上角的位置。
*
* @param {object} params - 计算的参数。
* @param {number} params.centerX - 矩形的中心点的 x 坐标。
* @param {number} params.centerY - 矩形的中心点的 y 坐标。
* @param {number} params.width - 矩形的宽度。
* @param {number} params.height - 矩形的高度。
* @param {number} params.angle - 矩形的旋转角度。
* @return {object} - 矩形的左上角位置。
*/
export const centerToTL = ({ centerX, centerY, width, height, angle }: any): IDzrPropsModelValue => ({
top: centerY - height / 2,
left: centerX - width / 2,
width,
height,
angle
})
/**
* 格式化数据并返回一个包含更新后尺寸和位置的对象。
*
* @param {IDzrPropsModelValue} data - 包含宽度和高度的数据。
* @param {number} centerX - 中心点的x坐标。
* @param {number} centerY - 中心点的y坐标。
* @return {object} - 一个包含更新后尺寸和位置的对象。
*/
export const formatData = (data: IDzrPropsModelValue, centerX: number, centerY: number) => {
const { width, height } = data
return {
width: Math.abs(width),
height: Math.abs(height),
left: centerX - Math.abs(width) / 2,
top: centerY - Math.abs(height) / 2
}
}
/**
* 生成随机字符串
* @param len 生成个数
*/
export const randomString = (len?: number) => {
len = len || 10
const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
const maxPos = str.length
let random_str = ''
for (let i = 0; i < len; i++) {
random_str += str.charAt(Math.floor(Math.random() * maxPos))
}
return random_str
}

View File

@@ -0,0 +1 @@
export type MouseTouchEvent = MouseEvent | TouchEvent

View File

@@ -0,0 +1,78 @@
import ace from 'ace-builds'
import themeMonokaiUrl from 'ace-builds/src-noconflict/theme-monokai?url'
ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl)
import workerBaseUrl from 'ace-builds/src-noconflict/worker-base?url'
ace.config.setModuleUrl('ace/mode/base', workerBaseUrl)
import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url'
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl)
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl)
import snippetsJsonUrl from 'ace-builds/src-noconflict/snippets/json?url'
ace.config.setModuleUrl('ace/snippets/json', snippetsJsonUrl)
import modeJavascriptUrl from 'ace-builds/src-noconflict/mode-javascript?url'
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl)
import workerJavascriptUrl from 'ace-builds/src-noconflict/worker-javascript?url'
ace.config.setModuleUrl('ace/mode/javascript_worker', workerJavascriptUrl)
import snippetsJavascriptUrl from 'ace-builds/src-noconflict/snippets/javascript?url'
ace.config.setModuleUrl('ace/snippets/javascript', snippetsJavascriptUrl)
import 'ace-builds/src-noconflict/ext-language_tools'
// ace.require('ace/ext/language_tools');
const langTools = ace.require('ace/ext/language_tools')
langTools.addCompleter({
getCompletions: function (
_editor: any,
_session: any,
_pos: any,
prefix: string | any[],
callback: (
arg0: null,
arg1: {
name: string //显示的名称
value: string //插入的值,
score: number //分数
meta: string //描述
}[]
) => void
) {
if (prefix.length === 0) {
callback(null, [])
return
}
callback(null, [
{
name: '$mtEventCallBack',
value: '$mtEventCallBack(type,$item_info.id)',
score: 1000,
meta: '执行订阅回调函数'
},
{
name: '$mtElMessage',
value: '$mtElMessage.success("成功")',
score: 1000,
meta: '消息提示'
},
{
name: '$mtElMessageBox',
value: `$mtElMessageBox.alert('This is a message', 'Title', {
confirmButtonText: 'OK',
callback: (action) => {
console.log(action)
},
})`,
score: 1000,
meta: '消息弹出框'
},
{
name: '$item_info',
value: '$item_info',
score: 1000,
meta: '回调函数中获取当前触发事件图形的信息'
}
])
}
})

View File

@@ -0,0 +1,37 @@
@-webkit-keyframes rotate360 {
0% {
-webkit-transform: rotate3d(0, 0, 1, 0deg);
transform: rotate3d(0, 0, 1, 0deg);
}
50% {
-webkit-transform: rotate3d(0, 0, 1, 180deg);
transform: rotate3d(0, 0, 1, 180deg);
}
to {
-webkit-transform: rotate3d(0, 0, 1, 360deg);
transform: rotate3d(0, 0, 1, 360deg);
}
}
@keyframes rotate360 {
0% {
-webkit-transform: rotate3d(0, 0, 1, 0deg);
transform: rotate3d(0, 0, 1, 0deg);
}
50% {
-webkit-transform: rotate3d(0, 0, 1, 180deg);
transform: rotate3d(0, 0, 1, 180deg);
}
to {
-webkit-transform: rotate3d(0, 0, 1, 360deg);
transform: rotate3d(0, 0, 1, 360deg);
}
}
.animate__rotate360 {
-webkit-animation-name: rotate360;
animation-name: rotate360;
animation-timing-function: linear;
-webkit-transform-origin: center;
transform-origin: center;
}

View File

@@ -0,0 +1,280 @@
<template>
<div class="add-element">
<el-dialog v-model="open" title="新增图元" width="500px" destroy-on-close @close="closeDialog">
<el-form :model="element" ref="ruleFormRef" :rules="rules" label-width="120px">
<el-form-item label="图元分类:" prop="elementSonType">
<el-select v-model="element.elementSonType" placeholder="请选择图元分类" style="width: 100%">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<!-- <el-form-item label="组件子类型:" prop="elementSonType">
<el-select
v-model="element.elementSonType"
placeholder="请选择组件子类型"
style="width: 100%"
>
<el-option
v-for="item in options1.filter(
(item) => item.key == element.elementType
)"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> -->
<!-- <el-form-item label="图元状态:" prop="elementForm">
<el-select
v-if="element.elementSonType == '电力状态图元'"
v-model="element.elementForm"
placeholder="请选择图元状态"
style="width: 100%"
@change="
(val) => {
changeEvent(val, args);
}
"
>
<el-option
v-for="item in StatusList1"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-else="
element.elementSonType == '电力系统基础图元' ||
element.elementSonType == '自定义图元'
"
v-model="element.elementForm"
placeholder="请选择图元状态"
style="width: 100%"
@change="
(val) => {
changeEvent(val, args);
}
"
>
<el-option
v-for="item in StatusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> -->
<!-- <el-form-item label="组件编码:" prop="elementCode">
<el-input
v-model="element.elementCode"
placeholder="请选择组件编码"
style="width: 100%"
/>
</el-form-item> -->
<el-form-item label="图元名称:" prop="elementName">
<el-input v-model="element.elementName" placeholder="请选择组件名称" style="width: 100%" />
</el-form-item>
<!-- <el-form-item label="组件标识:" prop="elementMark">
<el-input v-model="element.elementMark" placeholder="请选择组件标识" style="width: 100%" />
</el-form-item> -->
<el-form-item label="上传svg:">
<el-upload
ref="upload"
v-model="fileList"
style="width: 415px"
action="#"
multiple
accept="image/svg+xml"
:http-request="UploadSvg"
:on-remove="handleRemove"
:before-upload="beforeAvatarUpload"
:limit="1"
:on-exceed="handleExceed"
>
<el-button type="primary">上传</el-button>
</el-upload>
<el-dialog v-model="dialogVisible">
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</el-form-item>
<el-form-item>
<el-button @click="addNewComponent(ruleFormRef)" type="primary">保存</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { defineProps, getCurrentInstance, onMounted, ref, watch, reactive } from 'vue'
import { ElInput, ElFormItem, ElForm, ElDialog, ElUpload, ElMessage, ElButton, ElSelect, ElOption } from 'element-plus'
import type { UploadInstance, UploadProps, FormInstance, FormRules, UploadFile, UploadUserFile } from 'element-plus'
import { addElement, download } from '@/api/index'
import { leftAsideStore } from '@/export'
const instance = getCurrentInstance() // 获取当前组件实例
const open = ref(false)
const props = defineProps({
show: Boolean
})
const element: any = ref({
elementCode: '', //组件编码
elementForm: '', // 图元状态
elementMark: '', //组件标识
elementName: '', //图元名称
elementSonType: '', //组件子类型 图元分类
elementType: '', //组件分类
multipartFile: '' // 图元文件
})
interface RuleForm {
elementCode: string
elementForm: string
elementMark: string
elementName: string
elementSonType: string
elementType: string
}
const options = [
{
value: '电力基础图元',
label: '电力基础图元'
},
{
value: '自定义',
label: '自定义'
}
]
const fileList = ref<UploadFile[]>([]) // 上传文件列表
const dialogImageUrl = ref('')
const dialogVisible = ref(false) // 上传图片预览
const handleRemove = (file: UploadFile) => {
fileList.value = []
}
// 文件校验
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
if (rawFile.type !== 'image/svg+xml') {
ElMessage.error('只能上传svg格式文件!')
return false
}
return true
}
const handleExceed: UploadProps['onExceed'] = files => {
return ElMessage.error('只能上传1个svg文件!')
}
// 上传svg
// const UploadSvg = (params:any) => {
// fileList.value.push(params.file);
// };
const UploadSvg = (params: any) => {
return new Promise<void>(resolve => {
fileList.value.push(params.file)
resolve()
})
}
const handlePictureCardPreview = (file: UploadFile) => {
dialogImageUrl.value = file.url!
dialogVisible.value = true
}
const ruleFormRef = ref<FormInstance>()
const rules = reactive<FormRules<RuleForm>>({
elementCode: [{ required: true, message: '请输入组件编码', trigger: 'blur' }],
elementForm: [{ required: true, message: '请选择图元状态', trigger: 'change' }],
elementMark: [{ required: true, message: '请输入组件标识', trigger: 'blur' }],
elementName: [{ required: true, message: '请输入图元名称', trigger: 'blur' }],
elementSonType: [{ required: true, message: '请选择父类型', trigger: 'change' }],
elementType: [{ required: true, message: '请选择组件分类', trigger: 'change' }]
})
const closeDialog = () => {
open.value = false
if (instance) {
const emit = instance.emit
emit('update:show', false) // 向父组件发送更新后的状态
}
}
watch(
() => props.show,
val => {
if (val === true) {
open.value = true
element.value = {}
}
}
)
// 新增保存
const addNewComponent = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(valid => {
if (valid) {
if (fileList.value.length == 0) {
ElMessage({
message: '请上传svg文件!',
type: 'warning'
})
return Promise.resolve() // 显式返回 Promise<void>
}
let form = new FormData()
form.append('elementCode', element.value.elementName)
form.append('elementForm', '普通图元')
form.append('elementMark', element.value.elementName)
form.append('elementName', element.value.elementName)
form.append('elementSonType', element.value.elementSonType)
form.append('elementType', 'svg文件')
form.append('multipartFile', fileList.value[0])
addElement(form).then((res: any) => {
if (res.code == 'A0000') {
ElMessage({
message: '新增成功',
type: 'success'
})
closeDialog()
// 左侧列表渲染新增的图元
download({ filePath: res.data.path }).then((Svg: any) => {
// 动态添加svg
leftAsideStore.svgPush(res.data.elementSonType, [
{
id: res.data.id,
title: res.data.elementName,
type: 'svg',
thumbnail:
'data:image/svg+xml;utf8,' +
encodeURIComponent(Svg.replace(/(\sfill=(["']))[^"']*(\2)/g, '$1#000000$3')),
svg: Svg.replace(/\sfill=(["'])[^"']*\1/g, ''),
props: {
fill: {
type: 'color',
val: '#FF0000',
title: '填充色'
}
}
}
])
})
} else {
ElMessage({
message: res.message,
type: 'info'
})
}
})
}
return Promise.resolve() // 确保所有分支都返回 Promise<void>
})
}
</script>

View File

@@ -0,0 +1,86 @@
<template>
<ul ref="contextMenuRef" class="contextMenu" v-show="show">
<li
v-for="(item, key) in contextMenuProps.menuInfo.info"
:key="item.title"
@click="onItemClick(key, item, $event)"
>
<p :class="item.enable ? '' : 'disabled'">
{{ item.title }}
<span class="shortcut">{{ item.hot_key }}</span>
</p>
</li>
</ul>
</template>
<script setup lang="ts">
import type { ContextMenuInfoType, IContextMenuDetail, IContextMenuInfo } from '../../store/types'
type ContextMenuProps = {
menuInfo: IContextMenuDetail
show: boolean
}
const contextMenuProps = withDefaults(defineProps<ContextMenuProps>(), {})
const emits = defineEmits(['onContextMenuClick'])
const onItemClick = (key: ContextMenuInfoType, item: IContextMenuInfo, e: MouseEvent) => {
if (!item.enable) {
return
}
emits('onContextMenuClick', key, e)
}
</script>
<style scoped lang="less">
.contextMenu {
position: fixed;
z-index: 99999;
background: #ffffff;
padding: 5px 0;
margin: 0px;
display: block;
border-radius: 5px;
box-shadow: 2px 5px 10px rgba(0, 0, 0, 0.3);
left: v-bind('contextMenuProps.menuInfo.left + "px"');
top: v-bind('contextMenuProps.menuInfo.top + "px"');
li {
list-style: none;
padding: 0px;
margin: 0px;
}
.shortcut {
width: 115px;
text-align: right;
float: right;
}
p {
text-decoration: none;
display: block;
padding: 0px 15px 1px 20px;
margin: 0;
user-select: none;
-webkit-user-select: none;
}
p:hover {
background-color: #0cf;
color: #ffffff;
cursor: default;
}
.disabled {
color: #999;
}
.disabled:hover {
color: #999;
background-color: transparent;
}
li.separator {
border-top: solid 1px #e3e3e3;
padding-top: 5px;
margin-top: 5px;
}
}
</style>

View File

@@ -0,0 +1,26 @@
<template>
<img draggable="false" class="w-1/1 h-1/1" :src="img_url" />
</template>
<script setup lang="ts">
// @ts-nocheck
import { onMounted, ref, useSlots, watch } from 'vue'
import { renderToString } from 'vue/server-renderer'
import { svgToImgSrc } from '../../utils'
const img_url = ref('')
const slots = useSlots()
const setImgUrl = async () => {
const slotNodes = slots.default ? slots.default() : []
const slotStrings = await renderToString(slotNodes[0])
img_url.value = svgToImgSrc(slotStrings)
}
onMounted(async () => {
await setImgUrl()
})
watch(
() => slots.default(),
async () => {
await setImgUrl()
},
{ deep: true }
)
</script>

View File

@@ -0,0 +1,51 @@
<template>
<el-tree
:data="doneTreeProps.doneJson"
:props="defaultProps"
@node-click="handleNodeClick"
:default-expand-all="true"
:expand-on-click-node="false"
:highlight-current="true"
node-key="id"
:current-node-key="current_node_key"
>
<template #default="{ node, data }">
<div class="flex justify-between w-8/10">
<div>{{ node.label }}</div>
<el-button text circle size="small" class="mr-10px">
<el-icon :title="data.hide ? '隐藏' : '显示'" :size="20" @click.stop="changeHide(data)">
<svg-analysis :name="data.hide ? 'view-hide' : 'view-show'"></svg-analysis>
</el-icon>
</el-button>
</div>
</template>
</el-tree>
</template>
<script lang="ts" setup>
import { ElTree, ElButton, ElIcon } from 'element-plus'
import { computed } from 'vue'
import type { IDoneJson } from '@/components/mt-edit/store/types'
import SvgAnalysis from '@/components/mt-edit/components/svg-analysis/index.vue'
type DoneTree = {
doneJson: IDoneJson[]
selectedItemsId: string[] //已选中组件的id
}
const doneTreeProps = withDefaults(defineProps<DoneTree>(), {})
const emits = defineEmits(['updateSelectedItemsId', 'updateSelectedIdHide'])
const current_node_key = computed(() => {
return doneTreeProps.selectedItemsId.length == 1 ? doneTreeProps.selectedItemsId[0] : ''
})
const handleNodeClick = (data: IDoneJson) => {
emits('updateSelectedItemsId', data.id)
}
const changeHide = (data: IDoneJson) => {
emits('updateSelectedIdHide', data.id)
}
const defaultProps = {
children: 'nochildren',
label: 'title'
}
</script>

View File

@@ -0,0 +1,49 @@
<template>
<div class="hidden"></div>
</template>
<script setup lang="ts">
import type { MouseTouchEvent } from '../types'
type DragCanvasProps = {
scaleRatio: number
}
const dragCanvasProps = withDefaults(defineProps<DragCanvasProps>(), {
scaleRatio: 1
})
const emits = defineEmits(['dragCanvasMouseDown', 'dragCanvasMouseMove', 'dragCanvasMouseUp'])
const onMouseDown = (de: MouseTouchEvent) => {
let move_x = 0
let move_y = 0
// 记录最开始点击时鼠标位置
const d_x = de instanceof MouseEvent ? de.clientX : de.touches[0].pageX
const d_y = de instanceof MouseEvent ? de.clientY : de.touches[0].pageY
emits('dragCanvasMouseDown', d_x, d_y)
const onMouseMove = (e: MouseTouchEvent) => {
// 记录鼠标移动的位置
const m_x = e instanceof MouseEvent ? e.clientX : e.touches[0].pageX
const m_y = e instanceof MouseEvent ? e.clientY : e.touches[0].pageY
// 移动的距离
move_x = (m_x - d_x) / 1
move_y = (m_y - d_y) / 1
emits('dragCanvasMouseMove', move_x, move_y)
}
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
document.removeEventListener('touchmove', onMouseMove)
document.removeEventListener('touchend', onMouseUp)
emits('dragCanvasMouseUp', move_x, move_y)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
document.addEventListener('touchmove', onMouseMove)
document.addEventListener('touchend', onMouseUp)
}
defineExpose({
onMouseDown
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,196 @@
<template>
<svg
:id="lineRenderProps.itemJson.id"
class="mt-line-render"
:style="{
position: 'absolute',
left: `${-offset}px`,
top: `${-offset}px`,
width: `${lineRenderProps.canvasCfg.width + offset}px`,
height: `${lineRenderProps.canvasCfg.height + offset}px`
}"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
pointer-events="none"
>
<g>
<defs>
<marker
:id="'markerArrowStart' + lineRenderProps.itemJson.id"
viewBox="0 0 10 10"
refX="8"
refY="5"
markerWidth="6"
markerHeight="6"
orient="auto-start-reverse"
>
<path d="M 0 0 L 10 5 L 0 10 z" :fill="lineRenderProps.itemJson.props.stroke.val" />
</marker>
<marker
:id="'markerArrowEnd' + lineRenderProps.itemJson.id"
viewBox="0 0 10 10"
refX="8"
refY="5"
markerWidth="6"
markerHeight="6"
orient="auto"
>
<path d="M 0 0 L 10 5 L 0 10 z" :fill="lineRenderProps.itemJson.props.stroke.val" />
</marker>
</defs>
<path
:d="
positionArrarToPath(
lineRenderProps.itemJson.props.point_position.val,
lineRenderProps.itemJson.binfo.left + offset,
lineRenderProps.itemJson.binfo.top + offset
)
"
pointer-events="visibleStroke"
fill="none"
:stroke="
lineRenderProps.itemJson.props.ani_type.val === 'electricity'
? lineRenderProps.itemJson.props.ani_color.val
: lineRenderProps.itemJson.props.stroke.val
"
:stroke-width="lineRenderProps.itemJson.props['stroke-width'].val"
style="cursor: move"
stroke-dashoffset="0"
:stroke-dasharray="
lineRenderProps.itemJson.props.ani_type.val === 'electricity'
? lineRenderProps.itemJson.props['stroke-width'].val * 3
: 0
"
:marker-start="
lineRenderProps.itemJson.props?.['marker-start']?.val
? `url(#markerArrowStart${lineRenderProps.itemJson.id})`
: ''
"
:marker-end="
lineRenderProps.itemJson.props?.['marker-end']?.val
? `url(#markerArrowEnd${lineRenderProps.itemJson.id})`
: ''
"
class="real"
>
<animate
v-if="lineRenderProps.itemJson.props.ani_type.val === 'electricity'"
attributeName="stroke-dashoffset"
:from="lineRenderProps.itemJson.props.ani_reverse.val ? 0 : 1000"
:to="
lineRenderProps.itemJson.props.ani_reverse.val
? lineRenderProps.itemJson.props.ani_play.val
? 1000
: 0
: lineRenderProps.itemJson.props.ani_play.val
? 0
: 1000
"
:dur="`${
lineRenderProps.itemJson.props.ani_dur.val < 1 ? 1 : lineRenderProps.itemJson.props.ani_dur.val
}s`"
repeatCount="indefinite"
/>
</path>
</g>
</svg>
</template>
<script setup lang="ts">
import type { MouseTouchEvent } from '@/components/mt-dzr/utils/types'
import type { IDoneJson, IGlobalStoreCanvasCfg, IGlobalStoreGridCfg } from '../../store/types'
import { alignToGrid, positionArrarToPath } from '@/components/mt-edit/utils'
import { computed } from 'vue'
import { configStore } from '../../store/config'
type LineRenderProps = {
itemJson: IDoneJson
canvasCfg: IGlobalStoreCanvasCfg
grid: IGlobalStoreGridCfg
canvasDom: HTMLElement | null
mode: 'pen' | 'pencil'
}
const lineRenderProps = withDefaults(defineProps<LineRenderProps>(), {
mode: 'pen'
})
const lineRenderEmits = defineEmits(['drawLineEnd'])
const offset = configStore.lineRenderOffset
//如果网格关闭或者没有开启网格对齐网格大小为1
const grid_align_size = computed(() =>
!lineRenderProps.grid.align || !lineRenderProps.grid.enabled ? 1 : lineRenderProps.grid.size
)
const onMouseDown = (de: MouseTouchEvent, point_index: number, item: { x: number; y: number }) => {
de.stopPropagation()
// 记录鼠标按下时实际点的坐标
const { x: realityX, y: realityY } = item
// 记录最开始点击时鼠标位置
const d_x = de instanceof MouseEvent ? de.clientX : de.touches[0].pageX
const d_y = de instanceof MouseEvent ? de.clientY : de.touches[0].pageY
let new_x = 0
let new_y = 0
const onMouseMove = (e: MouseTouchEvent) => {
// 记录鼠标移动的位置
const m_x = e instanceof MouseEvent ? e.clientX : e.touches[0].pageX
const m_y = e instanceof MouseEvent ? e.clientY : e.touches[0].pageY
// 移动的距离
const move_x = de.ctrlKey ? 0 : alignToGrid((m_x - d_x) / lineRenderProps.canvasCfg.scale, 1) //感觉对齐网格有点体验不好 所以固定为一了
const move_y = de.shiftKey ? 0 : alignToGrid((m_y - d_y) / lineRenderProps.canvasCfg.scale, 1)
new_x = realityX + move_x
new_y = realityY + move_y
if (lineRenderProps.mode == 'pencil') {
const new_point_position = lineRenderProps.itemJson.props.point_position.val
new_point_position.push({
x: new_x,
y: new_y
})
return
} else {
const new_point_position = lineRenderProps.itemJson.props.point_position.val
new_point_position[point_index].x = new_x
new_point_position[point_index].y = new_y
}
}
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
document.removeEventListener('touchmove', onMouseMove)
document.removeEventListener('touchend', onMouseUp)
const itemRect = document.querySelector(`#${lineRenderProps.itemJson.id} g .real`)!.getBoundingClientRect()
const canvas_area_bounding_info = lineRenderProps.canvasDom!.getBoundingClientRect()
const new_left = (itemRect?.left - canvas_area_bounding_info?.left) / lineRenderProps.canvasCfg.scale
const new_top = (itemRect?.top - canvas_area_bounding_info?.top) / lineRenderProps.canvasCfg.scale
const move_x = new_left - lineRenderProps.itemJson.binfo.left
const move_y = new_top - lineRenderProps.itemJson.binfo.top
const new_item_json = {
...lineRenderProps.itemJson,
binfo: {
...lineRenderProps.itemJson.binfo,
left: new_left,
top: new_top,
width: itemRect?.width / lineRenderProps.canvasCfg.scale,
height: itemRect?.height / lineRenderProps.canvasCfg.scale
},
props: {
...lineRenderProps.itemJson.props,
point_position: {
...lineRenderProps.itemJson.props.point_position,
val: lineRenderProps.itemJson.props.point_position.val.map((m: { x: number; y: number }) => {
return {
x: m.x - move_x,
y: m.y - move_y
}
})
}
}
}
lineRenderEmits('drawLineEnd', new_item_json)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
document.addEventListener('touchmove', onMouseMove)
document.addEventListener('touchend', onMouseUp)
}
defineExpose({
onMouseDown
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,35 @@
<template>
<div>
<v-ace-editor
v-model:value="export_json"
lang="json"
theme="monokai"
style="height: 400px"
:options="{
useWorker: true,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
}"
/>
</div>
</template>
<script setup lang="ts">
import { VAceEditor } from 'vue3-ace-editor'
import type { IDoneJson, IGlobalStoreCanvasCfg, IGlobalStoreGridCfg } from '../../store/types'
import { computed } from 'vue'
import { genExportJson } from '../../composables'
type ExportProps = {
doneJson: IDoneJson[]
canvasCfg: IGlobalStoreCanvasCfg
gridCfg: IGlobalStoreGridCfg
}
const exportProps = withDefaults(defineProps<ExportProps>(), {})
const export_json = computed({
get: () => {
const { exportJson } = genExportJson(exportProps.canvasCfg, exportProps.gridCfg, exportProps.doneJson)
return JSON.stringify(exportJson, null, 2)
},
set: () => {}
})
</script>

View File

@@ -0,0 +1,44 @@
<template>
<div class="mt-group">
<div
class="absolute"
v-for="item in groupRender.itemJson.children"
:key="item.id"
:id="item.id"
:style="{
left: item.binfo.left + '%',
top: item.binfo.top + '%',
width: item.binfo.width + '%',
height: item.binfo.height + '%',
transform: `rotate(${item.binfo.angle}deg)`
}"
>
<render-item
:item-json="item"
:grid="groupRender.grid"
:canvas-cfg="groupRender.canvasCfg"
:canvas-dom="groupRender.canvasDom"
:lock-state="false"
></render-item>
</div>
</div>
</template>
<script setup lang="ts">
import RenderItem from '@/components/mt-edit/components/render-item/index.vue'
import type { IDoneJson, IGlobalStoreCanvasCfg, IGlobalStoreGridCfg } from '@/components/mt-edit/store/types'
type GroupRender = {
itemJson: IDoneJson
grid: IGlobalStoreGridCfg
canvasCfg: IGlobalStoreCanvasCfg
canvasDom: HTMLElement | null
}
const groupRender = withDefaults(defineProps<GroupRender>(), {})
</script>
<style scoped>
.mt-group {
left: v-bind('groupRender.itemJson.binfo.left+"px"');
top: v-bind('groupRender.itemJson.binfo.top+"px"');
width: v-bind('groupRender.itemJson.binfo.width+"px"');
height: v-bind('groupRender.itemJson.binfo.height+"px"');
}
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div>
<v-ace-editor
v-model:value="import_json"
lang="json"
theme="monokai"
style="height: 400px"
:options="{
useWorker: true,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
}"
/>
</div>
</template>
<script setup lang="ts">
import { VAceEditor } from 'vue3-ace-editor'
import { ref } from 'vue'
import type { IExportJson } from '../types'
import { globalStore } from '../../store/global'
import { useExportJsonToDoneJson } from '../../composables'
const import_json = ref('')
const onImport = () => {
return new Promise((resolve, reject) => {
try {
const json: IExportJson = JSON.parse(import_json.value)
console.log('🚀 ~ onImport ~ json:', json)
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(json)
globalStore.canvasCfg = canvasCfg
globalStore.gridCfg = gridCfg
globalStore.setGlobalStoreDoneJson(importDoneJson)
resolve(true)
} catch (error) {
resolve(false)
}
})
}
defineExpose({
onImport
})
</script>

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