首次提交

This commit is contained in:
李玉东 2025-08-07 16:39:28 +08:00
commit f8e1984f71
943 changed files with 347395 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

10
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# 依赖于环境的 Maven 主目录路径
/mavenHomeManager.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

18
.idea/checkstyle-idea.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.26.1</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds">
<option value="bundled-google-checks" />
</option>
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
</list>
</option>
</component>
</project>

View File

@ -0,0 +1,6 @@
This folder contains libraries copied from the "manager" project.
It is managed by the CheckStyle-IDEA IDE plugin.
Do not modify this folder while the IDE is running.
When the IDE is stopped, you may delete this folder at any time. It will be recreated as needed.
In order to prevent the CheckStyle-IDEA IDE plugin from creating this folder,
uncheck the "Copy libraries from project directory" option in the CheckStyle-IDEA settings dialog.

18
.idea/dataSources.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="manager@localhost" uuid="24e4b660-81e9-408e-afd2-0defda7cb4c9">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306/manager</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

15
.idea/encodings.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/manager-admin/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-admin/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-common/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-common/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-system/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-system/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-z-generation/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/manager-z-generation/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

18
.idea/misc.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ASMIdeaPluginConfiguration">
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

35
manager-admin/pom.xml Normal file
View File

@ -0,0 +1,35 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hshh</groupId>
<artifactId>manager</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>manager-admin</artifactId>
<packaging>jar</packaging>
<name>manager-admin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.hshh</groupId>
<artifactId>manager-system</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,274 @@
<!-- Page body -->
<style>
#tree-container {
width: 100%;
height: 600px;
overflow: auto;
background: #fff;
border-radius: .5rem;
box-shadow: 0 1px 3px rgba(0,0,0,.08);
padding: 1rem;
position: relative;
}
.node-rect {
fill: #fff;
stroke: #206bc4;
stroke-width: 2px;
rx: 8;
ry: 8;
filter: drop-shadow(0px 2px 6px #206bc420);
}
.node-text {
font-size: 15px;
fill: #206bc4;
text-anchor: middle;
font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
dominant-baseline: middle;
pointer-events: none;
}
.link {
fill: none;
stroke: #b7c4d2;
stroke-width: 2px;
}
@media (max-width: 600px) {
#tree-container {
height: 400px;
padding: .5rem;
}
}
.center-btn {
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%, -50%);
}
.context-menu {
position: absolute;
z-index: 9999;
min-width: 140px;
background: #fff;
border-radius: 6px;
box-shadow: 0 4px 18px rgba(60,72,88,0.12);
border: 1px solid #e9ecef;
font-size: 15px;
padding: 4px 0;
display: none;
}
.context-menu-item {
cursor: pointer;
padding: 8px 18px;
transition: background 0.18s;
color: #206bc4;
border: none;
background: none;
text-align: left;
width: 100%;
outline: none;
}
.context-menu-item:hover {
background: #f1f7fe;
color: #206bc4;
}
</style>
<link href="https://unpkg.com/@tabler/core@1.0.0-beta24/dist/css/tabler.min.css" rel="stylesheet">
<script src="https://d3js.org/d3.v7.min.js"></script>
<div class="page-body">
<div class="container-xl">
<!-- 面包屑导航 -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="#">指标管理</a>
</li>
</ol>
</nav>
<div class="row g-4 mb-4">
<div class="col-md-12" id="tree-container"></div>
</div>
</div>
</div>
<!-- 右键菜单 -->
<div id="context-menu" class="context-menu"></div>
<script>
let treeData = null;
/**
* 右键菜单渲染
*/
function showContextMenu(x, y, nodeData) {
// 定义菜单项
const menuItems = [
{ text: "添加子节点", action: "add" },
{ text: "编辑", action: "edit" },
{ text: "删除", action: "delete" }
];
const menu = document.getElementById("context-menu");
menu.innerHTML = "";
menuItems.forEach(item => {
const btn = document.createElement("button");
btn.className = "context-menu-item";
btn.textContent = item.text;
btn.onclick = function(e) {
e.stopPropagation();
menu.style.display = "none";
handleMenuAction(item.action, nodeData);
};
menu.appendChild(btn);
});
// 适应视窗,避免溢出
const winW = window.innerWidth, winH = window.innerHeight;
menu.style.left = (x + 150 > winW ? winW - 160 : x) + "px";
menu.style.top = (y + 120 > winH ? winH - 130 : y) + "px";
menu.style.display = "block";
}
function hideContextMenu() {
document.getElementById("context-menu").style.display = "none";
}
// 右键菜单回调
function handleMenuAction(action, nodeData) {
if (action === "add") {
// 简单示例: 添加子节点
if (!nodeData.children) nodeData.children = [];
const n = (nodeData.children.length || 0) + 1;
nodeData.children.push({ name: `新节点${n}`, weight: "0%" });
renderTree();
} else if (action === "edit") {
// 弹窗简单编辑
const newName = prompt("请输入节点名称:", nodeData.name);
if (newName && newName.trim()) {
nodeData.name = newName.trim();
renderTree();
}
} else if (action === "delete") {
// 删除节点(防止删根)
if (!nodeData.parent) {
alert("根节点不能删除!");
return;
}
const children = nodeData.parent.children;
const idx = children.indexOf(nodeData);
if (idx >= 0) {
children.splice(idx, 1);
renderTree();
}
}
}
// D3渲染
function renderTree() {
const container = d3.select("#tree-container");
container.selectAll("*").remove();
hideContextMenu();
if (!treeData) {
container.append("button")
.attr("type", "button")
.attr("class", "btn btn-primary center-btn")
.text("添加根节点")
.on("click", function() {
treeData = {
name: "根节点",
weight: "100%",
children: []
};
renderTree();
});
return;
}
const width = Math.max(600, window.innerWidth * 0.9);
const height = Math.max(400, window.innerHeight * 0.65);
const svg = container.append("svg")
.attr("width", "100%")
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);
// d3.hierarchy
const root = d3.hierarchy(treeData);
root.each(d => d.id = Math.random().toString(36).slice(2)); // 给每个节点一个唯一id
// 需要保留parent引用以便删除
function setParent(d, parent) {
d.parent = parent;
if (d.children) d.children.forEach(c => setParent(c, d));
}
setParent(treeData, null);
const treeLayout = d3.tree()
.size([width - 80, height - 100])
.separation((a, b) => a.parent === b.parent ? 1.2 : 1.8);
treeLayout(root);
// 连线
svg.append("g")
.selectAll("path")
.data(root.links())
.join("path")
.attr("class", "link")
.attr("d", d3.linkVertical()
.x(d => d.x + 40)
.y(d => d.y)
);
// 节点
const node = svg.append("g")
.selectAll("g")
.data(root.descendants())
.join("g")
.attr("transform", d => `translate(${d.x},${d.y})`);
const rectW = 80, rectH = 40;
// 方框
node.append("rect")
.attr("class", "node-rect")
.attr("width", rectW)
.attr("height", rectH)
.attr("x", 0)
.attr("y", 0)
.on("contextmenu", (event, d) => {
event.preventDefault();
showContextMenu(event.clientX, event.clientY, d.data);
});
// 名称
node.append("text")
.attr("class", "node-text")
.attr("x", rectW / 2)
.attr("y", rectH / 2 - 6)
.text(d => d.data.name);
// 权重
node.append("text")
.attr("class", "node-text")
.attr("x", rectW / 2)
.attr("y", rectH / 2 + 12)
.attr("font-size", "12px")
.attr("fill", "#425466")
.text(d => d.data.weight ? d.data.weight : "");
// 高亮交互
node.style("cursor", "pointer")
.on("mouseover", function() {
d3.select(this).select("rect").attr("stroke", "#2fb344").attr("stroke-width", 3);
})
.on("mouseout", function() {
d3.select(this).select("rect").attr("stroke", "#206bc4").attr("stroke-width", 2);
});
}
// 点击其它地方关闭菜单
</script>

View File

