init: UserBaseFront (frontend)

This commit is contained in:
chenxing
2026-08-10 14:41:13 +08:00
commit eea881b616
174 changed files with 32833 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
node_modules
src
public
config
dist/base
dist/ld
dist/_verify
.git
.workbuddy
*.log
vite.config.ts.timestamp-*
+7
View File
@@ -0,0 +1,7 @@
# 正式环境 - base
VITE_BASE_HOST=https://base.bestsch.com
VITE_SSO_HOST=https://sso.bestsch.com
VITE_SERVICE_HOST=https://base.bestsch.com/LearnCenter
VITE_ZIYUANKU_HOST=https://base.bestsch.com/BschZyk
VITE_ZHUANXIANG_HOST=https://base.bestsch.com/BschZncpd
VITE_IS_MOCK=false
+7
View File
@@ -0,0 +1,7 @@
# 开发环境 (dev)
VITE_BASE_HOST=http://base.bestsch.com
VITE_SSO_HOST=http://sso.bestsch.com
VITE_SERVICE_HOST=http://localhost:8060
VITE_ZIYUANKU_HOST=https://base.bestsch.com/BschZyk
VITE_ZHUANXIANG_HOST=https://base.bestsch.com/BschZncpd
VITE_IS_MOCK=false
+7
View File
@@ -0,0 +1,7 @@
# 正式环境 - ld
VITE_BASE_HOST=https://ld.bestsch.com
VITE_SSO_HOST=https://sso.bestsch.com
VITE_SERVICE_HOST=https://ld.bestsch.com/LearnCenter
VITE_ZIYUANKU_HOST=https://ld.bestsch.com/BschZyk
VITE_ZHUANXIANG_HOST=https://ld.bestsch.com/BschZncpd
VITE_IS_MOCK=false
+7
View File
@@ -0,0 +1,7 @@
# 正式环境 - 云海星通(部署在 www.yunhaixingtong.com/userbase)
VITE_BASE_HOST=http://www.yunhaixingtong.com
VITE_SSO_HOST=http://sso.yunhaixingtong.com
VITE_SERVICE_HOST=http://www.yunhaixingtong.com/userbase
VITE_ZIYUANKU_HOST=https://base.bestsch.com/BschZyk
VITE_ZHUANXIANG_HOST=https://base.bestsch.com/BschZncpd
VITE_IS_MOCK=false
+93
View File
@@ -0,0 +1,93 @@
name: ci-userbase-front
# 前端标准化 CI:npm ci -> vite build --mode prod(-> dist/prod) -> docker build(nginx) -> 推 Nexus -> 部署 160
# 触发:push 到 main / 手动 Run workflow
# 依赖仓库 Actions Secrets:NEXUS_USER / NEXUS_PASSWORD(ci-docker 账号,仅 docker-hosted 推送权)
on:
push:
branches: [main]
workflow_dispatch:
inputs:
tag:
description: 'image tag (default = short sha)'
required: false
default: 'auto'
deploy:
description: 'deploy to 160 after build (auto / skip)'
required: false
default: 'auto'
jobs:
build-and-push:
runs-on: ubuntu-latest
# docker:24 自带 docker CLI,复用宿主 docker daemon(act_runner v0.6.1 已挂载 docker.sock)。
container:
image: docker:24
steps:
- name: Install git + node (alpine)
run: apk add --no-cache git nodejs npm
# 内网 Gitea 无法访问 github.com 拉取 actions/checkout,改为直接 clone 本仓库
- name: Checkout (manual, internal Gitea)
run: |
git clone --depth 1 --branch main http://192.168.10.160:3000/${GITHUB_REPOSITORY}.git /tmp/src
cp -a /tmp/src/. .
rm -rf /tmp/src
- name: Compute image tag
id: meta
run: |
if [ "${{ inputs.tag }}" = "auto" ] || [ -z "${{ inputs.tag }}" ]; then
echo "tag=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
else
echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT
fi
- name: Install deps
run: npm ci
- name: Build (vite --mode prod -> dist/prod)
run: npm run build:prod
- name: Login to Nexus docker registry
run: echo "${{ secrets.NEXUS_PASSWORD }}" | docker login nexus:8083 -u ${{ secrets.NEXUS_USER }} --password-stdin
# 构建上下文 = 仓库根(front),Dockerfile 读取 dist/prod 构建 nginx 静态镜像
- name: Build image
run: docker build -t nexus:8083/docker-hosted/userbase-front:${{ steps.meta.outputs.tag }} -f docker/Dockerfile .
- name: Push image
run: docker push nexus:8083/docker-hosted/userbase-front:${{ steps.meta.outputs.tag }}
- name: Report build
run: echo "pushed nexus:8083/docker-hosted/userbase-front:${{ steps.meta.outputs.tag }}"
# 部署阶段(仅在 push 或手动 dispatch deploy=auto 时执行),运行在 160 的 act_runner 上。
# 前端容器只连 infra-infra-net,由 Caddy(external) 经 reverse_proxy userbase-front:80 转发,无需映射宿主机端口。
- name: Deploy (rollout with rollback)
if: github.event_name == 'push' || inputs.deploy == 'auto'
run: |
set +e
IMG=nexus:8083/docker-hosted/userbase-front:${{ steps.meta.outputs.tag }}
echo "deploying $IMG"
echo "${{ secrets.NEXUS_PASSWORD }}" | docker login nexus:8083 -u ${{ secrets.NEXUS_USER }} --password-stdin
docker pull "$IMG"
RB=userbase-front:rb-$(date +%s)
docker tag userbase-front:latest "$RB" 2>/dev/null || true
docker stop userbase-front 2>/dev/null; docker rm -f userbase-front 2>/dev/null
docker run -d --name userbase-front --restart unless-stopped --network infra-infra-net "$IMG"
OK=0
for i in $(seq 1 20); do
sleep 5
ST=$(docker inspect -f '{{.State.Running}}' userbase-front 2>/dev/null || echo false)
if [ "$ST" = "true" ]; then OK=1; break; fi
done
if [ "$OK" = "0" ]; then
echo "!! UNHEALTHY -> rollback to userbase-front:latest"
docker stop userbase-front 2>/dev/null; docker rm -f userbase-front 2>/dev/null
docker run -d --name userbase-front --restart unless-stopped --network infra-infra-net userbase-front:latest
echo "rolled back"; exit 7
fi
echo "DEPLOY OK: $IMG"
docker tag "$IMG" userbase-front:latest
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}' | grep userbase-front || true
+30
View File
@@ -0,0 +1,30 @@
# WorkBuddy local state
.workbuddy/
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
yarn.lock
.npmrc
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.timestamp-*.mjs
+15
View File
@@ -0,0 +1,15 @@
module.exports = {
extends: ["airbnb", "prettier", "prettier/react"],
singleQuote: false, // 是否强制使用单引号
printWidth: 120, // 超过最大值换行
tabWidth: 4,
htmlWhitespaceSensitivity: "ignore",
semi: true, // 结尾是否使用分号
//disableLanguages: ["vue"], // 不格式化vue文件,vue文件的格式化单独设置
endOfLine: "auto",
arrowParens: "avoid", // 箭头函数参数括号 默认avoid 可选 avoid| always
};
//如需显示webpack目录,运行以下命令
// npm run eject
//如需配合使eslint生效,运行以下命令
//npm install --save-dev eslint-plugin-prettier
+41
View File
@@ -0,0 +1,41 @@
import type { GeneratorConfig } from "@alova/wormhole";
export default {
generator: [
{
input: "http://localhost:8060/v2/api-docs",
// 文档平台类型
platform: "swagger",
// 生成代码的输出目录
output: "src/api",
// 响应数据的媒体类型
responseMediaType: "application/json",
// 请求体数据的媒体类型
bodyMediaType: "application/json",
// 生成的 API 版本
version: 1,
// 生成代码类型
type: "typescript",
// 全局 API 名称
global: "Apis",
splitImplementation: true,
implementation: "inline",
// API 处理函数
handleApi: apiDescriptor => {
// 过滤掉已废弃的 API
if (apiDescriptor.deprecated) {
return undefined;
}
const newOpId = apiDescriptor.summary?.trim() || apiDescriptor.operationId;
const url = apiDescriptor.url.replace(/^\/{platform}\//, "/api/");
return {
...apiDescriptor,
operationId: newOpId, // 关键:改掉它
url: apiDescriptor.url.replace(/^\/{platform}\//, "/api/"),
};
},
},
],
} as GeneratorConfig;
+6
View File
@@ -0,0 +1,6 @@
//铃铛debug
window.conf = {
baseHost: "http://basedebug.bestsch.com",
ssoHost: "http://ssodebug.bestsch.com",
serviceHost: "http://basedebug.bestsch.com/QualityEvaluate",
};
+10
View File
@@ -0,0 +1,10 @@
# UserBase 前端静态镜像(基于已构建好的 dist/prod)
# 构建上下文 = front 目录: docker build -f docker/Dockerfile -t <img> .
# 说明:caddy 用 handle_path /userbase/* 剥掉前缀后转发进来,故 nginx 直接以 / 提供服务
FROM nginx:1.27-alpine
RUN rm -rf /usr/share/nginx/html/*
COPY dist/prod/ /usr/share/nginx/html/
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
+26
View File
@@ -0,0 +1,26 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
# hash 路由,所有非静态资源请求回落到 index.html
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpe?g|gif|svg|woff2?|ttf|eot)$ {
expires 7d;
add_header Cache-Control "public, max-age=604800";
}
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="../../favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%- title %></title>
<link rel="stylesheet" href="./libs/ztree/zTreeStyle.css" />
<script src="./libs/jquery.min.js"></script>
<script src="./libs/lodash.min.js"></script>
<script src="./libs/ztree/jquery.ztree.all.min.js"></script>
<script src=" https://base.bestsch.com/BschHome/base/js/bschload.min.js?v=2025011001"></script>
<%- injectScript %>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+12041
View File
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
{
"name": "ordermeal",
"private": true,
"version": "0.0.0",
"nodeversion": "20.19.4",
"type": "module",
"scripts": {
"dev": "vite --mode dev",
"build": "vite build --mode base",
"build:base": "vite build --mode base",
"build:ld": "vite build --mode ld",
"build:prod": "vite build --mode prod",
"preview": "vite preview",
"api:gen": "alova gen -f"
},
"dependencies": {
"@types/lodash": "^4.14.196",
"alova": "^3.4.0",
"axios": "^0.24.0",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"mockjs": "^1.1.0",
"pinia": "^2.1.4",
"sass": "^1.64.1",
"view-ui-plus": "^1.3.16",
"vite-plugin-mock": "2.9.6",
"vue": "^3.4.19",
"vue-router": "4",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@alova/wormhole": "^1.5.0",
"@types/node": "^20.4.4",
"@unocss/preset-rem-to-px": "^66.6.0",
"@unocss/preset-uno": "^66.6.0",
"@vitejs/plugin-vue": "^5.0.4",
"fast-glob": "^3.3.2",
"sass-loader": "^10.0.1",
"typescript": "^5.2.2",
"unocss": "^66.6.0",
"unplugin-auto-import": "0.18.3",
"vite": "^5.1.4",
"vite-plugin-html": "^3.2.2",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^1.8.27"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+1
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+4
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+628
View File
@@ -0,0 +1,628 @@
/*
* JQuery zTree excheck v3.5.28
* http://treejs.cn/
*
* Copyright (c) 2010 Hunter.z
*
* Licensed same as jquery - MIT License
* http://www.opensource.org/licenses/mit-license.php
*
* email: hunter.z@263.net
* Date: 2017-01-20
*/
(function($){
//default consts of excheck
var _consts = {
event: {
CHECK: "ztree_check"
},
id: {
CHECK: "_check"
},
checkbox: {
STYLE: "checkbox",
DEFAULT: "chk",
DISABLED: "disable",
FALSE: "false",
TRUE: "true",
FULL: "full",
PART: "part",
FOCUS: "focus"
},
radio: {
STYLE: "radio",
TYPE_ALL: "all",
TYPE_LEVEL: "level"
}
},
//default setting of excheck
_setting = {
check: {
enable: false,
autoCheckTrigger: false,
chkStyle: _consts.checkbox.STYLE,
nocheckInherit: false,
chkDisabledInherit: false,
radioType: _consts.radio.TYPE_LEVEL,
chkboxType: {
"Y": "ps",
"N": "ps"
}
},
data: {
key: {
checked: "checked"
}
},
callback: {
beforeCheck:null,
onCheck:null
}
},
//default root of excheck
_initRoot = function (setting) {
var r = data.getRoot(setting);
r.radioCheckedList = [];
},
//default cache of excheck
_initCache = function(treeId) {},
//default bind event of excheck
_bindEvent = function(setting) {
var o = setting.treeObj,
c = consts.event;
o.bind(c.CHECK, function (event, srcEvent, treeId, node) {
event.srcEvent = srcEvent;
tools.apply(setting.callback.onCheck, [event, treeId, node]);
});
},
_unbindEvent = function(setting) {
var o = setting.treeObj,
c = consts.event;
o.unbind(c.CHECK);
},
//default event proxy of excheck
_eventProxy = function(e) {
var target = e.target,
setting = data.getSetting(e.data.treeId),
tId = "", node = null,
nodeEventType = "", treeEventType = "",
nodeEventCallback = null, treeEventCallback = null;
if (tools.eqs(e.type, "mouseover")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoverCheck";
}
} else if (tools.eqs(e.type, "mouseout")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoutCheck";
}
} else if (tools.eqs(e.type, "click")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "checkNode";
}
}
if (tId.length>0) {
node = data.getNodeCache(setting, tId);
switch (nodeEventType) {
case "checkNode" :
nodeEventCallback = _handler.onCheckNode;
break;
case "mouseoverCheck" :
nodeEventCallback = _handler.onMouseoverCheck;
break;
case "mouseoutCheck" :
nodeEventCallback = _handler.onMouseoutCheck;
break;
}
}
var proxyResult = {
stop: nodeEventType === "checkNode",
node: node,
nodeEventType: nodeEventType,
nodeEventCallback: nodeEventCallback,
treeEventType: treeEventType,
treeEventCallback: treeEventCallback
};
return proxyResult
},
//default init node of excheck
_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
if (!n) return;
var checkedKey = setting.data.key.checked;
if (typeof n[checkedKey] == "string") n[checkedKey] = tools.eqs(n[checkedKey], "true");
n[checkedKey] = !!n[checkedKey];
n.checkedOld = n[checkedKey];
if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true");
n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);
if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true");
n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);
if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true");
n.halfCheck = !!n.halfCheck;
n.check_Child_State = -1;
n.check_Focus = false;
n.getCheckStatus = function() {return data.getCheckStatus(setting, n);};
if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && n[checkedKey] ) {
var r = data.getRoot(setting);
r.radioCheckedList.push(n);
}
},
//add dom for check
_beforeA = function(setting, node, html) {
var checkedKey = setting.data.key.checked;
if (setting.check.enable) {
data.makeChkFlag(setting, node);
html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true?" style='display:none;'":""),"></span>");
}
},
//update zTreeObj, add method of check
_zTreeTools = function(setting, zTreeTools) {
zTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {
var checkedKey = this.setting.data.key.checked;
if (node.chkDisabled === true) return;
if (checked !== true && checked !== false) {
checked = !node[checkedKey];
}
callbackFlag = !!callbackFlag;
if (node[checkedKey] === checked && !checkTypeFlag) {
return;
} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {
return;
}
if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {
node[checkedKey] = checked;
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
if (callbackFlag) {
this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]);
}
}
}
zTreeTools.checkAllNodes = function(checked) {
view.repairAllChk(this.setting, !!checked);
}
zTreeTools.getCheckedNodes = function(checked) {
var childKey = this.setting.data.key.children;
checked = (checked !== false);
return data.getTreeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey], checked);
}
zTreeTools.getChangeCheckedNodes = function() {
var childKey = this.setting.data.key.children;
return data.getTreeChangeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey]);
}
zTreeTools.setChkDisabled = function(node, disabled, inheritParent, inheritChildren) {
disabled = !!disabled;
inheritParent = !!inheritParent;
inheritChildren = !!inheritChildren;
view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);
view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);
}
var _updateNode = zTreeTools.updateNode;
zTreeTools.updateNode = function(node, checkTypeFlag) {
if (_updateNode) _updateNode.apply(zTreeTools, arguments);
if (!node || !this.setting.check.enable) return;
var nObj = $$(node, this.setting);
if (nObj.get(0) && tools.uCanDo(this.setting)) {
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
}
}
},
//method of operate data
_data = {
getRadioCheckedList: function(setting) {
var checkedList = data.getRoot(setting).radioCheckedList;
for (var i=0, j=checkedList.length; i<j; i++) {
if(!data.getNodeCache(setting, checkedList[i].tId)) {
checkedList.splice(i, 1);
i--; j--;
}
}
return checkedList;
},
getCheckStatus: function(setting, node) {
if (!setting.check.enable || node.nocheck || node.chkDisabled) return null;
var checkedKey = setting.data.key.checked,
r = {
checked: node[checkedKey],
half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (node[checkedKey] ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))
};
return r;
},
getTreeCheckedNodes: function(setting, nodes, checked, results) {
if (!nodes) return [];
var childKey = setting.data.key.children,
checkedKey = setting.data.key.checked,
onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] == checked) {
results.push(nodes[i]);
if(onlyOne) {
break;
}
}
data.getTreeCheckedNodes(setting, nodes[i][childKey], checked, results);
if(onlyOne && results.length > 0) {
break;
}
}
return results;
},
getTreeChangeCheckedNodes: function(setting, nodes, results) {
if (!nodes) return [];
var childKey = setting.data.key.children,
checkedKey = setting.data.key.checked;
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] != nodes[i].checkedOld) {
results.push(nodes[i]);
}
data.getTreeChangeCheckedNodes(setting, nodes[i][childKey], results);
}
return results;
},
makeChkFlag: function(setting, node) {
if (!node) return;
var childKey = setting.data.key.children,
checkedKey = setting.data.key.checked,
chkFlag = -1;
if (node[childKey]) {
for (var i = 0, l = node[childKey].length; i < l; i++) {
var cNode = node[childKey][i];
var tmp = -1;
if (setting.check.chkStyle == consts.radio.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 2;
} else if (cNode[checkedKey]) {
tmp = 2;
} else {
tmp = cNode.check_Child_State > 0 ? 2:0;
}
if (tmp == 2) {
chkFlag = 2; break;
} else if (tmp == 0){
chkFlag = 0;
}
} else if (setting.check.chkStyle == consts.checkbox.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 1;
} else if (cNode[checkedKey] ) {
tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;
} else {
tmp = (cNode.check_Child_State > 0) ? 1 : 0;
}
if (tmp === 1) {
chkFlag = 1; break;
} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {
chkFlag = 1; break;
} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {
chkFlag = 1; break;
} else if (tmp > -1) {
chkFlag = tmp;
}
}
}
}
node.check_Child_State = chkFlag;
}
},
//method of event proxy
_event = {
},
//method of event handler
_handler = {
onCheckNode: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkedKey = setting.data.key.checked;
if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;
node[checkedKey] = !node[checkedKey];
view.checkNodeRelation(setting, node);
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
view.repairParentChkClassWithSelf(setting, node);
setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);
return true;
},
onMouseoverCheck: function(event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = true;
view.setChkClass(setting, checkObj, node);
return true;
},
onMouseoutCheck: function(event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = false;
view.setChkClass(setting, checkObj, node);
return true;
}
},
//method of tools for zTree
_tools = {
},
//method of operate ztree dom
_view = {
checkNodeRelation: function(setting, node) {
var pNode, i, l,
childKey = setting.data.key.children,
checkedKey = setting.data.key.checked,
r = consts.radio;
if (setting.check.chkStyle == r.STYLE) {
var checkedList = data.getRadioCheckedList(setting);
if (node[checkedKey]) {
if (setting.check.radioType == r.TYPE_ALL) {
for (i = checkedList.length-1; i >= 0; i--) {
pNode = checkedList[i];
if (pNode[checkedKey] && pNode != node) {
pNode[checkedKey] = false;
checkedList.splice(i, 1);
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
if (pNode.parentTId != node.parentTId) {
view.repairParentChkClassWithSelf(setting, pNode);
}
}
}
checkedList.push(node);
} else {
var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
for (i = 0, l = parentNode[childKey].length; i < l; i++) {
pNode = parentNode[childKey][i];
if (pNode[checkedKey] && pNode != node) {
pNode[checkedKey] = false;
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
}
}
}
} else if (setting.check.radioType == r.TYPE_ALL) {
for (i = 0, l = checkedList.length; i < l; i++) {
if (node == checkedList[i]) {
checkedList.splice(i, 1);
break;
}
}
}
} else {
if (node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.Y.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, true);
}
if (!node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.N.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, false);
}
if (node[checkedKey] && setting.check.chkboxType.Y.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, true);
}
if (!node[checkedKey] && setting.check.chkboxType.N.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, false);
}
}
},
makeChkClass: function(setting, node) {
var checkedKey = setting.data.key.checked,
c = consts.checkbox, r = consts.radio,
fullStyle = "";
if (node.chkDisabled === true) {
fullStyle = c.DISABLED;
} else if (node.halfCheck) {
fullStyle = c.PART;
} else if (setting.check.chkStyle == r.STYLE) {
fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART;
} else {
fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART);
}
var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle;
chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName;
return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName;
},
repairAllChk: function(setting, checked) {
if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {
var checkedKey = setting.data.key.checked,
childKey = setting.data.key.children,
root = data.getRoot(setting);
for (var i = 0, l = root[childKey].length; i<l ; i++) {
var node = root[childKey][i];
if (node.nocheck !== true && node.chkDisabled !== true) {
node[checkedKey] = checked;
}
view.setSonNodeCheckBox(setting, node, checked);
}
}
},
repairChkClass: function(setting, node) {
if (!node) return;
data.makeChkFlag(setting, node);
if (node.nocheck !== true) {
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
}
},
repairParentChkClass: function(setting, node) {
if (!node || !node.parentTId) return;
var pNode = node.getParentNode();
view.repairChkClass(setting, pNode);
view.repairParentChkClass(setting, pNode);
},
repairParentChkClassWithSelf: function(setting, node) {
if (!node) return;
var childKey = setting.data.key.children;
if (node[childKey] && node[childKey].length > 0) {
view.repairParentChkClass(setting, node[childKey][0]);
} else {
view.repairParentChkClass(setting, node);
}
},
repairSonChkDisabled: function(setting, node, chkDisabled, inherit) {
if (!node) return;
var childKey = setting.data.key.children;
if (node.chkDisabled != chkDisabled) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
if (node[childKey] && inherit) {
for (var i = 0, l = node[childKey].length; i < l; i++) {
var sNode = node[childKey][i];
view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);
}
}
},
repairParentChkDisabled: function(setting, node, chkDisabled, inherit) {
if (!node) return;
if (node.chkDisabled != chkDisabled && inherit) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);
},
setChkClass: function(setting, obj, node) {
if (!obj) return;
if (node.nocheck === true) {
obj.hide();
} else {
obj.show();
}
obj.attr('class', view.makeChkClass(setting, node));
},
setParentNodeCheckBox: function(setting, node, value, srcNode) {
var childKey = setting.data.key.children,
checkedKey = setting.data.key.checked,
checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;
data.makeChkFlag(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true) {
node[checkedKey] = value;
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}
if (node.parentTId) {
var pSign = true;
if (!value) {
var pNodes = node.getParentNode()[childKey];
for (var i = 0, l = pNodes.length; i < l; i++) {
if ((pNodes[i].nocheck !== true && pNodes[i].chkDisabled !== true && pNodes[i][checkedKey])
|| ((pNodes[i].nocheck === true || pNodes[i].chkDisabled === true) && pNodes[i].check_Child_State > 0)) {
pSign = false;
break;
}
}
}
if (pSign) {
view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);
}
}
},
setSonNodeCheckBox: function(setting, node, value, srcNode) {
if (!node) return;
var childKey = setting.data.key.children,
checkedKey = setting.data.key.checked,
checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;
var hasDisable = false;
if (node[childKey]) {
for (var i = 0, l = node[childKey].length; i < l; i++) {
var sNode = node[childKey][i];
view.setSonNodeCheckBox(setting, sNode, value, srcNode);
if (sNode.chkDisabled === true) hasDisable = true;
}
}
if (node != data.getRoot(setting) && node.chkDisabled !== true) {
if (hasDisable && node.nocheck !== true) {
data.makeChkFlag(setting, node);
}
if (node.nocheck !== true && node.chkDisabled !== true) {
node[checkedKey] = value;
if (!hasDisable) node.check_Child_State = (node[childKey] && node[childKey].length > 0) ? (value ? 2 : 0) : -1;
} else {
node.check_Child_State = -1;
}
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}
}
},
_z = {
tools: _tools,
view: _view,
event: _event,
data: _data
};
$.extend(true, $.fn.zTree.consts, _consts);
$.extend(true, $.fn.zTree._z, _z);
var zt = $.fn.zTree,
tools = zt._z.tools,
consts = zt.consts,
view = zt._z.view,
data = zt._z.data,
event = zt._z.event,
$$ = tools.$;
data.exSetting(_setting);
data.addInitBind(_bindEvent);
data.addInitUnBind(_unbindEvent);
data.addInitCache(_initCache);
data.addInitNode(_initNode);
data.addInitProxy(_eventProxy, true);
data.addInitRoot(_initRoot);
data.addBeforeA(_beforeA);
data.addZTreeTools(_zTreeTools);
var _createNodes = view.createNodes;
view.createNodes = function(setting, level, nodes, parentNode, index) {
if (_createNodes) _createNodes.apply(view, arguments);
if (!nodes) return;
view.repairParentChkClassWithSelf(setting, parentNode);
}
var _removeNode = view.removeNode;
view.removeNode = function(setting, node) {
var parentNode = node.getParentNode();
if (_removeNode) _removeNode.apply(view, arguments);
if (!node || !parentNode) return;
view.repairChkClass(setting, parentNode);
view.repairParentChkClass(setting, parentNode);
}
var _appendNodes = view.appendNodes;
view.appendNodes = function(setting, level, nodes, parentNode, index, initFlag, openFlag) {
var html = "";
if (_appendNodes) {
html = _appendNodes.apply(view, arguments);
}
if (parentNode) {
data.makeChkFlag(setting, parentNode);
}
return html;
}
})(jQuery);
File diff suppressed because it is too large Load Diff
+378
View File
@@ -0,0 +1,378 @@
/*-------------------------------------
zTree Style
version: 3.4
author: Hunter.z
email: hunter.z@263.net
website: http://code.google.com/p/jquerytree/
-------------------------------------*/
.ztree * {
padding: 0;
margin: 0;
font-size: 14px;
font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif
}
.ztree {
margin: 0;
padding: 5px;
color: #333
}
.ztree li {
padding: 0;
margin: 0;
list-style: none;
line-height: 17px;
text-align: left;
white-space: nowrap;
outline: 0
}
.ztree li ul {
margin: 0;
padding: 0 0 0 18px
}
.ztree li ul.line {
background: url(./img/line_conn.png) 0 0 repeat-y;
}
.ztree li a {
padding-right: 3px;
margin: 0;
cursor: pointer;
height: 21px;
color: #333;
background-color: transparent;
text-decoration: none;
vertical-align: top;
display: inline-block
}
.ztree li a:hover {
text-decoration: underline
}
.ztree li a.curSelectedNode {
padding-top: 0px;
background-color: #e5e5e5;
color: black;
height: 21px;
opacity: 0.8;
}
.ztree li a.curSelectedNode_Edit {
padding-top: 0px;
background-color: #e5e5e5;
color: black;
height: 21px;
border: 1px #666 solid;
opacity: 0.8;
}
.ztree li a.tmpTargetNode_inner {
padding-top: 0px;
background-color: #aaa;
color: white;
height: 21px;
border: 1px #666 solid;
opacity: 0.8;
filter: alpha(opacity=80)
}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {
height: 14px;
width: 80px;
padding: 0;
margin: 0;
font-size: 12px;
border: 1px #585956 solid;
*border: 0px
}
.ztree li span {
line-height: 21px;
margin-right: 2px
}
.ztree li span.button {
line-height: 0;
margin: 0;
padding: 0;
width: 21px;
height: 21px;
display: inline-block;
vertical-align: middle;
border: 0 none;
cursor: pointer;
outline: none;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
background-image: url("./img/bootstrap.png");
}
.ztree li span.button.chk {
width: 13px;
height: 13px;
margin: 0 2px;
cursor: auto
}
.ztree li span.button.chk.checkbox_false_full {
background-position: -5px -5px;
}
.ztree li span.button.chk.checkbox_false_full_focus {
background-position: -5px -26px;
}
.ztree li span.button.chk.checkbox_false_part {
background-position: -5px -48px;
}
.ztree li span.button.chk.checkbox_false_part_focus {
background-position: -5px -68px;
}
.ztree li span.button.chk.checkbox_false_disable {
background-position: -5px -89px;
}
.ztree li span.button.chk.checkbox_true_full {
background-position: -26px -5px;
}
.ztree li span.button.chk.checkbox_true_full_focus {
background-position: -26px -26px;
}
.ztree li span.button.chk.checkbox_true_part {
background-position: -26px -48px;
}
.ztree li span.button.chk.checkbox_true_part_focus {
background-position: -26px -68px;
}
.ztree li span.button.chk.checkbox_true_disable {
background-position: -26px -89px;
}
.ztree li span.button.chk.radio_false_full {
background-position: -47px -5px;
}
.ztree li span.button.chk.radio_false_full_focus {
background-position: -47px -26px;
}
.ztree li span.button.chk.radio_false_part {
background-position: -47px -47px;
}
.ztree li span.button.chk.radio_false_part_focus {
background-position: -47px -68px;
}
.ztree li span.button.chk.radio_false_disable {
background-position: -47px -89px;
}
.ztree li span.button.chk.radio_true_full {
background-position: -68px -5px;
}
.ztree li span.button.chk.radio_true_full_focus {
background-position: -68px -26px;
}
.ztree li span.button.chk.radio_true_part {
background-position: -68px -47px;
}
.ztree li span.button.chk.radio_true_part_focus {
background-position: -68px -68px;
}
.ztree li span.button.chk.radio_true_disable {
background-position: -68px -89px;
}
.ztree li span.button.switch {
width: 21px;
height: 21px
}
.ztree li span.button.root_open {
background-position: -105px -63px
}
.ztree li span.button.root_close {
background-position: -126px -63px
}
.ztree li span.button.roots_open {
background-position: -105px 0;
}
.ztree li span.button.roots_close {
background-position: -126px 0;
}
.ztree li span.button.center_open {
background-position: -105px -21px;
}
.ztree li span.button.center_close {
background-position: -126px -21px;
}
.ztree li span.button.bottom_open {
background-position: -105px -42px;
}
.ztree li span.button.bottom_close {
background-position: -126px -42px;
}
.ztree li span.button.noline_open {
background-position: -105px -84px;
}
.ztree li span.button.noline_close {
background-position: -126px -84px;
}
.ztree li span.button.root_docu {
background-position: -105px -63px;
}
.ztree li span.button.roots_docu {
background-position: -84px 0;
}
.ztree li span.button.center_docu {
background-position: -84px -21px;
}
.ztree li span.button.bottom_docu {
background-position: -84px -42px;
}
.ztree li span.button.noline_docu {
background: none;
}
.ztree li span.button.ico_open {
margin-right: 2px;
background-position: -147px -21px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.ico_close {
margin-right: 2px;
margin-right: 2px;
background-position: -147px 0;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.ico_docu {
margin-right: 2px;
background-position: -147px -43px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.edit {
margin-left: 2px;
margin-right: -1px;
background-position: -189px -21px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.edit:hover {
background-position: -168px -21px;
}
.ztree li span.button.remove {
margin-left: 2px;
margin-right: -1px;
background-position: -189px -42px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.remove:hover {
background-position: -168px -42px;
}
.ztree li span.button.add {
margin-left: 2px;
margin-right: -1px;
background-position: -189px 0;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.add:hover {
background-position: -168px 0;
}
ul.tmpTargetzTree {
background-color: #FFE6B0;
opacity: 0.8;
filter: alpha(opacity=80)
}
span.tmpzTreeMove_arrow {
width: 16px;
height: 21px;
display: inline-block;
padding: 0;
margin: 2px 0 0 1px;
border: 0 none;
position: absolute;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
background-position: -168px -84px;
background-image: url("./img/bootstrap.png");
z-index: 10000;
}
span.tmpzTreeMove_prev {
background: red;
}
ul.ztree.zTreeDragUL {
margin: 0;
padding: 0;
position: absolute;
width: auto;
height: auto;
overflow: hidden;
background-color: #cfcfcf;
border: 1px #00B83F dotted;
opacity: 0.8;
filter: alpha(opacity=80)
}
.ztreeMask {
z-index: 10000;
background-color: #cfcfcf;
opacity: 0.0;
filter: alpha(opacity=0);
position: absolute
}
+3
View File
@@ -0,0 +1,3 @@
.ztree li span.button {background-image:url("./img/bootstrap3.png");}
span.tmpzTreeMove_arrow {background-image:url("./img/bootstrap3.png");}
+194
View File
@@ -0,0 +1,194 @@
<script setup lang="ts">
import { ref, onMounted, reactive, provide, computed } from "vue";
import layout from "./components/layout.vue";
import { CurrentRole, LayoutData } from "./types/Basics";
import { useRouter } from "vue-router";
import config from "@/assets/config/host.config";
import { useDefaultStore } from "@/store/index.js";
import Apis from '@/api/index'
import { alovaInstance } from "@/utils/alova/alova-iview";
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import { UserRoleEnum } from "./types";
const store = useDefaultStore();
const router = useRouter();
const { $bus } = useCurrentInstance();
const refLayout = useTemplateRef('refLayout');
const isRouterAlive = ref(true),
isLogin = ref(false),
isNoAuthority = ref(false);
// 当前登录用户,供 resetMenuPath 事件复用
const currentUser = ref<any>(null);
const layoutData: LayoutData = reactive({
isAlone: false,
appName: null,
appList: [],
modList: [],
userInfo: null,
baseHost: null,
ssoHost: null,
});
const reload = () => {
isRouterAlive.value = false;
setTimeout(() => {
isRouterAlive.value = true;
}, 0);
};
provide("reload", reload);
const layoutInit = (info: any, modList: any[], appList: Array<any>, baseHost: string, ssoHost: string) => {
layoutData.appName = "系统管理";
layoutData.baseHost = baseHost;
layoutData.ssoHost = ssoHost;
let { id, name, profilePicture } = info;
layoutData.modList = modList || [];
// 有子菜单时不算「单模块独占」模式,需展示左侧菜单
const hasChildren = modList.some((m: any) => m.children && m.children.length > 0);
layoutData.isAlone = modList.length <= 1 && !hasChildren;
layoutData.userInfo = { id, name, avatar: profilePicture };
layoutData.appList = appList || [];
};
/**
* 角色判定
* 现基于 GetUserInfo 返回的 user.type 判定角色:
* type=1 → SuperAdmin,type=2 → School(不再有 Teacher 角色)
* 同时写入 currentRole 供下游 Utils.getCurrentRoleInfo 读取(保持兼容)
*/
const setCurrentRole = (user: any) => {
const userId = user?.id ?? null;
const roleId = user?.type ?? null;
const currentRole: CurrentRole = {
childId: null,
roleId,
schId: null,
userId,
};
localStorage.setItem("currentRole", encodeURI(JSON.stringify(currentRole)));
// 主题样式已本地化到 src/assets/styles/layout.css(含 default-theme / base.layout.beta / _iview_override),不再请求远程样式
if (user?.type === 1) {
store.setUserRole(UserRoleEnum.SuperAdmin);
} else {
// type=2 或其他 → School(默认)
store.setUserRole(UserRoleEnum.School);
}
};
onMounted(async () => {
const { baseHost, ssoHost } = config;
try {
var user: any = await alovaInstance.Request(Apis.Base.getUserInfo());
// 系统字典 & 模块列表(模块当前写死,后续接入接口)
await store.fetchSysDict();
await store.fetchModules();
currentUser.value = user;
setCurrentRole(user);
layoutInit(user, store.modules, store.modules, baseHost, ssoHost);
// 登录后直接跳转到左侧菜单第一个可用入口
// (顶层可能是单页,如「组,用户管理」;也可能是分组,取其首个子项)
// 仅在用户处于根路径时才跳转,避免刷新业务页(如 /app-manage/list)被强制拉回
const firstModule = store.modules[0];
const firstPage = firstModule?.children?.length
? firstModule.children[0].page
: firstModule?.page;
if (firstPage && router.currentRoute.value.path === "/") {
router.replace(firstPage);
}
isLogin.value = true;
} catch (error) {
console.log(error);
if (error != "redirect") Message.error("载入用户信息失败!");
}
});
const getRouterKey: (route: any) => string = route => {
let str = route?.name;
// if (str === "clocklist") str += "-" + route.params.id;
return str;
};
/**
* 需要被 keep-alive 缓存的组件名(按路由 meta.keepAlive 推导)。
* include 按组件 name 匹配,因此对应页面需 defineOptions({ name }) 与之相等。
*/
const cachedNames = computed(() =>
router.getRoutes().filter((r: any) => r.meta?.keepAlive).map((r: any) => r.name as string)
);
</script>
<template>
<layout ref="refLayout" v-if="isLogin" :layoutData="layoutData"></layout>
<div v-if="isLogin" :class="['base-wrap-main', layoutData.isAlone ? 'alone-page' : '']">
<template v-if="!isNoAuthority">
<router-view v-if="!!isRouterAlive" v-slot="{ Component, route }">
<transition name="fade" mode="out-in">
<keep-alive :include="cachedNames">
<component :is="Component" :key="getRouterKey(route)" />
</keep-alive>
</transition>
</router-view>
</template>
<div v-else class="no-authority-wrap">
<h3>暂无权限</h3>
<h6>如需查看,请联络管理员为您分配权限</h6>
</div>
</div>
</template>
<style lang="scss">
/* 开始过渡阶段,动画出去阶段 */
.fade-enter-active,
.fade-leave-active {
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
}
/* 进入开始 */
.fade-enter {
// transform: translateY(10px);
opacity: 0;
}
/* 出去终点 */
.fade-leave-active {
// transform: translateY(-10px);
// opacity: 0;
}
.back-enter-active,
.back-leave-active {
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
}
/* 进入开始 */
.back-enter {
display: none;
}
/* 出去终点 */
.back-leave-active {
display: none;
}
#app {
height: 100%;
}
.base-wrap-main .main-wrapper {
height: 100%;
}
</style>
+83
View File
@@ -0,0 +1,83 @@
/// <reference types='./globals.d.ts' />
/* tslint:disable */
/* eslint-disable */
/**
* 用户中心接口文档 - version 0.0.1-SNAPSHOT
*
* Demo project for Spring Boot
*
* OpenAPI version: 3.0.0
*
* Contact:
*
* NOTE: This file is auto generated by the alova's vscode plugin.
*
* https://alova.js.org/devtools/vscode
*
* **Do not edit the file manually.**
*/
export default {
'AppSettings.addApp': ['POST', '/api/app/AddApp'],
'AppSettings.addModule': ['POST', '/api/app/AddModule'],
'AppSettings.addType': ['POST', '/api/app/AddType'],
'AppSettings.appAuthzList': ['GET', '/api/app/AppAuthzList'],
'AppSettings.appList': ['GET', '/api/app/AppList'],
'AppSettings.appSort': ['POST', '/api/app/AppSort'],
'AppSettings.appSortList': ['GET', '/api/app/AppSortList'],
'AppSettings.appTypeList': ['GET', '/api/app/AppTypeList'],
'AppSettings.appTypeSort': ['POST', '/api/app/AppTypeSort'],
'AppSettings.deleteApp': ['POST', '/api/app/DeleteApp/{id}'],
'AppSettings.deleteModule': ['POST', '/api/app/DeleteModule/{id}'],
'AppSettings.deleteType': ['POST', '/api/app/DeleteType/{id}'],
'AppSettings.editApp': ['POST', '/api/app/EditApp/{id}'],
'AppSettings.editModule': ['POST', '/api/app/EditModule/{id}'],
'AppSettings.editType': ['POST', '/api/app/EditType/{id}'],
'AppSettings.moduleList': ['GET', '/api/app/ModuleList'],
'AppSettings.resetAppSecret': ['POST', '/api/app/ResetAppSecret/{id}'],
'AppRole.removeRoleUser': ['POST', '/api/approle/RemoveRoleUser'],
'AppRole.roleAdd': ['POST', '/api/approle/RoleAdd'],
'AppRole.roleDelete': ['POST', '/api/approle/RoleDelete/{id}'],
'AppRole.roleEdit': ['POST', '/api/approle/RoleEdit/{id}'],
'AppRole.roleList': ['GET', '/api/approle/RoleList'],
'AppRole.roleModuleTree': ['GET', '/api/approle/RoleModuleTree'],
'AppRole.roleUsers': ['GET', '/api/approle/RoleUsers'],
'AppRole.saveRoleModules': ['POST', '/api/approle/SaveRoleModules'],
'AppRole.saveRoleUsers': ['POST', '/api/approle/SaveRoleUsers'],
'AppRole.saveUserRoles': ['POST', '/api/approle/SaveUserRoles'],
'Base.getSysDict': ['GET', '/api/base/GetSysDict'],
'Base.getUserInfo': ['GET', '/api/base/GetUserInfo'],
'Base.manualHashCacheDemo': ['GET', '/api/base/ManualHashCacheDemo'],
'Base.RedirectTo': ['GET', '/api/base/RedirectTo/{id}'],
'Base.uploadFile': ['POST', '/api/base/UploadFile'],
'GroupAuthz.assignApps': ['POST', '/api/groupauthz/AssignApps'],
'GroupAuthz.getSchoolAppId': ['GET', '/api/groupauthz/GetSchoolAppId'],
'GroupAuthz.groupAppList': ['GET', '/api/groupauthz/GroupAppList'],
'GroupAuthz.groupModuleTree': ['GET', '/api/groupauthz/GroupModuleTree'],
'GroupAuthz.groupModuleTreeByCategory': ['GET', '/api/groupauthz/GroupModuleTreeByCategory'],
'GroupAuthz.groupUsers': ['GET', '/api/groupauthz/GroupUsers'],
'GroupAuthz.hasModulePerm': ['GET', '/api/groupauthz/HasModulePerm'],
'GroupAuthz.saveModulePerms': ['POST', '/api/groupauthz/SaveModulePerms'],
'GroupAuthz.searchUsers': ['GET', '/api/groupauthz/SearchUsers'],
'GroupAuthz.setGroupModule': ['POST', '/api/groupauthz/SetGroupModule'],
'GroupAuthz.setSchoolApp': ['POST', '/api/groupauthz/SetSchoolApp'],
'GroupAuthz.userGroupTree': ['GET', '/api/groupauthz/UserGroupTree'],
'GroupAuthz.userPermissionTree': ['GET', '/api/groupauthz/UserPermissionTree'],
'GroupAuthz.userRoles': ['GET', '/api/groupauthz/UserRoles'],
'OperationLog.list': ['GET', '/api/oplog/List'],
'OperationLog.download': ['GET', '/api/oplog/Download/{id}'],
'SysGroup.add': ['POST', '/api/sysgroup/Add'],
'SysGroup.batchAdd': ['POST', '/api/sysgroup/BatchAdd'],
'SysGroup.delete': ['POST', '/api/sysgroup/Delete/{id}'],
'SysGroup.edit': ['POST', '/api/sysgroup/Edit/{id}'],
'SysGroup.getSchoolTree': ['GET', '/api/sysgroup/GetSchoolTree'],
'SysGroup.getTree': ['GET', '/api/sysgroup/GetTree'],
'SysGroup.list': ['GET', '/api/sysgroup/List'],
'SysGroup.move': ['POST', '/api/sysgroup/Move'],
'SysGroup.sortChildren': ['POST', '/api/sysgroup/SortChildren'],
'SysUser.add': ['POST', '/api/sysuser/Add'],
'SysUser.delete': ['POST', '/api/sysuser/Delete/{id}'],
'SysUser.disable': ['POST', '/api/sysuser/Disable/{id}'],
'SysUser.edit': ['POST', '/api/sysuser/Edit/{id}'],
'SysUser.enable': ['POST', '/api/sysuser/Enable/{id}'],
'SysUser.list': ['GET', '/api/sysuser/List']
};
+97
View File
@@ -0,0 +1,97 @@
/* tslint:disable */
/* eslint-disable */
/**
* 用户中心接口文档 - version 0.0.1-SNAPSHOT
*
* Demo project for Spring Boot
*
* OpenAPI version: 3.0.0
*
* Contact:
*
* NOTE: This file is auto generated by the alova's vscode plugin.
*
* https://alova.js.org/devtools/vscode
*
* **Do not edit the file manually.**
*/
import { Method } from 'alova';
import apiDefinitions from './apiDefinitions';
const cache = Object.create(null);
const createFunctionalProxy = (
array: (string | symbol)[],
alovaInstance: Alova<any, any, any, any, any>,
configMap: any
) => {
const apiPathKey = array.join('.') as keyof typeof apiDefinitions;
if (cache[apiPathKey]) {
return cache[apiPathKey];
}
// create a new proxy instance
const proxy = new Proxy(function () {}, {
get(_, property) {
// record the target property, so that it can get the completed accessing paths
const newArray = [...array, property];
// always return a new proxy to continue recording accessing paths.
return createFunctionalProxy(newArray, alovaInstance, configMap);
},
apply(_, __, [config]) {
const apiItem = apiDefinitions[apiPathKey];
if (!apiItem) {
throw new Error(`the api path of \`${apiPathKey}\` is not found`);
}
const mergedConfig = {
...configMap[apiPathKey],
...config
};
const [method, url] = apiItem;
const pathParams = mergedConfig.pathParams;
const urlReplaced = url!.replace(/\{([^}]+)\}/g, (_, key) => {
const pathParam = pathParams[key];
return pathParam;
});
delete mergedConfig.pathParams;
let data = mergedConfig.data;
if (Object.prototype.toString.call(data) === '[object Object]' && typeof FormData !== 'undefined') {
let hasBlobData = false;
const formData = new FormData();
for (const key in data) {
if (Array.isArray(data[key])) {
for (const ele of data[key]) {
formData.append(key, ele);
if (ele instanceof Blob) {
hasBlobData = true;
}
}
} else {
formData.append(key, data[key]);
if (data[key] instanceof Blob) {
hasBlobData = true;
}
}
}
data = hasBlobData ? formData : data;
}
return new Method(method!.toUpperCase() as MethodType, alovaInstance, urlReplaced, mergedConfig, data);
}
});
cache[apiPathKey] = proxy;
return proxy;
};
export const createApis = (alovaInstance: Alova<any, any, any, any, any>, configMap: any) => {
const Apis = new Proxy({} as Apis, {
get(_, property) {
return createFunctionalProxy([property], alovaInstance, configMap);
}
});
return Apis;
};
export const mountApis = (Apis: Apis) => {
// define global variable `Apis`
(globalThis as any).Apis = Apis;
};
export const withConfigType = <Config extends MethodsConfigMap>(config: Config) => config;
+2949
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
import { createApis, withConfigType, mountApis } from "./createApis";
import { alovaInstance } from "@/utils/alova/alova-iview";
export const $$userConfigMap = withConfigType({});
const Apis = createApis(alovaInstance, $$userConfigMap);
mountApis(Apis);
export default Apis;
+67
View File
@@ -0,0 +1,67 @@
import { alovaInstance } from "@/utils/alova/alova-iview";
/**
* 通过网关转发 GET 开放请求
* @param baseHost 真实接口的域名
* @param url 真实接口的路径(含 query)
* @param params query 参数(可选)
*/
export function createRelayGet<T = any>(url: string, params?: any) {
return alovaInstance.Get<T>("/api/relay/doGet", {
params,
headers: {
RelayUrl: url, // 网关需要
},
cacheFor: 0,
});
}
/**
* 通过网关转发 POST 开放请求
* @param baseHost 真实接口的域名
* @param url 真实接口的路径(含 query)
* @param params query 参数(可选)
*/
export function createRelayPost<T = any>(url: string, params?: any, data?: any) {
const gatewayPath = data != null ? "/api/relay/doPost" : "/api/relay/doPost2";
return alovaInstance.Post<T>(gatewayPath, data, {
params: params ?? {},
headers: {
RelayUrl: url,
},
cacheFor: 0,
});
}
/**
* 通过网关转发 GET 授权请求
* @param baseHost 真实接口的域名
* @param url 真实接口的路径(含 query)
* @param params query 参数(可选)
*/
export function createRelayAuthGet<T = any>(url: string, params?: any) {
return alovaInstance.Get<T>("/api/relayAuth/doGet", {
params,
headers: {
RelayUrl: url, // 网关需要
},
cacheFor: 0,
});
}
/**
* 通过网关转发 POST 授权请求
* @param baseHost 真实接口的域名
* @param url 真实接口的路径(含 query)
* @param params query 参数(可选)
*/
export function createRelayAuthPost<T = any>(url: string, params?: any, data?: any) {
const gatewayPath = data != null ? "/api/relayAuth/doPost" : "/api/relayAuth/doPost2";
return alovaInstance.Post<T>(gatewayPath, data, {
params: params ?? {},
headers: {
RelayUrl: url,
},
cacheFor: 0,
});
}
+16
View File
@@ -0,0 +1,16 @@
import conf from "@/assets/config/host.config";
const baseHost = conf.relayConf.zhuanxiangHost;
import { createRelayAuthGet, createRelayAuthPost } from "./relay";
/**
* 专项相关接口
*/
class SpecialApi {
/** 获取专项列表 */
getSpecialList(subId: string, xdCode: number) {
const url = baseHost + "/api/getSpecialTypeBySchList";
const params = { subId, xdCode };
return createRelayAuthGet<any>(url, params);
}
}
export default new SpecialApi();
+32
View File
@@ -0,0 +1,32 @@
import conf from "@/assets/config/host.config";
const baseHost = conf.relayConf.ziyuankuHost;
import { createRelayAuthGet, createRelayAuthPost, createRelayGet, createRelayPost } from "./relay";
class ZiYuanApi {
/** 获取树节点 */
getNodeTree(schoolId: number, beginNode?: number, levelLimit?: number) {
const url = baseHost + "/oapi/base/nodeTree/get";
const params = { schoolId, beginNode, levelLimit };
return createRelayGet<any>(url, params);
}
/** 获取学校目录资源列表 */
getResourceByNodeId(params: any) {
const url = baseHost + "/oapi/base/getResourceAllByNodeIds";
return createRelayGet<any>(url, params);
}
linkNode(resourceIds: any[], nodeId: number) {
const url = baseHost + "/manage/platform/nodeTree/linkPlatformNode";
const params = { resourceIds: resourceIds.join(","), nodeId };
return createRelayAuthPost<any>(url, params);
}
selectTable(params: any) {
console.log("params", params);
const url = baseHost + "/manage/platform/nodeTree/selectPlatformResource";
return createRelayAuthGet<any>(url, params);
}
}
export default new ZiYuanApi();
+43
View File
@@ -0,0 +1,43 @@
import config from "./host.config";
import { AxiosRequestConfig } from "axios";
import { PcDebugUser } from "@/types/Basics";
const serviceUrl = config.isMock ? "" : config.serviceHost,
timeout: number = 15000;
let baseConfig: AxiosRequestConfig = {
baseURL: serviceUrl + "/",
headers: {
// "Content-Type": "application/x-www-form-urlencoded",
"Content-Type": "application/json;charset=urf-8",
yschapirequest: "1",
"Access-Control-Allow-Headers": "Set-Cookie",
"X-Requested-With": "XMLHttpRequest",
},
params: {},
data: {},
timeout, // 接口超时限制(ms)
withCredentials: true,
responseType: "json",
// transformRequest: [
// function (data) {
// if (typeof data == "string") return data;
// let ret = "";
// for (let it in data) {
// ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
// }
// return ret;
// },
// ],
// maxContentLength: 2000,
validateStatus(status) {
return status >= 200 && status < 300; // default
},
};
let debugUser: PcDebugUser = {
DebugUser: "zhd",
AppType: "ChildOptCourse",
};
export { baseConfig, debugUser };
+40
View File
@@ -0,0 +1,40 @@
import { BaseConf } from "@/types/Basics";
/**
* 通过 Vite 环境变量管理配置,不再依赖 window.conf / config.js
* 环境变量定义在项目根目录的 .env.dev / .env.base / .env.ld 中
*/
const env = import.meta.env;
let conf: BaseConf = {
baseHost: env.VITE_BASE_HOST,
ssoHost: env.VITE_SSO_HOST,
serviceHost: env.VITE_SERVICE_HOST,
relayConf: {
ziyuankuHost: env.VITE_ZIYUANKU_HOST,
zhuanxiangHost: env.VITE_ZHUANXIANG_HOST,
},
isMock: env.VITE_IS_MOCK === "true",
isDebug: env.DEV,
};
// HTTPS 自动升级:当前页面是 https 时,将所有 http:// 配置项升级为 https://
var ishttps = "https:" == document.location.protocol ? true : false;
if (ishttps) {
Object.keys(conf).forEach(element => {
if (typeof conf[element] === "string" && conf[element].indexOf("http://") > -1) {
conf[element] = conf[element].replace("http://", "https://");
}
});
// relayConf 内部也需要处理
if (conf.relayConf) {
Object.keys(conf.relayConf).forEach(key => {
const val = (conf.relayConf as any)[key];
if (typeof val === "string" && val.indexOf("http://") > -1) {
(conf.relayConf as any)[key] = val.replace("http://", "https://");
}
});
}
}
export default conf;
+100
View File
@@ -0,0 +1,100 @@
import { RootNodeDict } from "@/types";
import { cloneDeep } from "lodash";
const beforeCount = 7;
const ROUTE_MAP: any = {
0: {
superAdmin: [{ page: "/", name: "学习中心管理", icon: "home", modId: 1001 }],
school: [{ page: "/", name: "学习中心管理", icon: "home", modId: 1001 }],
teacher: [{ page: "/", name: "学习中心管理", icon: "home", modId: 1001 }],
},
1: {
superAdmin: [{ page: "/subject", name: "学段学科设置", icon: "home", modId: 1002 }],
school: [{ page: "/subject", name: "学段学科设置", icon: "home", modId: 1002 }],
teacher: [],
},
2: {
superAdmin: [
{ page: "/textbook/list", name: "基础教材设置", icon: "home", modId: 2001 },
{ page: "/textbook/school", name: "学校教材设置", icon: "home", modId: 2002 },
{ page: "/textbook/manage", name: "教材管理", icon: "home", modId: 2004 },
],
school: [
{ page: "/textbook", name: "教材设置", icon: "home", modId: 2003 },
{ page: "/textbook/manage", name: "教材管理", icon: "home", modId: 2004 },
],
teacher: [],
},
3: {
superAdmin: [
{ page: "/tutorboox/list", name: "基础教辅设置", icon: "home", modId: 3001 },
{ page: "/tutorboox/school", name: "学校教辅设置", icon: "home", modId: 3002 },
{ page: "/tutorboox/manage", name: "教辅管理", icon: "home", modId: 3004 },
],
school: [
{ page: "/tutorboox", name: "教辅设置", icon: "home", modId: 3003 },
{ page: "/tutorboox/manage", name: "教辅管理", icon: "home", modId: 3004 },
],
teacher: [],
},
4: {
superAdmin: [
{ page: "/knowbook/list", name: "基础知识点设置", icon: "home", modId: 4001 },
{ page: "/knowbook/school", name: "学校知识点设置", icon: "home", modId: 4002 },
{ page: "/knowbook/manage", name: "知识点管理", icon: "home", modId: 4004 },
],
school: [
{ page: "/knowbook", name: "知识点设置", icon: "home", modId: 4003 },
{ page: "/knowbook/manage", name: "知识点管理", icon: "home", modId: 4004 },
],
teacher: [],
},
5: {
superAdmin: [{ page: "/nodeauthorize", name: "开通设置", icon: "home", modId: 5001 }],
school: [{ page: "/nodeauthorize", name: "开通设置", icon: "home", modId: 5001 }],
teacher: [],
},
6: {
superAdmin: [{ page: "/interacttask", name: "交互设置", icon: "home", modId: 6001 }],
school: [{ page: "/interacttask", name: "交互设置", icon: "home", modId: 6001 }],
teacher: [],
},
};
export function getLeftMenuRoutes(entranceId: number, identity: number) {
const tempMap: any = cloneDeep(ROUTE_MAP);
RootNodeDict.forEach((element, index) => {
const idx = beforeCount + 1 + index;
const item = {
superAdmin: [
{
page: `/${element.path}/tree`,
name: element.v + "目录树",
icon: "home",
modId: idx * 1000 + 1,
},
{ page: "/enable/" + (index + 1), name: element.v + "目录开通", modId: idx * 1000 + 2 },
],
school: [{ page: `/${element.path}/tree`, name: "目录树列表", icon: "home", modId: idx * 1000 + 1 }],
teacher: [],
};
tempMap[idx] = item;
});
const entrance = tempMap[entranceId];
if (!entrance) return [];
let key: any = {
1: "superAdmin",
2: "school",
3: "teacher",
};
const list = entrance[key[identity]];
return list || [];
}
export function getRoutes(entranceId: number, identity: number, modId: number) {
const list = getLeftMenuRoutes(entranceId, identity);
return list.find((item: any) => item.modId === modId);
}
export { beforeCount };
+68
View File
@@ -0,0 +1,68 @@
import type { IModule } from "@/store";
/**
* 左侧菜单数据(系统管理功能分组)
* ----------------------------------------------------------------
* 当前直接 Promise.resolve 返回写死数据;后续接入真实接口时,
* 只需把 `return Promise.resolve(menu)` 替换为
* `return alovaInstance.Request(Apis.xxx.getMenu())`
* 即可无缝对接,调用方(store.fetchModules)无需任何改动。
*
* 分组结构:
* 1. 组,用户管理 —— 顶层独立选项卡(单页)
* 2. 应用管理 —— 顶层独立选项卡(= 应用列表主页 /app-manage/list);
* 页内按钮跳转「应用类别管理」子页(/app-manage/category,不在菜单里,
* 由 routes.ts 的 meta.parentId=1102 关联,面包屑「应用管理>应用类别管理」)
* 3. 权限管理 —— 父目录:应用开通 / 组授权 / 权限一览
* 4. 日志管理 —— 父目录:接口日志 / 系统日志
*
* 每个节点带唯一 id;子节点的 pid 由 layout.vue 的 flaten() 扁平化时
* 依据父节点 id 自动推导,用于「高亮自身 + 面包屑展示父级」联动。
* 菜单项不再渲染 icon。
*/
export function getMenuList(): Promise<IModule[]> {
const menu: IModule[] = [
// 1. 组,用户管理(顶层独立选项卡)
{
id: 1,
modId: 1101,
name: "组,用户管理",
page: "/group-user",
},
// 2. 应用管理(顶层独立选项卡,= 应用列表主页;页内按钮跳转应用类别管理子页)
{
id: 2,
modId: 1102,
name: "应用管理",
page: "/app-manage/list",
},
// 3. 权限管理(父目录)
{
id: 4,
modId: 1108,
name: "权限管理",
page: "",
childState: true,
children: [
{ id: 41, modId: 1103, name: "应用开通", page: "/app-open" },
{ id: 42, modId: 1104, name: "组授权", page: "/group-auth" },
{ id: 44, modId: 1110, name: "角色授权", page: "/role-authz/list" },
{ id: 43, modId: 1105, name: "权限一览", page: "/permission-view" },
],
},
// 4. 日志管理(父目录)
{
id: 5,
modId: 1109,
name: "日志管理",
page: "",
childState: true,
children: [
{ id: 51, modId: 1106, name: "接口日志", page: "/api-log" },
{ id: 52, modId: 1107, name: "系统日志", page: "/sys-log" },
{ id: 53, modId: 1111, name: "操作日志", page: "/oplog" },
],
},
];
return Promise.resolve(menu);
}
+4
View File
@@ -0,0 +1,4 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M41.65 64.5995C42.942 65.8915 45.05 66.2995 46.75 65.4495C49.742 64.1575 52.292 62.8995 54.842 60.7575C56.134 59.4655 56.984 57.7995 56.542 55.6575C56.1 53.1075 56.542 50.1155 57.834 47.5655C59.126 45.0155 61.642 43.3155 64.226 42.4655C65.926 42.0235 67.184 40.3235 67.626 38.6575C68.068 35.6655 68.068 32.2655 67.626 29.3075C67.184 27.6075 65.926 25.9075 64.226 25.4655C61.676 24.6155 59.126 22.9155 57.834 20.3655C56.542 17.8155 56.134 14.8235 56.542 12.2735C56.984 10.5735 56.1 8.43153 54.842 7.17353C52.292 5.06553 49.742 3.77353 46.75 2.48153C45.05 1.63153 42.942 2.03953 41.65 3.33153C37.4 7.24153 30.6 7.24153 26.35 3.39953C25.058 2.10753 22.95 1.69953 21.25 2.54953C18.292 3.80753 15.708 5.09953 13.158 7.24153C11.458 8.53353 11.016 10.2335 11.458 12.3415C12.75 17.8495 9.35 23.7995 3.842 25.4995C1.7 25.9415 0.442 27.6415 0.442 29.3415C0 31.0415 0 32.2995 0 33.9995C0 35.6995 0 36.9915 0.442 38.6915C0.442 40.3915 1.734 42.0915 3.842 42.4995C6.392 43.3495 8.942 45.0495 10.234 47.5995C11.526 50.1495 11.934 53.1415 11.492 55.6915C11.05 57.3915 11.934 59.4995 13.192 60.7915C15.742 62.9335 18.292 64.1915 21.284 65.4835C22.984 66.3335 25.126 65.9255 26.384 64.6335C30.6 60.3495 37.4 60.3495 41.65 64.5995Z" fill="#919BF2"/>
<path d="M24.208 34C24.208 35.2859 24.4613 36.5592 24.9534 37.7472C25.4455 38.9353 26.1667 40.0147 27.076 40.924C27.9853 41.8333 29.0647 42.5545 30.2528 43.0466C31.4408 43.5387 32.7141 43.792 34 43.792C35.2859 43.792 36.5592 43.5387 37.7472 43.0466C38.9353 42.5545 40.0147 41.8333 40.924 40.924C41.8333 40.0147 42.5545 38.9353 43.0466 37.7472C43.5387 36.5592 43.792 35.2859 43.792 34C43.792 32.7141 43.5387 31.4408 43.0466 30.2528C42.5545 29.0648 41.8333 27.9853 40.924 27.076C40.0147 26.1667 38.9353 25.4455 37.7472 24.9534C36.5592 24.4613 35.2859 24.208 34 24.208C32.7141 24.208 31.4408 24.4613 30.2528 24.9534C29.0647 25.4455 27.9853 26.1667 27.076 27.076C26.1667 27.9853 25.4455 29.0648 24.9534 30.2528C24.4613 31.4408 24.208 32.7141 24.208 34Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7245_84837)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M58.5962 56.782C57.2642 55.486 56.1722 54.142 55.3202 52.75C54.2762 54.346 52.8962 55.678 51.1802 56.746L50.4602 55.576C52.2602 54.532 53.6462 53.182 54.6182 51.526C53.8502 50.062 53.2622 48.478 52.8542 46.774C52.5182 47.434 52.1162 48.064 51.6482 48.664L50.8742 47.692C52.1462 45.856 53.0102 43.384 53.4662 40.276L54.7442 40.492C54.6122 41.332 54.4382 42.184 54.2222 43.048H58.8482V44.29H57.7322C57.6482 47.122 57.0722 49.564 56.0042 51.616C56.9162 53.164 58.0442 54.508 59.3882 55.648L58.5962 56.782ZM53.8622 44.29L53.5022 45.28C53.9342 47.128 54.5222 48.796 55.2662 50.284C56.0342 48.532 56.4542 46.534 56.5262 44.29H53.8622ZM43.8542 42.004H46.2122V40.402H47.4542V42.004H49.3802V43.156H47.4542V44.992H48.4982C49.4342 43.804 50.2562 42.502 50.9642 41.086L51.9722 41.608C51.3122 42.856 50.6282 43.984 49.9202 44.992H51.2522V46.198H49.0022C48.4862 46.81 47.9942 47.35 47.5262 47.818H50.5862V48.754C49.9742 49.474 49.2542 50.194 48.4262 50.914V51.796C49.5422 51.628 50.6102 51.406 51.6302 51.13V52.336C50.6942 52.588 49.6262 52.798 48.4262 52.966V55.054C48.4262 56.098 47.9162 56.62 46.8962 56.62H45.0962L44.7722 55.45C45.5282 55.51 46.0682 55.54 46.3922 55.54C46.9082 55.54 47.1662 55.264 47.1662 54.712V53.146C45.8342 53.302 44.5142 53.44 43.2062 53.56L43.0262 52.318C44.3342 52.258 45.7142 52.144 47.1662 51.976V50.662C47.8382 50.158 48.4682 49.594 49.0562 48.97H46.2662C45.3182 49.75 44.3882 50.392 43.4762 50.896L42.6662 49.978C43.1942 49.678 43.7342 49.342 44.2862 48.97H43.8722V47.818H45.7802C46.3682 47.326 46.9322 46.786 47.4722 46.198H43.0082V44.992H46.2122V43.156H43.8542V42.004Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7245_84837">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7245_84837)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M58.5962 56.782C57.2642 55.486 56.1722 54.142 55.3202 52.75C54.2762 54.346 52.8962 55.678 51.1802 56.746L50.4602 55.576C52.2602 54.532 53.6462 53.182 54.6182 51.526C53.8502 50.062 53.2622 48.478 52.8542 46.774C52.5182 47.434 52.1162 48.064 51.6482 48.664L50.8742 47.692C52.1462 45.856 53.0102 43.384 53.4662 40.276L54.7442 40.492C54.6122 41.332 54.4382 42.184 54.2222 43.048H58.8482V44.29H57.7322C57.6482 47.122 57.0722 49.564 56.0042 51.616C56.9162 53.164 58.0442 54.508 59.3882 55.648L58.5962 56.782ZM53.8622 44.29L53.5022 45.28C53.9342 47.128 54.5222 48.796 55.2662 50.284C56.0342 48.532 56.4542 46.534 56.5262 44.29H53.8622ZM43.8542 42.004H46.2122V40.402H47.4542V42.004H49.3802V43.156H47.4542V44.992H48.4982C49.4342 43.804 50.2562 42.502 50.9642 41.086L51.9722 41.608C51.3122 42.856 50.6282 43.984 49.9202 44.992H51.2522V46.198H49.0022C48.4862 46.81 47.9942 47.35 47.5262 47.818H50.5862V48.754C49.9742 49.474 49.2542 50.194 48.4262 50.914V51.796C49.5422 51.628 50.6102 51.406 51.6302 51.13V52.336C50.6942 52.588 49.6262 52.798 48.4262 52.966V55.054C48.4262 56.098 47.9162 56.62 46.8962 56.62H45.0962L44.7722 55.45C45.5282 55.51 46.0682 55.54 46.3922 55.54C46.9082 55.54 47.1662 55.264 47.1662 54.712V53.146C45.8342 53.302 44.5142 53.44 43.2062 53.56L43.0262 52.318C44.3342 52.258 45.7142 52.144 47.1662 51.976V50.662C47.8382 50.158 48.4682 49.594 49.0562 48.97H46.2662C45.3182 49.75 44.3882 50.392 43.4762 50.896L42.6662 49.978C43.1942 49.678 43.7342 49.342 44.2862 48.97H43.8722V47.818H45.7802C46.3682 47.326 46.9322 46.786 47.4722 46.198H43.0082V44.992H46.2122V43.156H43.8542V42.004Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7245_84837">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7245_84837)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M58.5962 56.782C57.2642 55.486 56.1722 54.142 55.3202 52.75C54.2762 54.346 52.8962 55.678 51.1802 56.746L50.4602 55.576C52.2602 54.532 53.6462 53.182 54.6182 51.526C53.8502 50.062 53.2622 48.478 52.8542 46.774C52.5182 47.434 52.1162 48.064 51.6482 48.664L50.8742 47.692C52.1462 45.856 53.0102 43.384 53.4662 40.276L54.7442 40.492C54.6122 41.332 54.4382 42.184 54.2222 43.048H58.8482V44.29H57.7322C57.6482 47.122 57.0722 49.564 56.0042 51.616C56.9162 53.164 58.0442 54.508 59.3882 55.648L58.5962 56.782ZM53.8622 44.29L53.5022 45.28C53.9342 47.128 54.5222 48.796 55.2662 50.284C56.0342 48.532 56.4542 46.534 56.5262 44.29H53.8622ZM43.8542 42.004H46.2122V40.402H47.4542V42.004H49.3802V43.156H47.4542V44.992H48.4982C49.4342 43.804 50.2562 42.502 50.9642 41.086L51.9722 41.608C51.3122 42.856 50.6282 43.984 49.9202 44.992H51.2522V46.198H49.0022C48.4862 46.81 47.9942 47.35 47.5262 47.818H50.5862V48.754C49.9742 49.474 49.2542 50.194 48.4262 50.914V51.796C49.5422 51.628 50.6102 51.406 51.6302 51.13V52.336C50.6942 52.588 49.6262 52.798 48.4262 52.966V55.054C48.4262 56.098 47.9162 56.62 46.8962 56.62H45.0962L44.7722 55.45C45.5282 55.51 46.0682 55.54 46.3922 55.54C46.9082 55.54 47.1662 55.264 47.1662 54.712V53.146C45.8342 53.302 44.5142 53.44 43.2062 53.56L43.0262 52.318C44.3342 52.258 45.7142 52.144 47.1662 51.976V50.662C47.8382 50.158 48.4682 49.594 49.0562 48.97H46.2662C45.3182 49.75 44.3882 50.392 43.4762 50.896L42.6662 49.978C43.1942 49.678 43.7342 49.342 44.2862 48.97H43.8722V47.818H45.7802C46.3682 47.326 46.9322 46.786 47.4722 46.198H43.0082V44.992H46.2122V43.156H43.8542V42.004Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7245_84837">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7245_84837)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M58.5962 56.782C57.2642 55.486 56.1722 54.142 55.3202 52.75C54.2762 54.346 52.8962 55.678 51.1802 56.746L50.4602 55.576C52.2602 54.532 53.6462 53.182 54.6182 51.526C53.8502 50.062 53.2622 48.478 52.8542 46.774C52.5182 47.434 52.1162 48.064 51.6482 48.664L50.8742 47.692C52.1462 45.856 53.0102 43.384 53.4662 40.276L54.7442 40.492C54.6122 41.332 54.4382 42.184 54.2222 43.048H58.8482V44.29H57.7322C57.6482 47.122 57.0722 49.564 56.0042 51.616C56.9162 53.164 58.0442 54.508 59.3882 55.648L58.5962 56.782ZM53.8622 44.29L53.5022 45.28C53.9342 47.128 54.5222 48.796 55.2662 50.284C56.0342 48.532 56.4542 46.534 56.5262 44.29H53.8622ZM43.8542 42.004H46.2122V40.402H47.4542V42.004H49.3802V43.156H47.4542V44.992H48.4982C49.4342 43.804 50.2562 42.502 50.9642 41.086L51.9722 41.608C51.3122 42.856 50.6282 43.984 49.9202 44.992H51.2522V46.198H49.0022C48.4862 46.81 47.9942 47.35 47.5262 47.818H50.5862V48.754C49.9742 49.474 49.2542 50.194 48.4262 50.914V51.796C49.5422 51.628 50.6102 51.406 51.6302 51.13V52.336C50.6942 52.588 49.6262 52.798 48.4262 52.966V55.054C48.4262 56.098 47.9162 56.62 46.8962 56.62H45.0962L44.7722 55.45C45.5282 55.51 46.0682 55.54 46.3922 55.54C46.9082 55.54 47.1662 55.264 47.1662 54.712V53.146C45.8342 53.302 44.5142 53.44 43.2062 53.56L43.0262 52.318C44.3342 52.258 45.7142 52.144 47.1662 51.976V50.662C47.8382 50.158 48.4682 49.594 49.0562 48.97H46.2662C45.3182 49.75 44.3882 50.392 43.4762 50.896L42.6662 49.978C43.1942 49.678 43.7342 49.342 44.2862 48.97H43.8722V47.818H45.7802C46.3682 47.326 46.9322 46.786 47.4722 46.198H43.0082V44.992H46.2122V43.156H43.8542V42.004Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7245_84837">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7245_84837)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M58.5962 56.782C57.2642 55.486 56.1722 54.142 55.3202 52.75C54.2762 54.346 52.8962 55.678 51.1802 56.746L50.4602 55.576C52.2602 54.532 53.6462 53.182 54.6182 51.526C53.8502 50.062 53.2622 48.478 52.8542 46.774C52.5182 47.434 52.1162 48.064 51.6482 48.664L50.8742 47.692C52.1462 45.856 53.0102 43.384 53.4662 40.276L54.7442 40.492C54.6122 41.332 54.4382 42.184 54.2222 43.048H58.8482V44.29H57.7322C57.6482 47.122 57.0722 49.564 56.0042 51.616C56.9162 53.164 58.0442 54.508 59.3882 55.648L58.5962 56.782ZM53.8622 44.29L53.5022 45.28C53.9342 47.128 54.5222 48.796 55.2662 50.284C56.0342 48.532 56.4542 46.534 56.5262 44.29H53.8622ZM43.8542 42.004H46.2122V40.402H47.4542V42.004H49.3802V43.156H47.4542V44.992H48.4982C49.4342 43.804 50.2562 42.502 50.9642 41.086L51.9722 41.608C51.3122 42.856 50.6282 43.984 49.9202 44.992H51.2522V46.198H49.0022C48.4862 46.81 47.9942 47.35 47.5262 47.818H50.5862V48.754C49.9742 49.474 49.2542 50.194 48.4262 50.914V51.796C49.5422 51.628 50.6102 51.406 51.6302 51.13V52.336C50.6942 52.588 49.6262 52.798 48.4262 52.966V55.054C48.4262 56.098 47.9162 56.62 46.8962 56.62H45.0962L44.7722 55.45C45.5282 55.51 46.0682 55.54 46.3922 55.54C46.9082 55.54 47.1662 55.264 47.1662 54.712V53.146C45.8342 53.302 44.5142 53.44 43.2062 53.56L43.0262 52.318C44.3342 52.258 45.7142 52.144 47.1662 51.976V50.662C47.8382 50.158 48.4682 49.594 49.0562 48.97H46.2662C45.3182 49.75 44.3882 50.392 43.4762 50.896L42.6662 49.978C43.1942 49.678 43.7342 49.342 44.2862 48.97H43.8722V47.818H45.7802C46.3682 47.326 46.9322 46.786 47.4722 46.198H43.0082V44.992H46.2122V43.156H43.8542V42.004Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7245_84837">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7186_97095)">
<path d="M52.5096 4.53333H43.443V2.26667C43.443 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2942 0 23.043 0C21.7918 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70484 4.53333 2.64297 8.5952 2.64297 13.6V54.4C2.64297 59.4048 6.70484 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.519 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.243 48.8512 16.243 47.6C16.243 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9654 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.243 35.2512 16.243 34C16.243 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9654 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.243 21.6512 16.243 20.4C16.243 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9654 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M44.1242 40.672C45.2522 41.032 46.2482 41.452 47.1122 41.932L46.4282 42.976C45.4922 42.424 44.5142 41.98 43.4942 41.644L44.1242 40.672ZM51.1982 40.402C51.0062 40.93 50.8502 41.314 50.7302 41.554H57.9842V42.328C57.7682 43.228 57.4802 44.104 57.1202 44.956L55.8782 44.578C56.1662 44.05 56.4242 43.42 56.6522 42.688H53.5922C53.5202 43.12 53.4122 43.516 53.2682 43.876C54.2042 45.256 56.0582 46.21 58.8302 46.738L58.3622 47.89C55.7222 47.35 53.8502 46.366 52.7462 44.938C52.5182 45.286 52.2782 45.592 52.0262 45.856C51.1262 46.696 49.6802 47.35 47.6882 47.818L47.2022 46.666C48.9782 46.282 50.2562 45.754 51.0362 45.082C51.6962 44.47 52.1342 43.672 52.3502 42.688H50.0462C49.5422 43.336 48.9482 43.93 48.2642 44.47L47.5082 43.462C48.6722 42.61 49.4762 41.536 49.9202 40.24L51.1982 40.402ZM56.7602 48.304V53.65H55.4642V49.51H46.4822V53.794H45.1862V48.304H56.7602ZM51.7562 50.302C51.5042 52.582 50.9582 54.118 50.1182 54.91C49.1702 55.894 47.0822 56.512 43.8542 56.764L43.3502 55.612C46.2182 55.444 48.1082 54.952 49.0202 54.136C49.8362 53.356 50.3162 52.042 50.4602 50.194L51.7562 50.302ZM47.3822 44.938C46.4822 45.874 45.3662 46.756 44.0342 47.584L43.1702 46.576C44.5262 45.808 45.6782 44.968 46.6262 44.056L47.3822 44.938ZM52.1702 53.596C54.4982 54.208 56.6282 54.946 58.5602 55.81L57.8582 56.89C55.7822 55.906 53.6642 55.138 51.5042 54.586L52.1702 53.596Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7186_97095">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7186_97102)">
<path d="M52.5096 4.53333H43.4429V2.26667C43.4429 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2941 0 23.0429 0C21.7917 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70481 4.53333 2.64294 8.5952 2.64294 13.6V54.4C2.64294 59.4048 6.70481 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.5189 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.2429 48.8512 16.2429 47.6C16.2429 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9653 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.2429 35.2512 16.2429 34C16.2429 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9653 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.2429 21.6512 16.2429 20.4C16.2429 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9653 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M46.2482 45.172H47.4902V47.962H49.3082V49.15H47.4902V51.67C48.1742 51.526 48.8222 51.382 49.4342 51.238V52.444L47.4902 52.894V56.818H46.2482V53.128C45.2402 53.308 44.1362 53.47 42.9362 53.614L42.7742 52.354C44.2382 52.186 45.3962 52.03 46.2482 51.886V49.15H43.2602L42.9902 48.016C43.5062 46.888 43.9862 45.484 44.4302 43.804H42.8282V42.562H44.7362C44.9402 41.65 45.0962 40.894 45.2042 40.294L46.4282 40.492L45.9962 42.562H49.2542V43.804H45.6902C45.2702 45.424 44.8142 46.81 44.3222 47.962H46.2482V45.172ZM49.8302 42.58H53.6822V40.366H54.9062V42.58H57.3002C56.9042 42.04 56.4182 41.464 55.8422 40.852L56.7062 40.312C57.3662 41.008 57.8762 41.608 58.2362 42.112L57.5702 42.58H59.2082V43.804H54.9062V45.46H58.5962V55.234C58.5962 56.218 58.1462 56.71 57.2462 56.71H56.0042L55.6802 55.486L56.8322 55.54C57.2042 55.54 57.3902 55.354 57.3902 54.982V52.84H54.9062V56.674H53.6822V52.84H51.3242V56.782H50.1182V45.46H53.6822V43.804H49.8302V42.58ZM53.6822 46.612H51.3242V48.646H53.6822V46.612ZM51.3242 49.762V51.724H53.6822V49.762H51.3242ZM57.3902 51.724V49.762H54.9062V51.724H57.3902ZM57.3902 48.646V46.612H54.9062V48.646H57.3902Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7186_97102">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7186_97108)">
<path d="M52.5096 4.53333H43.4429V2.26667C43.4429 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2941 0 23.0429 0C21.7917 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70481 4.53333 2.64294 8.5952 2.64294 13.6V54.4C2.64294 59.4048 6.70481 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.5189 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.2429 48.8512 16.2429 47.6C16.2429 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9653 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.2429 35.2512 16.2429 34C16.2429 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9653 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.2429 21.6512 16.2429 20.4C16.2429 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9653 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M55.2302 55.288C56.7302 55.288 58.0802 55.264 59.2802 55.216L59.0642 56.512H55.5182C51.2102 56.512 48.5162 56.278 47.4362 55.81C46.5002 55.414 45.6542 54.688 44.8982 53.632C44.5742 54.784 44.1242 55.846 43.5482 56.818L42.6122 55.99C43.5722 54.358 44.1002 52.516 44.1962 50.464L45.3482 50.608C45.3122 51.256 45.2522 51.826 45.1682 52.318C45.6362 53.05 46.1522 53.626 46.7162 54.046V49.672H43.1522V48.484H50.7842V49.672H47.8682V51.58H50.3342V52.732H47.8682V54.694C47.9762 54.73 48.0662 54.766 48.1382 54.802C49.1822 55.126 51.5462 55.288 55.2302 55.288ZM43.9622 40.996H50.1002V47.278H43.9622V40.996ZM48.8402 46.198V44.668H45.2222V46.198H48.8402ZM45.2222 43.66H48.8402V42.076H45.2222V43.66ZM51.0362 41.014H58.8122V42.202H55.5722C55.5122 42.73 55.4342 43.21 55.3382 43.642H58.3082V50.914H57.1022V44.758H52.7462V50.914H51.5942V43.642H54.1682C54.2642 43.234 54.3422 42.754 54.4022 42.202H51.0362V41.014ZM56.2202 50.968C57.3362 51.832 58.2722 52.696 59.0282 53.56L58.1102 54.46C57.4142 53.596 56.4962 52.708 55.3562 51.796L56.2202 50.968ZM54.3302 45.604H55.5182V48.142C55.4822 49.834 55.1522 51.202 54.5282 52.246C53.9282 53.182 52.9322 53.926 51.5402 54.478L50.8382 53.362C52.1222 52.894 53.0282 52.252 53.5562 51.436C54.0362 50.572 54.2942 49.474 54.3302 48.142V45.604Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7186_97108">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7186_97114)">
<path d="M52.5096 4.53333H43.4429V2.26667C43.4429 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2941 0 23.0429 0C21.7917 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70481 4.53333 2.64294 8.5952 2.64294 13.6V54.4C2.64294 59.4048 6.70481 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.5189 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.2429 48.8512 16.2429 47.6C16.2429 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9653 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.2429 35.2512 16.2429 34C16.2429 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9653 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.2429 21.6512 16.2429 20.4C16.2429 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9653 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M50.4602 48.826H48.7682V47.62H53.4302V48.826H51.7382V53.704C52.5902 53.512 53.3702 53.314 54.0782 53.11V54.316C52.5182 54.76 50.8322 55.138 49.0202 55.45L48.6962 54.226C49.3082 54.154 49.8962 54.064 50.4602 53.956V48.826ZM57.2822 56.53C56.6582 56.53 56.1122 56.062 55.6442 55.126C55.1042 54.046 54.7082 52.576 54.4562 50.716C54.2642 49.192 54.1322 47.218 54.0602 44.794H48.3542V43.534H54.0242C54.0002 42.838 53.9882 41.74 53.9882 40.24H55.2482C55.2482 41.752 55.2602 42.85 55.2842 43.534H58.8662V44.794H55.3022C55.3862 47.83 55.5782 50.218 55.8782 51.958C56.2742 53.998 56.7422 55.054 57.2822 55.126C57.6542 55.054 58.0202 53.95 58.3802 51.814L59.4062 52.642C58.8182 55.234 58.1102 56.53 57.2822 56.53ZM56.7962 40.222C57.5522 41.062 58.1522 41.818 58.5962 42.49L57.6962 43.12C57.2762 42.472 56.6702 41.692 55.8782 40.78L56.7962 40.222ZM44.9162 40.474C46.0442 41.374 47.0102 42.298 47.8142 43.246L46.9322 44.146C46.2002 43.246 45.2282 42.316 44.0162 41.356L44.9162 40.474ZM42.7562 45.802H46.5362V53.65C46.9682 53.23 47.5202 52.654 48.1922 51.922L48.5342 53.29C47.5262 54.382 46.4762 55.336 45.3842 56.152L44.8802 55C45.1442 54.772 45.2762 54.526 45.2762 54.262V47.044H42.7562V45.802Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7186_97114">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7186_97120)">
<path d="M52.5096 4.53333H43.4429V2.26667C43.4429 1.01547 42.4275 0 41.1763 0C39.9251 0 38.9096 1.01547 38.9096 2.26667V4.53333H25.3096V2.26667C25.3096 1.01547 24.2941 0 23.0429 0C21.7917 0 20.7763 1.01547 20.7763 2.26667V4.53333H11.7096C6.70481 4.53333 2.64294 8.5952 2.64294 13.6V54.4C2.64294 59.4048 6.70481 63.4667 11.7096 63.4667H52.5096C57.5144 63.4667 61.5763 59.4048 61.5763 54.4V13.6C61.5763 8.5952 57.5189 4.53333 52.5096 4.53333ZM45.7096 49.8667H18.5096C17.2584 49.8667 16.2429 48.8512 16.2429 47.6C16.2429 46.3488 17.2584 45.3333 18.5096 45.3333H45.7096C46.9608 45.3333 47.9763 46.3488 47.9763 47.6C47.9763 48.8512 46.9653 49.8667 45.7096 49.8667ZM45.7096 36.2667H18.5096C17.2584 36.2667 16.2429 35.2512 16.2429 34C16.2429 32.7488 17.2584 31.7333 18.5096 31.7333H45.7096C46.9608 31.7333 47.9763 32.7488 47.9763 34C47.9763 35.2512 46.9653 36.2667 45.7096 36.2667ZM45.7096 22.6667H18.5096C17.2584 22.6667 16.2429 21.6512 16.2429 20.4C16.2429 19.1488 17.2584 18.1333 18.5096 18.1333H45.7096C46.9608 18.1333 47.9763 19.1488 47.9763 20.4C47.9763 21.6512 46.9653 22.6667 45.7096 22.6667Z" fill="#A0CDF2"/>
<circle cx="51.5" cy="48.5" r="18.5" fill="white"/>
<circle cx="51.6914" cy="48.6912" r="14.6912" fill="#A0CDF2"/>
<path d="M42.9181 45.784H48.0661C48.2221 45.196 48.4081 44.452 48.6241 43.552H44.1421V42.346H48.8941C49.0021 41.854 49.1521 41.128 49.3441 40.168L50.6761 40.276L50.2621 42.346H58.0201V43.552H49.9921C49.8241 44.296 49.6441 45.04 49.4521 45.784H59.0821V47.044H49.1101C48.9421 47.62 48.6841 48.412 48.3361 49.42H56.9041V50.536C56.0161 51.904 54.6601 53.242 52.8361 54.55C53.8321 54.91 54.8701 55.348 55.9501 55.864L55.2301 56.998C52.5661 55.678 49.7821 54.628 46.8781 53.848L47.5621 52.84C48.7621 53.164 50.0581 53.566 51.4501 54.046C53.0941 52.966 54.4021 51.826 55.3741 50.626H46.4821C46.9501 49.366 47.3581 48.172 47.7061 47.044H42.9181V45.784Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_7186_97120">
<rect width="68" height="68" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+16
View File
@@ -0,0 +1,16 @@
<svg
t="1615860353141"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="6624"
width="14"
height="14"
>
<path
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
p-id="6625"
fill="#656667"
></path>
</svg>

