Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite

This commit is contained in:
X1627315083
2025-11-11 13:44:42 +08:00
24 changed files with 6899 additions and 4256 deletions

View File

@@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@@ -0,0 +1,947 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4292253" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe60a;</span>
<div class="name">角度</div>
<div class="code-name">&amp;#xe60a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe69e;</span>
<div class="name">水平翻转</div>
<div class="code-name">&amp;#xe69e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xec60;</span>
<div class="name">垂直翻转</div>
<div class="code-name">&amp;#xec60;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe8d1;</span>
<div class="name">clothes</div>
<div class="code-name">&amp;#xe8d1;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe647;</span>
<div class="name">材质</div>
<div class="code-name">&amp;#xe647;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe61b;</span>
<div class="name">IC-液化</div>
<div class="code-name">&amp;#xe61b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe751;</span>
<div class="name">上一层</div>
<div class="code-name">&amp;#xe751;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe604;</span>
<div class="name">上一层</div>
<div class="code-name">&amp;#xe604;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe68a;</span>
<div class="name">下一层</div>
<div class="code-name">&amp;#xe68a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe68b;</span>
<div class="name">上一层</div>
<div class="code-name">&amp;#xe68b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe6a1;</span>
<div class="name">审批</div>
<div class="code-name">&amp;#xe6a1;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe617;</span>
<div class="name">用户</div>
<div class="code-name">&amp;#xe617;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe601;</span>
<div class="name">使用次数</div>
<div class="code-name">&amp;#xe601;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe634;</span>
<div class="name">下拉</div>
<div class="code-name">&amp;#xe634;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe600;</span>
<div class="name">编辑</div>
<div class="code-name">&amp;#xe600;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64f;</span>
<div class="name">圆形</div>
<div class="code-name">&amp;#xe64f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe615;</span>
<div class="name">三角形</div>
<div class="code-name">&amp;#xe615;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe632;</span>
<div class="name">图层</div>
<div class="code-name">&amp;#xe632;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe616;</span>
<div class="name">平移</div>
<div class="code-name">&amp;#xe616;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe67b;</span>
<div class="name">橡皮</div>
<div class="code-name">&amp;#xe67b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64c;</span>
<div class="name">tx-fill-椭圆形</div>
<div class="code-name">&amp;#xe64c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe602;</span>
<div class="name">直线</div>
<div class="code-name">&amp;#xe602;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xec5f;</span>
<div class="name">线</div>
<div class="code-name">&amp;#xec5f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xea6f;</span>
<div class="name">正方形</div>
<div class="code-name">&amp;#xea6f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe62d;</span>
<div class="name">图层</div>
<div class="code-name">&amp;#xe62d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe685;</span>
<div class="name">点位</div>
<div class="code-name">&amp;#xe685;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe620;</span>
<div class="name">并集</div>
<div class="code-name">&amp;#xe620;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe668;</span>
<div class="name">并集</div>
<div class="code-name">&amp;#xe668;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe603;</span>
<div class="name">标签</div>
<div class="code-name">&amp;#xe603;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe85f;</span>
<div class="name">语言</div>
<div class="code-name">&amp;#xe85f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe626;</span>
<div class="name">撤销 返回 撤回 上一步</div>
<div class="code-name">&amp;#xe626;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe609;</span>
<div class="name">撤销 返回 撤回 上一步</div>
<div class="code-name">&amp;#xe609;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe66c;</span>
<div class="name">外套_长款外套1@1x</div>
<div class="code-name">&amp;#xe66c;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1762495405814') format('woff2'),
url('iconfont.woff?t=1762495405814') format('woff'),
url('iconfont.ttf?t=1762495405814') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-angle"></span>
<div class="name">
角度
</div>
<div class="code-name">.icon-angle
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-flip-horizontal"></span>
<div class="name">
水平翻转
</div>
<div class="code-name">.icon-flip-horizontal
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-flip-vertical"></span>
<div class="name">
垂直翻转
</div>
<div class="code-name">.icon-flip-vertical
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-clothes"></span>
<div class="name">
clothes
</div>
<div class="code-name">.icon-clothes
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-caizhi"></span>
<div class="name">
材质
</div>
<div class="code-name">.icon-caizhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-IC-yehua"></span>
<div class="name">
IC-液化
</div>
<div class="code-name">.icon-IC-yehua
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangyiceng"></span>
<div class="name">
上一层
</div>
<div class="code-name">.icon-shangyiceng
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangyiceng1"></span>
<div class="name">
上一层
</div>
<div class="code-name">.icon-shangyiceng1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiayiceng"></span>
<div class="name">
下一层
</div>
<div class="code-name">.icon-xiayiceng
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangyiceng2"></span>
<div class="name">
上一层
</div>
<div class="code-name">.icon-shangyiceng2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shenpi"></span>
<div class="name">
审批
</div>
<div class="code-name">.icon-shenpi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-yonghu"></span>
<div class="name">
用户
</div>
<div class="code-name">.icon-yonghu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-usetime"></span>
<div class="name">
使用次数
</div>
<div class="code-name">.icon-usetime
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiala"></span>
<div class="name">
下拉
</div>
<div class="code-name">.icon-xiala
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bianji"></span>
<div class="name">
编辑
</div>
<div class="code-name">.icon-bianji
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-circle"></span>
<div class="name">
圆形
</div>
<div class="code-name">.icon-circle
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-sanjiaoxing"></span>
<div class="name">
三角形
</div>
<div class="code-name">.icon-sanjiaoxing
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-tuceng"></span>
<div class="name">
图层
</div>
<div class="code-name">.icon-tuceng
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-move"></span>
<div class="name">
平移
</div>
<div class="code-name">.icon-move
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiangpi_huaban1"></span>
<div class="name">
橡皮
</div>
<div class="code-name">.icon-xiangpi_huaban1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-tx-fill-tuoyuanxing"></span>
<div class="name">
tx-fill-椭圆形
</div>
<div class="code-name">.icon-tx-fill-tuoyuanxing
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zhixian"></span>
<div class="name">
直线
</div>
<div class="code-name">.icon-zhixian
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xian"></span>
<div class="name">
线
</div>
<div class="code-name">.icon-xian
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-checkbox-full"></span>
<div class="name">
正方形
</div>
<div class="code-name">.icon-checkbox-full
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-tuceng1"></span>
<div class="name">
图层
</div>
<div class="code-name">.icon-tuceng1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dianwei"></span>
<div class="name">
点位
</div>
<div class="code-name">.icon-dianwei
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bingji"></span>
<div class="name">
并集
</div>
<div class="code-name">.icon-bingji
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-bingji1"></span>
<div class="name">
并集
</div>
<div class="code-name">.icon-bingji1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-biaoqian"></span>
<div class="name">
标签
</div>
<div class="code-name">.icon-biaoqian
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-yuyan"></span>
<div class="name">
语言
</div>
<div class="code-name">.icon-yuyan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fanchehui"></span>
<div class="name">
撤销 返回 撤回 上一步
</div>
<div class="code-name">.icon-fanchehui
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chehui"></span>
<div class="name">
撤销 返回 撤回 上一步
</div>
<div class="code-name">.icon-chehui
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-a-waitao_changkuanwaitao11x"></span>
<div class="name">
外套_长款外套1@1x
</div>
<div class="code-name">.icon-a-waitao_changkuanwaitao11x
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-angle"></use>
</svg>
<div class="name">角度</div>
<div class="code-name">#icon-angle</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-flip-horizontal"></use>
</svg>
<div class="name">水平翻转</div>
<div class="code-name">#icon-flip-horizontal</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-flip-vertical"></use>
</svg>
<div class="name">垂直翻转</div>
<div class="code-name">#icon-flip-vertical</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-clothes"></use>
</svg>
<div class="name">clothes</div>
<div class="code-name">#icon-clothes</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-caizhi"></use>
</svg>
<div class="name">材质</div>
<div class="code-name">#icon-caizhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-IC-yehua"></use>
</svg>
<div class="name">IC-液化</div>
<div class="code-name">#icon-IC-yehua</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangyiceng"></use>
</svg>
<div class="name">上一层</div>
<div class="code-name">#icon-shangyiceng</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangyiceng1"></use>
</svg>
<div class="name">上一层</div>
<div class="code-name">#icon-shangyiceng1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiayiceng"></use>
</svg>
<div class="name">下一层</div>
<div class="code-name">#icon-xiayiceng</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangyiceng2"></use>
</svg>
<div class="name">上一层</div>
<div class="code-name">#icon-shangyiceng2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shenpi"></use>
</svg>
<div class="name">审批</div>
<div class="code-name">#icon-shenpi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yonghu"></use>
</svg>
<div class="name">用户</div>
<div class="code-name">#icon-yonghu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-usetime"></use>
</svg>
<div class="name">使用次数</div>
<div class="code-name">#icon-usetime</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiala"></use>
</svg>
<div class="name">下拉</div>
<div class="code-name">#icon-xiala</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bianji"></use>
</svg>
<div class="name">编辑</div>
<div class="code-name">#icon-bianji</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-circle"></use>
</svg>
<div class="name">圆形</div>
<div class="code-name">#icon-circle</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-sanjiaoxing"></use>
</svg>
<div class="name">三角形</div>
<div class="code-name">#icon-sanjiaoxing</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-tuceng"></use>
</svg>
<div class="name">图层</div>
<div class="code-name">#icon-tuceng</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-move"></use>
</svg>
<div class="name">平移</div>
<div class="code-name">#icon-move</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiangpi_huaban1"></use>
</svg>
<div class="name">橡皮</div>
<div class="code-name">#icon-xiangpi_huaban1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-tx-fill-tuoyuanxing"></use>
</svg>
<div class="name">tx-fill-椭圆形</div>
<div class="code-name">#icon-tx-fill-tuoyuanxing</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zhixian"></use>
</svg>
<div class="name">直线</div>
<div class="code-name">#icon-zhixian</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xian"></use>
</svg>
<div class="name">线</div>
<div class="code-name">#icon-xian</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-checkbox-full"></use>
</svg>
<div class="name">正方形</div>
<div class="code-name">#icon-checkbox-full</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-tuceng1"></use>
</svg>
<div class="name">图层</div>
<div class="code-name">#icon-tuceng1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dianwei"></use>
</svg>
<div class="name">点位</div>
<div class="code-name">#icon-dianwei</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bingji"></use>
</svg>
<div class="name">并集</div>
<div class="code-name">#icon-bingji</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-bingji1"></use>
</svg>
<div class="name">并集</div>
<div class="code-name">#icon-bingji1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-biaoqian"></use>
</svg>
<div class="name">标签</div>
<div class="code-name">#icon-biaoqian</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yuyan"></use>
</svg>
<div class="name">语言</div>
<div class="code-name">#icon-yuyan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fanchehui"></use>
</svg>
<div class="name">撤销 返回 撤回 上一步</div>
<div class="code-name">#icon-fanchehui</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chehui"></use>
</svg>
<div class="name">撤销 返回 撤回 上一步</div>
<div class="code-name">#icon-chehui</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-a-waitao_changkuanwaitao11x"></use>
</svg>
<div class="name">外套_长款外套1@1x</div>
<div class="code-name">#icon-a-waitao_changkuanwaitao11x</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@@ -1,18 +1,30 @@
@font-face {
font-family: "iconfont"; /* Project id 4292253 */
src: url('iconfont.woff2?t=1759888699816') format('woff2'),
url('iconfont.woff?t=1759888699816') format('woff'),
url('iconfont.ttf?t=1759888699816') format('truetype');
src: url('iconfont.woff2?t=1762495405814') format('woff2'),
url('iconfont.woff?t=1762495405814') format('woff'),
url('iconfont.ttf?t=1762495405814') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 1.6rem;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-angle:before {
content: "\e60a";
}
.icon-flip-horizontal:before {
content: "\e69e";
}
.icon-flip-vertical:before {
content: "\ec60";
}
.icon-clothes:before {
content: "\e8d1";
}

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,27 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "8875396",
"name": "角度",
"font_class": "angle",
"unicode": "e60a",
"unicode_decimal": 58890
},
{
"icon_id": "15551512",
"name": "水平翻转",
"font_class": "flip-horizontal",
"unicode": "e69e",
"unicode_decimal": 59038
},
{
"icon_id": "46016160",
"name": "垂直翻转",
"font_class": "flip-vertical",
"unicode": "ec60",
"unicode_decimal": 60512
},
{
"icon_id": "20183053",
"name": "clothes",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2595,7 +2595,7 @@ export class CreateImageLayerCommand extends Command {
// 生成图层名称
const fileName =
this.layerName || `图片 ${new Date().toLocaleTimeString()}`;
this.layerName || `${new Date().toLocaleString()}`;
this.fabricImage.set({
id: this.imageId,

View File

@@ -589,11 +589,11 @@ function handleLayerClick(layer, event) {
layerManager?.setAllActiveGroupLayerCanvasObject?.(layer);
setActiveLayer(layer.children[0].id, { parentId: layer.id });
} else {
// 选中画布中的图层对象
layerManager?.selectLayerObjects(layer.id);
// 否则直接设置当前图层为活动图层
setActiveLayer(layer.id);
layerManager?.updateLayersObjectsInteractivity();
// 选中画布中的图层对象
layerManager?.selectLayerObjects(layer.id);
}
}
lastSelectedIndex.value = sortableRootLayers.value.findIndex((l) => l.id === layer.id);

View File

@@ -0,0 +1,729 @@
<template>
<transition name="fade">
<div
class="select-menu-panel"
v-if="visible"
:class="{ active: !closePanel }"
>
<div class="btn" @click="setClosePanel">
<i class="fi fi-br-angle-left"></i>
</div>
<!-- 变换工具顶部 -->
<div class="panel-select">
<!-- <div class="panel-header">
<div class="header-title">变换工具</div>
</div> -->
<!-- 分割线 -->
<!-- <div class="panel-divider"></div> -->
<!-- 变换工具内容 -->
<div class="tool-content">
<div
class="object-item"
v-for="v in activeObjects"
:key="v.id"
>
<div class="title">{{ v.layer?.name }}</div>
<div class="list">
<div>
<span class="label">W</span>
<input
type="number"
:value="v.width"
disabled
/>
</div>
<div>
<span class="label">H</span>
<input
type="number"
:value="v.height"
disabled
/>
</div>
<!-- <div>
<span class="label">X</span>
<input type="number" :value="v.left" disabled />
</div>
<div>
<span class="label">Y</span>
<input type="number" :value="v.top" disabled />
</div> -->
<div>
<span class="label iconfont icon-angle"></span>
<input
type="number"
:value="v.angle"
@change="(e) => changeAngle(e, v)"
/>
</div>
<div class="btn" @click="clickflipHorizontal(v)">
<i class="iconfont icon-flip-horizontal"></i>
<p class="tip">
{{ t("Canvas.flipHorizontal") }}
</p>
</div>
<div class="btn" @click="clickflipVertical(v)">
<i class="iconfont icon-flip-vertical"></i>
<p class="tip">
{{ t("Canvas.flipVertical") }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</transition>
</template>
<script setup>
import showViewVideo from "@/tool/mount";
import { ref, onMounted, watch, onUnmounted } from "vue";
import { useI18n } from "vue-i18n";
import { ToolCommand } from "../commands/ToolCommands";
import { OperationType } from "../utils/layerHelper";
import { TransformCommand } from "../commands/StateCommands";
const props = defineProps({
canvas: {
type: Object,
required: true,
},
commandManager: {
type: Object,
required: true,
},
selectManager: {
type: Object,
required: true,
},
layerManager: {
type: Object,
required: true,
},
toolManager: {
type: Object,
required: true,
},
activeTool: {
type: String,
required: false,
default: null,
},
});
// 响应式数据
const visible = ref(false);
//打开隐藏操作面板
const closePanel = ref(false);
const setClosePanel = () => {
closePanel.value = !closePanel.value;
};
// 国际化
const { t } = useI18n();
onMounted(() => {
setupCanvasListeners();
});
onUnmounted(() => {
removeCanvasListeners();
});
// 监听 activeTool 变化
watch(
() => props.activeTool,
(newTool) => {
if (newTool === OperationType.SELECT) {
show();
} else {
close();
}
},
{ immediate: true }
);
/**
* 显示面板
*/
function show() {
if (activeObjects.value.length === 0) return;
visible.value = true;
closePanel.value = true;
}
/**
* 关闭面板
*/
function close() {
visible.value = false;
}
// 获取当前选中的对象
const activeObjects = ref([]);
const getActiveObject = (e) => {
console.log("==========切换激活对象", e);
activeObjects.value = e.selected.map((v) => v);
activeObjects.value.forEach((v) => {
v.layer = props.layerManager.getLayerById(v.layerId);
});
if (activeObjects.value.length === 0) {
close();
} else {
show(false);
}
};
const lastSelectLayerId = inject("lastSelectLayerId");
const layers = inject("layers");
const transformObject = (activeObj, initialState, finalState) => {
const transformCmd = new TransformCommand({
canvas: props.canvas,
objectId: activeObj.id,
initialState,
finalState,
objectType: activeObj.type,
name: `变换 ${activeObj.type || "对象"}`,
layerManager: props.layerManager,
layers: layers,
lastSelectLayerId: lastSelectLayerId,
});
props.layerManager.commandManager.execute(transformCmd, {
name: "对象修改",
});
};
/**
* 根据左上角坐标计算旋转后的新坐标
* @param {number} W - 宽度
* @param {number} H - 高度
* @param {number} currentX - 当前左上角x坐标
* @param {number} currentY - 当前左上角y坐标
* @param {number} currentAngleDeg - 当前角度(度)
* @param {number} newAngleDeg - 新角度(度)
* @returns {Object} 旋转后的左上角坐标 {x, y}
*/
function calculateRotatedTopLeftDeg(
W,
H,
currentX,
currentY,
currentAngleDeg,
newAngleDeg
) {
const currentAngle = (currentAngleDeg * Math.PI) / 180;
const newAngle = (newAngleDeg * Math.PI) / 180;
// 1. 用当前角度计算中心点位置
const cosCurrent = Math.cos(currentAngle);
const sinCurrent = Math.sin(currentAngle);
const Cx = currentX + (W / 2) * cosCurrent - (H / 2) * sinCurrent;
const Cy = currentY + (W / 2) * sinCurrent + (H / 2) * cosCurrent;
// 2. 用新角度计算旋转后的左上角位置
const cosNew = Math.cos(newAngle);
const sinNew = Math.sin(newAngle);
const newX = Cx + (-W / 2) * cosNew - (-H / 2) * sinNew;
const newY = Cy + (-W / 2) * sinNew + (-H / 2) * cosNew;
return { x: newX, y: newY };
}
// 改变角度
const changeAngle = (e, obj) => {
const initialState = TransformCommand.captureTransformState(obj);
const finalState = { ...initialState };
const angle = e.target.value;
if (obj.originX === "left" && obj.originY === "top") {
const width = obj.width * obj.scaleX;
const height = obj.height * obj.scaleY;
const left = obj.left;
const top = obj.top;
const { x, y } = calculateRotatedTopLeftDeg(
width,
height,
left,
top,
obj.angle,
angle
);
finalState.left = x;
finalState.top = y;
}
finalState.angle = angle;
transformObject(obj, initialState, finalState);
};
// 水平翻转
const clickflipHorizontal = (obj) => {
const initialState = TransformCommand.captureTransformState(obj);
const finalState = { ...initialState };
finalState.flipX = !finalState.flipX;
transformObject(obj, initialState, finalState);
};
// 垂直翻转
const clickflipVertical = (obj) => {
const initialState = TransformCommand.captureTransformState(obj);
const finalState = { ...initialState };
finalState.flipY = !finalState.flipY;
transformObject(obj, initialState, finalState);
};
const updateActiveObjects = (arrs, keys) => {
arrs.forEach((v) => {
activeObjects.value.forEach((item) => {
if (item.id === v.id) {
keys.forEach((k) => {
item[k] =
typeof v[k] === "number"
? Number(v[k].toFixed(3))
: v[k];
});
}
});
activeObjects.value = [...activeObjects.value];
});
};
const objectRotatingChange = (e) => {
const arrs = [];
if (e.target._objects) {
e.target._objects.forEach((v) => arrs.push(v));
} else {
arrs.push(e.target);
}
updateActiveObjects(arrs, ["angle"]);
};
/**
* 设置画布事件监听
*/
function setupCanvasListeners() {
if (!props.canvas) return;
// 鼠标事件
props.canvas.on("selection:created", getActiveObject);
props.canvas.on("selection:updated", getActiveObject);
// props.canvas.on("selection:cleared", () => console.log("selection:cleared"));
props.canvas.on("object:rotating", objectRotatingChange);
}
/**
* 移除画布事件监听
*/
function removeCanvasListeners() {
if (!props.canvas) return;
// 移除鼠标事件
props.canvas.off("selection:created", getActiveObject);
props.canvas.off("selection:updated", getActiveObject);
// props.canvas.off("selection:cleared");
props.canvas.off("object:rotating", objectRotatingChange);
}
</script>
<style scoped lang="less">
.select-menu-panel {
position: absolute;
bottom: 22px;
left: 20px;
right: 20px;
max-width: min(90vw, 640px);
margin: 0 auto;
background-color: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border-radius: 8px;
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
z-index: 1000;
color: #333;
border: 1px solid rgba(0, 0, 0, 0.05);
user-select: none;
&.active {
transform: translateY(100%);
> .btn {
> i {
transform: rotate(90deg);
}
}
}
> .btn {
width: 100%;
height: 22px;
text-align: center;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
> i {
font-size: 1.4rem;
transform: rotate(270deg);
}
}
}
/* 平板和手机适配 */
@media screen and (max-width: 768px) {
.select-menu-panel {
bottom: 15px;
left: 15px;
right: 15px;
max-width: calc(100vw - 30px);
border-radius: 6px;
}
}
@media screen and (max-width: 480px) {
.select-menu-panel {
bottom: 10px;
left: 10px;
right: 10px;
max-width: calc(100vw - 20px);
}
}
.select-menu-panel.is-active {
transform: translateY(0);
}
.panel-header {
padding: 8px 15px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
background-color: rgba(255, 255, 255, 0.8);
border-radius: 8px 8px 0 0;
}
.header-title {
font-size: 13px;
font-weight: 500;
color: #333;
text-align: left;
}
.panel-select {
// padding: 0 0 10px;
}
/* 平板适配 */
@media screen and (max-width: 768px) {
.panel-header {
padding: 6px 12px;
border-radius: 6px 6px 0 0;
}
}
/* 手机适配 */
@media screen and (max-width: 480px) {
.panel-header {
padding: 5px 10px;
}
.header-title {
font-size: 12px;
}
}
.tool-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.05);
border: none;
border-radius: 6px;
padding: 6px;
color: #333;
cursor: pointer;
transition: all 0.2s;
}
.tool-btn span {
margin-top: 0;
font-size: 12px;
}
.tool-btn svg {
width: 24px;
height: 24px;
}
.tool-btn:hover {
background-color: rgba(0, 0, 0, 0.08);
}
.tool-btn.active {
background-color: #007aff;
color: white;
}
.panel-divider {
height: 1px;
background-color: rgba(0, 0, 0, 0.05);
margin: 0 10px 5px 10px;
}
.tool-content {
overflow-y: auto;
max-height: 220px;
margin-top: 10px;
padding: 0 10px;
> .object-item {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 10px 0;
&:last-child {
border-bottom: none;
}
> .title {
text-align: left;
margin-bottom: 5px;
}
> .list {
display: flex;
> div {
margin-right: 15px;
font-size: 14px;
color: #474747;
> .label {
margin-right: 5px;
}
> input {
width: 65px;
}
.iconfont {
font-size: 14px;
}
}
> div.btn {
position: relative;
min-width: 24px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
transition: background-color 0.2s;
background-color: rgba(0, 0, 0, 0);
> .tip {
position: absolute;
top: -5px;
left: 50%;
transform: translate(-50%, -100%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 0.4rem 0.8rem;
border-radius: 0.4rem;
margin-left: 0.8rem;
font-size: 1.2rem;
white-space: nowrap;
pointer-events: none;
display: none;
&::after {
content: "";
position: absolute;
top: 97%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid rgba(0, 0, 0, 0.8);
}
}
&:hover {
background-color: rgba(0, 0, 0, 0.08);
> .tip {
display: block;
}
}
}
}
}
}
/* 平板适配 - 每行4个按钮 */
@media screen and (max-width: 768px) {
.tool-content {
grid-template-columns: repeat(3, 1fr);
gap: 8px 6px;
padding: 0 8px;
}
}
/* 手机适配 - 每行3个按钮 */
@media screen and (max-width: 480px) {
.tool-content {
grid-template-columns: repeat(3, 1fr);
gap: 6px 4px;
padding: 0 6px;
}
.header-btn {
font-size: 11px;
padding: 2px 4px;
min-width: 28px;
}
}
.action-btn {
display: flex;
// flex-direction: column;
flex-direction: row;
align-items: center;
justify-content: center;
background: none;
border: none;
color: #333;
cursor: pointer;
padding: 0;
gap: 4px;
.c-svg {
width: auto;
}
}
.action-btn svg {
width: 22px;
height: 22px;
margin-bottom: 8px;
}
.btn-text {
display: block;
font-size: 12px;
text-align: center;
}
.action-btn:hover {
color: #007aff;
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* 对话框样式 */
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
}
.dialog-container {
background-color: #ffffff;
border-radius: 12px;
width: 280px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid rgba(0, 0, 0, 0.05);
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 15px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.dialog-header h3 {
margin: 0;
font-size: 15px;
color: #333;
font-weight: 500;
}
.close-dialog-btn {
background: none;
border: none;
color: #666;
font-size: 18px;
cursor: pointer;
padding: 0;
line-height: 1;
}
.dialog-content {
padding: 15px;
}
.feather-control {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.slider-control {
flex: 1;
height: 4px;
background: rgba(0, 0, 0, 0.1);
border-radius: 2px;
-webkit-appearance: none;
appearance: none;
margin-right: 10px;
}
.slider-control::-webkit-slider-thumb {
-webkit-appearance: none;
width: 12px;
height: 12px;
border-radius: 50%;
background: #007aff;
cursor: pointer;
}
.feather-value {
font-size: 14px;
color: #333;
min-width: 40px;
text-align: right;
}
.dialog-buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 15px;
}
.cancel-btn,
.confirm-btn {
padding: 8px 16px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
border: none;
}
.cancel-btn {
background-color: rgba(0, 0, 0, 0.05);
color: #333;
}
.confirm-btn {
background-color: #007aff;
color: white;
}
.color-picker {
width: 100%;
height: 40px;
border: none;
border-radius: 6px;
cursor: pointer;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s, transform 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(30px);
}
</style>

View File

@@ -0,0 +1,31 @@
### 鼠标事件
- `mouse:down`:鼠标按下时触发
- `mouse:up`:鼠标释放时触发
- `mouse:move`:鼠标移动时触发
- `mouse:over`:鼠标移入画布时触发
- `mouse:out`:鼠标移出画布时触发
### 对象交互事件
- `object:selected`:对象被选中时触发
- `object:modified`:对象属性(如位置、大小)修改后触发
- `object:rotating`:对象旋转过程中触发
- `object:scaling`:对象缩放过程中触发
- `object:skewing`:对象倾斜过程中触发
### 画布操作事件
- `before:render`:画布即将重绘前触发
- `after:render`:画布重绘完成后触发
- `selection:created`:选中对象集合创建时触发
- `selection:updated`:选中对象集合更新时触发
- `selection:cleared`:选中对象集合清除时触发
### 其他事件
- `object:added`:对象添加到画布时触发
- `object:removed`:对象从画布移除时触发
- `object:rotated`:对象旋转完成时触发
- `object:scaled`:对象缩放完成时触发
- `object:skewed`:对象倾斜完成时触发

View File

@@ -34,6 +34,7 @@ import LayersPanel from "./components/LayersPanel/LayersPanel.vue";
import BrushControlPanel from "./components/BrushControlPanel.vue";
import TextEditorPanel from "./components/TextEditorPanel.vue"; // 引入文本编辑面板
import LiquifyPanel from "./components/LiquifyPanel.vue"; // 引入液化编辑面板
import SelectMenuPanel from "./components/SelectMenuPanel.vue"; // 引入选择工具菜单组件
import SelectionPanel from "./components/SelectionPanel.vue"; // 引入选区面板
import { LayerType, OperationType } from "./utils/layerHelper.js";
import { ToolManager } from "./managers/ToolManager.js";
@@ -619,12 +620,22 @@ function updateCanvasSize() {
function updateCanvasColor() {
canvasManager.setCanvasColor(canvasColor.value);
}
function createLayerName(){
const layer = t("Canvas.layer")
// 检查图层名称是否已存在
let layerIndex = 1;
let layerName = `${layer + " " + layerIndex}`;
while (layerManager.getLayerByName(layerName)) {
layerIndex++;
layerName = `${layer} ${layerIndex}`;
}
return layerName;
}
async function addLayer() {
await layerManager.createLayer(t("Canvas.EmptyLayer"));
await layerManager.createLayer(createLayerName());
}
async function addTopLayer() {
await layerManager.createLayer(t("Canvas.EmptyLayer"), LayerType.EMPTY, {
await layerManager.createLayer(createLayerName(), LayerType.EMPTY, {
insertTop: true,
});
}
@@ -1173,6 +1184,17 @@ defineExpose({
:activeTool="activeTool"
/>
<!-- 选择工具菜单组件 -->
<SelectMenuPanel
v-if="canvasManagerLoaded && !enabledRedGreenMode"
:canvas="canvasManager && canvasManager.canvas"
:commandManager="commandManager"
:selectionManager="selectionManager"
:layerManager="layerManager"
:toolManager="toolManager"
:activeTool="activeTool"
/>
<div class="zoom-info">
{{ t("Canvas.Scale") }}: {{ currentZoom }}%
<button class="reset-zoom" @click="resetZoom">

View File

@@ -822,8 +822,8 @@ export class CanvasManager {
try {
// 如果当前有选中对象,先清除选中状态 否则导出有问题
this.canvas.discardActiveObject(); // 清除选中状态
this.canvas.renderAll(); // 重新渲染画布
// this.canvas.discardActiveObject(); // 清除选中状态
// this.canvas.renderAll(); // 重新渲染画布
// 自动设置红绿图模式相关参数
const enhancedOptions = {
...options,

View File

@@ -910,6 +910,17 @@ export class LayerManager {
return layer;
}
/**
* 根据name获取图层
* @param {string} layerName 图层名称
* @returns {Object|null} 图层对象或null
*/
getLayerByName(layerName) {
const layer = this.layers.value.find((layer) => layer.name === layerName);
return layer || null;
}
/**
* 获取当前图层对象的列表
* @param {string} layerId 可选指定图层ID默认使用当前活动图层
@@ -1208,6 +1219,10 @@ export class LayerManager {
}
// 切换到选择模式
this?.toolManager?.setTool(OperationType.SELECT);
if(objects.length === 1) {
this.canvas.setActiveObject(objects[0]);
return objects[0];
}
// 创建一个新的活动选择组
const activeSelection = new fabric.ActiveSelection(objects, {
canvas: this.canvas,

View File

@@ -181,10 +181,15 @@ export class CanvasEventManager {
setupMouseEvents() {
// 鼠标按下事件
this.canvas.on("mouse:down", (opt) => {
// console.log("==========鼠标按下",opt)
// 平滑停止任何正在进行的惯性动画
this.stopInertiaAnimation(true);
if (
// if (opt.e.which === 3 && this.editorMode === OperationType.SELECT) {
// console.log("==========选择模式鼠标右击画布对象")
// } else
if (
opt.e.altKey ||
opt.e.which === 2 ||
this.editorMode === OperationType.PAN

View File

@@ -44,16 +44,17 @@
:key="index"
class="image-item"
@click="handleImageClick(item)"
@dblclick="handleImageDoubleClick(item)"
>
<div class="image-wrapper">
<img
:src="item.url"
:alt="item.name || '图片'"
:alt="item.name"
@error="handleImageError"
loading="lazy"
/>
<div class="image-overlay">
<span class="image-name">{{ item.name || "未命名" }}</span>
<span class="image-name">{{ item.name }}</span>
</div>
</div>
<!-- <div class="image-select" v-show="selectList.includes(item.url)">
@@ -169,7 +170,11 @@ const handleImageClick = (item) => {
selectList.value.push(item.url)
}
};
// 处理图片双击
const handleImageDoubleClick = (item) => {
selectList.value = [item.url];
confirm();
}
// 处理图片加载错误
const handleImageError = (event) => {
event.target.src =

View File

@@ -1416,6 +1416,7 @@ export default defineComponent({
display: block;
max-height: 100%;
max-width: 100%;
object-fit: contain;
}
.delete_file_block {

View File

@@ -26,16 +26,17 @@
:key="index"
class="image-item"
@click="handleImageClick(item)"
@dblclick="handleImageDoubleClick(item)"
>
<div class="image-wrapper">
<img
v-lazy="item.url"
:alt="item.name || '图片'"
:alt="item.name"
@error="handleImageError"
loading="lazy"
/>
<div class="image-overlay">
<span class="image-name">{{ item.name || '未命名' }}</span>
<span class="image-name">{{ item.name }}</span>
</div>
</div>
<img class="selected-icon image-select" src="@/assets/images/icon/selected.png" v-show="selectList.includes(item.url)">
@@ -48,7 +49,6 @@
<!-- 加载状态 -->
<div v-if="loading && list.length > 0" class="loading-state">
<div class="loading-spinner"></div>
<p>加载中...</p>
</div>
<!-- 空状态 -->
@@ -279,6 +279,14 @@ const handleImageClick = item => {
}
}
// 处理图片双击
const handleImageDoubleClick = item => {
selectList.value = [item.url]
confirm()
}
// 处理分类切换
const handleChangeCategory = category => {
// console.log('handleChangeCategory',category)
@@ -307,6 +315,7 @@ const confirm = () => {
emitData = selectList.value
}
emits('select', emitData)
selectList.value = []
showPanel.value = false
}

View File

@@ -692,6 +692,7 @@ export default defineComponent({
display: block;
max-height: 100%;
max-width: 100%;
object-fit: contain;
}
&:hover .delete_like_file_block{
// display: block;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -280,7 +280,8 @@ export default defineComponent({
setPageSize(rem) {
const historyTable = this.$refs.historyTable
const height = historyTable.offsetHeight
const size = Math.trunc((height - 110) / 54)
const itemHeight = historyTable.getElementsByClassName("ant-table-thead")[0]?.offsetHeight || 54;
const size = Math.trunc((height - 60 - itemHeight) / itemHeight)
this.pageSize = Math.max(1, size)
if (rem) {
this.currentPage = 1
@@ -771,7 +772,7 @@ export default defineComponent({
padding: 0 1rem;
.operate_item {
font-size: 1.4rem;
// font-size: 1.4rem;
font-family: Roboto;
font-weight: 400;
color: #007ee5;