@ -0,0 +1,27 @@
package com.hshh;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Application.
*
* @author LiDongYU
* @since 2025/7/16
*/
@SpringBootApplication
@MapperScan({"com.hshh.system.**.mapper", "com.hshh.model.**.mapper",
"com.hshh.indicator.**.mapper"})
public class Application {
/**
* 入口启动函数.
*
* @param args 入口参数.
*/
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,218 @@
package com.hshh.data.controller;
import com.hshh.data.service.DataRecordService;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.FormValue;
import com.hshh.model.entity.ModelDefine;
import com.hshh.model.service.FormFieldConfigService;
import com.hshh.model.service.FormValueService;
import com.hshh.model.service.ModelDefineService;
import com.hshh.system.common.bean.BaseController;
import com.hshh.system.common.bean.ErrorField;
import com.hshh.system.common.bean.OperateResult;
import com.hshh.system.common.bean.PaginationBean;
import com.hshh.system.common.enums.ErrorCode;
import com.hshh.system.common.enums.ErrorMessage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 数据管理控制器.
*
* @author LiDongYU
* @since 2025/7/22
*/
@Controller
@RequestMapping("/data")
@Tag(name = "数据管理接口", description = "系统中数据列表;新增数据记录、编辑数据记录、删除数据记录")
public class DataController extends BaseController {
@Resource
private ModelDefineService modelDefineService;
/**
* 模型字段配置对象服务类.
*/
@Resource
private FormFieldConfigService formFieldConfigService;
/**
* 数据查询服务类.
*/
@Resource
private FormValueService formValueService;
/**
* 记录(record)服务类.
*/
@Resource
private DataRecordService dataRecordService;
/**
* 默认排序最大 999
*/
private final int maxOrder = 999;
/**
* 导航到数据管理主界面.
*
* @param model session容器
* @return /data/list.html
*/
@GetMapping("/list")
@Operation(summary = "导航到数据管理页面", description = "导航到数据管理页面")
public String index(PaginationBean request, Model model) {
List<ModelDefine> modelDefineList = modelDefineService.list(); //查询所有数据模型列表
modelDefineList.sort(Comparator.comparing(ModelDefine::getSortOrder)); //对模型数据列表排序
setCurrentActiveModelDefine(model, request, modelDefineList); //设置当前选中的数据模型;
model.addAttribute("modelDefineList", modelDefineList); //设置到session中
if (!modelDefineList.isEmpty()) {
List<FormFieldConfig> formConfigList = formFieldConfigService.getFormFieldConfigByModelId(
modelDefineList.get(0).getId()); //查询模型表头
sortFieldList(formConfigList); //排序
Map<String, String> headerMap = new LinkedHashMap<>(); //定义表头兑现
formConfigList.forEach(formFieldConfig -> {
headerMap.put(formFieldConfig.getFieldName(), formFieldConfig.getFieldLabel());
});
model.addAttribute("headerMap", headerMap);
//查询模型数据
List<FormValue> formDataList = formValueService.list(request);
List<Map<String, Object>> listMap = new ArrayList<>();
formDataList.forEach(formData -> {
listMap.add(formData.toMap()); //转为map对象放入listMap中
});
Long total = formValueService.count(request);
setPaginationInfo(request, listMap, total, model);
}
return "data/list";
}
/**
* 设置页面中那个数据模型tab被激活.
*
* @param model session容器
* @param request 请求参数
* @param modelDefineList 系统中数据模型列表
*/
private void setCurrentActiveModelDefine(Model model, PaginationBean request,
List<ModelDefine> modelDefineList) {
AtomicReference<ModelDefine> activeModelDefine = new AtomicReference<>(); //当前激活的数据模型tab页
modelDefineList.forEach(a -> {
if (request.getId() != null && request.getId().equals(a.getId())) {
a.setChecked(true);
activeModelDefine.set(a);
}
if (a.getSortOrder() == null) {
a.setSortOrder(maxOrder);
}
});
if (activeModelDefine.get() != null) {
model.addAttribute("currentModelDefine", activeModelDefine.get());
} else {
//设置默认第一个选中
modelDefineList.get(0).setChecked(true);
//设置查询参数为第一个
request.setId(modelDefineList.get(0).getId());
model.addAttribute("currentModelDefine", modelDefineList.get(0));
}
}
private void sortFieldList(List<FormFieldConfig> formConfigList) {
//如果sortOrder==null修改为999在排序
formConfigList.forEach(a -> {
if (a.getSortOrder() == null) {
a.setSortOrder(maxOrder);
}
});
formConfigList.sort(Comparator.comparingInt(FormFieldConfig::getSortOrder));
}
/**
* 根据模型ID获取form窗体.
*
* @param id 模型id
* @return form表单内容 div...
*/
@GetMapping("/getForm/{id}")
@Operation(summary = "获取form输入窗体", description = "根据模型ID获取form窗体")
@ResponseBody
public OperateResult<String> getForm(@PathVariable("id") Integer id) {
return OperateResult.success(dataRecordService.html(id), ErrorMessage.SUCCESS.getMessage());
}
/**
* 保存表单数据.
*
* @param formValue 表单值
* @return 操作结果
*/
@PostMapping("/form/save")
@ResponseBody
@Operation(summary = "保存记录", description = "保存对应模型ID对应的form表单记录")
public OperateResult<Void> saveRecord(@RequestBody FormValue formValue) {
//验证字段合法性
Integer modelId = formValue.getModelDefineId();
List<FormFieldConfig> fieldList = formFieldConfigService.getFormFieldConfigByModelId(modelId);
List<ErrorField> errors = dataRecordService.getErrorField(fieldList, formValue);
if (!errors.isEmpty()) {
return OperateResult.error(null, ErrorMessage.IllegalArgumentException.getMessage(),
ErrorCode.PARAM_FORMAT.getCode(), errors);
}
formValueService.saveOrUpdate(formValue);
return OperateResult.success();
}
/**
* 删除记录.
*
* @param id 记录ID
* @return 操作结果
*/
@ResponseBody
@GetMapping("/remove/{id}")
@Operation(summary = "删除记录", description = "根据ID删除记录")
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
formValueService.removeById(id);
return OperateResult.success();
}
/**
* 根据ID查看记录.
*
* @param id 记录ID
* @return 包含记录的操作结果
*/
@ResponseBody
@GetMapping("/{id}")
@Operation(summary = "删除记录", description = "根据ID删除记录")
public OperateResult<FormValue> view(@PathVariable("id") Integer id) {
FormValue formValue = formValueService.getById(id);
if (formValue == null) {
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
return OperateResult.success(formValue, ErrorMessage.SUCCESS.getMessage());
}
}

View File

@ -0,0 +1,31 @@
package com.hshh.data.service;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.FormValue;
import com.hshh.system.common.bean.ErrorField;
import java.util.List;
/**
* 数据模块服务类.
*
* @author LiDongYU
* @since 2025/7/22
*/
public interface DataRecordService {
/**
* 生成前端html页面.
*
* @param modelId 模块id
* @return <html...></html...>
*/
String html(Integer modelId);
/**
* 验证输入json字段是否符合预期.
* @param formConfigList 字段列表
* @param formValue 传入的值
* @return 错误信息
*/
List<ErrorField> getErrorField(List<FormFieldConfig> formConfigList, FormValue formValue);
}

View File

@ -0,0 +1,137 @@
package com.hshh.data.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.hshh.data.service.DataRecordService;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.FormValue;
import com.hshh.model.entity.ModelDefine;
import com.hshh.model.service.FormFieldConfigService;
import com.hshh.model.service.ModelDefineService;
import com.hshh.system.common.bean.ErrorField;
import com.hshh.system.common.bean.FieldType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* 数据管理实现类.
*
* @author LiDongYU
* @since 2025/7/22
*/
@Service
public class DataRecordServiceImpl implements DataRecordService {
/**
* 模型定义服务类.
*/
@Resource
private ModelDefineService modelDefineService;
/**
* 模型动态表单表 服务实现类.
*/
@Resource
private FormFieldConfigService formFieldConfigService;
//最大排序号
private static final int maxOrder = 999;
@Override
public String html(Integer modelId) {
//首先获取模型定义中,form中的字段显示方式,每行显示几个字段
ModelDefine modelDefine = modelDefineService.getById(modelId);
if (modelDefine == null) {
return "";
}
List<FormFieldConfig> fieldList = formFieldConfigService.getFormFieldConfigByModelId(
modelId);
fieldList.sort((a, b) -> {
if (a.getSortOrder() == null) {
a.setSortOrder(maxOrder);
}
if (b.getSortOrder() == null) {
b.setSortOrder(maxOrder);
}
return a.getSortOrder().compareTo(b.getSortOrder());
});
int rowPerCount = modelDefine.getFieldsPerRow() == null ? 1 : modelDefine.getFieldsPerRow();
int columns = 12 / rowPerCount;
String divClass = "col-12 col-md-" + columns;
StringBuffer sb = new StringBuffer();
sb.append("<div class=\"row\">");
fieldList.forEach(field -> {
handleField(field, sb, divClass);
});
sb.append("</div>");
return sb.toString();
}
/**
* 处理每个字段.
*
* @param field 字段
* @param sb html字符容器
* @param divClass 每个字段占用的格数 ,在不同的屏幕下
*/
private void handleField(FormFieldConfig field, StringBuffer sb, String divClass) {
String unit = "";
if (StringUtils.isNotBlank(field.getFieldUnit())) {
unit = "(" + field.getFieldUnit() + ")";
}
String required =
(field.getIsRequired() != null && field.getIsRequired() == 1) ? "required" : "";
sb.append("<div class=\"").append(divClass).append("\">");
sb.append("<div class=\"mb-3\">");
//增加标签
sb.append("<label class=\"form-label ").append(required).append("\">")
.append(field.getFieldLabel()).append(unit).append("</label>");
//输入域增加
handleInputType(field, sb);
//验证div
sb.append("<div class=\"invalid-feedback\" id=\"").append(field.getFieldId())
.append("_error_tip\"></div>");
//mb-3 闭合
sb.append("</div>");
//第一个div闭合
sb.append("</div>");
}
private void handleInputType(FormFieldConfig field, StringBuffer sb) {
if (field.getFieldType() == null) {
field.setFieldType("TEXT");
}
FieldType fieldType = FieldType.valueOf(field.getFieldType());
switch (fieldType) {
case TEXT:
sb.append("<input type=\"text\" name=\"").append(field.getFieldName()).append("\" id=\"")
.append(field.getFieldId())
.append("\" class=\"form-control\" autocomplete=\"off\" >");
break;
case NUMBER:
sb.append("<input type=\"number\" name=\"").append(field.getFieldName()).append("\" id=\"")
.append(field.getFieldId())
.append("\" class=\"form-control\" autocomplete=\"off\" >");
break;
default:
break;
}
}
@Override
public List<ErrorField> getErrorField(List<FormFieldConfig> formConfigList, FormValue formValue) {
List<ErrorField> errorFieldList = new ArrayList<>();
JSONObject json = JSON.parseObject(formValue.getModelData());
formConfigList.forEach(config -> {
Object valObject = json.getObject(config.getFieldName(), Object.class);
config.setValue(valObject);
Optional<ErrorField> error = config.validate();
error.ifPresent(errorFieldList::add);
});
return errorFieldList;
}
}

View File

@ -0,0 +1,242 @@
package com.hshh.indicator.controller;
import com.hshh.indicator.entity.Indicator;
import com.hshh.indicator.entity.IndicatorEvalItem;
import com.hshh.indicator.service.IndicatorEvalItemService;
import com.hshh.indicator.service.IndicatorService;
import com.hshh.model.entity.ModelDefine;
import com.hshh.model.service.ModelDefineService;
import com.hshh.system.common.bean.BaseController;
import com.hshh.system.common.bean.OperateResult;
import com.hshh.system.common.enums.ErrorCode;
import com.hshh.system.common.enums.ErrorMessage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 指标接口服务接口.
*
* @author LiDongYU
* @since 2025/7/22
*/
@Controller
@RequestMapping("/indicator")
@Tag(name = "指标管理接口", description = "指标树/保存指标/编辑指标/删除指标")
public class IndicatorController extends BaseController {
/**
* 指标服务类.
*/
@Resource
private IndicatorService indicatorService;
/**
* 模型定义服务类.
*/
@Resource
private ModelDefineService modelDefineService;
/**
* 评价集服务类.
*/
@Resource
private IndicatorEvalItemService indicatorEvalItemService;
/**
* 导航到列表页面. 获取所有的root指标显示到页面左侧.
*
* @param model session容器
* @param indicator 指标请求对象
* @return /indicator/list.html
*/
@RequestMapping("/list")
public String list(Model model, Indicator indicator) {
List<Indicator> rootList = indicatorService.queryRootList();
if (rootList != null && !rootList.isEmpty()) {
if (indicator.getId() != null) {
rootList.forEach(root -> {
if (root.getId().equals(indicator.getId())) {
root.setChecked(true);
}
});
} else {
rootList.get(0).setChecked(true);
}
}
model.addAttribute("rootList", rootList);
return "/indicator/list";
}
/**
* 导航到指标增加页面.
*
* @return /indicator/add_indicator.html
*/
@RequestMapping("/indicatorAdd")
@Operation(summary = "导航到指标管理页面", description = "导航到指标管理页面")
public String indicatorAdd(Boolean rootFlag, Model model) {
//根节点的增加/编辑
if (rootFlag) {
List<ModelDefine> modelDefineList = modelDefineService.list();
model.addAttribute("modelDefineList", modelDefineList);
}
return "/indicator/add_indicator";
}
/**
* 查看节点信息包含子节点.
*
* @param id 节点ID
* @return 节点对象
*/
@ResponseBody
@GetMapping("/{id}")
public OperateResult<Object> view(@PathVariable("id") Integer id) {
Indicator indicator = indicatorService.getIndicator(id);
if (indicator == null) {
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
return OperateResult.success(indicator, ErrorMessage.SUCCESS.getMessage());
}
/**
* 保存指标.
*
* @param indicator 指标对象
* @param bindingResult 字段验证信息
* @return 保存结果
*/
@PostMapping("/save")
@ResponseBody
@Operation(summary = "保存指标", description = "验证后保存指标")
public OperateResult<Object> save(@Valid @RequestBody Indicator indicator,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return errorsInputHandle(bindingResult);
}
//查看名称或者编码是否重复
List<Indicator> exitList = indicatorService.queryList(indicator.getTopId(), indicator.getName(),
indicator.getCode());
if (indicator.getId() == null) {
if (!exitList.isEmpty()) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
indicatorService.save(indicator);
} else { //编辑
if (!exitList.isEmpty()) {
if (!exitList.get(0).getId().equals(indicator.getId())) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
indicatorService.updateById(indicator);
}
}
return OperateResult.success(indicator, ErrorMessage.SUCCESS.getMessage());
}
/**
* 删除指定指标.
*
* @param id 指标ID
* @return 操作结果
*/
@GetMapping("/remove/{id}")
@ResponseBody
@Operation(summary = "删除指标", description = "根据ID删除指定指标")
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
if (id == null) {
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
//查询此ID下是否有子指标
List<Indicator> children = indicatorService.queryChildren(id);
if (children != null && !children.isEmpty()) {
return OperateResult.error(null, ErrorMessage.OBJ_HAS_SUB.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
indicatorService.removeById(id);
return OperateResult.success();
}
/**
* 导航到评价集设置页面.
*
* @return indicator/evaluation_list.html
*/
@GetMapping("/evaluationList")
public String evaluationList(Integer topIndicatorId, Integer indicatorId, Model model) {
List<Indicator> rootList = indicatorService.queryRootList();
if (rootList != null && !rootList.isEmpty()) {
if (topIndicatorId != null) {
for (Indicator indicator : rootList) {
if (indicator.getId().equals(topIndicatorId)) {
indicator.setChecked(true);
}
}
} else {
topIndicatorId = rootList.get(0).getId();
rootList.get(0).setChecked(true);
}
}
//查询所有没有孩子的子节点
List<Indicator> indicatorListWithoutChildren = indicatorService.selectNoChildByTopId(
topIndicatorId);
if (!indicatorListWithoutChildren.isEmpty()) {
if (indicatorId != null) {
for (Indicator indicator : indicatorListWithoutChildren) {
if (indicator.getId().equals(indicatorId)) {
indicator.setChecked(true);
}
}
} else {
indicatorListWithoutChildren.get(0).setChecked(true);
}
}
model.addAttribute("rootList", rootList);
model.addAttribute("indicatorListWithoutChildren", indicatorListWithoutChildren);
return "indicator/evaluation_list";
}
/**
* 导航到评价集增加页面.
*
* @return indicator/add_evaluation.html
*/
@RequestMapping("/evaluationAdd")
@Operation(summary = "导航到评价集增加页面", description = "导航到评价集增加页面")
public String evaluationAdd() {
return "indicator/add_evaluation";
}
/**
* 保存评价集.
*
* @param item
* @param bindingResult
* @return
*/
// @PostMapping("/evalItem/save")
// @ResponseBody
// public OperateResult<IndicatorEvalItem> saveEval(@Valid @RequestBody IndicatorEvalItem item,
// BindingResult bindingResult) {
//
// }
}

View File

@ -0,0 +1,18 @@
package com.hshh.indicator.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
/**
* <p>
* 指标规则表 前端控制器
* </p>
*
* @author liDongYu
* @since 2025-08-04
*/
@Controller
@RequestMapping("/indicator/indicatorEvalItem")
public class IndicatorEvalItemController {
}

View File

@ -0,0 +1,47 @@
package com.hshh.indicator.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Data;
/**
* <p>
* 指标表
* </p>
*
* @author liDongYu
* @since 2025-08-04
*/
@TableName("m_data_indicator")
@Data
public class Indicator implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer parentId;
@NotBlank(message = "编码不能为空")
@Size(max = 30, message = "编码不能超过30字符")
private String code;
@NotBlank(message = "名称不能为空")
@Size(max = 30, message = "名称不能超过30字符")
private String name;
@TableField(exist = false)
private List<Indicator> children;
private Integer topId; //顶级父ID
private Integer sortOrder;
@TableField(exist = false)
private boolean checked;
private Integer modelId;
}

View File

@ -0,0 +1,141 @@
package com.hshh.indicator.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* <p>
* 指标规则表
* </p>
*
* @author liDongYu
* @since 2025-08-04
*/
@TableName("m_data_indicator_eval_item")
public class IndicatorEvalItem implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer indicatorTopId;
private Integer indicatorId;
private Integer sortOrder;
@NotNull(message = "名称不能为空")
@Size(max = 50, message = "名称不能超过50字符")
private String evaluationName;
@NotNull(message = "符号不能为空")
@Size(max = 5, message = "名称不能超过5字符")
private String minSymbol;
@NotNull(message = "值不能为空")
@Size(max = 10, message = "值不能超过10字符")
private String minValue;
@NotNull(message = "符号不能为空")
@Size(max = 5, message = "名称不能超过5字符")
private String maxSymbol;
@NotNull(message = "值不能为空")
@Size(max = 10, message = "值不能超过10字符")
private String maxValue;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getIndicatorTopId() {
return indicatorTopId;
}
public void setIndicatorTopId(Integer indicatorTopId) {
this.indicatorTopId = indicatorTopId;
}
public Integer getIndicatorId() {
return indicatorId;
}
public void setIndicatorId(Integer indicatorId) {
this.indicatorId = indicatorId;
}
public Integer getSortOrder() {
return sortOrder;
}
public void setSortOrder(Integer sortOrder) {
this.sortOrder = sortOrder;
}
public String getEvaluationName() {
return evaluationName;
}
public void setEvaluationName(String evaluationName) {
this.evaluationName = evaluationName;
}
public String getMinSymbol() {
return minSymbol;
}
public void setMinSymbol(String minSymbol) {
this.minSymbol = minSymbol;
}
public String getMinValue() {
return minValue;
}
public void setMinValue(String minValue) {
this.minValue = minValue;
}
public String getMaxSymbol() {
return maxSymbol;
}
public void setMaxSymbol(String maxSymbol) {
this.maxSymbol = maxSymbol;
}
public String getMaxValue() {
return maxValue;
}
public void setMaxValue(String maxValue) {
this.maxValue = maxValue;
}
@Override
public String toString() {
return "IndicatorEvalItem{" +
"id = " + id +
", indicatorTopId = " + indicatorTopId +
", indicatorId = " + indicatorId +
", sortOrder = " + sortOrder +
", evaluationName = " + evaluationName +
", minSymbol = " + minSymbol +
", minValue = " + minValue +
", maxSymbol = " + maxSymbol +
", maxValue = " + maxValue +
"}";
}
}

View File

@ -0,0 +1,16 @@
package com.hshh.indicator.mapper;
import com.hshh.indicator.entity.IndicatorEvalItem;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 指标规则表 Mapper 接口
* </p>
*
* @author liDongYu
* @since 2025-08-04
*/
public interface IndicatorEvalItemMapper extends BaseMapper<IndicatorEvalItem> {
}

View File

@ -0,0 +1,23 @@
package com.hshh.indicator.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hshh.indicator.entity.Indicator;
import java.util.List;
import org.apache.ibatis.annotations.Param;
/**
* 指标表 Mapper 接口.
*
* @author liDongYu
* @since 2025-08-04
*/
public interface IndicatorMapper extends BaseMapper<Indicator> {
/**
* 查询没有子节点的指标.
*
* @param topId 祖先指标ID
* @return 指标集
*/
public List<Indicator> selectNoChildByTopId(@Param("topId") Integer topId);
}

View File

@ -0,0 +1,23 @@
package com.hshh.indicator.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hshh.indicator.entity.IndicatorEvalItem;
import java.util.List;
/**
* 指标规则表 服务类.
*
* @author liDongYu
* @since 2025-08-04
*/
public interface IndicatorEvalItemService extends IService<IndicatorEvalItem> {
/**
* 根据指标ID和名称查询记录.
*
* @param indicatorId 指标ID
* @param name 名称
* @return 记录
*/
List<IndicatorEvalItem> queryListByNameAndIndicatorId(Integer indicatorId, String name);
}

View File

@ -0,0 +1,56 @@
package com.hshh.indicator.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hshh.indicator.entity.Indicator;
import java.util.List;
/**
* 指标表 服务类.
*
* @author liDongYu
* @since 2025-08-04
*/
public interface IndicatorService extends IService<Indicator> {
/**
* 根据名称ID,编码获取此ID所有的顶级指标下包含的指标的名称和编码是否有一致.
*
* @param topId 指标ID(用于获取顶级父ID)
* @param name 名称
* @param code 编码
* @return 结果列表
*/
List<Indicator> queryList(Integer topId, String name, String code);
/**
* 获取所有的根指标.
*
* @return 根指标列表
*/
List<Indicator> queryRootList();
/**
* 获取指定ID的指标包含子节点.
*
* @param id 指定ID
* @return 对应指标
*/
Indicator getIndicator(Integer id);
/**
* 根据父节点查询直接孩子.
*
* @param parentId 父节点
* @return 孩子列表
*/
List<Indicator> queryChildren(Integer parentId);
/**
* 查询没有子节点的指标.
*
* @param topId 祖先指标ID
* @return 指标集
*/
List<Indicator> selectNoChildByTopId(Integer topId);
}

View File

@ -0,0 +1,29 @@
package com.hshh.indicator.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hshh.indicator.entity.IndicatorEvalItem;
import com.hshh.indicator.mapper.IndicatorEvalItemMapper;
import com.hshh.indicator.service.IndicatorEvalItemService;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* 指标规则表 服务实现类.
*
* @author liDongYu
* @since 2025-08-04
*/
@Service
public class IndicatorEvalItemServiceImpl extends
ServiceImpl<IndicatorEvalItemMapper, IndicatorEvalItem> implements
IndicatorEvalItemService {
@Override
public List<IndicatorEvalItem> queryListByNameAndIndicatorId(Integer indicatorId, String name) {
QueryWrapper<IndicatorEvalItem> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("indicator_id", indicatorId);
queryWrapper.eq("evaluation_name", name);
return this.list(queryWrapper);
}
}

View File

@ -0,0 +1,85 @@
package com.hshh.indicator.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hshh.indicator.entity.Indicator;
import com.hshh.indicator.mapper.IndicatorMapper;
import com.hshh.indicator.service.IndicatorService;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
/**
* <p>
* 指标表 服务实现类
* </p>
*
* @author liDongYu
* @since 2025-08-04
*/
@Service
public class IndicatorServiceImpl extends ServiceImpl<IndicatorMapper, Indicator> implements
IndicatorService {
@Override
public List<Indicator> queryList(@NotNull Integer topId, @NotNull String name,
@NotNull String code) {
QueryWrapper<Indicator> queryWrapper = new QueryWrapper<>();
if (topId != null) {
queryWrapper.eq("top_id", topId);
}
queryWrapper.and(wrapper -> wrapper.eq("name", name).or().eq("code", code));
return this.list(queryWrapper);
}
@Override
public List<Indicator> queryRootList() {
QueryWrapper<Indicator> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("parent_id");
queryWrapper.orderByAsc("sort_order");
return this.list(queryWrapper);
}
@Override
public Indicator getIndicator(Integer id) {
Indicator indicator = this.getById(id);
Map<Integer, List<Indicator>> map = this.list().stream()
.collect(Collectors.groupingBy(a -> a.getParentId() == null ? 0 : a.getParentId()));
if (indicator != null) {
recursionIndicator(indicator, map);
}
return indicator;
}
/**
* 递归设置指标的孩子节点.
*
* @param top 上级指标
* @param parentMap 以父ID分组,所包含的children
*/
private void recursionIndicator(Indicator top, Map<Integer, List<Indicator>> parentMap) {
if (parentMap.get(top.getId()) != null) {
top.setChildren(parentMap.get(top.getId()));
parentMap.get(top.getId()).forEach(child -> {
recursionIndicator(child, parentMap);
});
}
}
@Override
public List<Indicator> queryChildren(Integer parentId) {
QueryWrapper<Indicator> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id", parentId);
return this.list(queryWrapper);
}
@Override
public List<Indicator> selectNoChildByTopId(Integer topId) {
return this.baseMapper.selectNoChildByTopId(topId);
}
}

View File

@ -0,0 +1,18 @@
package com.hshh.model.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
/**
* <p>
* 动态表单实际对象记录表 前端控制器
* </p>
*
* @author liDongYu
* @since 2025-08-01
*/
@Controller
@RequestMapping("/model/formValue")
public class FormValueController {
}

View File

@ -0,0 +1,295 @@
package com.hshh.model.controller;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.ModelDefine;
import com.hshh.model.service.FormFieldConfigService;
import com.hshh.model.service.ModelDefineService;
import com.hshh.system.base.entity.DictItem;
import com.hshh.system.base.entity.DictType;
import com.hshh.system.base.entity.TableRelations;
import com.hshh.system.base.service.DictItemService;
import com.hshh.system.base.service.DictTypeService;
import com.hshh.system.base.service.TableRelationsService;
import com.hshh.system.common.bean.BaseController;
import com.hshh.system.common.bean.OperateResult;
import com.hshh.system.common.enums.ErrorCode;
import com.hshh.system.common.enums.ErrorMessage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 数据模型前端控制器.
*
* @author liDongYu
* @since 2025-07-31
*/
@Controller
@RequestMapping("/model")
@Tag(name = "数据模型接口", description = "数据模型接口;数据模型增加、编辑、删除;数据模型字段增加、编辑、删除")
public class ModelDefineController extends BaseController {
/**
* 数据模型服务类.
*/
@Resource
private ModelDefineService modelDefineService;
/**
* 模型数据中字段服务类.
*/
@Resource
private FormFieldConfigService formFieldConfigService;
/**
* 字典条目服务类.
*/
@Resource
private DictItemService dictItemService;
/**
* 字典类别服务类.
*/
@Resource
private DictTypeService dictTypeService;
/**
* 关联服务类.
*/
@Resource
private TableRelationsService tableRelationsService;
/**
* 字典中单位的编码.约定属性.
*/
private static final String UNIT = "unit";
/**
* 导航到数据模型定义页.
*
* @param modelDefine 模型类
* @param model session容器
* @return model/list.html
*/
@Operation(summary = "导航到数据模型定义页面", description = "导航到数据模型定义页面")
@GetMapping("/list")
public String list(ModelDefine modelDefine, Model model) {
List<ModelDefine> modelList = modelDefineService.list();
List<FormFieldConfig> fieldList = new ArrayList<>();
if (modelList != null) {
modelList.sort(Comparator.comparingInt(ModelDefine::getSortOrder));
if (modelDefine.getId() != null) {
for (ModelDefine innermodelDefine : modelList) {
if (innermodelDefine.getId().equals(modelDefine.getId())) {
innermodelDefine.setChecked(true);
break;
}
}
fieldList.addAll(formFieldConfigService.getFormFieldConfigByModelId(
modelDefine.getId()));
} else {
fieldList.addAll(formFieldConfigService.getFormFieldConfigByModelId(
modelList.get(0).getId()));
modelList.get(0).setChecked(true);
}
}
//当前中选中的字段列表
model.addAttribute("fieldList", fieldList);
//模型列表
model.addAttribute("modelList", modelList);
return "model/list";
}
/**
* 导航到数据模型增加页面.
*
* @return model/add_model.html
*/
@GetMapping("/add")
@Operation(summary = "数据模型增加页面", description = "导航到数据模型增加页面")
public String addModel() {
return "model/add_model";
}
/**
* 导航到数据模型字段增加页面.
*
* @param modelId 模型ID
* @param model session容器
* @return model/add_model_field.html
*/
@GetMapping("/add-field")
@Operation(summary = "数据模型字段增加页面", description = "导航到数据模型字段增加页面")
public String addModelField(Integer modelId, Model model) {
//查询字段单位
List<DictItem> items = dictItemService.selectItemByTypeCode(UNIT);
//列出所有字典类别
List<DictType> dictTypeList = dictTypeService.list();
model.addAttribute("typeList", dictTypeList);
model.addAttribute("items", items);
return "model/add_model_field";
}
/**
* 保存数据模型.
*
* @param modelDefine 数据模型
* @param bindingResult 绑定数据的错误信息
* @return 操作结果包含保存的对象
*/
@PostMapping("/saveModelDefine")
@Operation(summary = "数据模型保存", description = "保存数据模型")
@ResponseBody
public OperateResult<Object> saveModelDefine(@RequestBody @Valid ModelDefine modelDefine,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return errorsInputHandle(bindingResult);
}
//验证名称或者代码是否存在
ModelDefine exitModelDefine = modelDefineService.getModelDefineByModelCodeOrName(
modelDefine.getModelName(), modelDefine.getModelCode());
if (modelDefine.getId() == null) {
if (exitModelDefine != null) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
modelDefineService.save(modelDefine);
} else {
if (exitModelDefine != null) {
if (!exitModelDefine.getId().equals(modelDefine.getId())) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
modelDefineService.updateById(modelDefine);
}
}
return OperateResult.success(modelDefine, ErrorMessage.SUCCESS.getMessage());
}
/**
* 删除数据模型.
*
* @param id 要删除的ID
* @return 操作结果
*/
@GetMapping("/remove/{id}")
@Operation(summary = "删除数据模型", description = "根据ID删除数据模型")
@ResponseBody
public OperateResult<Void> removeModelDefine(@PathVariable("id") Integer id) {
//查看是否有字段若有字段则无法删除
List<FormFieldConfig> fieldList = formFieldConfigService.getFormFieldConfigByModelId(id);
if (fieldList != null && !fieldList.isEmpty()) {
return OperateResult.error(null, ErrorMessage.OBJ_HAS_SUB.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
//查看数据关联表是否有记录
List<TableRelations> relList = tableRelationsService.queryRel(id,
"m_data_model_define");
if (relList != null && !relList.isEmpty()) {
return OperateResult.error(null, ErrorMessage.OBJ_ALREADY_TAKEN.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
modelDefineService.removeById(id);
return OperateResult.success();
}
/**
* 给模型增加字段.
*
* @param config 模型字段配置
* @param bindResult 绑定数据的错误信息
* @return 操作结果包含保存的对象
*/
@PostMapping("/saveModelField")
@Operation(summary = "增加模型字段", description = "给模型增加字段")
@ResponseBody
public OperateResult<Object> saveFormConfig(@RequestBody @Valid FormFieldConfig config,
BindingResult bindResult) {
//验证输入
if (bindResult.hasErrors()) {
return errorsInputHandle(bindResult);
}
//验证字段是否有重复同一个模型下
List<FormFieldConfig> exitList = formFieldConfigService.getFormFieldConfigByLabelOrNameOrId(
config.getDataModelId(),
config.getFieldLabel(), config.getFieldName(), config.getFieldId());
if (config.getId() == null) {
if (exitList != null && !exitList.isEmpty()) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
formFieldConfigService.save(config);
} else {
if (exitList != null && !exitList.isEmpty()) {
if (!exitList.get(0).getId().equals(config.getId())) {
return OperateResult.error(null, ErrorMessage.NAME_OR_CODE_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
}
formFieldConfigService.updateById(config);
}
return OperateResult.success(config, ErrorMessage.SUCCESS.getMessage());
}
/**
* 删除模型字段.
*
* @param id 字段ID
* @return 操作结果
*/
@GetMapping("/remove/field/{id}")
@Operation(summary = "删除数据模型中某个字段", description = "根据字段ID删除数据模型中的字段")
@ResponseBody
public OperateResult<Void> removeModelDataField(@PathVariable("id") Integer id) {
formFieldConfigService.removeById(id);
return OperateResult.success();
}
/**
* 获取指定id的数据模型.
*
* @param id 数据模型id
* @return 数据模型对象
*/
@GetMapping("/{id}")
@Operation(summary = "获取数据模型", description = "根据模型ID获取数据模型对象")
@ResponseBody
public OperateResult<ModelDefine> getModelDefine(@PathVariable("id") Integer id) {
ModelDefine modelDefine = modelDefineService.getById(id);
if (modelDefine == null) {
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
return OperateResult.success(modelDefine, ErrorMessage.SUCCESS.getMessage());
}
/**
* 获取指定id的字段对象.
*
* @param id 字段id
* @return 字段对象
*/
@GetMapping("/field/{id}")
@Operation(summary = "获取数据模型中一个字段", description = "根据字段id获取字段对象")
@ResponseBody
public OperateResult<FormFieldConfig> getFieldConfig(@PathVariable("id") Integer id) {
FormFieldConfig formFieldConfig = formFieldConfigService.getById(id);
if (formFieldConfig == null) {
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
ErrorCode.BUSINESS_ERROR.getCode());
}
return OperateResult.success(formFieldConfig, ErrorMessage.SUCCESS.getMessage());
}
}

View File

@ -0,0 +1,156 @@
package com.hshh.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.hshh.system.common.bean.ErrorField;
import java.io.Serializable;
import java.util.Optional;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
/**
* <p>
* 模型动态表单表
* </p>
*
* @author liDongYu
* @since 2025-07-31
*/
@TableName("m_data_form_field_config")
@Data
public class FormFieldConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer dataModelId;
@NotBlank(message = "字段名称不能为空")
@Size(max = 10, message = "字段名称不能超过10字符")
@Pattern(regexp = "^[A-Za-z]+$", message = "字段ID只能包含英文字符")
private String fieldName;
@NotBlank(message = "字段ID不能为空")
@Size(max = 10, message = "字段ID不能超过10字符")
@Pattern(regexp = "^[A-Za-z]+$", message = "字段ID只能包含英文字符")
private String fieldId;
@NotBlank(message = "字段标签不能为空")
@Size(max = 20, message = "字段标签不能超过20字符")
private String fieldLabel;
private String fieldDefaultValue;
@NotBlank(message = "字段类型不能为空")
private String fieldType;
private Integer fieldOptionsId;
private String fieldPlaceholder;
private Byte readonlyFlag;
private Byte disabledFlag;
private Byte autocompleteFlag;
private Byte hiddenFlag;
private String formatFunc;
private Byte isRequired;
private String validateRule;
private Integer sortOrder;
private String description;
private String validateRuleMessage;
private Integer fieldMinSize;
private Integer fieldMaxSize;
private Double fieldMinVal;
private Double fieldMaxVal;
private String fieldUnit;
//字段值
@TableField(exist = false)
private Object value;
/**
* 验证值.
*
* @return 验证字段值是否满足规则
*/
public Optional<ErrorField> validate() {
String val = value == null ? "" : value.toString();
// 必填校验
if (isRequired != null && isRequired == 1 && StringUtils.isBlank(val)) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "不能为空"));
}
//最小长度
if (fieldMinSize != null && (fieldType.equalsIgnoreCase("text") || fieldType.equalsIgnoreCase(
"textarea")) && val.length() < fieldMinSize) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "最小长度为" + fieldMinSize));
}
// 最大长度
if (fieldMaxSize != null && (fieldType.equalsIgnoreCase("text") || fieldType.equalsIgnoreCase(
"textarea")) && val.length() > fieldMaxSize) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "最大长度为" + fieldMaxSize));
}
// 正则校验
if (validateRule != null && !val.isEmpty()) {
if (!java.util.regex.Pattern.matches(validateRule, val)) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "格式不正确"));
}
}
// 数值校验
if (fieldType.equalsIgnoreCase("number")) {
try {
double num = Double.parseDouble(val);
if (fieldMinVal != null && num < fieldMinVal) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "不能小于" + fieldMinVal));
}
if (fieldMaxVal != null && num > fieldMaxVal) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "不能大于" + fieldMaxVal));
}
} catch (NumberFormatException e) {
return Optional.of(new ErrorField(fieldId, fieldLabel + "必须为数字"));
}
}
return Optional.empty();
}
}