After

Width:  |  Height:  |  Size: 914 B

+4
View File
@@ -0,0 +1,4 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path d="M832 192H544l-64-64H192c-35.2 0-64 28.8-64 64v576c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64V256c0-35.2-28.8-64-64-64z m0 576H192V192h266.7l64 64H832v512z" fill="#999999"/>
<path d="M256 320h512v64H256z m0 128h384v64H256z m0 128h256v64H256z" fill="#cccccc"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

+13
View File
@@ -0,0 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="30" height="30" rx="3" fill="white" stroke="#DCDEE0" stroke-width="2" stroke-dasharray="4 4"/>
<g clip-path="url(#clip0_125_1092)">
<path d="M24 8H8V24H24V8Z" fill="white" fill-opacity="0.01"/>
<path d="M16.0209 11.3333L16.0087 20.6666" stroke="#666666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.3333 16H20.6667" stroke="#666666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_125_1092">
<rect width="16" height="16" fill="white" transform="translate(8 8)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 695 B

+15
View File
@@ -0,0 +1,15 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="30" height="30" rx="3" fill="white" stroke="#DCDEE0" stroke-width="2"/>
<g clip-path="url(#clip0_125_1099)">
<path d="M24 8H8V24H24V8Z" fill="white" fill-opacity="0.01"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6667 13H21.3333L20.3333 22.6667H11.6667L10.6667 13Z" stroke="#F15B43" stroke-width="1.125" stroke-linejoin="round"/>
<path d="M14.6667 16.3333V19.6667" stroke="#F15B43" stroke-width="1.125" stroke-linecap="round"/>
<path d="M17.3333 16.3333V19.6658" stroke="#F15B43" stroke-width="1.125" stroke-linecap="round"/>
<path d="M12 13L17.4414 9L20 13" stroke="#F15B43" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_125_1099">
<rect width="16" height="16" fill="white" transform="translate(8 8)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 919 B

+4
View File
@@ -0,0 +1,4 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path d="M482.214544 543.934407l-0.099952-59.970717 59.970718-0.099952 0.099951 59.970718-59.970717 0.099951z m119.941435-0.199902l-0.099952-59.970718 59.970718-0.099951 0.099951 59.970717-59.970717 0.099952z m119.941434-0.199903l-0.099951-59.970717 59.970718-0.099951 0.099951 59.970717-59.970718 0.099951z m119.941435-0.299853l-0.099951-59.970718 59.970717-0.099951 0.099952 59.970717-59.970718 0.099952z m119.941435-0.199903l-0.099951-59.970717 59.970717-0.099951 0.099951 59.970717-59.970717 0.099951z" />
<path d="M482.914202 1024l-0.099951-59.970717 59.970717-0.099952 0.099951 59.970718-59.970717 0.099951z m-0.199902-119.941435l-0.099952-59.970717 59.970718-0.099951 0.099951 59.970717-59.970717 0.099951z m-0.199903-119.941435l-0.099951-59.970717 59.970717-0.099951 0.099952 59.970717-59.970718 0.099951z m-0.199902-119.941435l-0.099951-59.970717 59.970717-0.099951 0.099951 59.970717-59.970717 0.099951z m-0.099951-119.941434l-0.099952-59.970718 59.970718-0.099951 0.099951 59.970717-59.970717 0.099952z m-0.199903-119.941435l-0.099951-59.970718 59.970718-0.099951 0.099951 59.970718-59.970718 0.099951z m-0.199902-119.941435l-0.099951-59.970718 59.970717-0.099951 0.099951 59.970718-59.970717 0.099951z m-0.199902-119.941435l-0.099952-59.970717 59.970718-0.099952 0.099951 59.970718-59.970717 0.099951z m-0.199903-119.941435l-0.099951-59.970717 59.970717-0.099951 0.099952 59.970717-59.970718 0.099951z" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7225_67996)">
<path d="M18 0H0V18H18V0Z" fill="white" fill-opacity="0.01"/>
<path d="M14.625 2.25H3.375C2.75368 2.25 2.25 2.75368 2.25 3.375V14.625C2.25 15.2463 2.75368 15.75 3.375 15.75H14.625C15.2463 15.75 15.75 15.2463 15.75 14.625V3.375C15.75 2.75368 15.2463 2.25 14.625 2.25Z" stroke="#5B6871" stroke-width="1.125" stroke-linejoin="round"/>
<path d="M9 6V12" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 9H12" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_7225_67996">
<rect width="18" height="18" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 793 B