View File

@ -0,0 +1,51 @@
package com.hshh.model.entity;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.hshh.system.common.bean.BaseBean;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;
/**
* <p>
* 动态表单实际对象记录表
* </p>
*
* @author liDongYu
* @since 2025-08-01
*/
@TableName("m_data_form_value")
@Data
public class FormValue extends BaseBean {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer modelDefineId;
private String modelData;
/**
* 把对象的id字段+modelData变成map.
*
* @return map键值对
*/
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("seq", getSeq());
JSONObject jsonObj = JSON.parseObject(modelData, JSONObject.class);
map.putAll(jsonObj);
return map;
}
}

View File

@ -0,0 +1,48 @@
package com.hshh.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Data;
/**
* <p>
*
* </p>
*
* @author liDongYu
* @since 2025-07-31
*/
@TableName("m_data_model_define")
@Data
public class ModelDefine implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@NotBlank(message = "数据模型编码不能为空")
@Size(max = 20, message = "编码长度不能超过20字符")
@Pattern(regexp = "^[A-Za-z]+$", message = "只能包含英文字符")
private String modelCode;
@NotBlank(message = "数据模型名称不能为空")
@Size(max = 20, message = "数据模型名称不能超过20字符")
private String modelName;
@TableField(exist = false)
private boolean checked;
private Integer sortOrder;
/**
* 每行显示几个字段.
*/
private Integer fieldsPerRow;
}