+5
View File
@@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 0H0V18H18V0Z" fill="white" fill-opacity="0.01"/>
<path d="M2.625 15.75H16.125" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.125 10.02V12.75H6.86895L14.625 4.99054L11.8857 2.25L4.125 10.02Z" stroke="#5B6871" stroke-width="1.125" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 424 B

+14
View File
@@ -0,0 +1,14 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7225_67984)">
<path d="M18 0H0V18H18V0Z" fill="white" fill-opacity="0.01"/>
<path d="M7 3V15" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 7L7 3" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 15V3" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 15L15 11" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_7225_67984">
<rect width="18" height="18" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 740 B

+1
View File
@@ -0,0 +1 @@
<svg t="1784779423851" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6101" width="24" height="24"><path d="M1016.32 494.08l-143.872-143.36c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84L936.96 486.4h-399.36V87.04l99.84 100.352c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84l-143.36-143.872c-9.728-9.728-26.112-9.728-35.84 0l-143.36 143.872c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0L486.4 87.04v399.36H87.04l100.352-99.84c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0l-143.872 143.36c-9.728 9.728-9.728 26.112 0 35.84l143.872 143.36c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84L87.04 537.6h399.36v399.36l-99.84-100.352c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84l143.36 143.872c9.728 9.728 26.112 9.728 35.84 0l143.36-143.872c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0L537.6 936.96v-399.36h399.36l-100.352 99.84c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0l143.872-143.36c10.24-9.728 10.24-26.112 0-35.84z" p-id="6102"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+14
View File
@@ -0,0 +1,14 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7225_67990)">
<path d="M18 0H0V18H18V0Z" fill="white" fill-opacity="0.01"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 5.625H15L13.875 16.5H4.125L3 5.625Z" stroke="#5B6871" stroke-width="1.125" stroke-linejoin="round"/>
<path d="M7.50073 9.37598V13.1261" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round"/>
<path d="M10.5009 9.375V13.1241" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round"/>
<path d="M4.5 5.62496L10.6216 1.125L13.5 5.625" stroke="#5B6871" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_7225_67990">
<rect width="18" height="18" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 795 B

+1
View File
@@ -0,0 +1 @@
<svg t="1784812882139" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3484" width="24" height="24"><path d="M446.112323 177.545051c137.567677 0.219798 252.612525 104.59798 266.162424 241.493333 13.562828 136.895354-78.778182 261.818182-213.617777 289.008485-134.852525 27.203232-268.386263-52.156768-308.945455-183.608889s25.018182-272.252121 151.738182-325.779394A267.235556 267.235556 0 0 1 446.112323 177.545051m0-62.060607c-182.794343 0-330.989899 148.195556-330.989899 330.989899s148.195556 330.989899 330.989899 330.989899 330.989899-148.195556 330.989899-330.989899-148.195556-330.989899-330.989899-330.989899z m431.321212 793.341415a30.849293 30.849293 0 0 1-21.94101-9.102223l-157.220202-157.220202c-11.752727-12.179394-11.584646-31.534545 0.37495-43.50707 11.972525-11.972525 31.327677-12.140606 43.494141-0.37495l157.220202 157.220202a31.036768 31.036768 0 0 1 6.723232 33.810101 31.004444 31.004444 0 0 1-28.651313 19.174142z m0 0" p-id="3485"></path></svg>

After

Width:  |  Height:  |  Size: 1014 B

+8
View File
@@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_161_3866" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.3333 0H10.6667V10.6667H0V13.3333H10.6667V24H13.3333V13.3333H24V10.6667H13.3333V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_161_3866)">
<rect x="-4" y="-4" width="32" height="32" fill="#646566"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 476 B