View File

@ -0,0 +1,16 @@
package com.hshh.model.mapper;
import com.hshh.model.entity.FormFieldConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 模型动态表单表 Mapper 接口
* </p>
*
* @author liDongYu
* @since 2025-07-31
*/
public interface FormFieldConfigMapper extends BaseMapper<FormFieldConfig> {
}

View File

@ -0,0 +1,31 @@
package com.hshh.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hshh.model.entity.FormValue;
import com.hshh.system.common.bean.PaginationBean;
import java.util.List;
/**
* 动态表单实际对象记录表 Mapper 接口.
*
* @author liDongYu
* @since 2025-08-01
*/
public interface FormValueMapper extends BaseMapper<FormValue> {
/**
* 查询列表.
*
* @param request 查询参数
* @return 查询结果
*/
List<FormValue> list(PaginationBean request);
/**
* 获取总数.
*
* @param request 查询参数
* @return 查询结果
*/
Long count(PaginationBean request);
}

View File

@ -0,0 +1,16 @@
package com.hshh.model.mapper;
import com.hshh.model.entity.ModelDefine;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author liDongYu
* @since 2025-07-31
*/
public interface ModelDefineMapper extends BaseMapper<ModelDefine> {
}

View File

@ -0,0 +1,35 @@
package com.hshh.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hshh.model.entity.FormFieldConfig;
import java.util.List;
import javax.validation.constraints.NotNull;
/**
* 模型动态表单表 服务类.
*
* @author liDongYu
* @since 2025-07-31
*/
public interface FormFieldConfigService extends IService<FormFieldConfig> {
/**
* 查看模型下是否有字段.
*
* @param modelId 模型ID
* @return 字段列表
*/
public List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId);
/**
* 查询符合条件的字段列表.
*
* @param modelId 模型Id
* @param label 标签
* @param name 名称
* @param id id
* @return 结果列表
*/
public List<FormFieldConfig> getFormFieldConfigByLabelOrNameOrId(@NotNull Integer modelId,
@NotNull String label, @NotNull String name, @NotNull String id);
}

View File

@ -0,0 +1,30 @@
package com.hshh.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hshh.model.entity.FormValue;
import com.hshh.system.common.bean.PaginationBean;
import java.util.List;
/**
* 动态表单实际对象记录表 服务类.
*
* @author liDongYu
* @since 2025-08-01
*/
public interface FormValueService extends IService<FormValue> {
/**
* 查询列表.
*
* @param request 查询参数
* @return 查询结果
*/
List<FormValue> list(PaginationBean request);
/**
* 获取总数.
*
* @param request 查询参数
* @return 查询结果
*/
Long count(PaginationBean request);
}

View File

@ -0,0 +1,26 @@
package com.hshh.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.ModelDefine;
import java.util.List;
/**
* 服务类.
*
* @author liDongYu
* @since 2025-07-31
*/
public interface ModelDefineService extends IService<ModelDefine> {
/**
* 根据模型名称和编码查找模型. 两者()的关系.
*
* @param modelName 模型名称
* @param modelCode 模型编码
* @return 模型
*/
public ModelDefine getModelDefineByModelCodeOrName(String modelName, String modelCode);
}

View File

@ -0,0 +1,38 @@
package com.hshh.model.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.mapper.FormFieldConfigMapper;
import com.hshh.model.service.FormFieldConfigService;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* 模型动态表单表 服务实现类.
*
* @author liDongYu
* @since 2025-07-31
*/
@Service
public class FormFieldConfigServiceImpl extends
ServiceImpl<FormFieldConfigMapper, FormFieldConfig> implements
FormFieldConfigService {
@Override
public List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId) {
QueryWrapper<FormFieldConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("data_model_id", modelId);
return this.list(queryWrapper);
}
@Override
public List<FormFieldConfig> getFormFieldConfigByLabelOrNameOrId(Integer modelId, String label,
String name, String id) {
QueryWrapper<FormFieldConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("data_model_id", modelId);
queryWrapper.and(wrapper -> wrapper.eq("field_label", label).or().eq("field_name", name).or()
.eq("field_id", id));
return this.list(queryWrapper);
}
}

View File

@ -0,0 +1,30 @@
package com.hshh.model.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hshh.model.entity.FormValue;
import com.hshh.model.mapper.FormValueMapper;
import com.hshh.model.service.FormValueService;
import com.hshh.system.common.bean.PaginationBean;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* 动态表单实际对象记录表 服务实现类.
*
* @author liDongYu
* @since 2025-08-01
*/
@Service
public class FormValueServiceImpl extends ServiceImpl<FormValueMapper, FormValue> implements
FormValueService {
@Override
public List<FormValue> list(PaginationBean request) {
return this.baseMapper.list(request);
}
@Override
public Long count(PaginationBean request) {
return this.baseMapper.count(request);
}
}

View File

@ -0,0 +1,32 @@
package com.hshh.model.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hshh.model.entity.FormFieldConfig;
import com.hshh.model.entity.ModelDefine;
import com.hshh.model.mapper.ModelDefineMapper;
import com.hshh.model.service.ModelDefineService;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* 服务实现类.
*
* @author liDongYu
* @since 2025-07-31
*/
@Service
public class ModelDefineServiceImpl extends ServiceImpl<ModelDefineMapper, ModelDefine> implements
ModelDefineService {
@Override
public ModelDefine getModelDefineByModelCodeOrName(String modelName, String modelCode) {
QueryWrapper<ModelDefine> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_name", modelName).or().eq("model_code", modelCode);
return this.list(queryWrapper).stream().findFirst().orElse(null);
}
}

View File