+8
View File
@@ -0,0 +1,8 @@
<svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_161_2681" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="3" y="3" width="12" height="12">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.7203 3.21967L14.7809 4.28033L10.061 9.00025L14.7809 13.7202L13.7203 14.7809L9.00034 10.0609L4.28039 14.7809L3.21973 13.7202L7.93968 9.00025L3.21975 4.28033L4.28041 3.21967L9.00034 7.93959L13.7203 3.21967Z" fill="white"/>
</mask>
<g mask="url(#mask0_161_2681)">
<rect width="18" height="18" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

+11
View File
@@ -0,0 +1,11 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="47" height="47" rx="23.5" fill="white" stroke="#EBEDF0"/>
<g clip-path="url(#clip0_23_1904)">
<path d="M26.3517 11.612L33.8684 15.829C35.3234 16.645 36.22 18.1532 36.22 19.7854V28.2146C36.22 29.8467 35.3235 31.355 33.8684 32.171L26.3517 36.3879C24.8965 37.2039 23.1035 37.2039 21.6484 36.3879L14.1317 32.171C12.6766 31.355 11.78 29.8467 11.78 28.2146V19.7854C11.78 18.1532 12.6765 16.645 14.1317 15.829L21.6484 11.612C23.1035 10.796 24.8965 10.796 26.3517 11.612ZM22.6913 12.9051L22.4469 13.0283L14.9303 17.2454C14.0639 17.7312 13.5079 18.5857 13.4213 19.5268L13.4093 19.7855V28.2146C13.4093 29.169 13.8932 30.0625 14.7021 30.6132L14.9307 30.7548L22.4468 34.9715C23.3263 35.4647 24.3975 35.5058 25.3088 35.095L25.5532 34.9716L33.0698 30.7545C33.9362 30.2687 34.4922 29.4142 34.5788 28.4732L34.5908 28.2144V19.7854C34.5908 18.8309 34.1069 17.9374 33.2981 17.3867L33.0694 17.2452L25.5533 13.0285C24.6738 12.5353 23.6026 12.4942 22.6913 12.905L22.6913 12.9051ZM23.9977 16.3019C24.4446 16.3019 24.8529 16.5478 25.0514 16.9368L26.7634 20.3038L30.5874 20.843C31.0306 20.9055 31.3986 21.207 31.5369 21.6205C31.6751 22.0341 31.5597 22.4882 31.239 22.7916L28.4732 25.4116L29.127 29.1123C29.2029 29.5411 29.0214 29.9745 28.659 30.2302C28.4797 30.3557 28.2695 30.43 28.0512 30.4452C27.8328 30.4603 27.6144 30.4156 27.4195 30.316L24 28.5688L20.5805 30.3162C20.3856 30.4158 20.1673 30.4604 19.9489 30.4453C19.7306 30.4301 19.5205 30.3558 19.3412 30.2303C18.9786 29.9746 18.7972 29.5413 18.8731 29.1123L19.527 25.4117L16.7564 22.7916C16.4357 22.4882 16.3202 22.0341 16.4585 21.6206C16.5968 21.2069 16.9648 20.9056 17.4078 20.843L21.2319 20.3039L22.944 16.9369C23.1425 16.5478 23.5507 16.3019 23.9977 16.3019V16.3019ZM23.9968 18.4555L22.301 21.7944L18.6183 22.3132L21.2834 24.8335L20.6436 28.4573L24 26.7428L27.3565 28.4575L26.7168 24.8344L29.3768 22.3133L25.6944 21.7945L23.9967 18.4556L23.9968 18.4555Z" fill="#5979EA"/>
</g>
<defs>
<clipPath id="clip0_23_1904">
<rect width="26" height="26" fill="white" transform="translate(11 11)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