@ -0,0 +1,36 @@
server:
port: 8080
spring:
thymeleaf:
cache: false
datasource:
url: jdbc:mysql://localhost:3306/manager?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 30000
pool-name: HikariCP
max-lifetime: 600000
connection-timeout: 30000
servlet:
multipart:
max-file-size: 20MB
max-request-size: 20MB
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
database-id: mysql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hshh.model.mapper.FormFieldConfigMapper">
</mapper>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hshh.model.mapper.FormValueMapper">
<select id="list" resultType="com.hshh.model.entity.FormValue"
parameterType="com.hshh.system.common.bean.PaginationBean" databaseId="mysql">
SELECT
@rownum := @rownum + 1 AS seq,
t.*
FROM (
SELECT * FROM m_data_form_value
<where>
<if test="id!=null">
and model_define_id = #{id}
</if>
<if test="search != null and search !='' ">
and model_data LIKE CONCAT('%',#{search},'%')
</if>
</where>
order by id asc ) t, ( SELECT @rownum := #{start} ) r limit
#{start},#{pageSize}
</select>
<select id="list" resultType="com.hshh.model.entity.FormValue"
parameterType="com.hshh.system.common.bean.PaginationBean" databaseId="dm">SELECT
t.seq,
t.*
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY id ASC) AS seq,
a.*
FROM m_data_form_value a
<where>
<if test="id!=null">
and model_define_id = #{id}
</if>
<if test="search != null and search !='' ">
and model_data LIKE '%'||#{search}||'%'
</if>
</where>
) t
WHERE t.seq > #{start} AND t.seq &lt;= (#{start} + #{pageSize})
</select>
<select id="count" resultType="java.lang.Long" databaseId="dm">
select count(id) from m_data_form_value
<where>
<if test="id!=null">
and model_define_id = #{id}
</if>
<if test="search != null and search !=''">
and (model_data LIKE '%'||#{search}||'%')
</if>
</where>
</select>
<select id="count" resultType="java.lang.Long" databaseId="mysql">
select count(id) from m_data_form_value
<where>
<if test="id!=null">
and model_define_id = #{id}
</if>
<if test="search != null and search !=''">
and (model_data LIKE CONCAT('%',#{search},'%'))
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hshh.indicator.mapper.IndicatorEvalItemMapper">
</mapper>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hshh.indicator.mapper.IndicatorMapper">
<select id="selectNoChildByTopId" resultType="com.hshh.indicator.entity.Indicator">
SELECT *
FROM m_data_indicator t1
WHERE t1.top_id = #{topId}
and t1.id NOT IN (SELECT t2.parent_id
FROM m_data_indicator t2
WHERE t2.top_id = #{topId} and t2.parent_id IS NOT NULL)
order by sort_order
</select>
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hshh.model.mapper.ModelDefineMapper">
</mapper>

View File

@ -0,0 +1,102 @@
.upload-container {
position: relative;
}
/* 圆形图标样式 */
.upload-icon {
width: 100px;
height: 100px;
border-radius: 50%;
background: #3498db;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 36px;
cursor: pointer;
transition: background 0.3s;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.upload-icon:hover {
background: #2980b9;
}
.upload-icon img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%; /* 保证圆形效果 */
}
#detail_jarImg_value img{
width: 20%;
height: 20%;
object-fit: cover;
border-radius: 50%; /* 保证圆形效果 */
}
/* 隐藏实际的文件输入框 */
#fileInput {
display: none;
}
.custom-alert-mask {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.18);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.custom-alert-box {
background: #fff;
border-radius: 14px;
box-shadow: 0 8px 32px rgba(60,90,130,0.13);
max-width: 90vw;
width: 340px;
padding: 32px 22px 22px 22px;
text-align: center;
position: relative;
animation: fadeIn 0.2s;
}
.custom-alert-icon {
margin-bottom: 12px;
}
.custom-alert-title {
font-size: 1.2em;
font-weight: 600;
color: #d98c1b;
margin-bottom: 14px;
letter-spacing: 1px;
}
.custom-alert-message {
font-size: 1em;
color: #4c5870;
margin-bottom: 28px;
word-break: break-all;
}
.custom-alert-btn {
padding: 8px 36px;
background: #d98c1b;
color: #fff;
border: none;
border-radius: 8px;
font-size: 1em;
cursor: pointer;
transition: background 0.2s;
}
.custom-alert-btn:hover {
background: #b06f10;
}
@keyframes fadeIn {
from { transform: translateY(30px) scale(0.92); opacity: 0; }
to { transform: translateY(0) scale(1); opacity: 1; }
}
@media (max-width: 450px) {
.custom-alert-box {
width: 96vw;
padding: 22px 6vw 14px 6vw;
}
.custom-alert-title { font-size: 1.1em; }
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,159 @@
/*
* Released under BSD License
* Copyright (c) 2014-2015 hizzgdev@163.com
*
* Project Home:
* https://github.com/hizzgdev/jsmind/
*/
/* important section */
.jsmind-inner{position:relative;overflow:auto;width:100%;height:100%;}/*box-shadow:0 0 2px #000;*/
.jsmind-inner{
moz-user-select:-moz-none;
-moz-user-select:none;
-o-user-select:none;
-khtml-user-select:none;
-webkit-user-select:none;
-ms-user-select:none;
user-select:none;
}
/* z-index:1 */
canvas{position:absolute;z-index:1;}
/* z-index:2 */
jmnodes{position:absolute;z-index:2;background-color:rgba(0,0,0,0);}/*background color is necessary*/
jmnode{position:absolute;cursor:default;max-width:400px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
jmexpander{position:absolute;width:11px;height:11px;display:block;overflow:hidden;line-height:12px;font-size:12px;text-align:center;border-radius:6px;border-width:1px;border-style:solid;cursor:pointer;}
/* default theme */
jmnode{padding:10px;background-color:#fff;color:#333;border-radius:5px;box-shadow:1px 1px 1px #666;font:16px/1.125 Verdana,Arial,Helvetica,sans-serif;}
jmnode:hover{box-shadow:2px 2px 8px #000;background-color:#ebebeb;color:#333;}
jmnode.selected{background-color:#11f;color:#fff;box-shadow:2px 2px 8px #000;}
jmnode.root{font-size:24px;}
jmexpander{border-color:gray;}
jmexpander:hover{border-color:#000;}
@media screen and (max-device-width: 1024px) {
jmnode{padding:5px;border-radius:3px;font-size:14px;}
jmnode.root{font-size:21px;}
}
/* primary theme */
jmnodes.theme-primary jmnode{background-color:#428bca;color:#fff;border-color:#357ebd;}
jmnodes.theme-primary jmnode:hover{background-color:#3276b1;border-color:#285e8e;}
jmnodes.theme-primary jmnode.selected{background-color:#f1c40f;color:#fff;}
jmnodes.theme-primary jmnode.root{}
jmnodes.theme-primary jmexpander{}
jmnodes.theme-primary jmexpander:hover{}
/* warning theme */
jmnodes.theme-warning jmnode{background-color:#f0ad4e;border-color:#eea236;color:#fff;}
jmnodes.theme-warning jmnode:hover{background-color:#ed9c28;border-color:#d58512;}
jmnodes.theme-warning jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-warning jmnode.root{}
jmnodes.theme-warning jmexpander{}
jmnodes.theme-warning jmexpander:hover{}
/* danger theme */
jmnodes.theme-danger jmnode{background-color:#d9534f;border-color:#d43f3a;color:#fff;}
jmnodes.theme-danger jmnode:hover{background-color:#d2322d;border-color:#ac2925;}
jmnodes.theme-danger jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-danger jmnode.root{}
jmnodes.theme-danger jmexpander{}
jmnodes.theme-danger jmexpander:hover{}
/* success theme */
jmnodes.theme-success jmnode{background-color:#5cb85c;border-color:#4cae4c;color:#fff;}
jmnodes.theme-success jmnode:hover{background-color:#47a447;border-color:#398439;}
jmnodes.theme-success jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-success jmnode.root{}
jmnodes.theme-success jmexpander{}
jmnodes.theme-success jmexpander:hover{}
/* info theme */
jmnodes.theme-info jmnode{background-color:#5dc0de;border-color:#46b8da;;color:#fff;}
jmnodes.theme-info jmnode:hover{background-color:#39b3d7;border-color:#269abc;}
jmnodes.theme-info jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-info jmnode.root{}
jmnodes.theme-info jmexpander{}
jmnodes.theme-info jmexpander:hover{}
/* greensea theme */
jmnodes.theme-greensea jmnode{background-color:#1abc9c;color:#fff;}
jmnodes.theme-greensea jmnode:hover{background-color:#16a085;}
jmnodes.theme-greensea jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-greensea jmnode.root{}
jmnodes.theme-greensea jmexpander{}
jmnodes.theme-greensea jmexpander:hover{}
/* nephrite theme */
jmnodes.theme-nephrite jmnode{background-color:#2ecc71;color:#fff;}
jmnodes.theme-nephrite jmnode:hover{background-color:#27ae60;}
jmnodes.theme-nephrite jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-nephrite jmnode.root{}
jmnodes.theme-nephrite jmexpander{}
jmnodes.theme-nephrite jmexpander:hover{}
/* belizehole theme */
jmnodes.theme-belizehole jmnode{background-color:#3498db;color:#fff;}
jmnodes.theme-belizehole jmnode:hover{background-color:#2980b9;}
jmnodes.theme-belizehole jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-belizehole jmnode.root{}
jmnodes.theme-belizehole jmexpander{}
jmnodes.theme-belizehole jmexpander:hover{}
/* wisteria theme */
jmnodes.theme-wisteria jmnode{background-color:#9b59b6;color:#fff;}
jmnodes.theme-wisteria jmnode:hover{background-color:#8e44ad;}
jmnodes.theme-wisteria jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-wisteria jmnode.root{}
jmnodes.theme-wisteria jmexpander{}
jmnodes.theme-wisteria jmexpander:hover{}
/* asphalt theme */
jmnodes.theme-asphalt jmnode{background-color:#34495e;color:#fff;}
jmnodes.theme-asphalt jmnode:hover{background-color:#2c3e50;}
jmnodes.theme-asphalt jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-asphalt jmnode.root{}
jmnodes.theme-asphalt jmexpander{}
jmnodes.theme-asphalt jmexpander:hover{}
/* orange theme */
jmnodes.theme-orange jmnode{background-color:#f1c40f;color:#fff;}
jmnodes.theme-orange jmnode:hover{background-color:#f39c12;}
jmnodes.theme-orange jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-orange jmnode.root{}
jmnodes.theme-orange jmexpander{}
jmnodes.theme-orange jmexpander:hover{}
/* pumpkin theme */
jmnodes.theme-pumpkin jmnode{background-color:#e67e22;color:#fff;}
jmnodes.theme-pumpkin jmnode:hover{background-color:#d35400;}
jmnodes.theme-pumpkin jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-pumpkin jmnode.root{}
jmnodes.theme-pumpkin jmexpander{}
jmnodes.theme-pumpkin jmexpander:hover{}
/* pomegranate theme */
jmnodes.theme-pomegranate jmnode{background-color:#e74c3c;color:#fff;}
jmnodes.theme-pomegranate jmnode:hover{background-color:#c0392b;}
jmnodes.theme-pomegranate jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-pomegranate jmnode.root{}
jmnodes.theme-pomegranate jmexpander{}
jmnodes.theme-pomegranate jmexpander:hover{}
/* clouds theme */
jmnodes.theme-clouds jmnode{background-color:#ecf0f1;color:#333;}
jmnodes.theme-clouds jmnode:hover{background-color:#bdc3c7;}
jmnodes.theme-clouds jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-clouds jmnode.root{}
jmnodes.theme-clouds jmexpander{}
jmnodes.theme-clouds jmexpander:hover{}
/* asbestos theme */
jmnodes.theme-asbestos jmnode{background-color:#95a5a6;color:#fff;}
jmnodes.theme-asbestos jmnode:hover{background-color:#7f8c8d;}
jmnodes.theme-asbestos jmnode.selected{background-color:#11f;color:#fff;}
jmnodes.theme-asbestos jmnode.root{}
jmnodes.theme-asbestos jmexpander{}
jmnodes.theme-asbestos jmexpander:hover{}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,530 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/
/* prettier-ignore */
/* prettier-ignore */
.payment {
width: 3.33332rem;
height: 2rem;
display: inline-block;
background: no-repeat center/100% 100%;
vertical-align: bottom;
font-style: normal;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
border-radius: 2px;
}
.payment-provider-2checkout {
background-image: url("../img/payments/2checkout.svg");
}
.payment-provider-2checkout-dark {
background-image: url("../img/payments/2checkout-dark.svg");
}
.payment-provider-alipay {
background-image: url("../img/payments/alipay.svg");
}
.payment-provider-alipay-dark {
background-image: url("../img/payments/alipay-dark.svg");
}
.payment-provider-amazon {
background-image: url("../img/payments/amazon.svg");
}
.payment-provider-amazon-dark {
background-image: url("../img/payments/amazon-dark.svg");
}
.payment-provider-americanexpress {
background-image: url("../img/payments/americanexpress.svg");
}
.payment-provider-americanexpress-dark {
background-image: url("../img/payments/americanexpress-dark.svg");
}
.payment-provider-applepay {
background-image: url("../img/payments/applepay.svg");
}
.payment-provider-applepay-dark {
background-image: url("../img/payments/applepay-dark.svg");
}
.payment-provider-bancontact {
background-image: url("../img/payments/bancontact.svg");
}
.payment-provider-bancontact-dark {
background-image: url("../img/payments/bancontact-dark.svg");
}
.payment-provider-bitcoin {
background-image: url("../img/payments/bitcoin.svg");
}
.payment-provider-bitcoin-dark {
background-image: url("../img/payments/bitcoin-dark.svg");
}
.payment-provider-bitpay {
background-image: url("../img/payments/bitpay.svg");
}
.payment-provider-bitpay-dark {
background-image: url("../img/payments/bitpay-dark.svg");
}
.payment-provider-blik {
background-image: url("../img/payments/blik.svg");
}
.payment-provider-blik-dark {
background-image: url("../img/payments/blik-dark.svg");
}
.payment-provider-cirrus {
background-image: url("../img/payments/cirrus.svg");
}
.payment-provider-cirrus-dark {
background-image: url("../img/payments/cirrus-dark.svg");
}
.payment-provider-clickandbuy {
background-image: url("../img/payments/clickandbuy.svg");
}
.payment-provider-clickandbuy-dark {
background-image: url("../img/payments/clickandbuy-dark.svg");
}
.payment-provider-coinkite {
background-image: url("../img/payments/coinkite.svg");
}
.payment-provider-coinkite-dark {
background-image: url("../img/payments/coinkite-dark.svg");
}
.payment-provider-dinersclub {
background-image: url("../img/payments/dinersclub.svg");
}
.payment-provider-dinersclub-dark {
background-image: url("../img/payments/dinersclub-dark.svg");
}
.payment-provider-directdebit {
background-image: url("../img/payments/directdebit.svg");
}
.payment-provider-directdebit-dark {
background-image: url("../img/payments/directdebit-dark.svg");
}
.payment-provider-discover {
background-image: url("../img/payments/discover.svg");
}
.payment-provider-discover-dark {
background-image: url("../img/payments/discover-dark.svg");
}
.payment-provider-dotpay {
background-image: url("../img/payments/dotpay.svg");
}
.payment-provider-dotpay-dark {
background-image: url("../img/payments/dotpay-dark.svg");
}
.payment-provider-dwolla {
background-image: url("../img/payments/dwolla.svg");
}
.payment-provider-dwolla-dark {
background-image: url("../img/payments/dwolla-dark.svg");
}
.payment-provider-ebay {
background-image: url("../img/payments/ebay.svg");
}
.payment-provider-ebay-dark {
background-image: url("../img/payments/ebay-dark.svg");
}
.payment-provider-epayco {
background-image: url("../img/payments/epayco.svg");
}
.payment-provider-epayco-dark {
background-image: url("../img/payments/epayco-dark.svg");
}
.payment-provider-eway {
background-image: url("../img/payments/eway.svg");
}
.payment-provider-eway-dark {
background-image: url("../img/payments/eway-dark.svg");
}
.payment-provider-giropay {
background-image: url("../img/payments/giropay.svg");
}
.payment-provider-giropay-dark {
background-image: url("../img/payments/giropay-dark.svg");
}
.payment-provider-googlewallet {
background-image: url("../img/payments/googlewallet.svg");
}
.payment-provider-googlewallet-dark {
background-image: url("../img/payments/googlewallet-dark.svg");
}
.payment-provider-ingenico {
background-image: url("../img/payments/ingenico.svg");
}
.payment-provider-ingenico-dark {
background-image: url("../img/payments/ingenico-dark.svg");
}
.payment-provider-jcb {
background-image: url("../img/payments/jcb.svg");
}
.payment-provider-jcb-dark {
background-image: url("../img/payments/jcb-dark.svg");
}
.payment-provider-klarna {
background-image: url("../img/payments/klarna.svg");
}
.payment-provider-klarna-dark {
background-image: url("../img/payments/klarna-dark.svg");
}
.payment-provider-laser {
background-image: url("../img/payments/laser.svg");
}
.payment-provider-laser-dark {
background-image: url("../img/payments/laser-dark.svg");
}
.payment-provider-maestro {
background-image: url("../img/payments/maestro.svg");
}
.payment-provider-maestro-dark {
background-image: url("../img/payments/maestro-dark.svg");
}
.payment-provider-mastercard {
background-image: url("../img/payments/mastercard.svg");
}
.payment-provider-mastercard-dark {
background-image: url("../img/payments/mastercard-dark.svg");
}
.payment-provider-mir {
background-image: url("../img/payments/mir.svg");
}
.payment-provider-mir-dark {
background-image: url("../img/payments/mir-dark.svg");
}
.payment-provider-monero {
background-image: url("../img/payments/monero.svg");
}
.payment-provider-monero-dark {
background-image: url("../img/payments/monero-dark.svg");
}
.payment-provider-neteller {
background-image: url("../img/payments/neteller.svg");
}
.payment-provider-neteller-dark {
background-image: url("../img/payments/neteller-dark.svg");
}
.payment-provider-ogone {
background-image: url("../img/payments/ogone.svg");
}
.payment-provider-ogone-dark {
background-image: url("../img/payments/ogone-dark.svg");
}
.payment-provider-okpay {
background-image: url("../img/payments/okpay.svg");
}
.payment-provider-okpay-dark {
background-image: url("../img/payments/okpay-dark.svg");
}
.payment-provider-paybox {
background-image: url("../img/payments/paybox.svg");
}
.payment-provider-paybox-dark {
background-image: url("../img/payments/paybox-dark.svg");
}
.payment-provider-paymill {
background-image: url("../img/payments/paymill.svg");
}
.payment-provider-paymill-dark {
background-image: url("../img/payments/paymill-dark.svg");
}
.payment-provider-payone {
background-image: url("../img/payments/payone.svg");
}
.payment-provider-payone-dark {
background-image: url("../img/payments/payone-dark.svg");
}
.payment-provider-payoneer {
background-image: url("../img/payments/payoneer.svg");
}
.payment-provider-payoneer-dark {
background-image: url("../img/payments/payoneer-dark.svg");
}
.payment-provider-paypal {
background-image: url("../img/payments/paypal.svg");
}
.payment-provider-paypal-dark {
background-image: url("../img/payments/paypal-dark.svg");
}
.payment-provider-paysafecard {
background-image: url("../img/payments/paysafecard.svg");
}
.payment-provider-paysafecard-dark {
background-image: url("../img/payments/paysafecard-dark.svg");
}
.payment-provider-payu {
background-image: url("../img/payments/payu.svg");
}
.payment-provider-payu-dark {
background-image: url("../img/payments/payu-dark.svg");
}
.payment-provider-payza {
background-image: url("../img/payments/payza.svg");
}
.payment-provider-payza-dark {
background-image: url("../img/payments/payza-dark.svg");
}
.payment-provider-przelewy24 {
background-image: url("../img/payments/przelewy24.svg");
}
.payment-provider-przelewy24-dark {
background-image: url("../img/payments/przelewy24-dark.svg");
}
.payment-provider-ripple {
background-image: url("../img/payments/ripple.svg");
}
.payment-provider-ripple-dark {
background-image: url("../img/payments/ripple-dark.svg");
}
.payment-provider-sage {
background-image: url("../img/payments/sage.svg");
}
.payment-provider-sage-dark {
background-image: url("../img/payments/sage-dark.svg");
}
.payment-provider-sepa {
background-image: url("../img/payments/sepa.svg");
}
.payment-provider-sepa-dark {
background-image: url("../img/payments/sepa-dark.svg");
}
.payment-provider-shopify {
background-image: url("../img/payments/shopify.svg");
}
.payment-provider-shopify-dark {
background-image: url("../img/payments/shopify-dark.svg");
}
.payment-provider-skrill {
background-image: url("../img/payments/skrill.svg");
}
.payment-provider-skrill-dark {
background-image: url("../img/payments/skrill-dark.svg");
}
.payment-provider-solo {
background-image: url("../img/payments/solo.svg");
}
.payment-provider-solo-dark {
background-image: url("../img/payments/solo-dark.svg");
}
.payment-provider-square {
background-image: url("../img/payments/square.svg");
}
.payment-provider-square-dark {
background-image: url("../img/payments/square-dark.svg");
}
.payment-provider-stripe {
background-image: url("../img/payments/stripe.svg");
}
.payment-provider-stripe-dark {
background-image: url("../img/payments/stripe-dark.svg");
}
.payment-provider-switch {
background-image: url("../img/payments/switch.svg");
}
.payment-provider-switch-dark {
background-image: url("../img/payments/switch-dark.svg");
}
.payment-provider-tpay {
background-image: url("../img/payments/tpay.svg");
}
.payment-provider-tpay-dark {
background-image: url("../img/payments/tpay-dark.svg");
}
.payment-provider-ukash {
background-image: url("../img/payments/ukash.svg");
}
.payment-provider-ukash-dark {
background-image: url("../img/payments/ukash-dark.svg");
}
.payment-provider-unionpay {
background-image: url("../img/payments/unionpay.svg");
}
.payment-provider-unionpay-dark {
background-image: url("../img/payments/unionpay-dark.svg");
}
.payment-provider-verifone {
background-image: url("../img/payments/verifone.svg");
}
.payment-provider-verifone-dark {
background-image: url("../img/payments/verifone-dark.svg");
}
.payment-provider-verisign {
background-image: url("../img/payments/verisign.svg");
}
.payment-provider-verisign-dark {
background-image: url("../img/payments/verisign-dark.svg");
}
.payment-provider-visa {
background-image: url("../img/payments/visa.svg");
}
.payment-provider-visa-dark {
background-image: url("../img/payments/visa-dark.svg");
}
.payment-provider-webmoney {
background-image: url("../img/payments/webmoney.svg");
}
.payment-provider-webmoney-dark {
background-image: url("../img/payments/webmoney-dark.svg");
}
.payment-provider-westernunion {
background-image: url("../img/payments/westernunion.svg");
}
.payment-provider-westernunion-dark {
background-image: url("../img/payments/westernunion-dark.svg");
}
.payment-provider-worldpay {
background-image: url("../img/payments/worldpay.svg");
}
.payment-provider-worldpay-dark {
background-image: url("../img/payments/worldpay-dark.svg");
}
.payment-xs {
width: 2.49999rem;
height: 1.5rem;
}
.payment-sm {
width: 3.33332rem;
height: 2rem;
}
.payment-md {
width: 6.66664rem;
height: 4rem;
}
.payment-lg {
width: 9.16663rem;
height: 5.5rem;
}
.payment-xl {
width: 11.66662rem;
height: 7rem;
}
.payment-2xl {
width: 18.33326rem;
height: 11rem;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,530 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/
/* prettier-ignore */
/* prettier-ignore */
.payment {
width: 3.33332rem;
height: 2rem;
display: inline-block;
background: no-repeat center/100% 100%;
vertical-align: bottom;
font-style: normal;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
border-radius: 2px;
}
.payment-provider-2checkout {
background-image: url("../img/payments/2checkout.svg");
}
.payment-provider-2checkout-dark {
background-image: url("../img/payments/2checkout-dark.svg");
}
.payment-provider-alipay {
background-image: url("../img/payments/alipay.svg");
}
.payment-provider-alipay-dark {
background-image: url("../img/payments/alipay-dark.svg");
}
.payment-provider-amazon {
background-image: url("../img/payments/amazon.svg");
}
.payment-provider-amazon-dark {
background-image: url("../img/payments/amazon-dark.svg");
}
.payment-provider-americanexpress {
background-image: url("../img/payments/americanexpress.svg");
}
.payment-provider-americanexpress-dark {
background-image: url("../img/payments/americanexpress-dark.svg");
}
.payment-provider-applepay {
background-image: url("../img/payments/applepay.svg");
}
.payment-provider-applepay-dark {
background-image: url("../img/payments/applepay-dark.svg");
}
.payment-provider-bancontact {
background-image: url("../img/payments/bancontact.svg");
}
.payment-provider-bancontact-dark {
background-image: url("../img/payments/bancontact-dark.svg");
}
.payment-provider-bitcoin {
background-image: url("../img/payments/bitcoin.svg");
}
.payment-provider-bitcoin-dark {
background-image: url("../img/payments/bitcoin-dark.svg");
}
.payment-provider-bitpay {
background-image: url("../img/payments/bitpay.svg");
}
.payment-provider-bitpay-dark {
background-image: url("../img/payments/bitpay-dark.svg");
}
.payment-provider-blik {
background-image: url("../img/payments/blik.svg");
}
.payment-provider-blik-dark {
background-image: url("../img/payments/blik-dark.svg");
}
.payment-provider-cirrus {
background-image: url("../img/payments/cirrus.svg");
}
.payment-provider-cirrus-dark {
background-image: url("../img/payments/cirrus-dark.svg");
}
.payment-provider-clickandbuy {
background-image: url("../img/payments/clickandbuy.svg");
}
.payment-provider-clickandbuy-dark {
background-image: url("../img/payments/clickandbuy-dark.svg");
}
.payment-provider-coinkite {
background-image: url("../img/payments/coinkite.svg");
}
.payment-provider-coinkite-dark {
background-image: url("../img/payments/coinkite-dark.svg");
}
.payment-provider-dinersclub {
background-image: url("../img/payments/dinersclub.svg");
}
.payment-provider-dinersclub-dark {
background-image: url("../img/payments/dinersclub-dark.svg");
}
.payment-provider-directdebit {
background-image: url("../img/payments/directdebit.svg");
}
.payment-provider-directdebit-dark {
background-image: url("../img/payments/directdebit-dark.svg");
}
.payment-provider-discover {
background-image: url("../img/payments/discover.svg");
}
.payment-provider-discover-dark {
background-image: url("../img/payments/discover-dark.svg");
}
.payment-provider-dotpay {
background-image: url("../img/payments/dotpay.svg");
}
.payment-provider-dotpay-dark {
background-image: url("../img/payments/dotpay-dark.svg");
}
.payment-provider-dwolla {
background-image: url("../img/payments/dwolla.svg");
}
.payment-provider-dwolla-dark {
background-image: url("../img/payments/dwolla-dark.svg");
}
.payment-provider-ebay {
background-image: url("../img/payments/ebay.svg");
}
.payment-provider-ebay-dark {
background-image: url("../img/payments/ebay-dark.svg");
}
.payment-provider-epayco {
background-image: url("../img/payments/epayco.svg");
}
.payment-provider-epayco-dark {
background-image: url("../img/payments/epayco-dark.svg");
}
.payment-provider-eway {
background-image: url("../img/payments/eway.svg");
}
.payment-provider-eway-dark {
background-image: url("../img/payments/eway-dark.svg");
}
.payment-provider-giropay {
background-image: url("../img/payments/giropay.svg");
}
.payment-provider-giropay-dark {
background-image: url("../img/payments/giropay-dark.svg");
}
.payment-provider-googlewallet {
background-image: url("../img/payments/googlewallet.svg");
}
.payment-provider-googlewallet-dark {
background-image: url("../img/payments/googlewallet-dark.svg");
}
.payment-provider-ingenico {
background-image: url("../img/payments/ingenico.svg");
}
.payment-provider-ingenico-dark {
background-image: url("../img/payments/ingenico-dark.svg");
}
.payment-provider-jcb {
background-image: url("../img/payments/jcb.svg");
}
.payment-provider-jcb-dark {
background-image: url("../img/payments/jcb-dark.svg");
}
.payment-provider-klarna {
background-image: url("../img/payments/klarna.svg");
}
.payment-provider-klarna-dark {
background-image: url("../img/payments/klarna-dark.svg");
}
.payment-provider-laser {
background-image: url("../img/payments/laser.svg");
}
.payment-provider-laser-dark {
background-image: url("../img/payments/laser-dark.svg");
}
.payment-provider-maestro {
background-image: url("../img/payments/maestro.svg");
}
.payment-provider-maestro-dark {
background-image: url("../img/payments/maestro-dark.svg");
}
.payment-provider-mastercard {
background-image: url("../img/payments/mastercard.svg");
}
.payment-provider-mastercard-dark {
background-image: url("../img/payments/mastercard-dark.svg");
}
.payment-provider-mir {
background-image: url("../img/payments/mir.svg");
}
.payment-provider-mir-dark {
background-image: url("../img/payments/mir-dark.svg");
}
.payment-provider-monero {
background-image: url("../img/payments/monero.svg");
}
.payment-provider-monero-dark {
background-image: url("../img/payments/monero-dark.svg");
}
.payment-provider-neteller {
background-image: url("../img/payments/neteller.svg");
}
.payment-provider-neteller-dark {
background-image: url("../img/payments/neteller-dark.svg");
}
.payment-provider-ogone {
background-image: url("../img/payments/ogone.svg");
}
.payment-provider-ogone-dark {
background-image: url("../img/payments/ogone-dark.svg");
}
.payment-provider-okpay {
background-image: url("../img/payments/okpay.svg");
}
.payment-provider-okpay-dark {
background-image: url("../img/payments/okpay-dark.svg");
}
.payment-provider-paybox {
background-image: url("../img/payments/paybox.svg");
}
.payment-provider-paybox-dark {
background-image: url("../img/payments/paybox-dark.svg");
}
.payment-provider-paymill {
background-image: url("../img/payments/paymill.svg");
}
.payment-provider-paymill-dark {
background-image: url("../img/payments/paymill-dark.svg");
}
.payment-provider-payone {
background-image: url("../img/payments/payone.svg");
}
.payment-provider-payone-dark {
background-image: url("../img/payments/payone-dark.svg");
}
.payment-provider-payoneer {
background-image: url("../img/payments/payoneer.svg");
}
.payment-provider-payoneer-dark {
background-image: url("../img/payments/payoneer-dark.svg");
}
.payment-provider-paypal {
background-image: url("../img/payments/paypal.svg");
}
.payment-provider-paypal-dark {
background-image: url("../img/payments/paypal-dark.svg");
}
.payment-provider-paysafecard {
background-image: url("../img/payments/paysafecard.svg");
}
.payment-provider-paysafecard-dark {
background-image: url("../img/payments/paysafecard-dark.svg");
}
.payment-provider-payu {
background-image: url("../img/payments/payu.svg");
}
.payment-provider-payu-dark {
background-image: url("../img/payments/payu-dark.svg");
}
.payment-provider-payza {
background-image: url("../img/payments/payza.svg");
}
.payment-provider-payza-dark {
background-image: url("../img/payments/payza-dark.svg");
}
.payment-provider-przelewy24 {
background-image: url("../img/payments/przelewy24.svg");
}
.payment-provider-przelewy24-dark {
background-image: url("../img/payments/przelewy24-dark.svg");
}
.payment-provider-ripple {
background-image: url("../img/payments/ripple.svg");
}
.payment-provider-ripple-dark {
background-image: url("../img/payments/ripple-dark.svg");
}
.payment-provider-sage {
background-image: url("../img/payments/sage.svg");
}
.payment-provider-sage-dark {
background-image: url("../img/payments/sage-dark.svg");
}
.payment-provider-sepa {
background-image: url("../img/payments/sepa.svg");
}
.payment-provider-sepa-dark {
background-image: url("../img/payments/sepa-dark.svg");
}
.payment-provider-shopify {
background-image: url("../img/payments/shopify.svg");
}
.payment-provider-shopify-dark {
background-image: url("../img/payments/shopify-dark.svg");
}
.payment-provider-skrill {
background-image: url("../img/payments/skrill.svg");
}
.payment-provider-skrill-dark {
background-image: url("../img/payments/skrill-dark.svg");
}
.payment-provider-solo {
background-image: url("../img/payments/solo.svg");
}
.payment-provider-solo-dark {
background-image: url("../img/payments/solo-dark.svg");
}
.payment-provider-square {
background-image: url("../img/payments/square.svg");
}
.payment-provider-square-dark {
background-image: url("../img/payments/square-dark.svg");
}
.payment-provider-stripe {
background-image: url("../img/payments/stripe.svg");
}
.payment-provider-stripe-dark {
background-image: url("../img/payments/stripe-dark.svg");
}
.payment-provider-switch {
background-image: url("../img/payments/switch.svg");
}
.payment-provider-switch-dark {
background-image: url("../img/payments/switch-dark.svg");
}
.payment-provider-tpay {
background-image: url("../img/payments/tpay.svg");
}
.payment-provider-tpay-dark {
background-image: url("../img/payments/tpay-dark.svg");
}
.payment-provider-ukash {
background-image: url("../img/payments/ukash.svg");
}
.payment-provider-ukash-dark {
background-image: url("../img/payments/ukash-dark.svg");
}
.payment-provider-unionpay {
background-image: url("../img/payments/unionpay.svg");
}
.payment-provider-unionpay-dark {
background-image: url("../img/payments/unionpay-dark.svg");
}
.payment-provider-verifone {
background-image: url("../img/payments/verifone.svg");
}
.payment-provider-verifone-dark {
background-image: url("../img/payments/verifone-dark.svg");
}
.payment-provider-verisign {
background-image: url("../img/payments/verisign.svg");
}
.payment-provider-verisign-dark {
background-image: url("../img/payments/verisign-dark.svg");
}
.payment-provider-visa {
background-image: url("../img/payments/visa.svg");
}
.payment-provider-visa-dark {
background-image: url("../img/payments/visa-dark.svg");
}
.payment-provider-webmoney {
background-image: url("../img/payments/webmoney.svg");
}
.payment-provider-webmoney-dark {
background-image: url("../img/payments/webmoney-dark.svg");
}
.payment-provider-westernunion {
background-image: url("../img/payments/westernunion.svg");
}
.payment-provider-westernunion-dark {
background-image: url("../img/payments/westernunion-dark.svg");
}
.payment-provider-worldpay {
background-image: url("../img/payments/worldpay.svg");
}
.payment-provider-worldpay-dark {
background-image: url("../img/payments/worldpay-dark.svg");
}
.payment-xs {
width: 2.49999rem;
height: 1.5rem;
}
.payment-sm {
width: 3.33332rem;
height: 2rem;
}
.payment-md {
width: 6.66664rem;
height: 4rem;
}
.payment-lg {
width: 9.16663rem;
height: 5.5rem;
}
.payment-xl {
width: 11.66662rem;
height: 7rem;
}
.payment-2xl {
width: 18.33326rem;
height: 11rem;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/
/* prettier-ignore */
/* prettier-ignore */

View File

@ -0,0 +1,8 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/

View File

@ -0,0 +1,10 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/
/* prettier-ignore */
/* prettier-ignore */

View File

@ -0,0 +1,8 @@
/*!
* Tabler v1.0.0-beta19 (https://tabler.io)
* @version 1.0.0-beta19
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,51 @@
.timeline {
position: relative;
max-width: 600px;
margin: 0 auto;
padding: 20px 0;
}
/* 中间竖线 */
.timeline::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 30px;
width: 4px;
background: #4B5320;
}
.timeline-item {
position: relative;
padding-left: 60px;
margin-bottom: 20px;
}
.timeline-item:last-child {
margin-bottom: 0;
}
/* 圆形节点 */
.timeline-item::before {
content: "";
position: absolute;
top: 0;
left: 18px;
width: 24px;
height: 24px;
border-radius: 50%;
background: #4B5320;
border: 4px solid #fff;
box-shadow: 0 0 3px rgba(0,0,0,0.3);
}
.timeline-item time {
font-size: 0.9em;
color: #999;
}
.timeline-item h3 {
margin: 5px 0;
font-size: 1.2em;
color: #333;
}
.timeline-item p {
margin: 5px 0 0;
color: #555;
line-height: 1.5;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="#00732f" d="M0 0h640v160H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><path d="M0 320h640v160H0z"/><path fill="red" d="M0 0h220v480H0z"/></svg>

After

Width:  |  Height:  |  Size: 221 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill-opacity=".7" d="M-79.7 0H603v512H-79.7z"/></clipPath></defs><g fill-rule="evenodd" clip-path="url(#a)" transform="translate(74.7) scale(.9375)"><path fill="#fff" d="M-120 0h763.3v511.5H-120z"/><path d="M-118.3.6h760.9v216.1h-761z"/><path fill="#0061ff" d="M21.3 203.2h505V317h-505z"/><path fill="#e20000" d="M642.8 1.8V512H262L642.8 1.7zm-761.5 0V512H262L-118.7 1.7z"/><path fill="#ffd600" d="M440.4 203.3L364 184l64.9-49-79.7 11.4 41-69.5-70.7 41L332.3 37l-47.9 63.8-19.3-74-21.7 76.3-47.8-65 13.7 83.2L138.5 78l41 69.5-77.4-12.5 63.8 47.8L86 203.3h354.3z"/></g></svg>

After

Width:  |  Height:  |  Size: 668 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" height="480"><path fill="#e41e20" d="M0 0h640v480H0z"/><path id="a" d="M272 93.3c-4.6 0-12.3 1.5-12.2 5-13-2.1-14.3 3.2-13.5 8 1.2-1.9 2.7-3 3.9-3.1 1.7-.3 3.5.3 5.4 1.4a21.6 21.6 0 0 1 4.8 4.1c-4.6 1.1-8.2.4-11.8-.2a16.5 16.5 0 0 1-5.7-2.4c-1.5-1-2-2-4.3-4.3-2.7-2.8-5.6-2-4.7 2.3 2.1 4 5.6 5.8 10 6.6 2.1.3 5.3 1 8.9 1 3.6 0 7.6-.5 9.8 0-1.3.8-2.8 2.3-5.8 2.8-3 .6-7.5-1.8-10.3-2.4.3 2.3 3.3 4.5 9.1 5.7 9.6 2 17.5 3.6 22.8 6.5a37.3 37.3 0 0 1 10.9 9.2c4.7 5.5 5 9.8 5.2 10.8 1 8.8-2.1 13.8-7.9 15.4-2.8.7-8-.7-9.8-2.9-2-2.2-3.7-6-3.2-12 .5-2.2 3.1-8.3.9-9.5a273.7 273.7 0 0 0-32.3-15.1c-2.5-1-4.5 2.4-5.3 3.8a50.2 50.2 0 0 1-36-23.7c-4.2-7.6-11.3 0-10.1 7.3 1.9 8 8 13.8 15.4 18 7.5 4.1 17 8.2 26.5 8 5.2 1 5.1 7.6-1 8.9-12.1 0-21.8-.2-30.9-9-6.9-6.3-10.7 1.2-8.8 5.4 3.4 13.1 22.1 16.8 41 12.6 7.4-1.2 3 6.6 1 6.7-8 5.7-22.1 11.2-34.6 0-5.7-4.4-9.6-.8-7.4 5.5 5.5 16.5 26.7 13 41.2 5 3.7-2.1 7.1 2.7 2.6 6.4-18.1 12.6-27.1 12.8-35.3 8-10.2-4.1-11 7.2-5 11 6.7 4 23.8 1 36.4-7 5.4-4 5.6 2.3 2.2 4.8-14.9 12.9-20.8 16.3-36.3 14.2-7.7-.6-7.6 8.9-1.6 12.6 8.3 5.1 24.5-3.3 37-13.8 5.3-2.8 6.2 1.8 3.6 7.3a53.9 53.9 0 0 1-21.8 18c-7 2.7-13.6 2.3-18.3.7-5.8-2-6.5 4-3.3 9.4 1.9 3.3 9.8 4.3 18.4 1.3 8.6-3 17.8-10.2 24.1-18.5 5.5-4.9 4.9 1.6 2.3 6.2-12.6 20-24.2 27.4-39.5 26.2-6.7-1.2-8.3 4-4 9 7.6 6.2 17 6 25.4-.2 7.3-7 21.4-22.4 28.8-30.6 5.2-4.1 6.9 0 5.3 8.4-1.4 4.8-4.8 10-14.3 13.6-6.5 3.7-1.6 8.8 3.2 9 2.7 0 8.1-3.2 12.3-7.8 5.4-6.2 5.8-10.3 8.8-19.9 2.8-4.6 7.9-2.4 7.9 2.4-2.5 9.6-4.5 11.3-9.5 15.2-4.7 4.5 3.3 6 6 4.1 7.8-5.2 10.6-12 13.2-18.2 2-4.4 7.4-2.3 4.8 5-6 17.4-16 24.2-33.3 27.8-1.7.3-2.8 1.3-2.2 3.3l7 7c-10.7 3.2-19.4 5-30.2 8l-14.8-9.8c-1.3-3.2-2-8.2-9.8-4.7-5.2-2.4-7.7-1.5-10.6 1 4.2 0 6 1.2 7.7 3.1 2.2 5.7 7.2 6.3 12.3 4.7 3.3 2.7 5 4.9 8.4 7.7l-16.7-.5c-6-6.3-10.6-6-14.8-1-3.3.5-4.6.5-6.8 4.4 3.4-1.4 5.6-1.8 7.1-.3 6.3 3.7 10.4 2.9 13.5 0l17.5 1.1c-2.2 2-5.2 3-7.5 4.8-9-2.6-13.8 1-15.4 8.3a17 17 0 0 0-1.2 9.3c.8-3 2.3-5.5 4.9-7 8 2 11-1.3 11.5-6.1 4-3.2 9.8-3.9 13.7-7.1 4.6 1.4 6.8 2.3 11.4 3.8 1.6 5 5.3 6.9 11.3 5.6 7 .2 5.8 3.2 6.4 5.5 2-3.3 1.9-6.6-2.5-9.6-1.6-4.3-5.2-6.3-9.8-3.8-4.4-1.2-5.5-3-9.9-4.3 11-3.5 18.8-4.3 29.8-7.8l7.7 6.8c1.5.9 2.9 1.1 3.8 0 6.9-10 10-18.7 16.3-25.3 2.5-2.8 5.6-6.4 9-7.3 1.7-.5 3.8-.2 5.2 1.3 1.3 1.4 2.4 4.1 2 8.2-.7 5.7-2.1 7.6-3.7 11-1.7 3.5-3.6 5.6-5.7 8.3-4 5.3-9.4 8.4-12.6 10.5-6.4 4.1-9 2.3-14 2-6.4.7-8 3.8-2.8 8.1 4.8 2.6 9.2 2.9 12.8 2.2 3-.6 6.6-4.5 9.2-6.6 2.8-3.3 7.6.6 4.3 4.5-5.9 7-11.7 11.6-19 11.5-7.7 1-6.2 5.3-1.2 7.4 9.2 3.7 17.4-3.3 21.6-8 3.2-3.5 5.5-3.6 5 1.9-3.3 9.9-7.6 13.7-14.8 14.2-5.8-.6-5.9 4-1.6 7 9.6 6.6 16.6-4.8 19.9-11.6 2.3-6.2 5.9-3.3 6.3 1.8 0 6.9-3 12.4-11.3 19.4 6.3 10.1 13.7 20.4 20 30.5l19.2-214L320 139c-2-1.8-8.8-9.8-10.5-11-.7-.6-1-1-.1-1.4.9-.4 3-.8 4.5-1-4-4.1-7.6-5.4-15.3-7.6 1.9-.8 3.7-.4 9.3-.6a30.2 30.2 0 0 0-13.5-10.2c4.2-3 5-3.2 9.2-6.7a86.3 86.3 0 0 1-19.5-3.8 37.4 37.4 0 0 0-12-3.4zm.8 8.4c3.8 0 6.1 1.3 6.1 2.9 0 1.6-2.3 2.9-6.1 2.9s-6.2-1.5-6.2-3c0-1.6 2.4-2.8 6.2-2.8z"/><use width="100%" height="100%" transform="matrix(-1 0 0 1 640 0)" xlink:href="#a"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="red" d="M0 0h640v160H0z"/><path fill="#00f" d="M0 160h640v160H0z"/><path fill="orange" d="M0 320h640v160H0z"/></svg>

After

Width:  |  Height:  |  Size: 193 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="red" d="M0 0h640v243.6H0z"/><path d="M0 236.4h640V480H0z"/></g><path fill="#ffec00" fill-rule="evenodd" d="M228.7 148.2c165.2 43.3 59 255.6-71.3 167.2l-8.8 13.6c76.7 54.6 152.6 10.6 174-46.4 22.2-58.8-7.6-141.5-92.6-150l-1.3 15.6z"/><path fill="#ffec00" fill-rule="evenodd" d="M170 330.8l21.7 10.1-10.2 21.8-21.7-10.2zm149-99.5h24v24h-24zm-11.7-38.9l22.3-8.6 8.7 22.3-22.3 8.7zm-26-29.1l17.1-16.9 16.9 17-17 16.9zm-26.2-39.8l22.4 8.4-8.5 22.4-22.4-8.4zM316 270l22.3 8.9-9 22.2-22.2-8.9zm-69.9 70l22-9.3 9.5 22-22 9.4zm-39.5 2.8h24v24h-24zm41.3-116l-20.3-15-20.3 14.6 8-23-20.3-15h24.5l8.5-22.6 7.8 22.7 24.7-.3-19.6 15.3 7 23.4z"/><path fill="#fe0" fill-rule="evenodd" d="M336 346.4c-1.2.4-6.2 12.4-9.7 18.2l3.7 1c13.6 4.8 20.4 9.2 26.2 17.5a7.9 7.9 0 0 0 10.2.7s2.8-1 6.4-5c3-4.5 2.2-8-1.4-11.1-11-8-22.9-14-35.4-21.3z"/><path fill-rule="evenodd" d="M365.3 372.8a4.3 4.3 0 1 1-8.7 0 4.3 4.3 0 0 1 8.6 0zm-21.4-13.6a4.3 4.3 0 1 1-8.7 0 4.3 4.3 0 0 1 8.7 0zm10.9 7a4.3 4.3 0 1 1-8.7 0 4.3 4.3 0 0 1 8.7 0z"/><path fill="#fe0" fill-rule="evenodd" d="M324.5 363.7c-42.6-24.3-87.3-50.5-130-74.8-18.7-11.7-19.6-33.4-7-49.9 1.2-2.3 2.8-1.8 3.4-.5 1.5 8 6 16.3 11.4 21.5C247 288.4 290 315.8 334 345.6c-3.4 5.8-6 12.3-9.5 18z"/><path fill="#ffec00" fill-rule="evenodd" d="M297.2 305.5l17.8 16-16 17.8-17.8-16z"/><path fill="none" stroke="#000" stroke-width="3" d="M331.5 348.8l-125-75.5m109.6 58.1L274 304.1m18.2 42.7L249.3 322"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="#3a7dce" fill-rule="evenodd" d="M0 0h640v480H0z"/><path fill="#fff" d="M184.8 225.3c-2.9-5.9-2.9-5.9-2.9-11.8-1.4 0-1.7.3-2.5 0-.8-.2-1.2 5.5-3.9 4.4-.4-.6 2-4.7-.6-6.4-.8-.5.2-3.9-.2-5.4 0 0-3.3 1.8-5.7-4.4-1.3-1.6-3 1.5-3 1.5s.8 1.9-.5 2.3c-1.9-1.4-3.2-.6-5.6-2.5-2.3-2 .5-4.1-4-5.7 3-7.4 3-6 10.2-8.9-4.4-3-4.4-3-7.3-7.4-4.3-1.4-5.7-3-10-5.9-5.8-7.3-8.7-22.1-8.7-32.4 3.6-3.5 8.6 11.8 15.9 16.2l10 4.4c5.8 3 7.3 6 11.6 8.9l13 4.4c5.8 4.4 8.7 10.3 13 11.8 4.7 0 5.6-2.7 7.1-3 8.5-.4 12.8-1.5 14.5-4 1.7-2.2 5.8 1.1 17.4-3.3l-1.5-6s3.1-2.5 7.3-1.4c-.2-2.7-.4-9.9 3.7-13.1-2.5-2.7-.9-4.6-.9-4.6s2.3-2.3 2.6-3.5c-1.2-6.5 1-6.6 1.6-8.5s-2-1.2-1.3-3.9c.7-2.6 4.9-3.2 5.5-5.4.5-2.2-1.2-3.3-1.1-3.8.9-2 .1-7 0-8.9 7.7-2 10.3-8.5 13-5.9 1.4-8.8 2.8-11.8 11.5-11.8 1.2-2.7-3.1-5-1.4-5.9 2.9-.3 5-.2 8.5 4.3 1 1.4 1.2-2 2.3-2.4 1-.4 3.7-.4 4-2.2.5-1.8 1-4.1 2.5-7 1.2-2.5 2.2.9 3.2 5.6 6.1.2 19.9 1.6 25.7 3.2 4.3 1.1 7.2-1.2 11.3-1.6 3.1 3.1 6 .8 7.6 7.5 2.3 3.6 6 .3 6.9 1.3 4.8 13.6 21.4 4.5 22.7 4.7 2 0 4.7 6 6.3 6 2.8-.5 2-2.4 4.4-1.7-.7 5.2 4.6 11 4.6 14.9 0 0 1.3.6 2.5-.5s2.3-4 3.3-4l6.5 1.2c7.8 2.8 11.8 3.4 14.8 4.8 1.5 2.6 2.8 4 5.7 3.5 2.4 1.6.6 3.8 2 3.9 3-1.5 3.9-3.1 6.8-1.6a17.6 17.6 0 0 1 7.2 7.4c0 1.4-1.5 7.3 0 16.2.7 3 1 5.3 4.1 10.3-.8 5.3 4 14 4 16.2 0 3-2.4 4.5-3.8 7.5 5.8 4.4 0 11.8-2.9 16.2 21.7 4.4 11.6 13.3 28.9 8.8-4.3 10.4-2.8 9.5 1.5 19.9-8.6 5.9-.2 7.7-6 15-.3.5 3.5 6.5 8.8 6.5-1.4 11.8-5.8 7.4-4.3 25-11.4-.2-6.8 13.3-14.4 11.9.4 8.4 4.3 9.2 2.8 17.7-5.7 1.5-5.7 1.5-8.6 5.9l-4.4-1.5c-1.4 7.4-4.3 8.9 0 16.3H439c-.1 2.5 2.5 3.2 3 5.9-.3 1-8.3 5.7-14.5 5.9-1.6 3.6 4.3 7.5 4 9.3-6.8 1.4-9.8 9.9-9.8 9.9s3.5 1.4 2.9 3c-1.9-1.5-2.9-1.6-5.8-1.6-1.4.4-5 0-8.3 5.8-3.7 1.2-5.5.8-8.3 4.6-1.2-3.7-3 0-5.2 1.4s-5.1 4.9-5.5 4.7c0-1 1.3-4.7 1.3-4.7l-7.2 1.5-.9.1c-.5 0-.4-4.3-1.8-4.1-1.3.1-5.2 5.5-6.6 5.6-1.3.2-1.7-1.7-2.9-1.5-1.1.2-3.4 5.6-4.2 5.8-.8.1-4-3.4-6.8-2.9-14.2 5.1-16.4-10-18.7-1.5-3-1.6-2.4-.7-5.4.1-2 .5-2.1-2.6-3.9-2.5-3.4 0-3.2 3.4-5.1 2.4-1.5-7-10.8-5.7-11.7-8.6-.7-3.1 4-3 5.6-5.2 1.1-3-1.3-4.1 3.5-7 6.2-4.3 2.6-6 3.7-9.2 2-4.6 2-5.8.4-9.9 0 0-4.9-13.2-5.8-13.2-3-.9-3 4.9-7.2 6.4-8.6 3-24-7.5-26.6-7.5-2.4 0-13.7 2.8-13.3-3-1.6 5.6-7.8 1.3-8.2 1.3-5.8 0-3.6 4.6-7.5 4.4-1.7-.6-19.5-1.6-19.5-1.6v3l-11.6-6-10-3c-8.7-2.9-4.4-10.3-18.8-5.8v-9H195c3-17.6 0-8.8-1.4-25l-5.8 1.5c-5.7-8 8-6.5-4.3-11.8 0 0 .2-8.8-2.9-6-.6.4 1.5 4.5 1.5 4.5-11.6-1.5-14.5-4.4-14.5-16.2 0 0 9.5 1.3 8.7 0a73 73 0 0 1-2.8-17.6c-.2-2 8.8-6.8 7-11.5 1.2-.4 4.4-.5 4.4-.5"/><path fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.1" d="M574.6 284.3a3 3 0 0 0 0 2.8c1-1.3.2-1.9 0-2.8z"/><path fill="none" stroke="#fff" stroke-linejoin="round" stroke-width="2" d="M203.3 167.8s-2.4-.3-1.9 1.8c.8-1.7 1.8-1.7 1.9-1.8zm.5-5c-1.3 0-3-.2-2.4 2 .8-1.7 2.4-1.9 2.4-2zm9.1 28.3s2.1-.1 1.6 2c-.8-1.6-1.5-1.9-1.6-2z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" height="480"><path fill="#74acdf" d="M0 0h640v480H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><g id="c" transform="translate(-64) scale(.96)"><path id="a" fill="#f6b40e" stroke="#85340a" stroke-width="1.1" d="M396.8 251.3l28.5 62s.5 1.2 1.3.9c.8-.4.3-1.5.3-1.5l-23.7-64m-.7 24.1c-.4 9.4 5.4 14.6 4.7 23-.8 8.5 3.8 13.2 5 16.5 1 3.3-1.3 5.2-.3 5.7s3-2.1 2.4-6.8c-.7-4.6-4.2-6-3.4-16.3.8-10.3-4.2-12.7-3-22"/><use width="100%" height="100%" transform="rotate(22.5 400 250)" xlink:href="#a"/><use width="100%" height="100%" transform="rotate(45 400 250)" xlink:href="#a"/><use width="100%" height="100%" transform="rotate(67.5 400 250)" xlink:href="#a"/><path id="b" fill="#85340a" d="M404.3 274.4c.5 9 5.6 13 4.6 21.3 2.2-6.5-3.1-11.6-2.8-21.2m-7.7-23.8l19.5 42.6-16.3-43.9"/><use width="100%" height="100%" transform="rotate(22.5 400 250)" xlink:href="#b"/><use width="100%" height="100%" transform="rotate(45 400 250)" xlink:href="#b"/><use width="100%" height="100%" transform="rotate(67.5 400 250)" xlink:href="#b"/></g><use width="100%" height="100%" transform="rotate(90 320 240)" xlink:href="#c"/><use width="100%" height="100%" transform="rotate(180 320 240)" xlink:href="#c"/><use width="100%" height="100%" transform="rotate(-90 320 240)" xlink:href="#c"/><circle cx="320" cy="240" r="26.7" fill="#f6b40e" stroke="#85340a" stroke-width="1.4"/><path id="h" fill="#843511" d="M329.1 234.3c-1.8 0-3.6.8-4.6 2.4 2 1.9 6.6 2 9.7-.2a7 7 0 0 0-5.1-2.2zm0 .4c1.7 0 3.4.8 3.6 1.6-2 2.3-5.3 2-7.4.4a4.3 4.3 0 0 1 3.8-2z"/><use width="100%" height="100%" transform="matrix(-1 0 0 1 640.2 0)" xlink:href="#d"/><use width="100%" height="100%" transform="matrix(-1 0 0 1 640.2 0)" xlink:href="#e"/><use width="100%" height="100%" transform="translate(18.1)" xlink:href="#f"/><use width="100%" height="100%" transform="matrix(-1 0 0 1 640.2 0)" xlink:href="#g"/><path fill="#85340a" d="M316 243.7a1.9 1.9 0 1 0 1.8 2.9 4 4 0 0 0 2.2.6h.2a3.9 3.9 0 0 0 2.3-.6 1.9 1.9 0 1 0 1.8-3c.5.3.8.7.8 1.3 0 .6-.5 1.2-1.2 1.2a1.2 1.2 0 0 1-1.2-1.2 3 3 0 0 1-2.6 1.7 3 3 0 0 1-2.5-1.7 1.2 1.2 0 0 1-1.3 1.2c-.6 0-1.2-.6-1.2-1.2s.3-1 .8-1.2zm2 5.5c-2.1 0-3 1.8-4.8 3 1-.4 1.9-1.2 3.3-2s2.7.2 3.5.2c.8 0 2-1 3.5-.2 1.4.8 2.3 1.6 3.3 2-1.9-1.2-2.7-3-4.8-3a5.5 5.5 0 0 0-2 .6 5.5 5.5 0 0 0-2-.7z"/><path fill="#85340a" d="M317.2 251.6c-.8 0-1.8.2-3.4.6 3.7-.8 4.5.5 6.2.5 1.6 0 2.4-1.3 6.1-.5-4-1.2-4.9-.4-6.1-.4-.8 0-1.4-.3-2.8-.2z"/><path fill="#85340a" d="M314 252.2h-.8c4.3.5 2.3 3 6.8 3s2.5-2.5 6.8-3c-4.5-.4-3.1 2.3-6.8 2.3-3.5 0-2.4-2.3-6-2.3zm9.7 6.7a3.7 3.7 0 0 0-7.4 0 3.8 3.8 0 0 1 7.4 0z"/><path id="e" fill="#85340a" d="M303.4 234.3c4.7-4.1 10.7-4.8 14-1.7a8 8 0 0 1 1.5 3.5c.4 2.3-.3 4.8-2.1 7.4l.8.4a14.6 14.6 0 0 0 1.6-9.4 13.3 13.3 0 0 0-.6-2.3c-4.5-3.7-10.7-4-15.2 2z"/><path id="d" fill="#85340a" d="M310.8 233c2.7 0 3.3.7 4.5 1.7 1.2 1 1.9.8 2 1 .3.2 0 .8-.3.6-.5-.2-1.3-.6-2.5-1.6s-2.5-1-3.7-1c-3.7 0-5.7 3-6.2 2.8-.3-.2 2.1-3.5 6.2-3.5z"/><use width="100%" height="100%" transform="translate(-18.4)" xlink:href="#h"/><circle id="f" cx="310.9" cy="236.3" r="1.9" fill="#85340a"/><path id="g" fill="#85340a" d="M305.9 237.5c3.5 2.7 7 2.5 9 1.3 2-1.3 2-1.7 1.6-1.7-.4 0-.8.4-2.4 1.3-1.7.8-4.1.8-8.2-.9z"/></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd"><path fill="#fff" d="M640 480H0V0h640z"/><path fill="#df0000" d="M640 480H0V320h640zm0-319.9H0V.1h640z"/></g></svg>

After

Width:  |  Height:  |  Size: 203 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g stroke-width="1pt"><path fill="#006" d="M0 0h640v480H0z"/><path fill="#fff" d="M0 0v28l307 222h38.7v-28L38.7 0H0zm345.7 0v28l-307 222H0v-28L307 0h38.7z"/><path fill="#fff" d="M144 0v250h57.6V0H144zM0 83.3v83.4h345.7V83.3H0z"/><path fill="#c00" d="M0 100v50h345.7v-50H0zM155.6 0v250H190V0h-34.5zM0 250l115.2-83.3H141L25.8 250H0zM0 0l115.2 83.3H89.5L0 18.6V0zm204.7 83.3L319.9 0h25.8L230.5 83.3h-25.8zm141 166.7l-115.2-83.3h25.7l89.5 64.7V250z"/><path fill="#fff" fill-rule="evenodd" d="M299.8 392.5l-43.7 3.8 6 43.4L232 408l-30.1 31.7 6-43.4-43.7-3.8 37.7-22.3-24.3-36.5 41 15.5 13.4-41.7 13.5 41.7 41-15.5-24.3 36.5m224.4 62.3L476 416.7l17.8 6.7 5.8-18.1 5.8 18.1 17.8-6.7-10.5 15.8 16.4 9.7-19 1.7 2.6 18.9-13-13.9-13.2 13.9 2.6-18.9-19-1.6m16.4-291.9L476 134.6l17.8 6.7 5.8-18.1 5.8 18.1 17.8-6.7-10.5 15.8 16.4 9.8-19 1.6 2.6 18.9-13-13.8-13.2 13.7 2.6-18.8-19-1.6M380.8 265l-10.5-15.8 17.8 6.7 5.8-18.1 5.9 18.1 17.8-6.7L407 265l16.4 9.7-19 1.7 2.7 18.9-13.2-13.9-13 13.9 2.5-18.9-19-1.6m216.3-38L570 221l17.8 6.7 5.8-18.1 5.9 18.1 17.8-6.7-10.5 15.8 16.3 9.7-19 1.7 2.6 18.8-13-13.8-13.2 13.8 2.6-18.8-19-1.7M542 320l-10.3 6.5 2.9-11.9-9.3-7.8 12.1-1 4.6-11.2 4.7 11.3 12.1.9-9.3 7.8 2.9 11.9"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill-opacity=".7" d="M106.3 0h1133.3v850H106.3z"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(.56472 0 0 .56482 -60 -.1)"><path fill="#0053a5" d="M0 0h1300v850H0z"/><g fill="#ffce00"><path d="M400 0h250v850H400z"/><path d="M0 300h1300v250H0z"/></g><g fill="#d21034"><path d="M475 0h100v850H475z"/><path d="M0 375h1300v100H0z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 450 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="#3f9c35" d="M.1 0h640v480H.1z"/><path fill="#ed2939" d="M.1 0h640v320H.1z"/><path fill="#00b9e4" d="M.1 0h640v160H.1z"/><circle cx="304" cy="240" r="72" fill="#fff"/><circle cx="320" cy="240" r="60" fill="#ed2939"/><path fill="#fff" d="M384 200l7.7 21.5 20.6-9.8-9.8 20.7L424 240l-21.5 7.7 9.8 20.6-20.6-9.8L384 280l-7.7-21.5-20.6 9.8 9.8-20.6L344 240l21.5-7.7-9.8-20.6 20.6 9.8L384 200z"/></svg>

After

Width:  |  Height:  |  Size: 473 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill-opacity=".7" d="M-85.3 0h682.6v512H-85.3z"/></clipPath></defs><g fill-rule="evenodd" clip-path="url(#a)" transform="translate(80) scale(.9375)"><path fill="#009" d="M-85.3 0h682.6v512H-85.3V0z"/><path fill="#FC0" d="M56.5 0l511 512.3V.3L56.5 0z"/><path fill="#FFF" d="M439.9 481.5L412 461.2l-28.6 20.2 10.8-33.2-28.2-20.5h35l10.8-33.2 10.7 33.3h35l-28 20.7 10.4 33zm81.3 10.4l-35-.1-10.7-33.3-10.8 33.2h-35l28.2 20.5-10.8 33.2 28.6-20.2 28 20.3-10.5-33 28-20.6zM365.6 384.7l28-20.7-35-.1-10.7-33.2-10.8 33.2-35-.1 28.2 20.5-10.8 33.3 28.6-20.3 28 20.4-10.5-33zm-64.3-64.5l28-20.6-35-.1-10.7-33.3-10.9 33.2h-34.9l28.2 20.5-10.8 33.2 28.6-20.2 27.9 20.3-10.4-33zm-63.7-63.6l28-20.7h-35L220 202.5l-10.8 33.2h-35l28.2 20.4-10.8 33.3 28.6-20.3 28 20.4-10.5-33zm-64.4-64.3l28-20.6-35-.1-10.7-33.3-10.9 33.2h-34.9L138 192l-10.8 33.2 28.6-20.2 27.9 20.3-10.4-33zm-63.6-63.9l27.9-20.7h-35L91.9 74.3 81 107.6H46L74.4 128l-10.9 33.2L92.1 141l27.8 20.4-10.3-33zm-64-64l27.9-20.7h-35L27.9 10.3 17 43.6h-35L10.4 64l-11 33.3L28.1 77l27.8 20.4-10.3-33zm-64-64L9.4-20.3h-35l-10.7-33.3L-47-20.4h-35L-53.7 0l-10.8 33.2L-35.9 13l27.8 20.4-10.3-33z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" height="480"><path fill="#00267f" d="M0 0h640v480H0z"/><path fill="#ffc726" d="M213.3 0h213.4v480H213.3z"/><path id="a" d="M319.8 135.5c-7 19-14 38.6-29.2 53.7 4.7-1.6 13-3 18.2-2.8v79.5l-22.4 3.3c-.8 0-1-1.3-1-3-2.2-24.7-8-45.5-14.8-67-.5-2.9-9-14-2.4-12 .8 0 9.5 3.6 8.2 1.9a85 85 0 0 0-46.4-24c-1.5-.3-2.4.5-1 2.2 22.4 34.6 41.3 75.5 41.1 124 8.8 0 30-5.2 38.7-5.2v56.1H320l2.5-156.7z"/><use width="100%" height="100%" transform="matrix(-1 0 0 1 639.5 0)" xlink:href="#a"/></svg>

After

Width:  |  Height:  |  Size: 577 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="#006a4e" d="M0 0h640v480H0z"/><circle cx="280" cy="240" r="160" fill="#f42a41"/></svg>

After

Width:  |  Height:  |  Size: 163 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd" stroke-width="1pt"><path d="M0 0h213.3v480H0z"/><path fill="#ffd90c" d="M213.3 0h213.4v480H213.3z"/><path fill="#f31830" d="M426.7 0H640v480H426.7z"/></g></svg>

After

Width:  |  Height:  |  Size: 248 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd"><path fill="#de0000" d="M640 479.6H.4V0H640z"/><path fill="#35a100" d="M639.6 480H0V240.2h639.6z"/><path fill="#fff300" d="M254.6 276.2l-106-72.4h131L320 86.6 360.4 204l131-.1-106 72.4 40.5 117.3-106-72.6L214 393.4"/></g></svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#d62612" d="M0 320h640v160H0z"/><path fill="#fff" d="M0 0h640v160H0z"/><path fill="#00966e" d="M0 160h640v160H0z"/></g></svg>

After

Width:  |  Height:  |  Size: 244 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill-opacity=".7" d="M0 0h640v480H0z"/></clipPath></defs><g fill-rule="evenodd" stroke-width="1pt" clip-path="url(#a)"><path fill="#e10011" d="M-32.5 0h720v480h-720z"/><path fill="#fff" d="M114.3 479.8l-146.8.2V0h146l94.3 30.4-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5 93.5 30.5-93.5 29.5"/></g></svg>

After

Width:  |  Height:  |  Size: 483 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill-opacity=".7" d="M-90.5 0H592v512H-90.5z"/></clipPath></defs><g fill-rule="evenodd" clip-path="url(#a)" transform="translate(84.9) scale(.9375)"><path fill="#00cf00" d="M-178 0l428.8 256L-178 512zm857.6 0L250.8 256l428.8 256z"/><path fill="red" d="M-178 0l428.8 256L679.6 0zm0 512l428.8-256 428.8 256z"/><path fill="#fff" d="M679.6 0h-79.9L-178 464.3V512h79.9L679.6 47.7z"/><path fill="#fff" d="M398.9 256a148 148 0 1 1-296.1 0 148 148 0 0 1 296 0z"/><path fill="#fff" d="M-178 0v47.7L599.7 512h79.9v-47.7L-98.1 0z"/><path fill="red" stroke="#00de00" stroke-width="3.9" d="M280 200.2l-19.3.3-10 16.4-9.9-16.4-19.2-.4 9.3-16.9-9.2-16.8 19.2-.4 10-16.4 9.9 16.5 19.2.4-9.3 16.8zm-64.6 111.6l-19.2.3-10 16.4-9.9-16.4-19.2-.4 9.3-16.9-9.2-16.8 19.2-.4 10-16.4 9.9 16.5 19.2.4-9.3 16.8zm130.6 0l-19.2.3-10 16.4-10-16.4-19.1-.4 9.3-16.9-9.3-16.8 19.2-.4 10-16.4 10 16.5 19.2.4-9.4 16.8z"/></g></svg>

After

Width:  |  Height:  |  Size: 991 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><defs><clipPath id="a"><path fill="gray" d="M67.6-154h666v666h-666z"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(.961 0 0 .7207 -65 111)"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#319400" d="M0-154h333v666H0z"/><path fill="#ffd600" d="M333-154h666v333H333z"/><path fill="#de2110" d="M333 179h666v333H333z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 415 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#00267f" d="M0 0h213.3v480H0z"/><path fill="#f31830" d="M426.7 0H640v480H426.7z"/></g></svg>

After

Width:  |  Height:  |  Size: 250 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480"><path fill="#21468b" d="M0 0h640v480H0z"/><path fill="#fff" d="M0 0h640v320H0z"/><path fill="#ae1c28" d="M0 0h640v160H0z"/></svg>

After

Width:  |  Height:  |  Size: 194 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.8 KiB

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