+231
View File
@@ -0,0 +1,231 @@
const userinfoResult = {
id: 186532,
account: "zhd",
name: "朱皓东",
idcard: "130203192009217969",
phone: null,
email: "",
birthday: null,
gender: 0,
profilePicture: "http://base.bestsch.com/upload/userPicture/186532_eae297df",
groupId: 3613,
type: 2,
status: 0,
createUser: 0,
orderNumber: 32767,
dept: null,
roleIds: [1, 1, 1, 1, 1, 4, 4, 4, 7, 7, 7],
roleList: [
{
roleId: 1,
schId: 1410,
userId: 186532,
},
{
roleId: 1,
schId: 3260,
userId: 186532,
},
{
roleId: 1,
schId: 6237,
userId: 186532,
},
{
roleId: 4,
schId: 1410,
userId: 186532,
},
{
roleId: 4,
schId: 3260,
userId: 186532,
},
{
roleId: 4,
schId: 6237,
userId: 186532,
},
{
roleId: 7,
schId: 1410,
userId: 186532,
},
{
roleId: 7,
schId: 3260,
userId: 186532,
},
{
roleId: 7,
schId: 6237,
userId: 186532,
},
],
groups: [
{
userId: 0,
groupId: 3613,
orderNumber: 32767,
schoolId: 3260,
bureauId: 1596,
},
{
userId: 0,
groupId: 4805,
orderNumber: 32767,
schoolId: 1410,
bureauId: 1596,
},
{
userId: 0,
groupId: 6277,
orderNumber: 32767,
schoolId: 6237,
bureauId: 1596,
},
{
userId: 0,
groupId: 3615,
orderNumber: 32767,
schoolId: 3260,
bureauId: 1596,
},
],
school: {
id: 3260,
name: "上海鸿育初级中学",
code: null,
parentId: 3318,
path: "1,1596,3318,",
level: 4,
type: 2,
order: "32767",
orderNo: 32767,
createUser: 0,
createDate: null,
children: [],
userList: [],
},
bureau: null,
schools: [
{
id: 3260,
name: "上海鸿育初级中学",
code: null,
parentId: 3318,
path: "1,1596,3318,",
level: 4,
type: 2,
order: "32767",
orderNo: 32767,
createUser: 0,
createDate: null,
children: [],
userList: [],
},
{
id: 1410,
name: "上海弘育高级中学",
code: null,
parentId: 3318,
path: "1,1596,3318,",
level: 4,
type: 2,
order: "2",
orderNo: 2,
createUser: 0,
createDate: null,
children: [],
userList: [],
},
{
id: 6237,
name: "上海弘育教育初级中学",
code: null,
parentId: 3318,
path: "1,1596,3318,",
level: 4,
type: 2,
order: "32767",
orderNo: 32767,
createUser: 0,
createDate: null,
children: [],
userList: [],
},
],
phone2: null,
schId: 0,
groupName: null,
};
const userModResult = [
{
id: 1105,
appId: 437,
modId: 1001,
name: "学习中心管理",
parentId: 0,
path: null,
level: 0,
page: "/",
icon: "",
orderNumber: 0,
usable: true,
children: [],
},
{
id: 1106,
appId: 437,
modId: 1002,
name: "数据统计",
parentId: 0,
path: null,
level: 0,
page: "/stats",
icon: "",
orderNumber: 0,
usable: true,
children: [],
},
{
id: 1107,
appId: 437,
modId: 1003,
name: "应用设置",
parentId: 0,
path: null,
level: 0,
page: "/appsettings",
icon: "",
orderNumber: 0,
usable: true,
children: [],
},
];
export default [
{
url: "/api/base/getUserInfo", //请求地址
method: "get", //请求方式
response: () => {
return {
code: 0,
msg: null,
data: userinfoResult,
};
},
},
{
url: "/api/base/GetUserMod", //请求地址
method: "get", //请求方式
response: () => {
return {
code: 0,
msg: null,
data: userModResult,
};
},
},
];
+7
View File
@@ -0,0 +1,7 @@
import { createProdMockServer } from "vite-plugin-mock/es/createProdMockServer";
import BaseMock from "./baseapi";
import RuleMock from "./ruleapi";
export function setupProdMockServer() {
createProdMockServer([...BaseMock, ...RuleMock]);
}
+69
View File
@@ -0,0 +1,69 @@
const baseTableResult = [
{
name: "套餐A",
date: new Date().getTime(),
bg: "../image/meal-bg.png",
content: "脆皮鸡腿 经典烤肠 海鲜菇炒肉丝 炒青菜 柿柿如意包 番茄蛋汤",
},
{
name: "套餐B",
date: new Date().getTime(),
bg: "../image/meal-bg.png",
content: "脆皮鸡腿 经典烤肠 海鲜菇炒肉丝 炒青菜 柿柿如意包 番茄蛋汤",
},
];
const baseTableResult2 = [
{
grade: "一年级",
className: "1班",
mealA: 32,
mealB: 28,
date: new Date().getTime(),
},
{
grade: "一年级",
className: "2班",
mealA: 31,
mealB: 38,
date: new Date().getTime(),
},
{
grade: "一年级",
className: "3班",
mealA: 25,
mealB: 38,
date: new Date().getTime(),
},
];
export default [
{
url: "/api/ordermeal/GetList", //请求地址
method: "get", //请求方式
response: () => {
return {
code: 0,
msg: null,
data: {
total: 10,
list: baseTableResult,
},
};
},
},
{
url: "/api/ordermeal/GetList2", //请求地址
method: "get", //请求方式
response: () => {
return {
code: 0,
msg: null,
data: {
total: 10,
list: baseTableResult2,
},
};
},
},
];
+17
View File
@@ -0,0 +1,17 @@
*{
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html,body,#app{
height: 100%;
}
body{
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
min-width: 1200px;
}
a{
text-decoration: none;
}
+2
View File
@@ -0,0 +1,2 @@
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain)*/
div, span, applet, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, big, cite, code,del, dfn, em, img, ins, kbd, q, s, samp,small, strike, strong, sub, sup, tt, var,b, u, i, center,dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td,article, aside, canvas, details, embed,figure, figcaption, footer, header, hgroup,menu, nav, output, ruby, section, summary,time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; vertical-align: baseline;}/* HTML5 display-role reset for older browsers */article, aside, details, figcaption, figure,footer, header, hgroup, menu, nav, section { display: block;}ol, ul { list-style: none;}blockquote, q { quotes: none;}blockquote:before, blockquote:after,q:before, q:after { content: ''; content: none;}table { border-collapse: collapse; border-spacing: 0;}
+84
View File
@@ -0,0 +1,84 @@
/*滚动条样式 */
/*第一种样式,所有的滚动条,都默认这个样子*/
*::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/*正常情况下滑块的样式*/
*::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, .05);
border-radius: 10px;
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
}
/*鼠标悬浮在该类指向的控件上时滑块的样式*/
*:hover::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, .2);
border-radius: 10px;
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
}
/*鼠标悬浮在滑块上时滑块的样式*/
*::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, .3);
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
}
/*正常时候的主干部分*/
*::-webkit-scrollbar-track {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: white;
}
/*鼠标悬浮在滚动条上的主干部分*/
*::-webkit-scrollbar-track:hover {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
background-color: rgba(0, 0, 0, .01);
}
/*第一种样式结束*/
/*第二种样式*/
.scroll2::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/*正常时候的主干部分*/
.scroll2::-webkit-scrollbar-track {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: white;
}
/*正常情况下滑块的样式*/
.scroll2::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, .05);
border-radius: 10px;
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
}
/*鼠标悬浮在该类指向的控件上时滑块的样式*/
.scroll2:hover::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, .2);
border-radius: 10px;
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
}
/*鼠标悬浮在滚动条上的主干部分*/
.scroll2::-webkit-scrollbar-track:hover {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
}
/*鼠标悬浮在滑块上时滑块的样式*/
.scroll2::-webkit-scrollbar-thumb:hover {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
}
/*第二种样式结束*/
@@ -0,0 +1,35 @@
.my-table {
width: 100%;
border-bottom: 1px solid #c7c7c7;
border-right: 1px solid #c7c7c7;
border-collapse: separate;
.td-title {
background: #fafafa;
vertical-align: middle;
color: #111;
font-weight: 550;
}
th {
background: #fafafa;
height: 20px;
line-height: 20px;
padding: 12px;
}
td {
height: 20px;
line-height: 20px;
padding: 12px;
}
th,
td {
border-top: 1px solid #c7c7c7;
border-left: 1px solid #c7c7c7;
margin-left: -1px;
margin-top: -1px;
text-align: center;
}
}
@@ -0,0 +1,59 @@
.rule-tree {
padding: 0 !important;
width: 280px !important;
.head-ul {
background: #f6f8f9;
border-bottom: 1px solid #ebeef5;
display: flex;
justify-content: space-evenly;
align-items: center;
height: 48px;
li {
width: 34px;
height: 34px;
box-sizing: content-box;
border-radius: 50%;
position: relative;
cursor: pointer;
.ivu-tooltip,
.ivu-tooltip-rel {
width: 100%;
height: 100%;
display: block;
}
svg {
position: absolute;
inset: 0;
margin: auto;
}
&:hover {
background-color: #eaeaea;
cursor: pointer;
}
&.disabled {
background-color: #fff;
cursor: not-allowed;
}
button {
display: inline-block;
width: 100%;
height: 100%;
border-radius: 50%;
color: #515a6e;
border: 0;
outline: none;
background-color: transparent;
cursor: inherit;
}
}
}
.body-box {
padding: 11px 0;
}
.ztree li span.button {
background-repeat: 10px;
}
}
@@ -0,0 +1,26 @@
table.small-table {
border: 1px solid #ebeef5;
border-radius: 5px;
th {
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
padding: 10px 20px;
}
td {
padding: 5px 20px;
}
tr:first-child td {
padding-top: 10px;
}
tr:last-child td {
padding-bottom: 10px;
}
.input-box {
width: 100px;
vertical-align: text-bottom;
display: inline-block;
}
.ivu-input-wrapper {
vertical-align: text-bottom;
}
}
+8
View File
@@ -0,0 +1,8 @@
$liColor: #969799, #e6a23c, #45b972, #eb0404;
@each $c in $liColor {
$i: index($liColor, $c);
.status-color-#{$i} {
color: $c;
}
}
File diff suppressed because one or more lines are too long
+117
View File
@@ -0,0 +1,117 @@
@import "base/base";
@import "base/bscroll.css";
@import "base/reset";
@import "utils/mixins";
@import "utils/utils";
@import "componets/status";
@import "componets/small_table";
@import "componets/my_table";
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.base-subtitle {
position: relative;
padding-left: 12px;
line-height: 24px;
font-size: 15px;
font-weight: 400;
&::before {
content: "";
display: block;
width: 3px;
background: #5979ea;
height: 15px;
border-radius: 4px;
position: absolute;
top: 5px;
left: 0;
}
}
h4.second-title {
@extend .base-subtitle;
&::before {
background: #5979ea;
}
}
h4.subtitle {
@extend .second-title;
&::before {
background: #bda366;
}
}
.details-wrap {
display: flex;
padding-top: 10px;
.left-box {
width: 200px;
height: 100%;
.user-list-ul {
height: calc(100% - 50px);
overflow-y: auto;
li {
height: 42px;
border: 1px solid #ebeef5;
border-top: none;
position: relative;
cursor: pointer;
transition: border 200ms;
img {
object-fit: cover;
width: 30px;
height: 30px;
border-radius: 3px;
}
span.stu-name {
height: 20px;
line-height: 20px;
display: inline-block;
width: 60px;
}
span.stu-card {
width: 50px;
text-align: right;
}
}
li.active {
// background: #f3f3f3;
color: #7892ed;
border-right: 3px solid #5979ea;
}
}
}
.right-box {
width: 100%;
padding: 0 15px;
}
}
.table-spin-load {
width: 60px;
height: 90px;
padding-top: 60px;
background-image: url(../image/loading.gif);
background-size: 60px 60px;
background-position: top center;
background-repeat: no-repeat;
border: none;
color: #577afb;
margin: 0 auto;
}
.ivu-table-cell-tree {
margin-right: 4px;
margin-bottom: 2px;
}
+13
View File
@@ -0,0 +1,13 @@
@mixin tag_mixin($bgColor,$textColor) {
width:64px;
height:20px ;
padding: 0 5px;
background: $bgColor;
color: $textColor;
font-size: 12px;
border-radius: 2px 2px 2px 2px;
text-align: center;
line-height: 20px;
}
+170
View File
@@ -0,0 +1,170 @@
// utils 工具// 颜色
@import "./varible";
.bg-error {
background-color: $color-error !important;
}
.text-error {
color: $color-error !important;
}
.text-success {
color: $color-success !important;
}
.text-warning {
color: $color-warning !important;
}
.text-primary {
color: $color-primary !important;
}
.text-normal {
color: #404042 !important;
}
.text-black {
color: #000;
}
.text-dark {
color: #333;
}
.text-deep {
color: #555;
}
.text-weak {
color: #b3b3b3;
}
.text-white {
color: #fff;
}
.text-error.disabled {
color: #aaa !important;
}
// 文字对齐
.tl {
text-align: left;
}
.tc {
text-align: center;
}
.tr {
text-align: right;
}
// 浮动与清除浮动
.fl {
float: left;
}
.fr {
float: right;
}
.fix {
*zoom: 1;
}
.fix:after {
display: table;
content: "";
clear: both;
}
// 显示
.dn {
display: none;
}
.di {
display: inline;
}
.db {
display: block;
}
.dib {
display: inline-block;
}
.dt {
display: table;
}
div.dib {
*display: inline;
*zoom: 1;
}
.vm {
vertical-align: middle;
}
.vib {
display: inline-block;
vertical-align: middle;
}
.ovh {
overflow: hidden;
}
// 定位
.pr {
position: relative;
}
.pa {
position: absolute;
}
.pf {
position: fixed;
}
.align-middle {
position: relative;
top: 50%;
transform: translateY(-50%);
}
.align-middle-wrap {
display: flex;
align-items: center;
}
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@for $i from 1 through 100 {
.width-#{$i} {
width: $i * 1%;
}
.height-#{$i} {
height: $i * 1px;
}
// @if $i<50 and $i%2==0 {
// @if $i<50 {
.ml-#{$i} {
margin-left: $i * 1px !important;
}
.mr-#{$i} {
margin-right: $i * 1px !important;
}
.mt-#{$i} {
margin-top: $i * 1px !important;
}
.mb-#{$i} {
margin-bottom: $i * 1px !important;
}
// }
}
// 字体
@for $i from 10 through 28 {
.f#{$i} {
font-size: $i * 1px;
}
}
// .chart-box {
// height: 50px;
// width: 100%;
// border-bottom: 50px solid;
// border-image: linear-gradient(90deg, #f55c65 0%, #fcced0 48%, #d4dffc 52%, #7194f5 100%) 50 50 50 50;
// }
// @for $i from 0 through 50 {
// .blue-#{$i} {
// background-color: rgba(#7194f5, 0.1 * $i * 0.2);
// }
// }
// @for $i from 0 through 50 {
// .red-#{$i} {
// background-color: rgba(#f55c65, 0.1 * $i * 0.2);
// }
// }
+22
View File
@@ -0,0 +1,22 @@
/*scss变量*/
// 主题色
$color-error: #e8684a;
$color-success: #45b972;
$color-warning: #e9b954;
$color-primary: #5979ea;
// 文字色
$color-black: #404042;
$color-dark: #333;
$color-deep: #555;
$color-pl: #999999;
$color-weak: #b3b3b3;
$color-white: #fff;
// 背景色
$bg-bar: #f9f9f9;
$bg-page: #f3f3f3;
$bg-page-light: #f9f9f9;
$border-color: #e9e9e9;
+94
View File
@@ -0,0 +1,94 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const $$userConfigMap: typeof import('./api/index')['$$userConfigMap']
const Button: typeof import('view-ui-plus')['Button']
const EffectScope: typeof import('vue')['EffectScope']
const Form: typeof import('view-ui-plus')['Form']
const FormItem: typeof import('view-ui-plus')['FormItem']
const Input: typeof import('view-ui-plus')['Input']
const Message: typeof import('view-ui-plus')['Message']
const Modal: typeof import('view-ui-plus')['Modal']
const Select: typeof import('view-ui-plus')['Select']
const Table: typeof import('view-ui-plus')['Table']
const api: typeof import('./api/index')['default']
const apiDefinitions: typeof import('./api/apiDefinitions')['default']
const computed: typeof import('vue')['computed']
const createApis: typeof import('./api/createApis')['createApis']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const mountApis: typeof import('./api/createApis')['mountApis']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useForm: typeof import('alova/client')['useForm']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const usePagination: typeof import('alova/client')['usePagination']
const useRequest: typeof import('alova/client')['useRequest']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useWatcher: typeof import('alova/client')['useWatcher']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const withConfigType: typeof import('./api/createApis')['withConfigType']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
+95
View File
@@ -0,0 +1,95 @@
<template>
<div class="improt-wrap">
<div class="form-item">
<label>案例下载:</label>
<a @click="downTempFile" href="javascript:;">点击下载模板.xls</a>
</div>
<div class="upload-panel">
<Upload type="drag" :on-success="onSuccess" :on-error="onError" :data="uploadData" :headers="uploadHeader"
:with-credentials="true" :action="uploadUrl"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
<div class="upload-box">
<Icon type="ios-paper" size="52" style="color: #6281eb"></Icon>
<h4>点击或将文件拖拽到这里上传</h4>
<div class="info">文件大小不超过50M 支持扩展名: xls,xlsx</div>
</div>
</Upload>
</div>
<Alert v-if="!!errorMsg" type="error" show-icon><span v-html="errorMsg"></span></Alert>
<Alert v-else-if="!!successMsg" type="success" show-icon>{{ successMsg }}</Alert>
<Alert v-else style="margin-bottom: 0" type="warning" show-icon>
请按照案例模板内容进行编辑,否则将无法导入。
</Alert>
</div>
</template>
<script>
import Utils from "@/utils";
export default {
props: {
tempFileUrl: String,
uploadUrl: String,
uploadData: Object,
},
data() {
return {
errorMsg: null,
successMsg: null,
};
},
computed: {
uploadHeader() {
const roleInfo = Utils.getCurrentRoleInfo();
roleInfo.schoolId = roleInfo.schId;
roleInfo.yschapirequest = 1;
// roleInfo.userType = 2;
return roleInfo;
},
},
methods: {
downTempFile() {
window.top.location.href = this.tempFileUrl;
},
onSuccess(res, file) {
if (res.code == 0) {
this.errorMsg = null;
this.successMsg = "操作成功!";
this.$emit("on-success");
} else {
this.errorMsg = res.msg;
}
},
onError(err, file) {
this.errorMsg = JSON.stringify(err);
console.log(err, file);
},
},
};
</script>
<style lang="scss" scoped>
.improt-wrap {
padding: 16px;
.form-item {
margin-bottom: 10px;
}
}
.upload-panel {
.upload-box {
background: #f7f8fc;
padding: 20px 0;
h4 {
color: #505c7e;
margin: 3px 0;
}
}
.info {
font-size: 13px;
color: #666;
}
}
</style>
+276
View File
@@ -0,0 +1,276 @@
<template>
<div class="group-tree-search-panel">
<div v-if="searchVisible" class="search-bar mt-8 mb-8">
<Input v-model="searchKeyword" :placeholder="searchPlaceholder" suffix="ios-search" search clearable
class="search-input" @on-search="onSearch" @on-clear="onClear" />
<Button v-if="showCloseButton" icon="md-close" @click="closeSearch" />
</div>
<div class="tree-body">
<MyTree v-if="!treeLoading" ref="refMyTree" :autoClick="autoClick" :treeData="treeData"
:setting="treeSetting" @on-tree-click="treeLink" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, nextTick, useTemplateRef } from "vue";
import { cloneDeep } from "lodash";
import { Message } from "view-ui-plus";
import MyTree from '@/components/MyTree.vue'
const GROUP_TYPE = {
NORMAL_GROUP: 1,
SCHOOL_GROUP: 2,
GRADE_GROUP: 3,
CLASS_GROUP: 4,
AREA_GROUP: 5,
STAGE_GROUP: 6,
TEACHER_GROUP: 7,
STUDENT_GROUP: 8,
} as const
const DEFAULT_CACHE_KEY = 'bsch.group-tree.selected-node'
const props = withDefaults(defineProps<{
treeApi: () => Promise<any[]>;
autoClick?: boolean;
defaultSearchVisible?: boolean;
showCloseButton?: boolean;
searchPlaceholder?: string;
cacheKey?: string;
}>(), {
autoClick: false,
defaultSearchVisible: true,
showCloseButton: false,
searchPlaceholder: '输入组名称搜索',
cacheKey: DEFAULT_CACHE_KEY,
})
const emit = defineEmits<{
'on-change': [treeNode: any]
'on-tree-data': [tree: any[]]
}>()
const curTreeNode = defineModel<any>('curTreeNode', { default: {} })
const refMyTree = useTemplateRef('refMyTree')
const treeLoading = ref(false)
const treeData = ref<any[]>([])
const searchKeyword = ref('')
const searchVisible = ref(props.defaultSearchVisible)
const treeSetting = ref({
view: { dblClickExpand: false, showIcon: false },
edit: { enable: false, showRemoveBtn: false, showRenameBtn: false, drag: false },
check: { enable: false },
callback: {},
})
function formatTree(list: any[], depth = 1): any[] {
return (list || []).map((node) => {
const children = node.children;
const hasChildren = Array.isArray(children) && children.length > 0;
const formatted: any = { ...node, isParent: hasChildren };
if (depth === 1) formatted.open = true;
if (hasChildren) {
formatted.children = formatTree(children, depth + 1);
} else {
delete formatted.children;
}
return formatted;
});
}
function findNodeById(list: any[], id?: number | null): any {
if (id == null) return null;
for (const node of list || []) {
if (Number(node.id) === Number(id)) return node;
const child = findNodeById(node.children || [], id);
if (child) return child;
}
return null;
}
function findFirstNodeByType(list: any[], type: number): any {
for (const node of list || []) {
if (Number(node.type) === type) return node;
const child = findFirstNodeByType(node.children || [], type);
if (child) return child;
}
return null;
}
function getCachedSelectedNodeId() {
try {
const raw = sessionStorage.getItem(props.cacheKey);
if (!raw) return null;
const cached = JSON.parse(raw);
const id = Number(cached?.id);
return Number.isFinite(id) ? id : null;
} catch {
return null;
}
}
function cacheSelectedNode(treeNode: any) {
if (!treeNode?.id) return;
sessionStorage.setItem(props.cacheKey, JSON.stringify({
id: Number(treeNode.id),
name: treeNode.name,
type: treeNode.type,
}));
}
function resolveInitialSelectId(list: any[], preferredId?: number | null) {
const preferred = findNodeById(list, preferredId);
if (preferred) return preferred.id;
const cached = findNodeById(list, getCachedSelectedNodeId());
if (cached) return cached.id;
const schoolNode = findFirstNodeByType(list, GROUP_TYPE.SCHOOL_GROUP);
if (schoolNode) return schoolNode.id;
if (props.autoClick && list.length) return list[0].id;
return list[0]?.id ?? null;
}
async function loadTree(preferredId?: number | null) {
treeLoading.value = true;
try {
const tree = await props.treeApi();
treeData.value = formatTree(tree || []);
emit('on-tree-data', cloneDeep(treeData.value));
} catch (e: any) {
Message.error(e?.message || '加载组织树失败');
} finally {
treeLoading.value = false;
}
if (!treeData.value.length) return;
await nextTick();
const selectId = resolveInitialSelectId(treeData.value, preferredId);
if (selectId != null) {
refMyTree.value?.reloadTree(selectId);
}
}
async function refreshTree(selectId?: number) {
await loadTree(selectId);
}
function treeLink(treeNode: any) {
const copyNode = cloneDeep(treeNode)
copyNode.children = [];
curTreeNode.value = copyNode;
cacheSelectedNode(copyNode);
emit('on-change', copyNode)
}
function onSearch() {
refMyTree.value?.search(searchKeyword.value);
}
function onClear() {
searchKeyword.value = '';
refMyTree.value?.search('');
}
function openSearch() {
searchVisible.value = true;
}
function closeSearch() {
searchVisible.value = false;
onClear();
}
function reloadTree(id?: number) {
refMyTree.value?.reloadTree(id);
}
function selectNode(id: number, isClick = true) {
refMyTree.value?.selectNode(id, isClick);
}
function removeNode(id: number) {
refMyTree.value?.removeNode(id);
}
function renameNode(id: number, name: string) {
refMyTree.value?.renameNode(id, name);
}
function getNodeById(id: number) {
return refMyTree.value?.getNodeById(id);
}
function addNote(pid: number, id: number, name: string, isParent?: boolean, children?: any[]) {
refMyTree.value?.addNote(pid, id, name, isParent, children);
}
function openTree(open: boolean) {
refMyTree.value?.openTree(open);
}
function searchByKeyword(keyword: string) {
searchKeyword.value = keyword;
onSearch();
}
function clearByKeyword() {
searchKeyword.value = '';
onClear();
}
loadTree()
defineExpose({
openSearch,
closeSearch,
onSearch,
onClear,
searchByKeyword,
clearByKeyword,
loadTree,
refreshTree,
reloadTree,
selectNode,
removeNode,
renameNode,
getNodeById,
addNote,
openTree,
})
</script>
<style lang="scss" scoped>
.group-tree-search-panel {
display: flex;
flex-direction: column;
height: 100%;
}
.search-bar {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 10px;
}
.search-input {
width: 100%;
}
.tree-body {
flex: 1;
min-height: 0;
}
.tree-body :deep(.ztree) {
height: 100%;
overflow-y: auto;
}
</style>
+178
View File
@@ -0,0 +1,178 @@
<template>
<div class="module-authz-tree">
<div v-for="node in visibleNodes" :key="node.id" class="tree-node"
:style="{ paddingLeft: `${(node.level || 1) * 18 - 18}px` }"
:class="{ 'is-leaf': !node.children?.length, 'is-expanded': node.expand !== false }">
<div class="node-main">
<span v-if="node.children?.length" class="expand-icon" @click.stop="toggleExpand(node)">
<Icon :type="node.expand === false ? 'ios-add' : 'ios-remove'" />
</span>
<span v-else class="expand-placeholder"></span>
<Checkbox :model-value="!!node.checked"
:disabled="loadingId === node.id && loadingType === 'check'"
@on-change="(checked: boolean) => onCheckChange(node, checked)">
<span class="node-name" :title="node.name">{{ node.name }}</span>
</Checkbox>
</div>
<div class="node-inherit">
<Checkbox :model-value="!!node.inheritFlag"
:disabled="!node.checked || (loadingId === node.id && loadingType === 'inherit')"
@on-change="(checked: boolean) => onInheritChange(node, checked)">
</Checkbox>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, reactive } from "vue";
export interface ModuleAuthzNode {
id: number;
name: string;
level?: number;
checked?: boolean;
inheritFlag?: boolean;
expand?: boolean;
children?: ModuleAuthzNode[];
}
const props = defineProps<{
nodes: ModuleAuthzNode[];
appId: number;
groupId: number;
loadingId?: number | null;
loadingType?: "check" | "inherit" | null;
}>();
const emit = defineEmits<{
(e: "module-change", payload: {
appId: number;
groupId: number;
moduleId: number;
checked: boolean;
inheritFlag: boolean;
type: "check" | "inherit";
}): void;
}>();
const expandMap = reactive<Record<number, boolean>>({});
function buildLocalNodes(nodes: ModuleAuthzNode[]): ModuleAuthzNode[] {
return (nodes || []).map((n) => ({
...n,
expand: expandMap[n.id] ?? true,
children: buildLocalNodes(n.children || []),
}));
}
const localNodes = computed<ModuleAuthzNode[]>(() => buildLocalNodes(props.nodes));
const visibleNodes = computed<ModuleAuthzNode[]>(() => {
const result: ModuleAuthzNode[] = [];
const walk = (list: ModuleAuthzNode[]) => {
for (const node of list) {
result.push(node);
if (node.children?.length && node.expand !== false) {
walk(node.children);
}
}
};
walk(localNodes.value);
return result;
});
function toggleExpand(node: ModuleAuthzNode) {
expandMap[node.id] = node.expand === false;
}
function onCheckChange(node: ModuleAuthzNode, checked: boolean) {
node.checked = checked;
if (!checked) {
node.inheritFlag = false;
}
emit("module-change", {
appId: props.appId,
groupId: props.groupId,
moduleId: node.id,
checked,
inheritFlag: !!node.inheritFlag,
type: "check",
});
}
function onInheritChange(node: ModuleAuthzNode, checked: boolean) {
node.inheritFlag = checked;
emit("module-change", {
appId: props.appId,
groupId: props.groupId,
moduleId: node.id,
checked: !!node.checked,
inheritFlag: checked,
type: "inherit",
});
}
</script>
<style lang="scss" scoped>
.module-authz-tree {
user-select: none;
}
.tree-node {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0;
min-height: 32px;
border-bottom: 1px dashed #f0f0f0;
&:last-child {
border-bottom: none;
}
&:hover {
background-color: #f7f7f7;
}
}
.node-main {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
gap: 4px;
}
.expand-icon {
width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #999;
font-size: 16px;
flex-shrink: 0;
&:hover {
color: #2d8cf0;
}
}
.expand-placeholder {
width: 18px;
flex-shrink: 0;
}
.node-name {
font-size: 13px;
color: #333;
}
.node-inherit {
width: 80px;
text-align: center;
flex-shrink: 0;
}
</style>
+76
View File
@@ -0,0 +1,76 @@
<template>
<Modal v-model="isModal" @on-visible-change="showChange" :title="title">
<Alert type="warning" class="mb-1" show-icon>
<template #icon>
<Icon type="ios-bulb-outline" :class="{ 'mt-5': !info }" slot="icon" :size="28"></Icon>
</template>
<div v-if="msg" :class="['message-box', info ? '' : 'mt-10 mb-10 ml-10']">{{ msg }}</div>
<template #desc v-if="info" slot="desc">{{ info }}</template>
</Alert>
<template #footer>
<Button type="primary" :loading="okLoading" @click="onOkClick">{{ confirmText }}</Button>
<Button :loading="cancleLoading" @click="onCancleClick">{{ closeText }}</Button>
</template>
</Modal>
</template>
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { Modal, Button, Alert, Icon } from "view-ui-plus";
const isModal = ref(false),
okLoading = ref(false),
cancleLoading = ref(false);
const props = withDefaults(
defineProps<{
title?: string;
msg: string;
info?: string;
isLoading?: boolean;
confirmText?: string;
closeText?: string;
confirmFn: any;
closeFn: any;
destroy: Function;
}>(),
{
title: "提示",
isLoading: true,
confirmText: "确认",
closeText: "取消",
}
);
onMounted(function () {
setTimeout(() => {
isModal.value = true;
}, 0);
});
const onOkClick = async () => {
if (!!props.isLoading) okLoading.value = true;
const { onOk, reslove } = props.confirmFn;
await Promise.resolve(onOk());
isModal.value = false;
okLoading.value = false;
reslove(true);
};
const onCancleClick = async () => {
if (!!props.isLoading) cancleLoading.value = true;
const { onCancel, reslove } = props.closeFn;
if (typeof onCancel !== "undefined") await Promise.resolve(onCancel());
cancleLoading.value = false;
isModal.value = false;
reslove(false);
};
const showChange = (state: boolean) => {
if (!state) {
props.destroy();
}
};
</script>
<style></style>
+42
View File
@@ -0,0 +1,42 @@
import { MyConfirm } from "@/types/Basics";
import confirm from "./Confirm.vue";
import { createApp } from "vue";
export default ({ title, msg, info, confirmText, closeText, isLoading, onOk, onCancel }: MyConfirm) => {
return new Promise<boolean>((reslove, reject) => {
const instance = createApp(confirm, {
title,
msg,
info,
confirmText,
closeText,
isLoading,
confirmFn: {
onOk,
reslove,
},
closeFn: {
onCancel,
reslove,
},
destroy: () => {
closeUnmount();
},
});
// 创建一个节点
const vnode = document.createElement("div");
// 添加到body元素上
document.body.appendChild(vnode);
// 实例挂载到节点上
instance.mount(vnode);
// 关闭状态
// 注册实例并移除节点
function closeUnmount() {
setTimeout(() => {
instance.unmount();
document.body.removeChild(vnode);
}, 100);
}
});
};
+214
View File
@@ -0,0 +1,214 @@
<template>
<div>
<div :id="domId" :ref="domId" class="ztree"></div>
</div>
</template>
<script>
export default {
props: {
treeData: {
type: Object,
},
setting: {
type: Object,
default: {},
},
autoClick: {
type: Boolean,
default: true,
},
isCheck: {
typeof: Boolean,
default: false,
},
},
data() {
return {
domId: "",
treeSetting: _.cloneDeep(this.setting),
treeObj: null,
highlightNodes: [],
};
},
created() {
this.$watch("treeData", val => {
if (val) {
this.$nextTick(() => {
this.initTree(this.treeData, this.domId);
});
}
});
},
mounted() {
this.domId = this.uuid();
if (this.treeData) {
this.$nextTick(() => {
this.initTree(this.treeData, this.domId);
});
}
},
methods: {
uuid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
},
reloadTree(nodeId) {
this.initTree(this.treeData, this.domId);
if (nodeId != null) {
this.$nextTick(() => {
this.selectNode(nodeId, true); // 第二个参数 true 会 emit on-tree-click
});
}
},
initTree(_data, _domId) {
const _this = this;
_this.treeSetting.callback.onClick = (event, treeId, treeNode, clickFlag) => {
// console.log(event, treeId, treeNode, clickFlag);
if (_this.isCheck) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
treeObj.checkNode(treeNode, !treeNode.checked, true);
}
_this.$emit("on-tree-click", treeNode);
};
_this.treeSetting.callback.beforeDrop = (treeId, treeNodes, targetNode, moveType) => {
if (moveType == "inner") {
// 移除限制,允许叶子节点接受子节点
} else {
if (targetNode.pid === 0) return false;
}
return true;
};
_this.treeSetting.callback.beforeDrag = (treeId, treeNodes) => {
return treeNodes[0].drag !== false;
};
_this.treeSetting.callback.beforeClick = (treeId, treeNode, clickFlag) => {
return !(treeNode.click === false);
};
_this.treeSetting.callback.onDrop = (event, treeId, treeNodes, targetNode, moveType) => {
_this.$emit("on-tree-drag", { treeNodes, targetNode, moveType });
};
_this.treeSetting.callback.onCheck = (event, treeId, treeNode) => {
_this.$emit("on-tree-check", treeNode);
};
_this.treeObj = $.fn.zTree.init($("#" + _domId), _this.treeSetting, _data);
if (_this.autoClick) {
if (Array.isArray(this.treeData)) {
let id = this.treeData[0].id;
_this.selectNode(id);
} else {
let id = this.treeData.id;
_this.selectNode(id);
}
}
},
selectNode(id, isClick = true) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
if (node == null) return false;
treeObj.selectNode(node);
treeObj.expandNode(node, true, false, false);
treeObj.selectNode(node);
if (isClick) this.$emit("on-tree-click", node);
},
openTree(open) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
treeObj.expandAll(open);
},
removeNode(id) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
var pnode = node.getParentNode();
treeObj.removeNode(node);
pnode.isParent = true;
treeObj.updateNode(pnode);
this.selectNode(pnode.id);
},
getNodeById(id) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
return node;
},
// 仅更新节点勾选状态,不级联、不触发 onCheck 回调
checkNodeById(id, checked) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
if (!treeObj) return;
var node = treeObj.getNodesByFilter(node => node.id == id, true);
if (node) treeObj.checkNode(node, !!checked, false);
},
renameNode(id, name) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
node.name = name;
treeObj.updateNode(node);
},
addNote(pid, id, name, isParent, children) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var pnode = treeObj.getNodesByFilter(node => node.id == pid, true);
var newNode = { pid, id, name, isParent };
if (children && children.length) newNode.children = children;
treeObj.addNodes(pnode, -1, newNode);
},
setHighlight(node, on = true) {
const a = $('#' + node.tId + '_a');
if (on) a.addClass('ztree-search-highlight');
else a.removeClass('ztree-search-highlight');
},
clearHighlight() {
(this.highlightNodes || []).forEach(n => this.setHighlight(n, false));
this.highlightNodes = [];
},
search(keyword) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
if (!treeObj) return;
this.clearHighlight();
const kw = (keyword || '').trim().toLowerCase();
if (!kw) return;
const matchNodes = treeObj.getNodesByFilter(
(node) => node.name && node.name.toLowerCase().includes(kw),
false
) || [];
if (!matchNodes.length) {
if (this.$Message && this.$Message.info) this.$Message.info('未搜索到匹配组');
return;
}
matchNodes.forEach(n => {
let p = n;
while (p) {
treeObj.expandNode(p, true, false, false);
p = p.getParentNode();
}
});
this.highlightNodes = matchNodes;
matchNodes.forEach(n => this.setHighlight(n, true));
this.selectNode(matchNodes[0].id, true);
},
},
};
</script>
<style>
.ztree-search-highlight {
background-color: #ff6600 !important;
}
.ztree li a.curSelectedNode {
background-color: #ffe4bb !important;
}
</style>
+234
View File
@@ -0,0 +1,234 @@
<template>
<div style="height: 100%;">
<div class="tree-search-bar">
<Input v-model="keyword" placeholder="输入学校,回车查找" suffix="ios-search" clearable @on-enter="onSearch"
@on-clear="onSearch" style="width:100%;margin-bottom: 10px;" />
</div>
<div :id="domId" :ref="domId" class="ztree"></div>
</div>
</template>
<script>
export default {
props: {
treeData: {
type: Object,
},
setting: {
type: Object,
default: {
view: {
dblClickExpand: false,
showIcon: false,
},
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: false,
},
check: {
enable: false,
},
callback: {},
},
},
autoClick: {
type: Boolean,
default: true,
},
isCheck: {
typeof: Boolean,
default: false,
},
},
data() {
return {
domId: "",
treeSetting: _.cloneDeep(this.setting),
treeObj: null,
keyword: '',
highlightNodes: []
};
},
created() {
this.$watch("treeData", val => {
console.log(val);
if (val) {
console.log(val);
this.$nextTick(() => {
this.initTree(this.treeData, this.domId);
});
}
});
},
mounted() {
this.domId = this.uuid();
},
methods: {
uuid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
},
reloadTree() {
this.treeData.open = true;
this.initTree(this.treeData, this.domId);
},
initTree(_data, _domId) {
const _this = this;
_this.treeSetting.callback.onClick = (event, treeId, treeNode, clickFlag) => {
// console.log(event, treeId, treeNode, clickFlag);
if (_this.isCheck) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
treeObj.checkNode(treeNode, !treeNode.checked, true);
}
_this.$emit("on-tree-click", treeNode);
};
_this.treeSetting.callback.beforeDrop = (treeId, treeNodes, targetNode, moveType) => {
if (moveType == "inner") {
if (!targetNode.isParent) return false;
} else {
if (targetNode.pid === 0) return false;
}
};
_this.treeSetting.callback.beforeClick = (treeId, treeNode, clickFlag) => {
return !(treeNode.click === false);
};
_this.treeSetting.callback.onDrop = (event, treeId, treeNodes, targetNode, moveType) => {
_this.$emit("on-tree-drag", { treeNodes, targetNode, moveType });
};
_this.treeSetting.callback.onCheck = (event, treeId, treeNode) => {
_this.$emit("on-tree-check", treeNode);
};
_this.treeObj = $.fn.zTree.init($("#" + _domId), _this.treeSetting, _data);
if (_this.autoClick) {
if (Array.isArray(this.treeData)) {
let id = this.treeData[0].id;
_this.selectNode(id);
} else {
let id = this.treeData.id;
_this.selectNode(id);
}
}
},
selectNode(id, isClick = true) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
if (node == null) return false;
treeObj.selectNode(node);
treeObj.expandNode(node, true, false, false);
treeObj.selectNode(node);
if (isClick) this.$emit("on-tree-click", node);
},
openTree(open) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
treeObj.expandAll(open);
},
removeNode(id) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
var pnode = node.getParentNode();
treeObj.removeNode(node);
pnode.isParent = true;
treeObj.updateNode(pnode);
this.selectNode(pnode.id);
},
getNodeById(id) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
return node;
},
renameNode(id, name) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var node = treeObj.getNodesByFilter(node => node.id == id, true);
node.name = name;
treeObj.updateNode(node);
},
addNote(pid, id, name, isParent) {
const _domId = this.domId;
var treeObj = $.fn.zTree.getZTreeObj(_domId);
var pnode = treeObj.getNodesByFilter(node => node.id == pid, true);
var newNode = { pid, id, name, isParent };
treeObj.addNodes(pnode, -1, newNode);
},
onSearch() {
this.clearHighlight();
if (!this.keyword) return;
this.doSearch(this.keyword);
},
doSearch(key) {
const treeObj = this.treeObj;
// 1. 模糊匹配
const matchNodes = treeObj.getNodesByFilter(node =>
node.type == 2 &&
node.name && node.name.toLowerCase().includes(key.toLowerCase())
);
if (!matchNodes.length) {
this.$Message.info('未搜索到匹配学校')
return;
}
// 2. 展开所有命中节点的父节点
matchNodes.forEach(n => {
let p = n.getParentNode();
while (p) {
treeObj.expandNode(p, true, false, false);
p = p.getParentNode();
}
});
// 3. 高亮
this.highlightNodes = matchNodes;
matchNodes.forEach(n => this.setHighlight(n, true));
// const box = document.getElementById('treeBox');
// const nodeEl = document.getElementById(matchNodes[0].tId);
// box.scrollTop = nodeEl.offsetTop - box.clientHeight / 2; // 居中
if (matchNodes.length) {
const treeObj = this.treeObj;
console.log(matchNodes[0]);
this.selectNode(matchNodes[0].id);
// treeObj.selectNode(matchNodes[0]); // 先选中,会自动滚入可视区
//this.$nextTick(() => treeObj.cancelSelectedNode()); // 取消选中,保持纯高亮
}
},
setHighlight(node, on = true) {
const a = $('#' + node.tId + '_a');
if (on) a.addClass('ztree-search-highlight');
else a.removeClass('ztree-search-highlight');
},
clearHighlight() {
this.highlightNodes.forEach(n => this.setHighlight(n, false));
this.highlightNodes = [];
}
},
};
</script>
<style>
.ztree {
height: calc(100% - 60px);
overflow-y: auto;
}
.ztree-search-highlight {
background-color: #ff6600 !important;
}
.ztree li a.curSelectedNode {
background-color: #ffe4bb !important;
}
</style>
+43
View File
@@ -0,0 +1,43 @@
<script setup lang="ts">
import { ref, computed, withDefaults } from "vue";
interface Props {
prefix?: string;
name?: string;
color?: string;
hoverColor?: string;
size?: string | number;
}
const props = withDefaults(defineProps<Props>(), {
prefix: "icon",
name: "",
color: "#000",
});
const isHover = ref(false);
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
const svgStyle = computed(() => {
if (!!props.size) return { width: props.size + "px", height: props.size + "px" };
else return null;
});
const compColor = computed(() => {
if (!props.hoverColor) return props.color;
else {
return !!isHover.value ? props.hoverColor : props.color;
}
});
</script>
<template>
<svg
@mouseover="isHover = true"
@mouseout="isHover = false"
aria-hidden="true"
:color="compColor"
:style="svgStyle"
>
<use :xlink:href="symbolId" :fill="compColor" :color="compColor" />
</svg>
</template>

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