Compare commits
327 Commits
7bf1a0bd57
...
StableVers
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ed5a37e5b | ||
|
|
5546c71ec0 | ||
|
|
8a7776a4b6 | ||
|
|
a1281c8e3f | ||
|
|
9a40e69081 | ||
|
|
e27b43dc67 | ||
|
|
b6a55a8124 | ||
| 6cace08a51 | |||
| 6207095221 | |||
|
|
7bb38bf2e5 | ||
|
|
743fc762d6 | ||
| 7297e4e7a4 | |||
| 3bff1ebb66 | |||
| 0d1656ee0a | |||
| 7d0873d874 | |||
| 82941bca7c | |||
| 949ff9292d | |||
|
|
11c9de8ced | ||
|
|
fd518ad9b3 | ||
|
|
a2b45e2041 | ||
|
|
da64b57c1c | ||
|
|
7c14b1d831 | ||
|
|
8966b52430 | ||
|
|
5fa049f73d | ||
|
|
575445f767 | ||
|
|
f43c56236b | ||
|
|
4352f7c2f4 | ||
|
|
c6b1bdbdf1 | ||
|
|
f16aa6ea14 | ||
|
|
a25abeb527 | ||
|
|
d359cd7763 | ||
| 23085d9a9b | |||
| bb021ae9ac | |||
| bfb4e128f5 | |||
| 2f9b33e4ca | |||
|
|
35c6dfe29c | ||
|
|
48c37e0810 | ||
| b869a82fae | |||
| e61a8e372d | |||
|
|
f5a74991c9 | ||
|
|
e58e8540c9 | ||
| e75ed7684e | |||
| 918d71072b | |||
|
|
242bc7a01d | ||
|
|
02ad8a340a | ||
|
|
0c250a21b4 | ||
|
|
f781060e7b | ||
|
|
832c9101ab | ||
|
|
c48e836f8e | ||
|
|
6f0780ac2e | ||
|
|
5acb91e584 | ||
|
|
f66ba9e6fa | ||
| 7a90cb8db9 | |||
| dafe87fad8 | |||
| c44747e2c2 | |||
|
|
341c765c73 | ||
|
|
ed6cc294a5 | ||
|
|
a77dc718f9 | ||
|
|
86953a91a1 | ||
| cabbb653bd | |||
| 99533c12b6 | |||
|
|
59da67e4b4 | ||
|
|
1428f191dd | ||
|
|
13024cdd99 | ||
|
|
fd85ea02c1 | ||
|
|
c196ab6678 | ||
|
|
c005b85c06 | ||
|
|
b50dbbc246 | ||
|
|
01d09f4c34 | ||
|
|
79c9a66296 | ||
|
|
761b1b3512 | ||
|
|
b2cb7378d6 | ||
| 4d9ea75146 | |||
| f7e6926ee9 | |||
| 7aba4e30c9 | |||
| dc1ab330cf | |||
|
|
18c70fe6a3 | ||
|
|
5c746aca4d | ||
|
|
72c4898101 | ||
|
|
a905971dae | ||
| 69643dbc83 | |||
| f3a707d6d8 | |||
| 8f4a43db14 | |||
| 186a158114 | |||
| 3da4a97400 | |||
|
|
96b3636aea | ||
| 228e3d56b5 | |||
| 99ea7eedc7 | |||
| d4fb435db9 | |||
| 0c8b3ee8f1 | |||
| ca782d0aff | |||
|
|
3dfb607b91 | ||
|
|
981b4dad5c | ||
|
|
181e6a87b8 | ||
| 287825b4bf | |||
| 1ffc303721 | |||
|
|
bdf1bb2669 | ||
|
|
1fe79ffcf9 | ||
| 758f63615a | |||
| 20145742c5 | |||
| 8ec9b1bcea | |||
| a9cb6e16e9 | |||
|
|
5690fc6c5b | ||
|
|
9db6a589f0 | ||
|
|
896490e57b | ||
| fca04ba44b | |||
| 25e4fc06c6 | |||
|
|
4bd7740753 | ||
|
|
c428bfd93b | ||
|
|
2a29c6b2cc | ||
|
|
e9d7203804 | ||
|
|
5d7cec520b | ||
|
|
fe72df0c07 | ||
|
|
7c04332290 | ||
|
|
73d912d3cd | ||
|
|
b320294764 | ||
|
|
4913d02c93 | ||
|
|
56916c8d10 | ||
|
|
393a06eceb | ||
|
|
fdb6a87ab4 | ||
| 6d868c7c7a | |||
| 89a89ea5ef | |||
|
|
811e179889 | ||
|
|
0e0eed2566 | ||
|
|
8588c74ffd | ||
|
|
62e7f34c98 | ||
|
|
8f0a56965f | ||
|
|
59422e54d8 | ||
|
|
012f0ef1b5 | ||
|
|
ec4ae4a259 | ||
|
|
8da66d54c0 | ||
|
|
2839953d8e | ||
|
|
2d5d1b7a5e | ||
|
|
33aaf0b600 | ||
|
|
bf4d7bdba8 | ||
|
|
944071201d | ||
|
|
f6556ec9a9 | ||
|
|
8967439d4e | ||
|
|
85ae158952 | ||
|
|
813d2e9645 | ||
|
|
d94ade6641 | ||
|
|
eda893ce10 | ||
|
|
c8cb2de9ab | ||
|
|
7cda2cce27 | ||
| 41893cab86 | |||
| b23531f18b | |||
| de78bfc051 | |||
|
|
0a507fb158 | ||
|
|
a18dead4ff | ||
|
|
76047b763d | ||
| 0930e8cc77 | |||
|
|
9f09a2f31b | ||
|
|
1e0bf83d12 | ||
|
|
1764e2a0bf | ||
|
|
0729917a7e | ||
|
|
b7f7aea0b7 | ||
|
|
4dfa9433fd | ||
|
|
79293901b3 | ||
|
|
03a9e2f52c | ||
|
|
fb1d09d98e | ||
|
|
8ff7a31e92 | ||
|
|
65323febee | ||
|
|
b158341d6e | ||
|
|
44674b5396 | ||
|
|
9cecbdcf9b | ||
|
|
a6b0a60eb6 | ||
|
|
68067aa777 | ||
|
|
ca6fe65dd8 | ||
| 564e179082 | |||
| dc469add22 | |||
| d54e656192 | |||
|
|
ba49b02ebe | ||
|
|
06fa763f26 | ||
|
|
6ad81a1896 | ||
|
|
9b0ec12738 | ||
|
|
26abb2aa88 | ||
|
|
07b7a6f1d7 | ||
| bff3ea8459 | |||
| 29e68757a6 | |||
| 12ea0f7c35 | |||
|
|
920d01a972 | ||
|
|
13b4767992 | ||
|
|
086481bfb9 | ||
|
|
89bdba45be | ||
|
|
8d0b792fd4 | ||
|
|
a6bfca3b2f | ||
|
|
a1b51d5807 | ||
|
|
2f32cee502 | ||
|
|
a05655da1c | ||
|
|
6cdc8c5486 | ||
|
|
972743d3b8 | ||
|
|
df5cb918a2 | ||
|
|
bc8ce0bd47 | ||
|
|
4afe1b637e | ||
|
|
55ede508cb | ||
|
|
fbb66fd192 | ||
|
|
c87b41ae11 | ||
|
|
142c24a947 | ||
|
|
2ee200e1ba | ||
|
|
86db2f22a1 | ||
|
|
9cc012b851 | ||
|
|
c5b7365977 | ||
|
|
43464ae85e | ||
|
|
39c85cd1d1 | ||
|
|
3c77c97532 | ||
|
|
2ab23d0f30 | ||
|
|
85d4569a25 | ||
|
|
cd7d572e43 | ||
| 37157ca94d | |||
| a30897a4b2 | |||
| 9a62d277f2 | |||
|
|
0de5fe276a | ||
|
|
ca17956135 | ||
| 028c6a6540 | |||
| 9d8c3155e6 | |||
|
|
6c921730ef | ||
|
|
eaa94edfac | ||
|
|
1b30a7a873 | ||
|
|
59399d672f | ||
|
|
bb5c319a7f | ||
|
|
b114d352f6 | ||
|
|
ea4b27776a | ||
|
|
faa6db9c73 | ||
|
|
6b5c2c0b2e | ||
|
|
de3cb37bc1 | ||
|
|
9a69450fb6 | ||
|
|
513eac9e49 | ||
|
|
8c4f4c206b | ||
|
|
c731df2ae7 | ||
|
|
40c9bb1190 | ||
|
|
ef1c1c349d | ||
| 1c49dc25b1 | |||
| 542583efc6 | |||
| f8f5b98854 | |||
|
|
39a65add7c | ||
|
|
0feade1f5b | ||
|
|
5d45eee7a3 | ||
|
|
d31a809fa8 | ||
|
|
750d90ee0b | ||
|
|
70537847bc | ||
|
|
4688f234d9 | ||
|
|
5599edfcd0 | ||
|
|
73c2d1d41e | ||
|
|
2fad680490 | ||
|
|
85da122590 | ||
|
|
62e977c703 | ||
|
|
a1e0e19412 | ||
|
|
b10fd72008 | ||
|
|
a78056c898 | ||
|
|
07c261d74c | ||
|
|
fc28d78357 | ||
|
|
6bee02dfa5 | ||
|
|
e19c850214 | ||
| 9bdd0a23d3 | |||
| 08b8a52d83 | |||
|
|
11fb6f908c | ||
|
|
27198cc35b | ||
|
|
844694d638 | ||
| 695a91ac1c | |||
| 4fd66fcc05 | |||
| aa193f08cb | |||
|
|
3692361551 | ||
|
|
008e14ec57 | ||
|
|
248732b085 | ||
|
|
033950babe | ||
|
|
dbd1651a37 | ||
|
|
25ad9799f8 | ||
|
|
747a3b0ebc | ||
|
|
27e43f3c97 | ||
| 516ad19db7 | |||
| d1af68d60a | |||
|
|
eb1de5abb3 | ||
|
|
cdcb18c02c | ||
| f11805c65a | |||
| ce21acba93 | |||
| a48e517e76 | |||
|
|
f837542797 | ||
|
|
74b43e431b | ||
|
|
c20ef9d00c | ||
|
|
a7b5cc1685 | ||
|
|
5971ab56c0 | ||
|
|
7ff2c2095a | ||
|
|
9613d2b5b2 | ||
|
|
94b9977ef6 | ||
|
|
315254b6d5 | ||
|
|
31c2ca4e8b | ||
|
|
af5f178476 | ||
|
|
0aae85e94d | ||
|
|
4c25e4a5a3 | ||
|
|
87fd5b9a93 | ||
|
|
e81049c332 | ||
|
|
28bc0f2f0e | ||
|
|
4126e0b24d | ||
|
|
e4cdebfe40 | ||
|
|
55f4e5626e | ||
| a0a751c661 | |||
| 9aa3a2f889 | |||
|
|
43e3a79124 | ||
|
|
6b0d26ed6e | ||
|
|
9b29939bfe | ||
|
|
0add8bc412 | ||
|
|
618b9bab1f | ||
|
|
226e183f52 | ||
|
|
b78832875c | ||
|
|
c4c4753403 | ||
| 3014414c97 | |||
| 6a5a0930e9 | |||
|
|
f813384a6e | ||
|
|
a720fba84e | ||
|
|
2b7db933d9 | ||
|
|
ba5b1657a5 | ||
|
|
30109fdb79 | ||
|
|
83226f006c | ||
|
|
a5e21c93b3 | ||
|
|
1989c22562 | ||
|
|
882740592c | ||
|
|
0c995054a2 | ||
|
|
6780c0fbb1 | ||
|
|
7101daeb90 | ||
|
|
0d0de45a25 | ||
|
|
28b6153ab0 | ||
|
|
7a4fc0736d | ||
| fb1bfc353c | |||
| cc0127f195 | |||
|
|
f4043d6f61 | ||
|
|
9912f310ec | ||
|
|
1df7b62fe6 |
2
.env.dev
@@ -7,5 +7,7 @@ VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
|||||||
# VITE_APP_BASE_URL = 'https://www.api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://www.api.aida.com.hk'
|
||||||
# 徐佩
|
# 徐佩
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.31.118:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.31.118:5567'
|
||||||
|
# 李天祥
|
||||||
|
# VITE_APP_BASE_URL = 'http://192.168.31.82:5567'
|
||||||
# 海波
|
# 海波
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.31.34:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.31.34:5567'
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ VITE_USER_NODE_ENV = 'development'
|
|||||||
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
||||||
|
|
||||||
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
||||||
|
|
||||||
|
|||||||
33
.prettierrc.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/** @type {import('prettier').Config} */
|
||||||
|
module.exports = {
|
||||||
|
// 打印宽度
|
||||||
|
printWidth: 100,
|
||||||
|
// 使用 4 空格缩进
|
||||||
|
tabWidth: 4,
|
||||||
|
// 使用 4 空格缩进,不使用制表符
|
||||||
|
useTabs: true,
|
||||||
|
// 行尾使用 LF (Unix 风格)
|
||||||
|
endOfLine: 'lf',
|
||||||
|
// 语句末尾使用分号
|
||||||
|
semi: false,
|
||||||
|
// 使用单引号
|
||||||
|
singleQuote: false,
|
||||||
|
// 对象和数组末尾不添加尾随逗号
|
||||||
|
trailingComma: 'none',
|
||||||
|
// JSX 引号使用单引号
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
// 括号内侧空格
|
||||||
|
bracketSpacing: true,
|
||||||
|
// JSX 标签不换行
|
||||||
|
bracketSameLine: false,
|
||||||
|
// 箭头函数参数始终使用括号
|
||||||
|
arrowParens: 'always',
|
||||||
|
// HTML、Vue、Angular 和 Markdown 使用 LF
|
||||||
|
htmlWhitespaceSensitivity: 'css',
|
||||||
|
// Vue 文件脚本和样式缩进
|
||||||
|
vueIndentScriptAndStyle: false,
|
||||||
|
// 行注释位置在注释上方,不加空格
|
||||||
|
proseWrap: 'preserve',
|
||||||
|
// 根据文件类型自动推断
|
||||||
|
embeddedLanguageFormatting: 'auto',
|
||||||
|
};
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="/css/sloganFamily.css">
|
<link rel="stylesheet" href="/css/sloganFamily.css">
|
||||||
<link rel="stylesheet" href="/css/pingfang.css">
|
<link rel="stylesheet" href="/css/pingfang.css">
|
||||||
|
<link rel="stylesheet" href="/css/fonts/fontFamily.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
BIN
public/css/fonts/ARIAL.ttf
Normal file
BIN
public/css/fonts/ARIALBD.ttf
Normal file
BIN
public/css/fonts/ArialMdm.ttf
Normal file
BIN
public/css/fonts/InstrumentSans-Bold.ttf
Normal file
BIN
public/css/fonts/InstrumentSans-Regular.ttf
Normal file
BIN
public/css/fonts/Poppins-Medium.ttf
Normal file
BIN
public/css/fonts/Poppins-Regular.ttf
Normal file
BIN
public/css/fonts/Poppins-SemiBold.ttf
Normal file
41
public/css/fonts/fontFamily.css
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* 字体定义 */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Arial';
|
||||||
|
src: url('./fonts/ARIAL.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'ArialBold';
|
||||||
|
src: url('./fonts/ARIALBD.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'ArialMedium';
|
||||||
|
src: url('./fonts/ArialMdm.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Poppins';
|
||||||
|
src: url('./fonts/Poppins-Regular.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PoppinsMedium';
|
||||||
|
src: url('./fonts/Poppins-Medium.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PoppinsBold';
|
||||||
|
src: url('./fonts/Poppins-SemiBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Instrument';
|
||||||
|
src: url('./InstrumentSans-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'InstrumentBold';
|
||||||
|
src: url('./InstrumentSans-Bold.ttf') format('truetype');
|
||||||
|
}
|
||||||
BIN
public/image/events/award-poster-zh.gif
Normal file
|
After Width: | Height: | Size: 15 MiB |
BIN
public/image/events/award-poster.gif
Normal file
|
After Width: | Height: | Size: 15 MiB |
17
src/assets/icons/CBrush2.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="201.000000pt" height="200.000000pt" viewBox="0 0 201.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M1654 1990 c-26 -8 -153 -110 -162 -129 -1 -3 81 -89 183 -191 l185
|
||||||
|
-185 56 55 c30 30 62 67 70 82 22 41 18 123 -8 176 -29 57 -126 158 -169 176
|
||||||
|
-47 20 -118 27 -155 16z"/>
|
||||||
|
<path d="M868 1243 c-525 -527 -498 -492 -568 -725 -54 -179 -59 -219 -30
|
||||||
|
-248 19 -19 29 -21 64 -16 113 18 361 105 431 152 28 18 251 235 498 481 l447
|
||||||
|
448 -188 188 -187 187 -467 -467z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 799 B |
17
src/assets/icons/CEraser2.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M757 1273 c-214 -214 -402 -406 -418 -427 -32 -43 -37 -82 -15 -124
|
||||||
|
23 -44 327 -338 376 -363 l45 -24 463 -3 462 -3 0 46 0 45 -342 0 -343 0 342
|
||||||
|
343 c187 188 346 352 352 364 16 32 13 74 -7 105 -9 14 -110 116 -224 227
|
||||||
|
l-207 201 -47 0 -48 0 -389 -387z m207 -342 l209 -209 -128 -131 c-76 -78
|
||||||
|
-144 -138 -169 -151 -51 -24 -106 -26 -149 -4 -41 20 -337 314 -337 334 0 13
|
||||||
|
347 370 360 370 3 0 99 -94 214 -209z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 847 B |
1
src/assets/icons/CFile.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="#00000073" aria-hidden="true" viewBox="64 64 896 896"><path d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 985 B |
20
src/assets/icons/CMarquee.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M250 1545 l0 -205 80 0 80 0 0 -340 0 -340 -80 0 -80 0 0 -205 0
|
||||||
|
-205 205 0 205 0 0 80 0 80 340 0 340 0 0 -80 0 -80 205 0 205 0 0 205 0 205
|
||||||
|
-80 0 -80 0 0 340 0 340 80 0 80 0 0 205 0 205 -205 0 -205 0 0 -80 0 -80
|
||||||
|
-340 0 -340 0 0 80 0 80 -205 0 -205 0 0 -205z m320 0 l0 -125 -120 0 -120 0
|
||||||
|
0 125 0 125 120 0 120 0 0 -125z m1100 0 l0 -125 -120 0 -120 0 0 125 0 125
|
||||||
|
120 0 120 0 0 -125z m-330 -125 l0 -80 85 0 85 0 0 -340 0 -340 -85 0 -85 0 0
|
||||||
|
-80 0 -80 -340 0 -340 0 0 80 0 80 -85 0 -85 0 0 340 0 340 85 0 85 0 0 80 0
|
||||||
|
80 340 0 340 0 0 -80z m-770 -965 l0 -125 -120 0 -120 0 0 125 0 125 120 0
|
||||||
|
120 0 0 -125z m1100 0 l0 -125 -120 0 -120 0 0 125 0 125 120 0 120 0 0 -125z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,68 +1,29 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 184.06 163.52">
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
<defs>
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
<style>
|
||||||
width="103.000000pt" height="92.000000pt" viewBox="0 0 103.000000 92.000000"
|
.cls-1, .cls-2 {
|
||||||
preserveAspectRatio="xMidYMid meet">
|
fill: #333;
|
||||||
|
}
|
||||||
|
|
||||||
<g transform="translate(0.000000,92.000000) scale(0.100000,-0.100000)"
|
.cls-2 {
|
||||||
fill="#000000" stroke="none">
|
stroke: #333;
|
||||||
<path d="M365 895 c-5 -2 -36 -6 -67 -10 -45 -5 -58 -10 -59 -23 0 -11 -2 -12
|
stroke-miterlimit: 10;
|
||||||
-6 -4 -7 17 -32 15 -40 -4 -4 -11 -8 -12 -13 -4 -5 8 -13 9 -21 4 -7 -4 -22
|
}
|
||||||
-9 -34 -10 -11 -1 -41 -11 -66 -21 l-47 -18 20 -63 c11 -38 23 -60 30 -56 6 4
|
</style>
|
||||||
8 -1 3 -15 -3 -11 -3 -21 2 -21 4 0 9 -12 9 -26 1 -14 5 -28 8 -32 4 -3 33 3
|
</defs>
|
||||||
66 15 33 11 61 19 62 18 2 -2 1 -139 -2 -304 l-5 -301 309 2 309 3 -2 108 c-2
|
<path class="cls-2" d="M35.53,54.52c-.76-.96-.84-1.16-2.06-1.12-4.02.13-16.7,6.5-19.81,4.48C12.45,52.21-1.21,21.14.68,18.17c56.98-23.47,125.74-23.63,182.7,0,1.88,2.98-11.77,34.04-12.98,39.72-3.11,2.01-15.78-4.36-19.81-4.48-1.23-.04-1.3.16-2.06,1.12v48c2.87,3.81,14.6,2.98,14.05,8.95-1.06,5.75-12.53,3.84-13.85,8.24l.34,39.85c.08.98-1.55,3.46-2.04,3.46H37.03c-2.08,0-1.5-3.59-1.5-4.5V54.52ZM41.53,47.52v108.5h101v-36c-7.66,1.58-6.82,23.41-12.7,24.86-1.18.17-2.67-.14-3.63-.79-2.98-2.02-6.47-24.26-10.3-25.81-.94-.38-4.46.95-5.31-1.9-1.01-3.4,3.85-4,4.01-5.02-.12-4.15-6.85-15.14-3.84-18.1,4.45-3.04,8.95,1.93,13.76,1.74-1.35-3.15-2.75-11.61,2.46-11.03s3.05,9.89,1.55,13.02l14,4.01v-53.5c0-5.17,22.25,4.69,23.94,3.46,1.7-8.98,7.54-18.42,9.64-26.94.32-1.3.79-1.48-.58-2.5-2.81-2.08-21.4-6.93-25.98-8.02-10.05-2.4-20.36-3.72-30.52-5.53-2.44.17-3.98,7.98-6.05,10.97-13.1,18.91-41.58,12.05-45.92-9.95l-2-1.02c-19.44,3.3-39.69,6.08-57.48,14.6l10.03,28.4c4.22.52,22.41-8.34,23.94-3.46ZM110.53,8.02h-37c4,20.53,33,20.53,37,0Z"/>
|
||||||
77 2 113 11 125 10 12 10 14 1 8 -7 -4 -13 -2 -13 4 0 6 10 8 23 5 18 -5 26
|
<path class="cls-1" d="M89.27,117.8c-.94.96-10.2,1.42-11.25-.78-4.1-8.61,17.67-5.76,11.25.78Z"/>
|
||||||
-1 36 17 9 17 10 18 6 3 -5 -16 -4 -18 6 -7 18 17 -1 34 -40 37 l-32 2 -2 151
|
<path class="cls-1" d="M94.79,117.8c-6.42-6.54,15.35-9.39,11.25-.78-1.05,2.19-10.31,1.74-11.25.78Z"/>
|
||||||
c-1 82 0 147 3 144 9 -12 44 -11 52 1 5 8 8 7 8 -4 0 -14 26 -28 52 -29 11 0
|
<path class="cls-1" d="M60.62,113.11c1.1-1.64,14.59-2.57,12.84,3.27-1.14,3.81-16.87,2.76-12.84-3.27Z"/>
|
||||||
39 70 33 80 -3 5 1 11 7 13 10 4 9 8 -2 16 -13 10 -8 15 12 12 8 -1 38 91 32
|
<path class="cls-1" d="M62.18,46.17h9.69s1.53,3.19,1.53,3.19c-1.22,4.73-18.53,3.97-11.22-3.19Z"/>
|
||||||
98 -2 2 -10 -2 -18 -8 -9 -7 -17 -8 -20 -2 -3 5 0 11 6 14 7 2 -18 14 -56 26
|
<path class="cls-1" d="M112.19,46.18l10.91.77.34,3.47c-.87,2.65-12.93,2.92-12.96-1.9l1.7-2.34Z"/>
|
||||||
-38 12 -71 19 -74 16 -3 -3 -11 0 -18 6 -8 6 -20 9 -28 6 -8 -3 -16 -2 -18 3
|
<path class="cls-1" d="M56.23,84.18c6.63-1.86,6.45,14.76-.7,11.35-2.24-1.07-2.61-10.42.7-11.35Z"/>
|
||||||
-5 15 -154 30 -286 29 -70 0 -131 -2 -137 -4z m21 -30 c-6 -18 3 -47 14 -40 4
|
<path class="cls-1" d="M89.37,46.16l.96,3.22c-.81,4.5-16.92,3.98-12.37-2.43l11.42-.79Z"/>
|
||||||
2 18 -7 30 -20 27 -29 17 -34 -14 -7 -20 16 -20 16 -7 -1 23 -29 66 -47 112
|
<path class="cls-1" d="M94.68,46.16l11.42.79.34,3.47c-1.03,3.13-16.69,2.9-11.76-4.26Z"/>
|
||||||
-47 34 0 40 3 35 16 -5 14 -4 15 9 4 13 -11 19 -9 36 6 12 11 29 35 38 54 15
|
<path class="cls-1" d="M54.75,63.76c-1.01-.99-2.01-12.94,3.11-11.63,5.4,1.38,2.78,17.42-3.11,11.63Z"/>
|
||||||
31 20 35 58 35 24 0 43 -2 43 -5 0 -11 115 -27 121 -18 3 5 9 2 13 -7 4 -13
|
<path class="cls-1" d="M129.31,63.76c-5.88,5.78-8.51-10.25-3.11-11.63,5.12-1.31,4.12,10.64,3.11,11.63Z"/>
|
||||||
14 -16 34 -12 15 2 36 1 47 -4 16 -7 14 -8 -10 -5 l-30 5 32 -14 c39 -18 39
|
<path class="cls-1" d="M59.44,68.12c1.19.8,3.28,13.19-3.02,12.43l-2.23-1.77c-.57-2.83-.34-14.39,5.25-10.66Z"/>
|
||||||
-19 14 -83 -15 -38 -17 -52 -8 -61 9 -9 8 -11 -7 -5 -16 6 -18 4 -12 -19 3
|
<path class="cls-1" d="M59.44,111.92c-5.59,3.73-5.82-7.83-5.25-10.66l2.23-1.77c6.3-.76,4.22,11.63,3.02,12.43Z"/>
|
||||||
-14 2 -29 -4 -32 -6 -3 -7 1 -4 9 6 16 -9 20 -73 19 -12 0 -20 4 -17 8 3 5 -4
|
<path class="cls-1" d="M129.32,79.79c-5.12,5.18-7.81-7.81-4.7-11.67l3.28.02,1.48,1.52c-.35,2.45,1.51,8.54-.07,10.13Z"/>
|
||||||
9 -15 9 -20 0 -21 -5 -21 -151 l0 -151 -27 8 c-16 4 -38 7 -50 7 -19 -1 -21 2
|
|
||||||
-13 17 15 28 12 57 -6 57 -11 0 -15 -8 -12 -27 4 -24 1 -27 -23 -26 -15 1 -25
|
|
||||||
4 -22 9 2 4 -2 7 -10 7 -9 0 -14 -10 -14 -25 0 -13 3 -22 8 -19 5 3 6 -1 3 -9
|
|
||||||
-2 -7 0 -25 5 -40 8 -20 7 -25 -3 -21 -7 3 -13 -2 -13 -11 0 -12 7 -15 26 -11
|
|
||||||
14 3 21 3 14 0 -7 -3 -9 -12 -6 -20 3 -7 10 -11 16 -7 5 3 7 1 4 -4 -9 -14 3
|
|
||||||
-74 12 -68 4 2 7 -6 7 -18 -1 -32 32 -34 44 -3 5 14 7 34 5 46 -3 13 0 18 7
|
|
||||||
14 8 -5 9 -1 5 10 -4 9 -3 15 2 12 5 -3 12 1 15 10 3 8 2 12 -4 9 -6 -3 -10
|
|
||||||
-1 -10 4 0 13 3 13 24 5 13 -5 16 -24 16 -103 0 -63 4 -102 13 -111 10 -12 9
|
|
||||||
-12 -4 -2 -13 10 -88 12 -300 10 l-284 -3 3 303 3 302 -26 0 c-14 0 -25 -4
|
|
||||||
-25 -10 0 -5 -7 -6 -17 -3 -9 4 -14 2 -10 -3 4 -6 -6 -9 -24 -6 -28 4 -41 -11
|
|
||||||
-19 -21 6 -3 5 -4 -2 -3 -7 2 -13 11 -13 22 -1 32 -25 104 -35 104 -5 0 -6 7
|
|
||||||
-3 17 4 10 2 14 -5 9 -7 -4 -10 2 -8 17 3 29 14 47 29 47 7 0 3 -8 -8 -17
|
|
||||||
l-20 -16 20 8 c11 4 28 10 37 12 10 3 18 9 18 13 0 4 6 7 12 7 22 -2 158 26
|
|
||||||
158 32 0 3 20 6 45 5 25 0 45 3 45 8 0 4 3 8 6 8 3 0 4 -7 0 -15z m237 -5 c-3
|
|
||||||
-9 1 -8 11 4 9 11 16 15 16 9 0 -6 -7 -16 -15 -23 -8 -7 -15 -9 -15 -4 0 10
|
|
||||||
-29 -28 -30 -40 0 -4 8 -5 17 -2 15 6 15 4 -2 -14 -22 -24 -37 -26 -28 -4 5
|
|
||||||
14 3 15 -15 5 -26 -14 -77 -14 -103 -1 -10 6 -27 27 -38 48 l-19 37 113 0 c95
|
|
||||||
0 112 -2 108 -15z"/>
|
|
||||||
<path d="M346 641 c-3 -5 1 -12 10 -15 23 -9 36 -7 29 4 -3 6 1 7 9 4 9 -3 16
|
|
||||||
-1 16 5 0 13 -56 15 -64 2z"/>
|
|
||||||
<path d="M440 640 c0 -16 33 -26 38 -12 2 7 8 10 13 6 5 -3 9 0 9 5 0 6 -13
|
|
||||||
11 -30 11 -16 0 -30 -5 -30 -10z"/>
|
|
||||||
<path d="M530 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
|
|
||||||
-9z"/>
|
|
||||||
<path d="M620 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
|
|
||||||
-9z"/>
|
|
||||||
<path d="M310 593 c0 -20 5 -30 16 -30 10 0 14 8 12 25 -4 37 -28 40 -28 5z"/>
|
|
||||||
<path d="M697 613 c-13 -13 -7 -50 8 -50 10 0 15 10 15 29 0 27 -9 35 -23 21z"/>
|
|
||||||
<path d="M317 534 c-4 -4 -7 -20 -7 -36 0 -35 23 -34 28 1 4 25 -10 46 -21 35z"/>
|
|
||||||
<path d="M692 503 c4 -39 28 -42 28 -4 0 21 -5 31 -16 31 -11 0 -14 -8 -12
|
|
||||||
-27z"/>
|
|
||||||
<path d="M312 415 c4 -33 22 -33 26 0 2 18 -1 25 -13 25 -12 0 -15 -7 -13 -25z"/>
|
|
||||||
<path d="M312 329 c2 -19 8 -33 13 -31 15 3 12 55 -3 60 -10 3 -13 -5 -10 -29z"/>
|
|
||||||
<path d="M342 278 c3 -7 19 -14 37 -16 24 -3 32 0 29 10 -3 7 -19 14 -37 16
|
|
||||||
-24 3 -32 0 -29 -10z"/>
|
|
||||||
<path d="M443 275 c0 -10 10 -15 29 -15 18 0 28 5 28 15 0 10 -10 15 -28 15
|
|
||||||
-19 0 -29 -5 -29 -15z"/>
|
|
||||||
<path d="M530 275 c0 -10 10 -15 33 -15 22 0 28 3 18 9 -11 7 -11 9 0 14 8 3
|
|
||||||
-1 6 -18 6 -23 1 -33 -4 -33 -14z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
src/assets/images/award/apply_bg.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
3
src/assets/images/award/arrow_down.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="22" height="12" viewBox="0 0 22 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1 1L11 11L21 1" stroke="#585858" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 212 B |
BIN
src/assets/images/award/arrow_right.png
Normal file
|
After Width: | Height: | Size: 327 B |
BIN
src/assets/images/award/banner.mp4
Normal file
BIN
src/assets/images/award/banner_chinese.mp4
Normal file
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 492 KiB |
BIN
src/assets/images/award/certification_bg.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
src/assets/images/award/checked.png
Normal file
|
After Width: | Height: | Size: 913 B |
4
src/assets/images/award/close.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.6144 18.7388L5.16736 4.29184C4.95412 4.0786 4.60838 4.0786 4.39514 4.29184C4.18189 4.50509 4.18189 4.85082 4.39514 5.06407L18.8421 19.5111C19.0554 19.7243 19.4011 19.7243 19.6144 19.5111C19.8276 19.2978 19.8276 18.9521 19.6144 18.7388Z" fill="#232323"/>
|
||||||
|
<path d="M5.15908 19.5378L19.6061 5.09079C19.8193 4.87755 19.8193 4.53181 19.6061 4.31857C19.3928 4.10533 19.0471 4.10533 18.8339 4.31857L4.38685 18.7656C4.17361 18.9788 4.17361 19.3246 4.38685 19.5378C4.6001 19.751 4.94583 19.751 5.15908 19.5378Z" fill="#232323"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 636 B |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 137 KiB |
BIN
src/assets/images/award/criteria_1.png
Normal file
|
After Width: | Height: | Size: 339 KiB |
BIN
src/assets/images/award/criteria_2.png
Normal file
|
After Width: | Height: | Size: 443 KiB |
BIN
src/assets/images/award/criteria_3.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
src/assets/images/award/criteria_4.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
src/assets/images/award/criteria_bg.png
Normal file
|
After Width: | Height: | Size: 400 KiB |
BIN
src/assets/images/award/desmond.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
src/assets/images/award/diego.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
src/assets/images/award/expired.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
9
src/assets/images/award/facebook.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<rect width="20" height="20" rx="2.79453" fill="url(#pattern0_226_198)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0_226_198" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_226_198" transform="scale(0.0104167)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_226_198" width="96" height="96" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAKcUlEQVR4AeydSewlRR3H3xtHUXAZdz2YGQ+aeDDiCYgCMxwENFGMMdF4cDx48gB6VOOuiR4UPWlkGSAsBxK2BMI6wxYgLMOSEJYAQ9jXGbZh58/n0/Oq6ffmLd3Vr1/369f/1PfV0lW/qvr+flVdr7pe/9f1Cv6tra1tAseDU8FDYDdYVWffd9L584CcbCpIZy+3AqhgK9hOBQ+BE8FWYIUb8FfV2feD6fxxQE40SBXyU+K53EwFQPpmIOmnInEz6Nx0BlTINjkDMxUxUQEU3gDUqlavpU+vtrs6yoCcqYh/waMjZfR6Eh+rAApYWOKPT3J1H2UYOIHCTktySnDY7aeADPkOpeHcXSyWAcnfPuB2SMaQAsjgUNHyLTCUsYuUZkBOXS3JcSpsSAGk/gGYEa9zFTDgrPL7rNxUAVi/y8puzs+yU034BLhOV5OpAqhrSDPEO1cdAy7pE+mJAtCI1r86U0/S9Vo/3E1IviMkCqApqzj1rNHvebl3EFRUnkbfW4f1a/neHJDRuUgGipJvNe4wbHQEfM/YCmCUpP6gz1rvs4QfBXeDO8GN4HpwNdgxgiuJXwvM8zD+XvA+EOQRzO2OUwHpHTl3seXLOEp+tgevEbkX3ADOBaeD/4C/gz8O4PJc/I74b8Ffwb/BNeAZEOsOVgFOQbEClqGc5Gudwva+zccT4H5wIXBF8n/8k8Apot/vnw0uAtvBDnD1ANfi3wguBeeQ92LwJIh1m9uuAMkfJedVErT2M/G1dBXgtHI7ca35Zfy8bg8Z3wCxboMKGPpqHCupoeW0eqEiXqSNEn0G/n/B/7DiK8Gt4FHwNNgL3uTaRMeiRXnhugqYmj9knOAnCphwrVXJr9Abb6qn4Z8FbgLeePGKORSkMkOh9xPQiPHiXKnCcVVWXipLkCuc56jR6cZ53rn9Okh8EbxFeuJGrDpJy/nh6idn1vHZ2qiAbE93E7kMuLrZmSWdtNSRnlVamr6IwAIVUHl3AonO0Ya9mUr8yRB8BdgVWoDFN6bfjWlIICfSl/BsUW+4flnS+h/IXjCMMpyaDNaOtihAqxeB0FsInA0uhOys5WfzcLl+1xYFBCb9kuXUcx8JD0J+eqMl3iM+OlJMrhVtUECW1Kdh83JwPrgLJG6ecz6ysqNIhSd1xH60QQHZvr9E5A7ghpqbZAR7Wn5Vc74jrJTsNigga5H39Ho992ueZLqRHKL53IhlTyyE3OyI+xgZ/TKGF+faoAB7rhVq8Y8QeQEUcnnJHyP046R9AES7tijgeRi4DdwM0t3JPMSaR6sWlO0RPwB8AXwVHAGOBFuAD1AOxz8UHAN+TP5jwOdAtGuLAtzhfBwWJD/dnQykkj7WQWJ2+pJ8404r36TAT8BvgIcV/oQfng34LODXxH2MeyT+p0G0a4sCvPk6/wuXobkIUUEik/nrhH8AfgF+Dr4FtgAVcgS+4aPwDweHgI3gQOD9JntvIGmfm/XZFgVIgN9+heFZ/R66zkhw2vksiZJ67MD/BH5e56acoydv/jRfWxTgDfgxrHk3iNmfl3wt22nHeX19ytC+wCzrjiJf0W1RgFav9dunGDjvf42CXwGj5JPUiybYwtPQFgVo9bnn/jGEuJx0/nfaqYzsMfXm/4nSuMINSpM0Edsky5b6QhVbcVtGQGz/Qzl5yCpg1pwfypX2rbi0kBYIkHC/TYeuOCJCuFJ/mRUgaYGc6GXgQICEi0G0l5Ud0irxl1kBWUJcuZTpi+QrIytzIeEyja6igVpediqYVoekhesuQV0JhXhR32Ws36ZDuazskDbNt93Trk+81jQF2NCYznj6Id0D6imlGFSeSixW6r3cGk1Muxu3DNXynM89SOXJYw9Q+XD9KvrqjwfDSWXTPJ18Keme0bwE3404vChnWc95eopCmR5d9OBtqC/4tuEKavCQ1058z5h6uNc223aSirkmjgB74Kk1j4b7Q3F3Hz2R7K5k2JH0lLI7lV4zj3k912nZGPgoU3L/SeG/AevzNHSoL/jW607oP8jjQV6V4PFEonGuqQrQsi5hX+cc4EnkG/B90uVJ5YCrBmk34T8M9rKpth7ktkTy+gOV9ZR9BewC1nMNvrLDyehQn76n6m7muqeqt0G5I0FjIRjnmqoA52Tn9aK9ehtycs/F5HXujn2w7j3H+4ZtLdrONH9TFWDn0keLWGouq4bQ3OQHBmLKDNrjvF+4vlBv8JuqANuVbg3EkBQ6WJF/AHLdQRVpO0kr7Oxo4UILKKDFa2ELqCqqChXwGUoKwwTjXFMVENebxZXSOD5EdaLUN+hOAbAY4bT6T1LuU6A7lgIJi3ZhBHyQig3jxbk5joC4BixpKUeAx1GE4ehudAqIo06rP4iiwjDBONdUBbi+Tr8gDdbdcT2sppRLT+8BrR0BKsAt4mroi5A6YgQuk53/RStXQXbqI4GnvF/ERkgKxSf65ge5ZoGRNnwYoZ4lso2tnIIc4n7LpJ+FnJtrWmeRQkXzK9v1/0cNlEUu7ZetJKL85ylzLNb5Q3A0OAx4UtkTygFHkRZOK28kfCBWWnQzbs0ylD0IKOMQfGUqO5yItj7r/gbXTPe86Hdp35dBaddUBXhz8yDsr+ih++9/wXd/3mcCwtPKPgvwmYCnlD04axmyRTm/UHnS2Xd8hvp8BmBdwvCfkezzAOv8DmGNBK+ca5oC3B725uvyzre4HEr3JNdzmyrEV+sITyd77Wiu/wh8G5Q5py+ZHspVlmdDD0OedVhXgPWrJNvzJa47/7tSc8FANM41TQG2J+am5gtHymwJeM/xeGJRFm1vzD0krUcBaaQhgTwd0upEaLIKkMQQL+pbNnvTz8qeJqs/7WKea01UQJ52qyQR8vpUyukrxIv6Eq6MUC4rO6RV4i+rAkbJcC4eTSsSVwFlZRSpL83bFgWkHVq2QKeAmjXWKaBTQM0M1Fx9NwI6BdTMQM3VdyOgU0DNDNRc/XKOgJpJm2f1nQLmyWaErE4BEaTNs0ingHmyGSGrU0AEafMsogJK/cRmno1ZQVl7OgXUq/VdKsBfANbbjNWtPVGA/zlidSmot+c7HAEX1NuGla79gnX9ft+XW3fT0OLt4Ha5dwRYtf/aQ38KuktzZsAfmO97VQGa8EfHjoQ519GJm8CAPwpPjD6MAPP9zI8OC2HAY5ZJRakCGAXeB5JhkVzpPqpi4ES4TqzfClIFGAEeQu2WpRBRkXOal+NU/JAC0IzbEt/nqhnxOjdHBuR0y4DjVOyQAkwlQ5KRsD5eY52n2ULjYg70hrL6fT6yMrKyuVTaOatI/n6c7qcAqxoowReZLss9wZ80je2L/ckBFaCMHFkLZ5HDseQraWKjUcIe8EsyuTraT3Ok1+0kLbThKQK+uQovyr1OKV/ahJe4rOwkIeJDzjbLIXBqHytiogJCbgpvA18kriIcSgQb4zwRnby4mxb5PwTwopxlfUmUilBmlJBBIVeTW+UM+CavQfJ4b6YCQjGEqQinJZXhT3n8T0UqZKJ2Q9kKfa1ey3UESF5sVZb1lWe+/cp3FaVyZgTsu5buF1k52QRPTjfpMnNG+d67AAAA///vdBW6AAAABklEQVQDAJAXvRKwmZ6CAAAAAElFTkSuQmCC"/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/images/award/first_bg.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
src/assets/images/award/form_bg.png
Normal file
|
After Width: | Height: | Size: 930 KiB |
BIN
src/assets/images/award/grand_bg.png
Normal file
|
After Width: | Height: | Size: 262 KiB |
BIN
src/assets/images/award/gregory.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
src/assets/images/award/jae.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
src/assets/images/award/judges_bg.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
10
src/assets/images/award/linkdin.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_226_195)">
|
||||||
|
<path d="M-0.00195312 1.4335C-0.00195312 0.641696 0.656004 0 1.46782 0H18.5422C19.354 0 20.0119 0.641696 20.0119 1.4335V18.5804C20.0119 19.3722 19.354 20.0139 18.5422 20.0139H1.46782C0.656004 20.0139 -0.00195312 19.3722 -0.00195312 18.5804V1.4335ZM6.18109 16.7541V7.71661H3.17776V16.7541H6.18109ZM4.68005 6.482C5.72703 6.482 6.37873 5.78902 6.37873 4.92092C6.35996 4.03405 5.72828 3.35983 4.70006 3.35983C3.67185 3.35983 3.00013 4.0353 3.00013 4.92092C3.00013 5.78902 3.65183 6.482 4.66003 6.482H4.68005ZM10.8193 16.7541V11.7069C10.8193 11.4367 10.8393 11.1665 10.9194 10.9739C11.1358 10.4347 11.6299 9.87561 12.4605 9.87561C13.5475 9.87561 13.9815 10.7037 13.9815 11.9195V16.7541H16.9848V11.5705C16.9848 8.79361 15.5038 7.50271 13.5274 7.50271C11.9338 7.50271 11.2196 8.37832 10.8193 8.995V9.02627H10.7993L10.8193 8.995V7.71661H7.81723C7.85475 8.5647 7.81723 16.7541 7.81723 16.7541H10.8193Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_226_195">
|
||||||
|
<rect width="20.0139" height="20.0139" rx="1.55252" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/images/award/point.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
src/assets/images/award/prizes_bg.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
src/assets/images/award/progress.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
src/assets/images/award/qrcode.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src/assets/images/award/second_bg.png
Normal file
|
After Width: | Height: | Size: 253 KiB |
BIN
src/assets/images/award/selection_bg.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
src/assets/images/award/successful.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
9
src/assets/images/award/tiktok.svg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
src/assets/images/award/tim.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 61 KiB |
BIN
src/assets/images/award/upload.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
src/assets/images/award/upload_video_icon.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
src/assets/images/award/vincenzo.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
12
src/assets/images/award/weichat.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_226_203)">
|
||||||
|
<path d="M20 17C20 18.6569 18.6569 20 17 20H3C1.34307 20 0 18.6569 0 17V3C0 1.34313 1.34313 0 3 0H17C18.6569 0 20 1.34313 20 3V17Z" fill="white"/>
|
||||||
|
<path d="M13.3881 7.45803C11.7739 7.54236 10.3702 8.03169 9.2306 9.13723C8.0792 10.2542 7.55366 11.6228 7.69726 13.3195C7.06633 13.2414 6.49166 13.1554 5.91373 13.1067C5.71413 13.0899 5.47726 13.1138 5.3082 13.2092C4.747 13.5258 4.20906 13.8834 3.57133 14.282C3.68833 13.7528 3.76406 13.2894 3.89813 12.8437C3.99673 12.5161 3.95106 12.3338 3.64926 12.1204C1.71153 10.7523 0.894728 8.70496 1.50599 6.59703C2.07153 4.64703 3.46033 3.46443 5.3474 2.84796C7.92313 2.00663 10.8177 2.86483 12.3839 4.90976C12.9495 5.64843 13.2964 6.47749 13.3881 7.45803ZM5.95893 6.80123C5.9738 6.41569 5.63973 6.06836 5.24293 6.05676C4.83666 6.04483 4.50253 6.35529 4.49066 6.75563C4.47866 7.16136 4.789 7.48649 5.1982 7.49689C5.60386 7.50716 5.94393 7.19629 5.95893 6.80123ZM9.835 6.05649C9.43673 6.06383 9.1002 6.40303 9.10726 6.79009C9.11453 7.19129 9.44466 7.50516 9.8542 7.50023C10.2648 7.49529 10.5762 7.17809 10.5723 6.76843C10.5689 6.36629 10.2403 6.04909 9.835 6.05649Z" fill="#232323"/>
|
||||||
|
<path d="M17.0146 17.5216C16.5035 17.294 16.0346 16.9525 15.5354 16.9004C15.0381 16.8484 14.5154 17.1353 13.9951 17.1885C12.4104 17.3506 10.9907 16.909 9.82001 15.8264C7.59355 13.767 7.91168 10.6094 10.4876 8.92184C12.777 7.42197 16.1345 7.92197 17.7487 10.0031C19.1573 11.8191 18.9917 14.2298 17.2721 15.7554C16.7745 16.1969 16.5955 16.5602 16.9148 17.1423C16.9737 17.2498 16.9804 17.3858 17.0146 17.5216ZM11.1963 11.8883C11.5217 11.8886 11.7897 11.634 11.802 11.3126C11.815 10.9723 11.5413 10.6869 11.2006 10.6855C10.8632 10.684 10.5806 10.9734 10.5924 11.3086C10.6035 11.6288 10.8733 11.8879 11.1963 11.8883ZM14.9471 10.6868C14.6314 10.6846 14.3631 10.9431 14.3502 11.2621C14.3365 11.6032 14.6017 11.8834 14.9393 11.8842C15.2658 11.8854 15.5239 11.6384 15.5357 11.3134C15.5483 10.9715 15.2831 10.6892 14.9471 10.6868Z" fill="#232323"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_226_203">
|
||||||
|
<rect width="20" height="20" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
4
src/assets/images/award/xiaohongshu.svg
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
src/assets/images/canvas/add.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src/assets/images/canvas/remove.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/images/canvas/shubiao-l.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/images/canvas/shubiao-r.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
@@ -2,92 +2,129 @@
|
|||||||
"eventsList": [
|
"eventsList": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title":"Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
||||||
"imgUrl": "/image/events/workshop-En.jpg"
|
"imgUrl": "/image/events/workshop-En.jpg"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"title":"AiDA X SFT AI Fashion Award 2024",
|
"title": "AiDA X SFT AI Fashion Award 2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA Global Design Awards 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem":[
|
"eventsItem": [
|
||||||
{
|
{
|
||||||
"id":1,
|
"id": 3,
|
||||||
"title":"Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
"title": "AiDA Global Design Awards 2026",
|
||||||
"imgUrl": "/image/events/workshop-En.jpg",
|
"imgUrl": "/image/events/award-poster.gif",
|
||||||
"textList":[
|
"tips": "For inquiries: awards2026@code-create.com.hk",
|
||||||
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph":[
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text":"🎨AiDA Workshop!"
|
"text": "Click the “View Details” button for more information and to join the competition! The AiDA Global Design Award 2026 is an international design competition hosted by Code‑Create, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers worldwide the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":"The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
|
"paragraph": [
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":"<b>⚠️ATTENTION❗❗</b>"
|
"text": "Participants have the opportunity to compete for cash prizes totaling up to US$9,000, gain global media exposure showcased by top international platforms, and connect with designers and industry leaders worldwide. Finalists will also attend an exclusive award ceremony in Hong Kong, with travel allowance, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"1. Add the tag in the work description #AiDAworkshop_2024"
|
|
||||||
},{
|
|
||||||
"text":"2. One winner only"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"✅Round-trip transportation fee (only within China)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"✅One night accommodation fee"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"⌛️Deadline: October 31, 2024"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id":2,
|
"id": 1,
|
||||||
"title":"AiDA X SFT AI Fashion Award 2024",
|
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
||||||
|
"imgUrl": "/image/events/workshop-En.jpg",
|
||||||
|
"textList": [
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "🎨AiDA Workshop!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "<b>⚠️ATTENTION❗❗</b>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "1. Add the tag in the work description #AiDAworkshop_2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "2. One winner only"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "✅Round-trip transportation fee (only within China)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "✅One night accommodation fee"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "⌛️Deadline: October 31, 2024"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "AiDA X SFT AI Fashion Award 2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png",
|
"imgUrl": "/image/events/Fashion-Award-2024.png",
|
||||||
"textList":[
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph":[
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text":"With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion."
|
"text": "With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":"The competition is open to all SFT students, with the winners having the chance to win cash prizes (up to 20,000 HKD), internship opportunity at BESFXXK (will work with the renowned designer, Mr Jae Hyuk Lim, for the BESFXXK collection, that will be featured at NY Fashion Week and Paris Fashion Week) and more surprises! Scan the QR code to learn more."
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "The competition is open to all SFT students, with the winners having the chance to win cash prizes (up to 20,000 HKD), internship opportunity at BESFXXK (will work with the renowned designer, Mr Jae Hyuk Lim, for the BESFXXK collection, that will be featured at NY Fashion Week and Paris Fashion Week) and more surprises! Scan the QR code to learn more."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,88 +2,125 @@
|
|||||||
"eventsList": [
|
"eventsList": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
||||||
"imgUrl": "/image/events/workshop-Cn.jpg"
|
"imgUrl": "/image/events/workshop-Cn.jpg"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"title":"AiDA X SFT AI时尚设计比赛2024",
|
"title": "AiDA X SFT AI时尚设计比赛2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA全球设计奖 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster-zh.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem":[
|
"eventsItem": [
|
||||||
{
|
{
|
||||||
"id":1,
|
"id": 3,
|
||||||
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
"title": "AiDA全球设计奖 2026",
|
||||||
"imgUrl": "/image/events/workshop-Cn.jpg",
|
"imgUrl": "/image/events/award-poster-zh.gif",
|
||||||
"textList":[
|
"tips": "如有疑问,请联系:awards2026@code-create.com.hk",
|
||||||
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph":[
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text":"🎨这是一趟艺术巅峰之旅!AiDA Workshop!"
|
"text": "秉承推动 AI 赋能创意设计的初衷,Code‑Create 举办了「AiDA 全球设计大奖 2026」,面向来全球的设计师,鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":"参与过程很简单,利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞)将被邀请至11月14日 举办的AiDA Workshop香港线下活动,与英国皇家艺术学院(RCA)、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流!(名额仅限1名)"
|
"paragraph": [
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":"<b>⚠️注意❗❗</b>"
|
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅津贴,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"1. 作品描述添加tag: #AiDAworkshop_2024"
|
|
||||||
},{
|
|
||||||
"text":"2. 一个冠军名额"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"<b>🤩Code-Create将提供(适用条款条规):</b>"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"✅往返机票/动车费用(仅限中国地区)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"✅一晚酒店住宿费用"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},{
|
|
||||||
"paragraph":[
|
|
||||||
{
|
|
||||||
"text":"⌛️截止时间:2024.10.31"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id":2,
|
"id": 1,
|
||||||
"title":"AiDA X SFT AI时尚设计比赛2024",
|
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png",
|
"imgUrl": "/image/events/workshop-Cn.jpg",
|
||||||
"textList":[
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph":[
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text":"秉承着激发学生使用AI进行时尚设计的创新能力的初衷,Code-Create和香港理工大学时装及纺织学院(SFT)共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验,为未来的时尚设计行业打下了坚实的基础,成为时尚界的AI先锋。"
|
"text": "🎨这是一趟艺术巅峰之旅!AiDA Workshop!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
"paragraph":[
|
|
||||||
{
|
{
|
||||||
"text":" 此次比赛面向全体SFT 学生,最终获奖者将赢取丰厚奖金(最高可达2万港币),获得在BESFXXK的实习机会(将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "参与过程很简单,利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞)将被邀请至11月14日 举办的AiDA Workshop香港线下活动,与英国皇家艺术学院(RCA)、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流!(名额仅限1名)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "<b>⚠️注意❗❗</b>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "1. 作品描述添加tag: #AiDAworkshop_2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "2. 一个冠军名额"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "<b>🤩Code-Create将提供(适用条款条规):</b>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "✅往返机票/动车费用(仅限中国地区)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "✅一晚酒店住宿费用"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "⌛️截止时间:2024.10.31"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "AiDA X SFT AI时尚设计比赛2024",
|
||||||
|
"imgUrl": "/image/events/Fashion-Award-2024.png",
|
||||||
|
"textList": [
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "秉承着激发学生使用AI进行时尚设计的创新能力的初衷,Code-Create和香港理工大学时装及纺织学院(SFT)共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验,为未来的时尚设计行业打下了坚实的基础,成为时尚界的AI先锋。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": " 此次比赛面向全体SFT 学生,最终获奖者将赢取丰厚奖金(最高可达2万港币),获得在BESFXXK的实习机会(将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2488,3 +2488,25 @@ textarea:focus {
|
|||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.flex-center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.flex-1{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -2406,3 +2406,25 @@ textarea:focus{
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.flex-center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.flex-1{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -2,21 +2,36 @@
|
|||||||
<div class="account_systemMessage">
|
<div class="account_systemMessage">
|
||||||
<div class="account_generalMessage_title modal_title_text">
|
<div class="account_generalMessage_title modal_title_text">
|
||||||
<!-- <span>系统消息</span> -->
|
<!-- <span>系统消息</span> -->
|
||||||
<div class="account_generalMessage_title_setting" @click="allRead">{{$t('account.AllRead')}}</div>
|
<div class="account_generalMessage_title_setting" @click="allRead">
|
||||||
|
{{ $t("account.AllRead") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" v-for="item in dataList" :key="item.id" @click="setRead(item)">
|
</div>
|
||||||
|
<div
|
||||||
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
v-for="item in dataList"
|
||||||
|
:key="item.id"
|
||||||
|
@click="setRead(item)"
|
||||||
|
>
|
||||||
<a-badge :dot="item.isRead == 0"></a-badge>
|
<a-badge :dot="item.isRead == 0"></a-badge>
|
||||||
<div class="account_generalMessage_item_title">
|
<div class="account_generalMessage_item_title">
|
||||||
<div class="account_generalMessage_item_title_text" :title="item.content">{{ item.content.title }}</div>
|
<div class="account_generalMessage_item_title_text" :title="item.content">
|
||||||
|
{{ item.content.title }}
|
||||||
|
</div>
|
||||||
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal_title_text_intro">
|
<div class="modal_title_text_intro">
|
||||||
{{ item.content.content }}
|
{{ item.content.content }}
|
||||||
<span v-if="item.content.link" class="account_generalMessage_item_link">{{ item.content.link }}</span>
|
<span v-if="item.content.link" class="account_generalMessage_item_link">{{
|
||||||
|
item.content.link
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" style="display:flex;justify-content: center;" v-if="dataList.length == 0 && isNoData">
|
<div
|
||||||
{{$t('account.dataNull')}}
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
style="display: flex; justify-content: center"
|
||||||
|
v-if="dataList.length == 0 && isNoData"
|
||||||
|
>
|
||||||
|
{{ $t("account.dataNull") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="page_loading_box" v-show="!isNoData">
|
<div class="page_loading_box" v-show="!isNoData">
|
||||||
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
||||||
@@ -27,117 +42,135 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent,computed,ref,reactive,nextTick,toRefs,createVNode, onMounted} from 'vue'
|
import {
|
||||||
import { Https } from "@/tool/https";
|
defineComponent,
|
||||||
import { useRouter,useRoute } from 'vue-router'
|
computed,
|
||||||
import { useStore } from "vuex";
|
ref,
|
||||||
import { useI18n } from 'vue-i18n'
|
reactive,
|
||||||
|
nextTick,
|
||||||
|
toRefs,
|
||||||
|
createVNode,
|
||||||
|
onMounted
|
||||||
|
} from "vue"
|
||||||
|
import { Https } from "@/tool/https"
|
||||||
|
import { useRouter, useRoute } from "vue-router"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
import { isValidUrl } from "@/tool/util"
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components: {},
|
||||||
},
|
|
||||||
// emits:['putListData'],
|
// emits:['putListData'],
|
||||||
props:['setReadStatus','setAllmessage','getHistory'],
|
props: ["setReadStatus", "setAllmessage", "getHistory"],
|
||||||
setup(prop,{emit}) {
|
setup(prop, { emit }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
let accountMessage = reactive({
|
let accountMessage = reactive({
|
||||||
dataList: [],
|
dataList: [],
|
||||||
page:1,
|
page: 1,
|
||||||
size:10,
|
size: 10,
|
||||||
isNoData: false,
|
isNoData: false,
|
||||||
isShowMark: false,
|
isShowMark: false
|
||||||
})
|
})
|
||||||
let loadingDom:any = ref(null)
|
let loadingDom: any = ref(null)
|
||||||
let setmessageList = ()=>{
|
let setmessageList = () => {
|
||||||
accountMessage.isShowMark = true
|
accountMessage.isShowMark = true
|
||||||
let data = {
|
let data = {
|
||||||
page: accountMessage.page,
|
page: accountMessage.page,
|
||||||
size: accountMessage.size,
|
size: accountMessage.size
|
||||||
}
|
}
|
||||||
prop.getHistory(data).then((rv:any)=>{
|
prop.getHistory(data)
|
||||||
|
.then((rv: any) => {
|
||||||
accountMessage.isShowMark = false
|
accountMessage.isShowMark = false
|
||||||
|
|
||||||
if(rv.content.length == 0) {
|
if (rv.content.length == 0) {
|
||||||
accountMessage.isNoData = true
|
accountMessage.isNoData = true
|
||||||
}else{
|
} else {
|
||||||
rv.content.forEach((item:any) => {
|
rv.content.forEach((item: any) => {
|
||||||
item.content = JSON.parse(item.content)
|
item.content = JSON.parse(item.content)
|
||||||
});
|
})
|
||||||
accountMessage.dataList.push(...rv.content)
|
accountMessage.dataList.push(...rv.content)
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
})
|
||||||
|
.catch(() => {
|
||||||
accountMessage.isShowMark = false
|
accountMessage.isShowMark = false
|
||||||
accountMessage.isNoData = true
|
accountMessage.isNoData = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let setRead = (item:any)=>{
|
let setRead = (item: any) => {
|
||||||
prop.setReadStatus(item).then((rv:any)=>{
|
let content = item.content.content
|
||||||
item.isRead = 1
|
if (isValidUrl(content)) {
|
||||||
}).catch((err:any)=>{
|
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
|
||||||
})
|
content += "&env=dev"
|
||||||
}
|
}
|
||||||
let allRead = ()=>{
|
window.open(content, "_blank")
|
||||||
// emit('setAllmessage')
|
}
|
||||||
prop.setAllmessage().then(()=>{
|
|
||||||
accountMessage.dataList.forEach((item:any)=>{
|
prop.setReadStatus(item)
|
||||||
|
.then((rv: any) => {
|
||||||
item.isRead = 1
|
item.isRead = 1
|
||||||
})
|
})
|
||||||
}).catch((err:any)=>{
|
.catch((err: any) => {})
|
||||||
|
}
|
||||||
|
let allRead = () => {
|
||||||
|
// emit('setAllmessage')
|
||||||
|
prop.setAllmessage()
|
||||||
|
.then(() => {
|
||||||
|
accountMessage.dataList.forEach((item: any) => {
|
||||||
|
item.isRead = 1
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
.catch((err: any) => {})
|
||||||
}
|
}
|
||||||
// provide('exhibitionList',exhibitionList)
|
// provide('exhibitionList',exhibitionList)
|
||||||
onMounted (()=>{
|
onMounted(() => {
|
||||||
accountMessage.isNoData = false
|
accountMessage.isNoData = false
|
||||||
accountMessage.page = 0
|
accountMessage.page = 0
|
||||||
let imgParent:any = document.querySelector('.account_systemMessage .page_loading')
|
let imgParent: any = document.querySelector(".account_systemMessage .page_loading")
|
||||||
new IntersectionObserver(
|
new IntersectionObserver(
|
||||||
(entries, observer) => {
|
(entries, observer) => {
|
||||||
// 如果不是相交,则直接返回
|
// 如果不是相交,则直接返回
|
||||||
// console.log(entries[0]);
|
// console.log(entries[0]);
|
||||||
if (!entries[0].intersectionRatio) return;
|
if (!entries[0].intersectionRatio) return
|
||||||
accountMessage.page+=1
|
accountMessage.page += 1
|
||||||
setmessageList()
|
setmessageList()
|
||||||
},
|
}
|
||||||
// { root:worksPage }
|
// { root:worksPage }
|
||||||
).observe(loadingDom.value);
|
).observe(loadingDom.value)
|
||||||
})
|
})
|
||||||
return{
|
return {
|
||||||
...toRefs(accountMessage),
|
...toRefs(accountMessage),
|
||||||
setmessageList,
|
setmessageList,
|
||||||
setRead,
|
setRead,
|
||||||
allRead,
|
allRead,
|
||||||
loadingDom,
|
loadingDom
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data() {
|
||||||
return{
|
return {}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.account_systemMessage{
|
.account_systemMessage {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.account_generalMessage_item{
|
.account_generalMessage_item {
|
||||||
font-size: var(--aida-fsize1-6);
|
font-size: var(--aida-fsize1-6);
|
||||||
.account_generalMessage_item_title{
|
.account_generalMessage_item_title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
.account_generalMessage_item_title_text{
|
.account_generalMessage_item_title_text {
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.modal_title_text_intro{
|
.modal_title_text_intro {
|
||||||
margin-left: 4rem;
|
margin-left: 4rem;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal_title_text_intro{
|
.modal_title_text_intro {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="admin_page">
|
<div class="admin_page all-user">
|
||||||
<div class="admin_table_search">
|
<div class="admin_table_search">
|
||||||
<div class="admin_state">
|
<div class="admin_state">
|
||||||
<div class="admin_state_item">
|
<div class="admin_state_item">
|
||||||
@@ -18,7 +18,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="admin_state_item">
|
<div class="admin_state_item">
|
||||||
<span>{{ $t('admin.UserName') }}:</span>
|
<span>{{ $t('admin.UserName') }}:</span>
|
||||||
<SelectUser v-model:value="ids" multiple valueKey="label" labelKey="email" />
|
<!-- <a-select
|
||||||
|
v-model:value="ids"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 230px"
|
||||||
|
:field-names="{ label: 'label', value: 'label' }"
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:placeholder="$t('admin.selectUserName')"
|
||||||
|
max-tag-count="responsive"
|
||||||
|
:options="allUserList"
|
||||||
|
@keydown.enter="gettrialList"
|
||||||
|
></a-select> -->
|
||||||
|
<SelectUser v-model="ids" labelKey="label" valueKey="label" multiple />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_search">
|
<div class="admin_search">
|
||||||
@@ -81,18 +92,11 @@
|
|||||||
}"
|
}"
|
||||||
@click="plan.status !== 'PENDING' && selectPlanFilter(plan.id)"
|
@click="plan.status !== 'PENDING' && selectPlanFilter(plan.id)"
|
||||||
>
|
>
|
||||||
<a-tooltip v-if="plan.status === 'PENDING'">
|
|
||||||
<template #title>{{ $t('admin.PlanStart') }} {{ plan.startTime }}</template>
|
|
||||||
<span class="plan_name">{{ plan.name }}</span>
|
|
||||||
<MoreOutlined class="plan_more_icon" />
|
|
||||||
</a-tooltip>
|
|
||||||
<template v-else>
|
|
||||||
<span class="plan_name">{{ plan.name }}</span>
|
<span class="plan_name">{{ plan.name }}</span>
|
||||||
<MoreOutlined
|
<MoreOutlined
|
||||||
class="plan_more_icon"
|
class="plan_more_icon"
|
||||||
@click.stop="plan.status !== 'PENDING' && openPlanRenameModal(plan)"
|
@click.stop="plan.status !== 'PENDING' && openPlanRenameModal(plan)"
|
||||||
/>
|
/>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-table
|
<a-table
|
||||||
@@ -159,9 +163,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
ref,
|
ref,
|
||||||
createVNode,
|
createVNode,
|
||||||
@@ -170,16 +174,16 @@ import {
|
|||||||
toRefs,
|
toRefs,
|
||||||
unref,
|
unref,
|
||||||
watch
|
watch
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { formatTime } from '@/tool/util'
|
import { formatTime } from '@/tool/util'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { Https } from '@/tool/https'
|
import { Https } from '@/tool/https'
|
||||||
import { Modal, message, Input } from 'ant-design-vue'
|
import { Modal, message, Input } from 'ant-design-vue'
|
||||||
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
|
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
|
||||||
import allUserPoerationsVue from './addAllUser.vue'
|
import allUserPoerationsVue from './addAllUser.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import SelectUser from '@/component/common/SelectUser.vue'
|
import SelectUser from '@/component/common/SelectUser.vue'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { allUserPoerationsVue, MoreOutlined, SelectUser },
|
components: { allUserPoerationsVue, MoreOutlined, SelectUser },
|
||||||
setup() {
|
setup() {
|
||||||
const store: any = useStore()
|
const store: any = useStore()
|
||||||
@@ -193,6 +197,9 @@ export default defineComponent({
|
|||||||
let filter: any = reactive({
|
let filter: any = reactive({
|
||||||
dataList: [],
|
dataList: [],
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
|
allUserList: computed(() => {
|
||||||
|
return store.state.adminPage.allUserList
|
||||||
|
}),
|
||||||
allCountry: [],
|
allCountry: [],
|
||||||
rowSelection: computed(() => {
|
rowSelection: computed(() => {
|
||||||
return {
|
return {
|
||||||
@@ -432,9 +439,6 @@ export default defineComponent({
|
|||||||
organizationId: orgId,
|
organizationId: orgId,
|
||||||
status: ['ACTIVE', 'PENDING']
|
status: ['ACTIVE', 'PENDING']
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
res.forEach(plan => {
|
|
||||||
plan.startTime = formatTime(plan.currentPeriodStart, 'YYYY-MM-DD hh:mm:ss')
|
|
||||||
})
|
|
||||||
// 将与当前用户 subscriptionPlanId 相同的订阅计划放到第一个
|
// 将与当前用户 subscriptionPlanId 相同的订阅计划放到第一个
|
||||||
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
|
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
|
||||||
if (userSubscriptionPlanId && Array.isArray(res)) {
|
if (userSubscriptionPlanId && Array.isArray(res)) {
|
||||||
@@ -449,7 +453,6 @@ export default defineComponent({
|
|||||||
} else {
|
} else {
|
||||||
planFilterOptions.value = res
|
planFilterOptions.value = res
|
||||||
}
|
}
|
||||||
console.log(planFilterOptions.value)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 监听组织ID,获取到值后再拉取订阅计划
|
// 监听组织ID,获取到值后再拉取订阅计划
|
||||||
@@ -664,27 +667,27 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.admin_page {
|
.admin_page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.admin_table_content {
|
.admin_table_content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.admin_page .admin_table_search .admin_state {
|
.admin_page .admin_table_search .admin_state {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 70%;
|
width: 70%;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
.admin_page .admin_table_search .admin_search {
|
.admin_page .admin_table_search .admin_search {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
width: 30%;
|
width: 30%;
|
||||||
@@ -692,8 +695,8 @@ export default defineComponent({
|
|||||||
height: 4rem;
|
height: 4rem;
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.plan_list {
|
.plan_list {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
// flex-wrap: wrap;
|
// flex-wrap: wrap;
|
||||||
@@ -749,13 +752,13 @@ export default defineComponent({
|
|||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.subscription-plan-cell {
|
.subscription-plan-cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.rename-plan-form {
|
.rename-plan-form {
|
||||||
padding: 2rem 0;
|
padding: 2rem 0;
|
||||||
.admin_state_item {
|
.admin_state_item {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -765,5 +768,13 @@ export default defineComponent({
|
|||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
.all-user {
|
||||||
|
.admin_table_content {
|
||||||
|
:deep(.ant-table-wrapper) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -148,6 +148,7 @@
|
|||||||
total: total,
|
total: total,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
bordered: false,
|
bordered: false,
|
||||||
|
showTotal: (total) => `Total Transaction: ${total}`
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, text, record, index }">
|
<template #bodyCell="{ column, text, record, index }">
|
||||||
@@ -465,13 +466,16 @@ export default defineComponent({
|
|||||||
(rv: any) => {
|
(rv: any) => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
// this.dataList = rv
|
// this.dataList = rv
|
||||||
|
// console.log('rv----',rv);
|
||||||
|
|
||||||
filter.dataList = rv.content;
|
filter.dataList = rv.content;
|
||||||
filterData.total = rv.total;
|
filterData.total = rv.total;
|
||||||
filter.tableLoading = false;
|
filter.tableLoading = false;
|
||||||
filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
|
filterData.totalPayer = rv.totalAmount;
|
||||||
const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
|
// filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
|
||||||
return total + (isNaN(value) ? 0 : value);
|
// const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
|
||||||
}, 0);
|
// return total + (isNaN(value) ? 0 : value);
|
||||||
|
// }, 0);
|
||||||
|
|
||||||
// this.workspaceItem.position = this.singleTypeList[0].label
|
// this.workspaceItem.position = this.singleTypeList[0].label
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="admin_page">
|
<div class="admin_page">
|
||||||
<div class="admin_table_search" :style="{height:isAwayOrUnfold?'7rem':''}">
|
<div class="admin_table_search" :style="{ height: isAwayOrUnfold ? '7rem' : '' }">
|
||||||
<div class="admin_state">
|
<div class="admin_state">
|
||||||
<div class="admin_state_item">
|
<div class="admin_state_item">
|
||||||
<span>Create Time:</span>
|
<span>Create Time:</span>
|
||||||
@@ -8,16 +8,11 @@
|
|||||||
style="width: 250px"
|
style="width: 250px"
|
||||||
class="range_picker"
|
class="range_picker"
|
||||||
v-model:value="rangePickerValue"
|
v-model:value="rangePickerValue"
|
||||||
:placeholder="[
|
:placeholder="[$t('HistoryPage.StartDate'), $t('HistoryPage.EndDate')]"
|
||||||
$t('HistoryPage.StartDate'),
|
|
||||||
$t('HistoryPage.EndDate'),
|
|
||||||
]"
|
|
||||||
valueFormat="YYYY-MM-DD"
|
valueFormat="YYYY-MM-DD"
|
||||||
>
|
>
|
||||||
<template #suffixIcon>
|
<template #suffixIcon>
|
||||||
<span
|
<span class="icon iconfont range_picker_icon icon-rili"></span>
|
||||||
class="icon iconfont range_picker_icon icon-rili"
|
|
||||||
></span>
|
|
||||||
</template>
|
</template>
|
||||||
</a-range-picker>
|
</a-range-picker>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,38 +58,50 @@
|
|||||||
show-search
|
show-search
|
||||||
></a-select>
|
></a-select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Orgnization:</span>
|
||||||
|
<a-select
|
||||||
|
v-model:value="organizationId"
|
||||||
|
placeholder="Select the organization"
|
||||||
|
allow-clear
|
||||||
|
style="width: 250px"
|
||||||
|
@popupScroll="handleOrganizationScroll"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in organizationOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_search">
|
<div class="admin_search">
|
||||||
<div class="admin_search_item" @click="searchHistoryList" :style="{height:isAwayOrUnfold?'4rem':''}">
|
<div
|
||||||
|
class="admin_search_item"
|
||||||
|
@click="searchHistoryList"
|
||||||
|
:style="{ height: isAwayOrUnfold ? '4rem' : '' }"
|
||||||
|
>
|
||||||
Search
|
Search
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_search_item" @click="addhHistoryList">
|
<div class="admin_search_item" @click="addhHistoryList">Add</div>
|
||||||
Add
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_state_list">
|
<div class="admin_state_list">
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('year')">
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('year')"
|
|
||||||
>
|
|
||||||
Nearly a year
|
Nearly a year
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('month')">
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('month')"
|
|
||||||
>
|
|
||||||
Last month
|
Last month
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('week')">Last week</div>
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('week')"
|
|
||||||
>
|
|
||||||
Last week
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="awayOrUnfold" :class="{ active: isAwayOrUnfold }">
|
||||||
<div class="awayOrUnfold" :class="{active:isAwayOrUnfold}">
|
<span
|
||||||
<span class="icon iconfont menu_icon icon-xiala" @click="()=>isAwayOrUnfold = !isAwayOrUnfold"></span>
|
class="icon iconfont menu_icon icon-xiala"
|
||||||
|
@click="() => (isAwayOrUnfold = !isAwayOrUnfold)"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_table_content" ref="historyTable">
|
<div class="admin_table_content" ref="historyTable">
|
||||||
<a-table
|
<a-table
|
||||||
@@ -104,24 +111,19 @@
|
|||||||
:data-source="dataList"
|
:data-source="dataList"
|
||||||
:scroll="{ y: historyTableHeight }"
|
:scroll="{ y: historyTableHeight }"
|
||||||
@change="changePage"
|
@change="changePage"
|
||||||
:showSorterTooltip='false'
|
:showSorterTooltip="false"
|
||||||
:pagination="{
|
:pagination="{
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
current: currentPage,
|
current: currentPage,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
total: total,
|
total: total,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
bordered: false,
|
bordered: false
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, text, record, index }">
|
<template #bodyCell="{ column, text, record, index }">
|
||||||
<div class="operate_list" v-if="column?.Operations">
|
<div class="operate_list" v-if="column?.Operations">
|
||||||
<div
|
<div class="operate_item" @click="setAagree(record)">Edit</div>
|
||||||
class="operate_item"
|
|
||||||
@click="setAagree(record)"
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</div>
|
|
||||||
<!-- <div
|
<!-- <div
|
||||||
class="operate_item"
|
class="operate_item"
|
||||||
@click="deleteGroup(record, index)"
|
@click="deleteGroup(record, index)"
|
||||||
@@ -132,34 +134,29 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</div>
|
</div>
|
||||||
<allUserPoerationsVue ref="allUserPoerationsVue" @searchHistoryList="searchHistoryList"></allUserPoerationsVue>
|
<allUserPoerationsVue
|
||||||
|
ref="allUserPoerationsVue"
|
||||||
|
@searchHistoryList="searchHistoryList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import { defineComponent, ref, createVNode, computed, reactive, toRefs, onMounted } from "vue"
|
||||||
defineComponent,
|
import { formatTime } from "@/tool/util"
|
||||||
ref,
|
import { useStore } from "vuex"
|
||||||
createVNode,
|
import { Https } from "@/tool/https"
|
||||||
computed,
|
import allUserPoerationsVue from "./allUserPoerations.vue"
|
||||||
reactive,
|
import SelectUser from "@/component/common/SelectUser.vue"
|
||||||
toRefs,
|
|
||||||
onMounted,
|
|
||||||
} from "vue";
|
|
||||||
import { formatTime } from "@/tool/util";
|
|
||||||
import { useStore } from "vuex";
|
|
||||||
import { Https } from "@/tool/https";
|
|
||||||
import allUserPoerationsVue from "./allUserPoerations.vue";
|
|
||||||
import SelectUser from '@/component/common/SelectUser.vue'
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {allUserPoerationsVue,SelectUser},
|
components: { allUserPoerationsVue, SelectUser },
|
||||||
setup() {
|
setup() {
|
||||||
const store:any = useStore()
|
const store: any = useStore()
|
||||||
let filter: any = reactive({
|
let filter: any = reactive({
|
||||||
dataList: [],
|
dataList: [],
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
allCountry:[],
|
allCountry: [],
|
||||||
isAwayOrUnfold:false
|
isAwayOrUnfold: false
|
||||||
});
|
})
|
||||||
let filterData: any = reactive({
|
let filterData: any = reactive({
|
||||||
rangePickerValue: [],
|
rangePickerValue: [],
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
@@ -172,40 +169,41 @@ export default defineComponent({
|
|||||||
occupation: "",
|
occupation: "",
|
||||||
systemUser: "",
|
systemUser: "",
|
||||||
order: "", //'Ascending 升序 Descending 降序'
|
order: "", //'Ascending 升序 Descending 降序'
|
||||||
orderBy:'',
|
orderBy: "",
|
||||||
userName: "",
|
userName: "",
|
||||||
});
|
organizationId: null
|
||||||
|
})
|
||||||
let state: any = ref([
|
let state: any = ref([
|
||||||
{
|
{
|
||||||
label: "all",
|
label: "all",
|
||||||
value: "",
|
value: ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'visitor',
|
label: "visitor",
|
||||||
value:'0',
|
value: "0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'yearly',
|
label: "yearly",
|
||||||
value:'1',
|
value: "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'monthly',
|
label: "monthly",
|
||||||
value:'2',
|
value: "2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'trial',
|
label: "trial",
|
||||||
value:'3',
|
value: "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "userInEvent",
|
label: "userInEvent",
|
||||||
value: "4",
|
value: "4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Edu Admin",
|
label: "Edu Admin",
|
||||||
value: "7",
|
value: "7"
|
||||||
},
|
}
|
||||||
]);
|
])
|
||||||
let renameData: any = ref({}); //修改名字选中的数据
|
let renameData: any = ref({}) //修改名字选中的数据
|
||||||
const columns: any = computed(() => {
|
const columns: any = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -213,25 +211,25 @@ export default defineComponent({
|
|||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "id",
|
dataIndex: "id",
|
||||||
key: "id",
|
key: "id",
|
||||||
width:100,
|
width: 100,
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Email",
|
title: "Email",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "userEmail",
|
dataIndex: "userEmail",
|
||||||
key: "userEmail",
|
key: "userEmail",
|
||||||
width:200,
|
width: 200,
|
||||||
ellipsis:true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "User Name",
|
title: "User Name",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "userName",
|
dataIndex: "userName",
|
||||||
key: "userName",
|
key: "userName",
|
||||||
width:150,
|
width: 150,
|
||||||
ellipsis:true
|
ellipsis: true
|
||||||
// customRender: (record: any) => {
|
// customRender: (record: any) => {
|
||||||
// let time = formatTime(
|
// let time = formatTime(
|
||||||
// record.text / 1000,
|
// record.text / 1000,
|
||||||
@@ -245,77 +243,77 @@ export default defineComponent({
|
|||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "language",
|
dataIndex: "language",
|
||||||
key: "language",
|
key: "language",
|
||||||
width:100,
|
width: 100,
|
||||||
ellipsis:true,
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Valid Start Time",
|
title: "Valid Start Time",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "validStartTime",
|
dataIndex: "validStartTime",
|
||||||
key: "validstartTime",
|
key: "validstartTime",
|
||||||
width:200,
|
width: 200,
|
||||||
ellipsis:true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let time = ''
|
let time = ""
|
||||||
if(record.text){
|
if (record.text) {
|
||||||
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
|
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
}
|
}
|
||||||
return time
|
return time
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Valid End Time",
|
title: "Valid End Time",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "validEndTime",
|
dataIndex: "validEndTime",
|
||||||
key: "validendTime",
|
key: "validendTime",
|
||||||
width:200,
|
width: 200,
|
||||||
ellipsis:true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let time = ''
|
let time = ""
|
||||||
if(record.text){
|
if (record.text) {
|
||||||
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
|
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
}
|
}
|
||||||
return time
|
return time
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Country or Region",
|
title: "Country or Region",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "country",
|
dataIndex: "country",
|
||||||
key: "country",
|
key: "country",
|
||||||
width:200,
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Create Date",
|
title: "Create Date",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "createDate",
|
dataIndex: "createDate",
|
||||||
key: "createDate",
|
key: "createDate",
|
||||||
width:200,
|
width: 200,
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Is Beginner",
|
title: "Is Beginner",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "isBeginner",
|
dataIndex: "isBeginner",
|
||||||
key: "isBeginner",
|
key: "isBeginner",
|
||||||
width:80,
|
width: 80,
|
||||||
ellipsis:true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let str;
|
let str
|
||||||
if (record.value == 1) {
|
if (record.value == 1) {
|
||||||
str = "Yes";
|
str = "Yes"
|
||||||
} else {
|
} else {
|
||||||
str = "No";
|
str = "No"
|
||||||
|
}
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
return str;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Machine Room Ip',
|
title: "Machine Room Ip",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "browserIdentifiers",
|
dataIndex: "browserIdentifiers",
|
||||||
key: "browserIdentifiers",
|
key: "browserIdentifiers",
|
||||||
width:200,
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Credits",
|
title: "Credits",
|
||||||
@@ -326,11 +324,11 @@ export default defineComponent({
|
|||||||
// resizable: true,
|
// resizable: true,
|
||||||
dataIndex: "credits",
|
dataIndex: "credits",
|
||||||
key: "credits",
|
key: "credits",
|
||||||
width:100,
|
width: 100,
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'User Type',
|
title: "User Type",
|
||||||
align: "center",
|
align: "center",
|
||||||
// width: 150,
|
// width: 150,
|
||||||
// minWidth: 100,
|
// minWidth: 100,
|
||||||
@@ -338,84 +336,84 @@ export default defineComponent({
|
|||||||
// resizable: true,
|
// resizable: true,
|
||||||
dataIndex: "systemUser",
|
dataIndex: "systemUser",
|
||||||
key: "systemUser",
|
key: "systemUser",
|
||||||
width:100,
|
width: 100,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let str;
|
let str
|
||||||
if (record.value == 0) {
|
if (record.value == 0) {
|
||||||
str = "visitor";
|
str = "visitor"
|
||||||
} else if (record.value == 1) {
|
} else if (record.value == 1) {
|
||||||
str = "yearly";
|
str = "yearly"
|
||||||
} else if (record.value == 2) {
|
} else if (record.value == 2) {
|
||||||
str = "monthly";
|
str = "monthly"
|
||||||
} else if (record.value == 3) {
|
} else if (record.value == 3) {
|
||||||
str = "trial";
|
str = "trial"
|
||||||
} else if (record.value == 4) {
|
} else if (record.value == 4) {
|
||||||
str = "userInEvent";
|
str = "userInEvent"
|
||||||
} else if (record.value == 7) {
|
} else if (record.value == 7) {
|
||||||
str = "Edu Admin";
|
str = "Edu Admin"
|
||||||
|
}
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
return str;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Operations",
|
title: "Operations",
|
||||||
key: "operation",
|
key: "operation",
|
||||||
width:120,
|
width: 120,
|
||||||
align: "center",
|
align: "center",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
// slots:{customRender:'action'}
|
// slots:{customRender:'action'}
|
||||||
Operations: true,
|
Operations: true
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
});
|
})
|
||||||
//改变页码
|
//改变页码
|
||||||
let changePage = (e: any, filters:any, sorter:any) => {
|
let changePage = (e: any, filters: any, sorter: any) => {
|
||||||
filterData.currentPage = e.current;
|
filterData.currentPage = e.current
|
||||||
filterData.pageSize = e.pageSize;
|
filterData.pageSize = e.pageSize
|
||||||
if(sorter.order){
|
if (sorter.order) {
|
||||||
if(sorter.columnKey == 'id'){
|
if (sorter.columnKey == "id") {
|
||||||
filterData.orderBy = 'id'
|
filterData.orderBy = "id"
|
||||||
}else if(sorter.columnKey == "createDate"){
|
} else if (sorter.columnKey == "createDate") {
|
||||||
filterData.orderBy = 'time'
|
filterData.orderBy = "time"
|
||||||
}else if(sorter.columnKey == "credits"){
|
} else if (sorter.columnKey == "credits") {
|
||||||
filterData.orderBy = 'credits'
|
filterData.orderBy = "credits"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(sorter.order){
|
if (sorter.order) {
|
||||||
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending";
|
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending"
|
||||||
}else{
|
} else {
|
||||||
filterData.order = ''
|
filterData.order = ""
|
||||||
|
}
|
||||||
|
gettrialList()
|
||||||
}
|
}
|
||||||
gettrialList();
|
|
||||||
};
|
|
||||||
|
|
||||||
//查询列表
|
//查询列表
|
||||||
let searchHistoryList = () => {
|
let searchHistoryList = () => {
|
||||||
filterData.currentPage = 1;
|
filterData.currentPage = 1
|
||||||
gettrialList();
|
gettrialList()
|
||||||
};
|
}
|
||||||
let clearHistoryList = () => {
|
let clearHistoryList = () => {
|
||||||
filterData.rangePickerValue = [],
|
;((filterData.rangePickerValue = []),
|
||||||
filterData.currentPage = 1,
|
(filterData.currentPage = 1),
|
||||||
filterData.pageSize = 10,
|
(filterData.pageSize = 10),
|
||||||
filterData.total = 0,
|
(filterData.total = 0),
|
||||||
filterData.country = "",
|
(filterData.country = ""),
|
||||||
filterData.email = "",
|
(filterData.email = ""),
|
||||||
filterData.userType = "",
|
(filterData.userType = ""),
|
||||||
filterData.ids = [],
|
(filterData.ids = []),
|
||||||
filterData.occupation = "",
|
(filterData.occupation = ""),
|
||||||
filterData.order = "", //'Ascending 升序 Descending 降序'
|
(filterData.order = ""), //'Ascending 升序 Descending 降序'
|
||||||
filterData.orderBy = "", //'Ascending 升序 Descending 降序'
|
(filterData.orderBy = ""), //'Ascending 升序 Descending 降序'
|
||||||
filterData.systemUser = "",
|
(filterData.systemUser = ""),
|
||||||
filterData.userName = "";
|
(filterData.userName = ""))
|
||||||
};
|
}
|
||||||
let setHistoryListData = () => {
|
let setHistoryListData = () => {
|
||||||
let startDate: any = filterData.rangePickerValue?.[0]
|
let startDate: any = filterData.rangePickerValue?.[0]
|
||||||
? filterData.rangePickerValue[0] + " " + "00:00:00"
|
? filterData.rangePickerValue[0] + " " + "00:00:00"
|
||||||
: "";
|
: ""
|
||||||
let endDate: any = filterData.rangePickerValue?.[1]
|
let endDate: any = filterData.rangePickerValue?.[1]
|
||||||
? filterData.rangePickerValue[1] + " " + "23:59:59"
|
? filterData.rangePickerValue[1] + " " + "23:59:59"
|
||||||
: "";
|
: ""
|
||||||
let data = {
|
let data = {
|
||||||
endTime: endDate,
|
endTime: endDate,
|
||||||
startTime: startDate,
|
startTime: startDate,
|
||||||
@@ -430,63 +428,118 @@ export default defineComponent({
|
|||||||
order: filterData.order,
|
order: filterData.order,
|
||||||
orderBy: filterData.orderBy,
|
orderBy: filterData.orderBy,
|
||||||
userName: filterData.userName,
|
userName: filterData.userName,
|
||||||
};
|
organizationId: filterData.organizationId
|
||||||
return data;
|
}
|
||||||
};
|
return data
|
||||||
|
}
|
||||||
//获取列表
|
//获取列表
|
||||||
let gettrialList = () => {
|
let gettrialList = () => {
|
||||||
filter.tableLoading = true;
|
filter.tableLoading = true
|
||||||
let data = setHistoryListData();
|
let data = setHistoryListData()
|
||||||
Https.axiosPost(Https.httpUrls.getUserInfo, data).then(
|
Https.axiosPost(Https.httpUrls.getUserInfo, data).then((rv: any) => {
|
||||||
(rv: any) => {
|
|
||||||
if (rv) {
|
if (rv) {
|
||||||
// this.dataList = rv
|
// this.dataList = rv
|
||||||
filter.dataList = rv.records;
|
filter.dataList = rv.records
|
||||||
filterData.total = rv.total;
|
filterData.total = rv.total
|
||||||
filter.tableLoading = false;
|
filter.tableLoading = false
|
||||||
|
|
||||||
// this.workspaceItem.position = this.singleTypeList[0].label
|
// this.workspaceItem.position = this.singleTypeList[0].label
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
let lastGeTrialList = (str: string) => {
|
let lastGeTrialList = (str: string) => {
|
||||||
clearHistoryList();
|
clearHistoryList()
|
||||||
let currentDate = new Date();
|
let currentDate = new Date()
|
||||||
let currentTimestamp = Math.floor(currentDate.getTime() / 1000);
|
let currentTimestamp = Math.floor(currentDate.getTime() / 1000)
|
||||||
// 计算30天前的时间戳
|
// 计算30天前的时间戳
|
||||||
let thirtyDaysAgoTimestamp;
|
let thirtyDaysAgoTimestamp
|
||||||
if (str == "year") {
|
if (str == "year") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60
|
||||||
} else if (str == "month") {
|
} else if (str == "month") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60
|
||||||
} else if (str == "week") {
|
} else if (str == "week") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60
|
||||||
|
}
|
||||||
|
filterData.rangePickerValue[0] = formatTime(thirtyDaysAgoTimestamp, "YYYY-MM-DD")
|
||||||
|
gettrialList()
|
||||||
}
|
}
|
||||||
filterData.rangePickerValue[0] = formatTime(
|
|
||||||
thirtyDaysAgoTimestamp,
|
|
||||||
"YYYY-MM-DD"
|
|
||||||
);
|
|
||||||
gettrialList();
|
|
||||||
};
|
|
||||||
let filterOption = (input: any, option: any) => {
|
let filterOption = (input: any, option: any) => {
|
||||||
// 使用 option.label 进行搜索
|
// 使用 option.label 进行搜索
|
||||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
};
|
}
|
||||||
let addhHistoryList = () => {
|
let addhHistoryList = () => {
|
||||||
allUserPoerationsVue.value.init('Add','')
|
allUserPoerationsVue.value.init("Add", "")
|
||||||
};
|
}
|
||||||
let allUserPoerationsVue = ref()
|
let allUserPoerationsVue = ref()
|
||||||
let setAagree = (data:any) =>{
|
let setAagree = (data: any) => {
|
||||||
allUserPoerationsVue.value.init('Edit',data)
|
allUserPoerationsVue.value.init("Edit", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const organizationOptions = ref([])
|
||||||
|
const organizationParams = reactive({
|
||||||
|
page: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
const organizationLoading = ref(false)
|
||||||
|
const getOrganizationList = async (isLoadMore = false) => {
|
||||||
|
console.log("111111")
|
||||||
|
if (organizationLoading.value) return
|
||||||
|
if (isLoadMore) {
|
||||||
|
const loaded = organizationParams.page * organizationParams.size
|
||||||
|
if (organizationParams.total && loaded >= organizationParams.total) return
|
||||||
|
organizationParams.page += 1
|
||||||
|
} else {
|
||||||
|
organizationParams.page = 1
|
||||||
|
organizationOptions.value = []
|
||||||
|
}
|
||||||
|
organizationLoading.value = true
|
||||||
|
try {
|
||||||
|
const { total, ...requestParams } = organizationParams
|
||||||
|
const rv: any = await Https.axiosPost(
|
||||||
|
Https.httpUrls.queryOrganization,
|
||||||
|
requestParams
|
||||||
|
)
|
||||||
|
if (rv) {
|
||||||
|
const newRecords = rv.records || []
|
||||||
|
// 遍历新数据,如果已存在则覆盖,不存在则追加
|
||||||
|
newRecords.forEach((newOrg: any) => {
|
||||||
|
const newOrgId = String(newOrg.id)
|
||||||
|
const existingIndex = organizationOptions.value.findIndex(
|
||||||
|
(org: any) => String(org.id) === newOrgId
|
||||||
|
)
|
||||||
|
if (existingIndex !== -1) {
|
||||||
|
// 如果已存在,用新数据覆盖旧项
|
||||||
|
organizationOptions.value[existingIndex] = newOrg
|
||||||
|
} else {
|
||||||
|
// 如果不存在,追加到末尾
|
||||||
|
organizationOptions.value.push(newOrg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
organizationParams.total = rv.total || 0
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
organizationLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOrganizationScroll = (e: any) => {
|
||||||
|
const target = e?.target
|
||||||
|
if (!target) return
|
||||||
|
const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 20
|
||||||
|
if (nearBottom) {
|
||||||
|
getOrganizationList(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let allCountry: any = sessionStorage.getItem("allCountry");
|
let allCountry: any = sessionStorage.getItem("allCountry")
|
||||||
if (allCountry) {
|
if (allCountry) {
|
||||||
filter.allCountry = JSON.parse(allCountry);
|
filter.allCountry = JSON.parse(allCountry)
|
||||||
}
|
}
|
||||||
gettrialList();
|
gettrialList()
|
||||||
});
|
getOrganizationList()
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
...toRefs(filter),
|
...toRefs(filter),
|
||||||
...toRefs(filterData),
|
...toRefs(filterData),
|
||||||
@@ -501,29 +554,32 @@ export default defineComponent({
|
|||||||
filterOption,
|
filterOption,
|
||||||
allUserPoerationsVue,
|
allUserPoerationsVue,
|
||||||
setAagree,
|
setAagree,
|
||||||
};
|
handleOrganizationScroll,
|
||||||
|
getOrganizationList,
|
||||||
|
organizationOptions,
|
||||||
|
organizationParams
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
historyTableHeight: 0,
|
historyTableHeight: 0,
|
||||||
handleResizeColumn: (w: any, col: any) => {
|
handleResizeColumn: (w: any, col: any) => {
|
||||||
col.width = w;
|
col.width = w
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let historyTable: any = this.$refs.historyTable;
|
let historyTable: any = this.$refs.historyTable
|
||||||
this.historyTableHeight = historyTable.clientHeight - 200;
|
this.historyTableHeight = historyTable.clientHeight - 200
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.admin_page .admin_table_search .admin_state {
|
.admin_page .admin_table_search .admin_state {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.admin_page{
|
.admin_page {
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -321,6 +321,7 @@ export default defineComponent({
|
|||||||
data = setEditData()
|
data = setEditData()
|
||||||
if (!data.userName || !data.userEmail || !data.validEndTime || !data.systemUser)
|
if (!data.userName || !data.userEmail || !data.validEndTime || !data.systemUser)
|
||||||
return message.warning('Please check the input box marked with *')
|
return message.warning('Please check the input box marked with *')
|
||||||
|
delete data.userName
|
||||||
Https.axiosPost(Https.httpUrls.modifyUser, {}, { params: data }).then(rv => {
|
Https.axiosPost(Https.httpUrls.modifyUser, {}, { params: data }).then(rv => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
cancelDsign()
|
cancelDsign()
|
||||||
|
|||||||
99
src/component/Administrator/globalAwardPopularity.vue
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div class="admin_page globalAwardPopularity" ref="adminPage">
|
||||||
|
<div class="admin_table_search">
|
||||||
|
<div class="admin_state">
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Current Time:</span>
|
||||||
|
<span>{{ currentTimeStr }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Raw Visi Count:</span>
|
||||||
|
<span>{{ rawVisitCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Unique Visit Count:</span>
|
||||||
|
<span>{{ uniqueVisitCount }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="admin_search">
|
||||||
|
<div class="admin_search_item" @click="getGlobalAwardPopularity">
|
||||||
|
<i class="fi fi-br-refresh"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="admin_table_content" ref="questionnaireTable">
|
||||||
|
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, createVNode,toRefs, computed,reactive, onMounted, nextTick } from "vue";
|
||||||
|
import { Https } from "@/tool/https";
|
||||||
|
import type { TableColumnsType } from 'ant-design-vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {},
|
||||||
|
setup() {
|
||||||
|
const currentTime = ref(new Date())
|
||||||
|
const currentTimeStr = computed(()=>{
|
||||||
|
return currentTime.value.toLocaleString()
|
||||||
|
})
|
||||||
|
const rawVisitCount = ref(0)
|
||||||
|
const uniqueVisitCount = ref(0)
|
||||||
|
const getGlobalAwardPopularity = () => {
|
||||||
|
Https.axiosGet(Https.httpUrls.getGlobalAwardPopularity,).then((rv)=>{
|
||||||
|
currentTime.value = new Date()
|
||||||
|
rawVisitCount.value = rv.rawVisitCount
|
||||||
|
uniqueVisitCount.value = rv.uniqueVisitCount
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(()=>{
|
||||||
|
getGlobalAwardPopularity()
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
currentTimeStr,
|
||||||
|
getGlobalAwardPopularity,
|
||||||
|
rawVisitCount,
|
||||||
|
uniqueVisitCount,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.admin_page.globalAwardPopularity{
|
||||||
|
.admin_table_search{
|
||||||
|
// flex: 1;
|
||||||
|
width: min-content;
|
||||||
|
justify-content: flex-start;
|
||||||
|
border-radius: 2rem;
|
||||||
|
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2);
|
||||||
|
margin-left: 2rem;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
.admin_state{
|
||||||
|
flex-direction: column;
|
||||||
|
width: auto;
|
||||||
|
cursor: auto;
|
||||||
|
.admin_state_item{
|
||||||
|
> span{
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.admin_search{
|
||||||
|
i{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -207,7 +207,8 @@ export class BackgroundSizeCommand extends Command {
|
|||||||
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
||||||
|
|
||||||
// 记录原尺寸
|
// 记录原尺寸
|
||||||
this.backgroundObject = findObjectById(this.canvas, this.bgLayer.fabricObject.id).object;
|
this.bgId = this.bgLayer.fabricObject?.id || this.bgLayer.fabricObjects?.[0]?.id;
|
||||||
|
this.backgroundObject = findObjectById(this.canvas, this.bgId).object;
|
||||||
|
|
||||||
this.oldWidth = this.backgroundObject.width;
|
this.oldWidth = this.backgroundObject.width;
|
||||||
this.oldHeight = this.backgroundObject.height;
|
this.oldHeight = this.backgroundObject.height;
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
);
|
);
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
console.log("==========",layer);
|
|
||||||
if (!layer) return false;
|
if (!layer) return false;
|
||||||
|
|
||||||
if(!isUndo){
|
if(!isUndo){
|
||||||
@@ -107,7 +106,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断fabricObjects是否是组对象
|
// 判断fabricObjects是否是组对象
|
||||||
const firstObj = layer.fabricObjects?.[0] || null;
|
const firstObj = layer.fabricObjects?.[0] || null;
|
||||||
// 如果没有找到第一个对象,则直接添加到当前画布
|
// 如果没有找到第一个对象,则直接添加到当前画布
|
||||||
@@ -174,8 +172,8 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
}
|
}
|
||||||
const canvasObj = findObjectById(this.canvas, firstObj?.id)?.object;
|
const canvasObj = findObjectById(this.canvas, firstObj?.id)?.object;
|
||||||
if (
|
if (
|
||||||
(canvasObj && canvasObj.type === "group") ||
|
canvasObj && (canvasObj.type === "group" ||
|
||||||
canvasObj._objects?.length > 0
|
canvasObj._objects?.length > 0)
|
||||||
) {
|
) {
|
||||||
this.newFill.set({
|
this.newFill.set({
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -343,10 +341,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
|||||||
minTop = Infinity,
|
minTop = Infinity,
|
||||||
maxRight = -Infinity,
|
maxRight = -Infinity,
|
||||||
maxBottom = -Infinity;
|
maxBottom = -Infinity;
|
||||||
console.log(
|
|
||||||
"计算当前所有对象的边界信息:===>",
|
|
||||||
this.originalfabricObjects.length
|
|
||||||
);
|
|
||||||
this.originalfabricObjects?.forEach((obj) => {
|
this.originalfabricObjects?.forEach((obj) => {
|
||||||
const { object } = findObjectById(this.canvas, obj.id) || {};
|
const { object } = findObjectById(this.canvas, obj.id) || {};
|
||||||
if (object) {
|
if (object) {
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
insertObjectAtZIndex,
|
insertObjectAtZIndex,
|
||||||
removeCanvasObjectByObject,
|
removeCanvasObjectByObject,
|
||||||
createPatternTransform,
|
createPatternTransform,
|
||||||
|
getTransformScaleAngle,
|
||||||
|
imageAddGapToCanvas,
|
||||||
} from "../utils/helper";
|
} from "../utils/helper";
|
||||||
import { restoreFabricObject } from "../utils/objectHelper";
|
import { restoreFabricObject } from "../utils/objectHelper";
|
||||||
|
|
||||||
const scale = 0.3;// 默认缩放比例
|
|
||||||
|
|
||||||
export const FillSourceToBase64 = (source) => {
|
export const FillSourceToBase64 = (source) => {
|
||||||
if (source?.toDataURL) {
|
if (source?.toDataURL) {
|
||||||
return source.toDataURL?.();
|
return source.toDataURL?.();
|
||||||
@@ -38,7 +38,6 @@ export class FillRepeatCommand extends Command {
|
|||||||
this.fillRepeat = options.fillRepeat;
|
this.fillRepeat = options.fillRepeat;
|
||||||
this.oldObjects = null;
|
this.oldObjects = null;
|
||||||
this.oldLocked = null;
|
this.oldLocked = null;
|
||||||
this.oldIsDisableUnlock = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute() {
|
async execute() {
|
||||||
@@ -63,17 +62,15 @@ export class FillRepeatCommand extends Command {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
image.set({
|
image.set({
|
||||||
id: object.id,
|
...this.copyObjectProperties(object),
|
||||||
layerId: object.layerId,
|
|
||||||
layerName: object.layerName,
|
|
||||||
...(fill_.originalInfo || {
|
...(fill_.originalInfo || {
|
||||||
top: object.top,
|
top: object.top,
|
||||||
left: object.left,
|
left: object.left,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
|
||||||
this.oldLocked = layer.locked;
|
// this.oldLocked = layer.locked;
|
||||||
layer.locked = false;
|
// layer.locked = false;
|
||||||
|
|
||||||
this.canvas.add(image);
|
this.canvas.add(image);
|
||||||
this.canvas.remove(object);
|
this.canvas.remove(object);
|
||||||
@@ -109,24 +106,35 @@ export class FillRepeatCommand extends Command {
|
|||||||
height: object.height,
|
height: object.height,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const fdObject = this.canvasManager.getFixedLayerObject();
|
||||||
const bgObject = this.canvasManager.getBackgroundLayerObject();
|
const bgObject = this.canvasManager.getBackgroundLayerObject();
|
||||||
|
const tObject = fdObject || bgObject;
|
||||||
|
const tWidth = tObject.width;
|
||||||
|
const tHeight = tObject.height;
|
||||||
|
|
||||||
|
// const offsetX = object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2;
|
||||||
|
// const offsetY = object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2;
|
||||||
|
const scaleX_ = tWidth / img.width / 5;
|
||||||
|
const scaleY_ = tHeight / img.height / 5;
|
||||||
|
const scale_ = tWidth > tHeight ? scaleX_ : scaleY_;
|
||||||
|
|
||||||
|
const patternTransform = object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale_, 0);
|
||||||
|
const scale = getTransformScaleAngle(patternTransform).scale;
|
||||||
|
const offsetX = tWidth / 2 - img.width * scale / 2;
|
||||||
|
const offsetY = tHeight / 2 - img.height * scale / 2;
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
source: img,
|
source: img,
|
||||||
repeat: this.fillRepeat,
|
repeat: this.fillRepeat,
|
||||||
patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0),
|
patternTransform,
|
||||||
offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : bgObject.width / 2, // 水平偏移
|
offsetX, // 水平偏移
|
||||||
offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : bgObject.height / 2, // 垂直偏移
|
offsetY, // 垂直偏移
|
||||||
});
|
});
|
||||||
const rect = new fabric.Rect({
|
const rect = new fabric.Rect({
|
||||||
id: object.id,
|
...this.copyObjectProperties(object),
|
||||||
layerId: object.layerId,
|
|
||||||
layerName: object.layerName,
|
|
||||||
fill_,
|
fill_,
|
||||||
});
|
});
|
||||||
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
|
||||||
this.oldLocked = layer.locked;
|
// this.oldLocked = layer.locked;
|
||||||
// this.oldIsDisableUnlock = layer.isDisableUnlock;
|
|
||||||
// layer.isDisableUnlock = true;
|
|
||||||
if (this.oldObjects.type === "rect") {
|
if (this.oldObjects.type === "rect") {
|
||||||
rect.set({
|
rect.set({
|
||||||
width: object.width,
|
width: object.width,
|
||||||
@@ -142,17 +150,17 @@ export class FillRepeatCommand extends Command {
|
|||||||
flipY: object.flipY,
|
flipY: object.flipY,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let scaleX = bgObject.scaleX || 1;
|
let scaleX = tObject.scaleX || 1;
|
||||||
let scaleY = bgObject.scaleY || 1;
|
let scaleY = tObject.scaleY || 1;
|
||||||
rect.set({
|
rect.set({
|
||||||
width: bgObject.width,
|
width: tWidth,
|
||||||
height: bgObject.height,
|
height: tHeight,
|
||||||
top: bgObject.top - bgObject.height * scaleY / 2,
|
top: tObject.top - tHeight * scaleY / 2,
|
||||||
left: bgObject.left - bgObject.width * scaleX / 2,
|
left: tObject.left - tWidth * scaleX / 2,
|
||||||
scaleX,
|
scaleX,
|
||||||
scaleY,
|
scaleY,
|
||||||
});
|
});
|
||||||
layer.locked = true;
|
// layer.locked = true;
|
||||||
}
|
}
|
||||||
rect.set("fill", pattern);
|
rect.set("fill", pattern);
|
||||||
this.canvas.add(rect);
|
this.canvas.add(rect);
|
||||||
@@ -181,14 +189,23 @@ export class FillRepeatCommand extends Command {
|
|||||||
this.canvas.remove(object);
|
this.canvas.remove(object);
|
||||||
this.canvas.add(this.oldObjects);
|
this.canvas.add(this.oldObjects);
|
||||||
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
|
||||||
layer.locked = this.oldLocked;
|
// layer.locked = this.oldLocked;
|
||||||
// layer.isDisableUnlock = this.oldIsDisableUnlock;
|
|
||||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||||
await this.layerManager?.sortLayersWithTool?.();
|
await this.layerManager?.sortLayersWithTool?.();
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
|
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 复制原对象的属性
|
||||||
|
copyObjectProperties(object) {
|
||||||
|
return {
|
||||||
|
id: object.id,
|
||||||
|
layerId: object.layerId,
|
||||||
|
layerName: object.layerName,
|
||||||
|
isPrintTrims: object.isPrintTrims,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -227,6 +244,10 @@ export class FillRepeatChangeCommand extends Command {
|
|||||||
...this.newPattern,
|
...this.newPattern,
|
||||||
});
|
});
|
||||||
object.set("fill", pattern);
|
object.set("fill", pattern);
|
||||||
|
if (object.globalCompositeOperation_) {
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -273,7 +294,7 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
this.oldGapY = null;
|
this.oldGapY = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(isUndo = false) {
|
async execute(isCommand = true, isUndo = false) {
|
||||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||||
console.warn("图层不存在或没有 fabric 对象");
|
console.warn("图层不存在或没有 fabric 对象");
|
||||||
@@ -304,21 +325,18 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
object.fill_.gapY = this.newGapY;
|
object.fill_.gapY = this.newGapY;
|
||||||
}
|
}
|
||||||
const image = new Image();
|
const image = new Image();
|
||||||
|
image.crossOrigin = "anonymous";
|
||||||
image.src = object.fill_.source;
|
image.src = object.fill_.source;
|
||||||
await image.decode();
|
await image.decode();
|
||||||
object.fill_.width = image.width;
|
object.fill_.width = image.width;
|
||||||
object.fill_.height = image.height;
|
object.fill_.height = image.height;
|
||||||
// 创建透明 Canvas
|
|
||||||
const tcanvas = document.createElement('canvas');
|
|
||||||
tcanvas.width = image.width + object.fill_.gapX;
|
|
||||||
tcanvas.height = image.height + object.fill_.gapY;
|
|
||||||
const ctx = tcanvas.getContext('2d');
|
|
||||||
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
|
||||||
ctx.drawImage(image, 0, 0);
|
|
||||||
|
|
||||||
const fill = object.get("fill");
|
const fill = object.get("fill");
|
||||||
fill.source = tcanvas;
|
fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY);
|
||||||
object.set("fill", new fabric.Pattern(fill));
|
object.set("fill", new fabric.Pattern(fill));
|
||||||
|
if (isCommand && object.globalCompositeOperation_) {
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -328,7 +346,7 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
console.warn("没有旧间隙可恢复");
|
console.warn("没有旧间隙可恢复");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await this.execute(true);
|
await this.execute(true, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,11 +147,11 @@ export class LassoCutoutCommand extends CompositeCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 确定源图层
|
// 确定源图层
|
||||||
const sourceLayer = this.layerManager.getActiveLayer();
|
// const sourceLayer = this.layerManager.getActiveLayer();
|
||||||
if (!sourceLayer) {
|
// if (!sourceLayer) {
|
||||||
console.error("无法执行套索抠图:源图层无效");
|
// console.error("无法执行套索抠图:源图层无效");
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 获取源图层的所有对象(包括子图层)
|
// 获取源图层的所有对象(包括子图层)
|
||||||
// const sourceObjects = this._getLayerObjects(sourceLayer);
|
// const sourceObjects = this._getLayerObjects(sourceLayer);
|
||||||
@@ -225,7 +225,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
|||||||
|
|
||||||
const layers = this.layerManager.layers.value;
|
const layers = this.layerManager.layers.value;
|
||||||
var topLayerIndex = 0;
|
var topLayerIndex = 0;
|
||||||
layers.forEach((layer, index) => {
|
if(this.originalLayer)layers.forEach((layer, index) => {
|
||||||
if (layer.id === this.originalLayer.id) {
|
if (layer.id === this.originalLayer.id) {
|
||||||
topLayerIndex = index;
|
topLayerIndex = index;
|
||||||
}else if (layer.children.length > 0) {
|
}else if (layer.children.length > 0) {
|
||||||
|
|||||||
@@ -280,8 +280,13 @@ export class PasteLayerCommand extends Command {
|
|||||||
isCut: undefined,
|
isCut: undefined,
|
||||||
serializedObjects: undefined,
|
serializedObjects: undefined,
|
||||||
};
|
};
|
||||||
|
if(this.newLayer.isPrintTrims){
|
||||||
if (this.insertIndex !== undefined && this.insertIndex !== null) {
|
this.layers.value.forEach((layer) => {
|
||||||
|
if (layer.isPrintTrimsGroup) {
|
||||||
|
layer.children.unshift(this.newLayer);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else if (this.insertIndex !== undefined && this.insertIndex !== null) {
|
||||||
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
|
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
|
||||||
} else {
|
} else {
|
||||||
this.layers.value.push(this.newLayer);
|
this.layers.value.push(this.newLayer);
|
||||||
@@ -3684,7 +3689,7 @@ export class ChangeFixedImageCommand extends Command {
|
|||||||
opacity: currentObj.opacity,
|
opacity: currentObj.opacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
|
// console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3794,7 +3799,7 @@ export class ChangeFixedImageCommand extends Command {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
if (insertSuccess) {
|
if (insertSuccess) {
|
||||||
console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
|
// console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
|
||||||
} else {
|
} else {
|
||||||
// 如果插入失败,回退到普通添加
|
// 如果插入失败,回退到普通添加
|
||||||
this.canvas.add(newImage);
|
this.canvas.add(newImage);
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ export class ChangeFixedImageCommand extends Command {
|
|||||||
opacity: currentObj.opacity,
|
opacity: currentObj.opacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
|
// console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,7 +716,7 @@ export class ChangeFixedImageCommand extends Command {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
if (insertSuccess) {
|
if (insertSuccess) {
|
||||||
console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
|
// console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
|
||||||
} else {
|
} else {
|
||||||
// 如果插入失败,回退到普通添加
|
// 如果插入失败,回退到普通添加
|
||||||
this.canvas.add(newImage);
|
this.canvas.add(newImage);
|
||||||
|
|||||||
56
src/component/Canvas/CanvasEditor/commands/PartCommands.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { Command } from "./Command.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部件绘制命令
|
||||||
|
*/
|
||||||
|
export class PartDrawCommand extends Command {
|
||||||
|
constructor(options) {
|
||||||
|
super({
|
||||||
|
name: "部件绘制命令",
|
||||||
|
saveState: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.canvas = options.canvas;
|
||||||
|
this.partManager = options.partManager;
|
||||||
|
this.partCanvas = options.partCanvas;
|
||||||
|
this.oldPartCanvas = this.partManager.partCanvas;
|
||||||
|
}
|
||||||
|
execute() {
|
||||||
|
this.partManager.drawPartCanvas(this.partCanvas);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
undo() {
|
||||||
|
this.partManager.drawPartCanvas(this.oldPartCanvas);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 部件点选绘制命令
|
||||||
|
*/
|
||||||
|
export class PartPointDrawCommand extends Command {
|
||||||
|
constructor(options) {
|
||||||
|
super({
|
||||||
|
name: "部件点选绘制命令",
|
||||||
|
saveState: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.canvas = options.canvas;
|
||||||
|
this.partManager = options.partManager;
|
||||||
|
this.partCanvas = options.partCanvas;
|
||||||
|
this.pointList = options.pointList;
|
||||||
|
this.oldPartCanvas = this.partManager.partCanvas;
|
||||||
|
this.oldPointList = [...this.partManager.pointList];
|
||||||
|
}
|
||||||
|
async execute() {
|
||||||
|
const list = [...this.pointList];
|
||||||
|
const canvas = this.partCanvas;
|
||||||
|
const res = await this.partManager.pointDrawPartCanvas(list, canvas);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
async undo() {
|
||||||
|
const list = [...this.oldPointList];
|
||||||
|
const canvas = this.oldPartCanvas;
|
||||||
|
const res = await this.partManager.pointDrawPartCanvas(list, canvas);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -285,17 +285,15 @@ export class RasterizeLayerCommand extends Command {
|
|||||||
// 提取排序后的对象
|
// 提取排序后的对象
|
||||||
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
|
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
|
||||||
|
|
||||||
console.log(
|
// console.log(`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合` );
|
||||||
`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
|
// console.log(
|
||||||
);
|
// "🔢 对象z-index顺序:",
|
||||||
console.log(
|
// objectsWithZIndex.map((item) => ({
|
||||||
"🔢 对象z-index顺序:",
|
// id: item.object.id,
|
||||||
objectsWithZIndex.map((item) => ({
|
// type: item.object.type,
|
||||||
id: item.object.id,
|
// zIndex: item.zIndex,
|
||||||
type: item.object.type,
|
// }))
|
||||||
zIndex: item.zIndex,
|
// );
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -611,17 +609,17 @@ export class ExportLayerToImageCommand extends Command {
|
|||||||
// 提取排序后的对象
|
// 提取排序后的对象
|
||||||
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
|
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
|
||||||
|
|
||||||
console.log(
|
// console.log(
|
||||||
`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
|
// `📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
|
||||||
);
|
// );
|
||||||
console.log(
|
// console.log(
|
||||||
"🔢 对象z-index顺序:",
|
// "🔢 对象z-index顺序:",
|
||||||
objectsWithZIndex.map((item) => ({
|
// objectsWithZIndex.map((item) => ({
|
||||||
id: item.object.id,
|
// id: item.object.id,
|
||||||
type: item.object.type,
|
// type: item.object.type,
|
||||||
zIndex: item.zIndex,
|
// zIndex: item.zIndex,
|
||||||
}))
|
// }))
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
|||||||
absolutePositioned: true,
|
absolutePositioned: true,
|
||||||
opacity: 0.01, // 设置为几乎透明
|
opacity: 0.01, // 设置为几乎透明
|
||||||
id: generateId("redGreenImageMask_"),
|
id: generateId("redGreenImageMask_"),
|
||||||
|
rx: 15,
|
||||||
|
ry: 15,
|
||||||
});
|
});
|
||||||
// this.canvas.add(this.redGreenImageMask);
|
// this.canvas.add(this.redGreenImageMask);
|
||||||
this.canvas.clipPath = this.redGreenImageMask;
|
this.canvas.clipPath = this.redGreenImageMask;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class TransformCommand extends Command {
|
|||||||
this.layerManager = options.layerManager;
|
this.layerManager = options.layerManager;
|
||||||
this.layers = options.layers || null;
|
this.layers = options.layers || null;
|
||||||
this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID
|
this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID
|
||||||
|
this.isCommand = options.isCommand == undefined ? true : options.isCommand
|
||||||
const targetObject =
|
const targetObject =
|
||||||
findObjectById(this.canvas, this.objectId)?.object || null;
|
findObjectById(this.canvas, this.objectId)?.object || null;
|
||||||
|
|
||||||
@@ -189,6 +189,11 @@ export class TransformCommand extends Command {
|
|||||||
object.set(key, value);
|
object.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.isCommand && object.globalCompositeOperation_){
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 确保对象更新
|
// 确保对象更新
|
||||||
object.setCoords();
|
object.setCoords();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ const isVisible = computed(() => {
|
|||||||
OperationType.ERASER,
|
OperationType.ERASER,
|
||||||
OperationType.RED_BRUSH,
|
OperationType.RED_BRUSH,
|
||||||
OperationType.GREEN_BRUSH,
|
OperationType.GREEN_BRUSH,
|
||||||
|
OperationType.PART_BRUSH,
|
||||||
|
OperationType.PART_ERASER,
|
||||||
].includes(props.activeTool);
|
].includes(props.activeTool);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const layerManager = inject("layerManager");
|
|||||||
const isShowLayerPanel = inject("isShowLayerPanel", ref(false));
|
const isShowLayerPanel = inject("isShowLayerPanel", ref(false));
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
title: String,
|
||||||
activeTool: String,
|
activeTool: String,
|
||||||
canvasWidth: Number,
|
canvasWidth: Number,
|
||||||
canvasHeight: Number,
|
canvasHeight: Number,
|
||||||
@@ -22,6 +23,7 @@ const props = defineProps({
|
|||||||
default: true, // 是否显示图层面板
|
default: true, // 是否显示图层面板
|
||||||
},
|
},
|
||||||
isBackgroundChangeable: Boolean,
|
isBackgroundChangeable: Boolean,
|
||||||
|
isChangeCanvasSize: Boolean,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
@@ -273,7 +275,7 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="canvas-header">
|
<div class="canvas-header">
|
||||||
<div class="canvas-header-wrapper">
|
<div class="canvas-header-wrapper">
|
||||||
<span class="canvas-title">{{ $t('Canvas.Canvas') }}</span>
|
<span class="canvas-title">{{ props.title || $t("Canvas.Canvas") }}</span>
|
||||||
<!-- 默认设置 -->
|
<!-- 默认设置 -->
|
||||||
<!-- v-if="
|
<!-- v-if="
|
||||||
!activeTool ||
|
!activeTool ||
|
||||||
@@ -284,6 +286,7 @@ onMounted(() => {
|
|||||||
<div class="setting-group">
|
<div class="setting-group">
|
||||||
<span class="setting-label">{{ $t("Canvas.width") }}</span>
|
<span class="setting-label">{{ $t("Canvas.width") }}</span>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
|
:disabled="!isChangeCanvasSize"
|
||||||
:value="canvasWidth?.toFixed(2)"
|
:value="canvasWidth?.toFixed(2)"
|
||||||
class="setting-input"
|
class="setting-input"
|
||||||
:min="1"
|
:min="1"
|
||||||
@@ -300,6 +303,7 @@ onMounted(() => {
|
|||||||
<div class="setting-group">
|
<div class="setting-group">
|
||||||
<span class="setting-label">{{ $t("Canvas.height") }}</span>
|
<span class="setting-label">{{ $t("Canvas.height") }}</span>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
|
:disabled="!isChangeCanvasSize"
|
||||||
:value="canvasHeight?.toFixed(2)"
|
:value="canvasHeight?.toFixed(2)"
|
||||||
class="setting-input"
|
class="setting-input"
|
||||||
:min="1"
|
:min="1"
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ const canDeleteComputed = computed(() => {
|
|||||||
return parentLayer?.children?.length > 1;
|
return parentLayer?.children?.length > 1;
|
||||||
}
|
}
|
||||||
// 否则直接返回根图层的可删除状态
|
// 否则直接返回根图层的可删除状态
|
||||||
return props.layers.length > 3;
|
return true;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -414,14 +414,14 @@ function deleteSelectedLayers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查删除后是否还有足够的普通图层
|
// 检查删除后是否还有足够的普通图层
|
||||||
const remainingNormalLayers = layers.value.filter(
|
// const remainingNormalLayers = layers.value.filter(
|
||||||
(layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
|
// (layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
|
||||||
).length;
|
// ).length;
|
||||||
|
|
||||||
if (remainingNormalLayers < 1) {
|
// if (remainingNormalLayers < 1) {
|
||||||
console.warn("不能删除所有普通图层");
|
// console.warn("不能删除所有普通图层");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 确认删除
|
// 确认删除
|
||||||
if (selectedLayers.length > 1) {
|
if (selectedLayers.length > 1) {
|
||||||
@@ -584,15 +584,16 @@ function handleLayerClick(layer, event) {
|
|||||||
// 如果不是多选模式,才可激活图层
|
// 如果不是多选模式,才可激活图层
|
||||||
// 1.如果是组,则设置组下的第一个子图层为活动图层
|
// 1.如果是组,则设置组下的第一个子图层为活动图层
|
||||||
// 2.否则直接设置活动图层
|
// 2.否则直接设置活动图层
|
||||||
if (isGroupLayerType(layer) && layer.children && layer.children.length > 0) {
|
if (isGroupLayerType(layer) && layer.children && layer.children.length > 0 && !layer.isPrintTrimsGroup) {
|
||||||
// 如果是组图层,设置第一个子图层为活动图层
|
// 如果是组图层,设置第一个子图层为活动图层
|
||||||
layerManager?.setAllActiveGroupLayerCanvasObject?.(layer);
|
layerManager?.setAllActiveGroupLayerCanvasObject?.(layer);
|
||||||
setActiveLayer(layer.children[0].id, { parentId: layer.id });
|
setActiveLayer(layer.children[0].id, { parentId: layer.id });
|
||||||
} else {
|
} else {
|
||||||
|
let id = layer.isPrintTrimsGroup ? layer.children?.[0]?.id || layer.id : layer.id;
|
||||||
// 选中画布中的图层对象
|
// 选中画布中的图层对象
|
||||||
layerManager?.selectLayerObjects(layer.id);
|
layerManager?.selectLayerObjects(id);
|
||||||
// 否则直接设置当前图层为活动图层
|
// 否则直接设置当前图层为活动图层
|
||||||
setActiveLayer(layer.id);
|
setActiveLayer(id);
|
||||||
layerManager?.updateLayersObjectsInteractivity();
|
layerManager?.updateLayersObjectsInteractivity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -876,13 +877,15 @@ function toggleSelectedLayersVisibility() {
|
|||||||
|
|
||||||
function canDeleteLayers() {
|
function canDeleteLayers() {
|
||||||
const selectedLayers = getSelectedLayers();
|
const selectedLayers = getSelectedLayers();
|
||||||
|
console.log(selectedLayers);
|
||||||
if (selectedLayers.length === 0) return false;
|
if (selectedLayers.length === 0) return false;
|
||||||
|
|
||||||
// 检查是否包含不能删除的图层
|
// 检查是否包含不能删除的图层
|
||||||
const undeletableLayers = selectedLayers.filter((layer) => layer.isBackground || layer.isFixed);
|
const undeletableLayers = selectedLayers.filter((layer) => layer.isBackground || layer.isFixed);
|
||||||
|
|
||||||
if (undeletableLayers.length > 0) return false;
|
if (undeletableLayers.length > 0) return false;
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
// 检查删除后是否还有足够的普通图层
|
// 检查删除后是否还有足够的普通图层
|
||||||
const remainingNormalLayers = layers.value.filter(
|
const remainingNormalLayers = layers.value.filter(
|
||||||
(layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
|
(layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
const palletRef = ref(null)
|
const palletRef = ref(null)
|
||||||
watch(()=>palletData.color_,(newVal:any)=>{
|
watch(()=>palletData.color_,(newVal:any)=>{
|
||||||
if(!newVal?.rgba?.r)return
|
if(newVal?.rgba?.r == null)return
|
||||||
if(palletData.color?.gradient?.gradientShow){
|
if(palletData.color?.gradient?.gradientShow){
|
||||||
palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = {
|
palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = {
|
||||||
r:newVal.rgba.r,
|
r:newVal.rgba.r,
|
||||||
@@ -143,7 +143,7 @@ export default defineComponent({
|
|||||||
},{deep: true })
|
},{deep: true })
|
||||||
const setOperate = ()=>{
|
const setOperate = ()=>{
|
||||||
if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7'))
|
if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7'))
|
||||||
palletData.color.rgba = palletData.color?.rgba?.r?palletData.color.rgba:{r:0,g:0,b:0,a:1}
|
palletData.color.rgba = palletData.color?.rgba?.r != null?palletData.color.rgba:{r:0,g:0,b:0,a:1}
|
||||||
palletData.gradient.selectIndex = 0
|
palletData.gradient.selectIndex = 0
|
||||||
palletData.gradient.gradientShow = true
|
palletData.gradient.gradientShow = true
|
||||||
if(!palletData.color.gradient){
|
if(!palletData.color.gradient){
|
||||||
@@ -257,7 +257,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
}
|
}
|
||||||
const openPallet = ()=>{
|
const openPallet = ()=>{
|
||||||
if(palletData.palletShow && props.selectColor?.rgba?.r){
|
if(palletData.palletShow && props.selectColor?.rgba?.r != null){
|
||||||
if(props.selectColor.gradient){
|
if(props.selectColor.gradient){
|
||||||
palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba
|
palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -15,6 +15,20 @@
|
|||||||
{{ t("Canvas.GarmentPartSelector") }}
|
{{ t("Canvas.GarmentPartSelector") }}
|
||||||
</div>
|
</div>
|
||||||
<!-- 移除关闭按钮,完全通过工具切换控制显示隐藏 -->
|
<!-- 移除关闭按钮,完全通过工具切换控制显示隐藏 -->
|
||||||
|
<div class="tip">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src="/src/assets/images/canvas/shubiao-l.png"
|
||||||
|
/>
|
||||||
|
<span>{{ t("Canvas.LeftClickAdd") }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src="/src/assets/images/canvas/shubiao-r.png"
|
||||||
|
/>
|
||||||
|
<span>{{ t("Canvas.RightClickRemove") }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tool-types">
|
<div class="tool-types">
|
||||||
@@ -23,9 +37,9 @@
|
|||||||
:key="item.type"
|
:key="item.type"
|
||||||
:class="[
|
:class="[
|
||||||
'tool-btn',
|
'tool-btn',
|
||||||
{ active: selectionType === item.type },
|
{ active: toolType === item.type },
|
||||||
]"
|
]"
|
||||||
@click="setSelectionType(item.type)"
|
@click="setPartType(item.type)"
|
||||||
>
|
>
|
||||||
<svg-icon :name="item.icon" :size="item.size" />
|
<svg-icon :name="item.icon" :size="item.size" />
|
||||||
<span>{{ item.label }}</span>
|
<span>{{ item.label }}</span>
|
||||||
@@ -37,23 +51,21 @@
|
|||||||
|
|
||||||
<!-- 底部选区操作工具栏 -->
|
<!-- 底部选区操作工具栏 -->
|
||||||
<div class="tool-actions">
|
<div class="tool-actions">
|
||||||
<div class="action-btn" @click="copySelectionToNewLayer">
|
<div class="action-btn" @click="onCreate">
|
||||||
<svg-icon name="CPaste" size="16" />
|
<svg-icon name="CPaste" size="16" />
|
||||||
<span class="btn-text">{{
|
<span class="btn-text">{{
|
||||||
$t("Canvas.creation")
|
$t("Canvas.creation")
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-btn" @click="cutSelectionToNewLayer">
|
<!-- <div class="action-btn" @click="onCopyCreate">
|
||||||
<svg-icon name="CCut" size="26" />
|
<svg-icon name="CCut" size="26" />
|
||||||
<span class="btn-text">{{
|
<span class="btn-text">{{
|
||||||
$t("Canvas.CreateAndCopy")
|
$t("Canvas.CreateAndCopy")
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="action-btn" @click="clearSelectionContent">
|
<div class="action-btn" @click="onReset">
|
||||||
<svg-icon name="CClear" size="18" />
|
<svg-icon name="CCut" size="26" />
|
||||||
<span class="btn-text">{{
|
<span class="btn-text">{{ $t("Canvas.TheClearlySelectedContent") }}</span>
|
||||||
$t("Canvas.TheClearlySelectedContent")
|
|
||||||
}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,23 +76,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from "vue";
|
import { ref, onMounted, watch } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import {
|
|
||||||
CreateSelectionCommand,
|
|
||||||
InvertSelectionCommand,
|
|
||||||
FeatherSelectionCommand,
|
|
||||||
FillSelectionCommand,
|
|
||||||
} from "../commands/SelectionCommands";
|
|
||||||
import { ToolCommand } from "../commands/ToolCommands";
|
|
||||||
import {
|
|
||||||
LassoCutoutCommand,
|
|
||||||
ClearSelectionCommand,
|
|
||||||
// CutSelectionToNewLayerCommand,
|
|
||||||
} from "../commands/LassoCutoutCommand";
|
|
||||||
|
|
||||||
import { OperationType } from "../utils/layerHelper";
|
import { OperationType } from "../utils/layerHelper";
|
||||||
import { ClearSelectionContentCommand } from "../commands/ClearSelectionContentCommand";
|
// 国际化
|
||||||
import { CutSelectionToNewLayerCommand } from "../commands/CutSelectionToNewLayerCommand";
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
canvas: {
|
canvas: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -90,7 +88,7 @@
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
selectionManager: {
|
partManager: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
@@ -115,7 +113,7 @@
|
|||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const selectionType = ref("rectangle");
|
const toolType = ref(OperationType.PART);
|
||||||
//打开隐藏操作面板
|
//打开隐藏操作面板
|
||||||
const closePanel = ref(false);
|
const closePanel = ref(false);
|
||||||
const setClosePanel = () => {
|
const setClosePanel = () => {
|
||||||
@@ -125,32 +123,30 @@
|
|||||||
const toolList = [
|
const toolList = [
|
||||||
{
|
{
|
||||||
type: OperationType.PART,
|
type: OperationType.PART,
|
||||||
label: "Point Selection",
|
label: t("Canvas.PointSelection"),
|
||||||
icon: "CPoint",
|
icon: "CPoint",
|
||||||
size: "20",
|
size: "20",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: OperationType.PART_RECTANGLE,
|
type: OperationType.PART_RECTANGLE,
|
||||||
label: "Marquee Selection",
|
label: t("Canvas.MarqueeSelection"),
|
||||||
icon: "CRectangle",
|
icon: "CMarquee",
|
||||||
size: "26",
|
size: "20",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: OperationType.PART_BRUSH,
|
type: OperationType.PART_BRUSH,
|
||||||
label: "Brush Selection",
|
label: t("Canvas.BrushSelection"),
|
||||||
icon: "CBrush",
|
icon: "CBrush2",
|
||||||
size: "24",
|
size: "16",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: OperationType.PART_ERASER,
|
type: OperationType.PART_ERASER,
|
||||||
label: "Erase",
|
label: t("Canvas.Erase"),
|
||||||
icon: "CEraser",
|
icon: "CEraser2",
|
||||||
size: "24",
|
size: "22",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 国际化
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
onMounted(() => {});
|
onMounted(() => {});
|
||||||
|
|
||||||
@@ -169,13 +165,7 @@
|
|||||||
if (selectionTools.includes(newTool)) {
|
if (selectionTools.includes(newTool)) {
|
||||||
show();
|
show();
|
||||||
// 根据工具类型设置选区类型
|
// 根据工具类型设置选区类型
|
||||||
selectionType.value = newTool;
|
toolType.value = newTool;
|
||||||
|
|
||||||
// 更新选区管理器的选区类型
|
|
||||||
if (props.selectionManager) {
|
|
||||||
props.selectionManager.setSelectionType(selectionType.value);
|
|
||||||
props.selectionManager.setupSelectionEvents();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -201,20 +191,28 @@
|
|||||||
/**
|
/**
|
||||||
* 设置选区类型
|
* 设置选区类型
|
||||||
*/
|
*/
|
||||||
function setSelectionType(type) {
|
function setPartType(type) {
|
||||||
selectionType.value = type;
|
toolType.value = type;
|
||||||
|
|
||||||
// 通过 ToolManager 切换工具,这会自动通知 SelectionManager
|
// 通过 ToolManager 切换工具,这会自动通知 partManager
|
||||||
if (props.toolManager) {
|
if (props.toolManager) {
|
||||||
props.toolManager.setToolWithCommand(type);
|
props.toolManager.setToolWithCommand(type);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 备用方案:如果没有 toolManager,直接更新 selectionManager
|
// 创建
|
||||||
else if (props.selectionManager) {
|
function onCreate() {
|
||||||
props.selectionManager.setSelectionType(type);
|
props.partManager.createPart();
|
||||||
props.selectionManager.setupSelectionEvents();
|
|
||||||
}
|
}
|
||||||
|
// 复制并创建
|
||||||
|
function onCopyCreate() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 清空当前点位
|
||||||
|
function onReset() {
|
||||||
|
props.partManager.clearPart();
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -290,6 +288,28 @@
|
|||||||
// border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
// border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
background-color: rgba(255, 255, 255, 0.8);
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
border-radius: 8px 8px 0 0;
|
border-radius: 8px 8px 0 0;
|
||||||
|
position: relative;
|
||||||
|
> .tip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
> img {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
@@ -370,33 +390,9 @@
|
|||||||
|
|
||||||
.tool-actions {
|
.tool-actions {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
padding: 0 10px;
|
padding: 0 30px;
|
||||||
}
|
|
||||||
|
|
||||||
/* 平板适配 - 每行4个按钮 */
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.tool-actions {
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
gap: 8px 6px;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 手机适配 - 每行3个按钮 */
|
|
||||||
@media screen and (max-width: 480px) {
|
|
||||||
.tool-actions {
|
|
||||||
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 {
|
.action-btn {
|
||||||
@@ -436,5 +432,4 @@
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<span class="label">{{ t("Canvas.scale") }}</span>
|
<span class="label">{{ t("Canvas.scale") }}</span>
|
||||||
<slider
|
<slider
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="500"
|
:max="1000"
|
||||||
:step="1"
|
:step="1"
|
||||||
is-input
|
is-input
|
||||||
:tipFormatter="(v) => `${scale}%`"
|
:tipFormatter="(v) => `${scale}%`"
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
is-input
|
is-input
|
||||||
:tipFormatter="(v) => `${v}px`"
|
:tipFormatter="(v) => `${v}px`"
|
||||||
:value="gapX"
|
:value="gapX"
|
||||||
@input="(e) => emit('inputFill_Gap', e, gapY)"
|
@input="(e) => emit('inputFillGap', e, gapY)"
|
||||||
@change="(e) => emit('changeFill_Gap', e, gapY)"
|
@change="(e) => emit('changeFillGap', e, gapY)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
@@ -45,26 +45,26 @@
|
|||||||
is-input
|
is-input
|
||||||
:tipFormatter="(v) => `${v}px`"
|
:tipFormatter="(v) => `${v}px`"
|
||||||
:value="gapY"
|
:value="gapY"
|
||||||
@input="(e) => emit('inputFill_Gap', gapX, e)"
|
@input="(e) => emit('inputFillGap', gapX, e)"
|
||||||
@change="(e) => emit('changeFill_Gap', gapX, e)"
|
@change="(e) => emit('changeFillGap', gapX, e)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">{{ t("Canvas.offset") }}</span>
|
<span class="label">{{ t("Canvas.offset") }}</span>
|
||||||
<offset-tool
|
<offset-tool
|
||||||
:left="offsetX"
|
:left="offset.x"
|
||||||
:top="offsetY"
|
:top="offset.y"
|
||||||
@input="(e) => emit('inputFillOffset', e)"
|
@input="inputFillOffset"
|
||||||
@change="(e) => emit('changeFillOffset', e)"
|
@change="changeFillOffset"
|
||||||
:show-dish="false"
|
:show-dish="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="repeat-setting-item offset">
|
<div class="repeat-setting-item offset">
|
||||||
<offset-tool
|
<offset-tool
|
||||||
:left="offsetX"
|
:left="offset.x"
|
||||||
:top="offsetY"
|
:top="offset.y"
|
||||||
@input="(e) => emit('inputFillOffset', e)"
|
@input="inputFillOffset"
|
||||||
@change="(e) => emit('changeFillOffset', e)"
|
@change="changeFillOffset"
|
||||||
:show-input="false"
|
:show-input="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,6 +79,16 @@
|
|||||||
import Slider from "../tools/Slider.vue";
|
import Slider from "../tools/Slider.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const emit = defineEmits([
|
||||||
|
"inputFillAngle",
|
||||||
|
"changeFillAngle",
|
||||||
|
"inputFillOffset",
|
||||||
|
"changeFillOffset",
|
||||||
|
"inputFillScale",
|
||||||
|
"changeFillScale",
|
||||||
|
"inputFillGap",
|
||||||
|
"changeFillGap",
|
||||||
|
]);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
object: {
|
object: {
|
||||||
@@ -89,36 +99,53 @@
|
|||||||
const angle = computed(
|
const angle = computed(
|
||||||
() => getTransformScaleAngle(props.object.fill?.patternTransform).angle
|
() => getTransformScaleAngle(props.object.fill?.patternTransform).angle
|
||||||
);
|
);
|
||||||
const scale = computed(() => {
|
|
||||||
const patternTransform = props.object.fill?.patternTransform;
|
|
||||||
const scaleValue = getTransformScaleAngle(patternTransform).scale * 100;
|
|
||||||
return Number(Number(scaleValue).toFixed(2));
|
|
||||||
});
|
|
||||||
const gapX = computed(() => props.object.fill_?.gapX || 0);
|
const gapX = computed(() => props.object.fill_?.gapX || 0);
|
||||||
const gapY = computed(() => props.object.fill_?.gapY || 0);
|
const gapY = computed(() => props.object.fill_?.gapY || 0);
|
||||||
const offsetX = computed(
|
|
||||||
() => (props.object.fill?.offsetX / props.object.width) * 100
|
// 缩放比例
|
||||||
);
|
const scale = computed(() => {
|
||||||
const offsetY = computed(
|
const object = props.object;
|
||||||
() => (props.object.fill?.offsetY / props.object.height) * 100
|
const patternTransform = object.fill?.patternTransform;
|
||||||
);
|
const scaleValue = getTransformScaleAngle(patternTransform).scale;
|
||||||
const emit = defineEmits([
|
const scaleX = scaleValue / (object.width / object.fill_.width / 5);
|
||||||
"inputFillAngle",
|
const scaleY = scaleValue / (object.height / object.fill_.height / 5);
|
||||||
"changeFillAngle",
|
const scaleXY = object.width > object.height ? scaleX : scaleY;
|
||||||
"inputFillOffset",
|
return Number(Number(scaleXY * 100).toFixed(2));
|
||||||
"changeFillOffset",
|
});
|
||||||
"inputFillScale",
|
const inputFillScale = (e) => setFillScale(e, true);
|
||||||
"changeFillScale",
|
const changeFillScale = (e) => setFillScale(e, false);
|
||||||
"inputFill_Gap",
|
const setFillScale = (e, isInput) => {
|
||||||
"changeFill_Gap",
|
const object = props.object;
|
||||||
]);
|
|
||||||
const inputFillScale = (e) => {
|
|
||||||
const scale = e / 100;
|
const scale = e / 100;
|
||||||
emit("inputFillScale", scale);
|
const scaleX = (object.width / object.fill_.width / 5) * scale;
|
||||||
|
const scaleY = (object.height / object.fill_.height / 5) * scale;
|
||||||
|
const scaleXY = object.width > object.height ? scaleX : scaleY;
|
||||||
|
emit(isInput ? "inputFillScale" : "changeFillScale", scaleXY);
|
||||||
};
|
};
|
||||||
const changeFillScale = (e) => {
|
|
||||||
const scale = e / 100;
|
// 偏移量
|
||||||
emit("changeFillScale", scale);
|
const offset = computed(() => {
|
||||||
|
const object = props.object;
|
||||||
|
const patternTransform = object.fill?.patternTransform;
|
||||||
|
const scale = getTransformScaleAngle(patternTransform).scale;
|
||||||
|
const offsetX = object.fill?.offsetX;
|
||||||
|
const offsetY = object.fill?.offsetY;
|
||||||
|
const twidth = object.fill_?.width;
|
||||||
|
const theight = object.fill_?.height;
|
||||||
|
const x = ((offsetX + (twidth * scale) / 2) * 100) / object.width;
|
||||||
|
const y = ((offsetY + (theight * scale) / 2) * 100) / object.height;
|
||||||
|
return { x, y };
|
||||||
|
});
|
||||||
|
const inputFillOffset = (e) => setFillOffset(e, true);
|
||||||
|
const changeFillOffset = (e) => setFillOffset(e, false);
|
||||||
|
const setFillOffset = (e, isInput) => {
|
||||||
|
const { left, top } = e;
|
||||||
|
const object = props.object;
|
||||||
|
const patternTransform = object.fill?.patternTransform;
|
||||||
|
const scale = getTransformScaleAngle(patternTransform).scale;
|
||||||
|
const x = (left / 100) * object.width - (object.fill_?.width * scale) / 2;
|
||||||
|
const y = (top / 100) * object.height - (object.fill_?.height * scale) / 2;
|
||||||
|
emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y });
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -126,6 +153,7 @@
|
|||||||
.repeat-setting {
|
.repeat-setting {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
width: 228px;
|
width: 228px;
|
||||||
|
overflow: hidden;
|
||||||
> .title {
|
> .title {
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
v-for="v in activeObjects"
|
v-for="v in activeObjects"
|
||||||
:key="v.id"
|
:key="v.id"
|
||||||
>
|
>
|
||||||
<div class="title">{{ v.layer?.name }}</div>
|
<!-- <div class="title">{{ v.layer?.name }}</div> -->
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div
|
<div
|
||||||
class="input"
|
class="input"
|
||||||
@@ -125,6 +125,10 @@
|
|||||||
"
|
"
|
||||||
:options="selectOptions"
|
:options="selectOptions"
|
||||||
@change="(e) => changeFillRepeat(e, v)"
|
@change="(e) => changeFillRepeat(e, v)"
|
||||||
|
:disabled="
|
||||||
|
v.layer?.metadata?.sourceData?.type ===
|
||||||
|
'trims'
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 平铺设置 -->
|
<!-- 平铺设置 -->
|
||||||
@@ -154,11 +158,11 @@
|
|||||||
@changeFillScale="
|
@changeFillScale="
|
||||||
(e) => changeFillScale(e, v)
|
(e) => changeFillScale(e, v)
|
||||||
"
|
"
|
||||||
@inputFill_Gap="
|
@inputFillGap="
|
||||||
(x, y) => inputFill_Gap(x, y, v)
|
(x, y) => inputFillGap(x, y, v)
|
||||||
"
|
"
|
||||||
@changeFill_Gap="
|
@changeFillGap="
|
||||||
(x, y) => changeFill_Gap(x, y, v)
|
(x, y) => changeFillGap(x, y, v)
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -282,10 +286,10 @@
|
|||||||
activeObjects.value.forEach((v) => {
|
activeObjects.value.forEach((v) => {
|
||||||
v.layer = props.layerManager.getLayerById(v.layerId);
|
v.layer = props.layerManager.getLayerById(v.layerId);
|
||||||
});
|
});
|
||||||
if (activeObjects.value.length === 0) {
|
if (activeObjects.value.length === 1) {
|
||||||
close();
|
|
||||||
} else {
|
|
||||||
show();
|
show();
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//取消当前选中
|
//取消当前选中
|
||||||
@@ -311,6 +315,7 @@
|
|||||||
layerManager: props.layerManager,
|
layerManager: props.layerManager,
|
||||||
layers: layers,
|
layers: layers,
|
||||||
lastSelectLayerId: lastSelectLayerId,
|
lastSelectLayerId: lastSelectLayerId,
|
||||||
|
isCommand,
|
||||||
});
|
});
|
||||||
if (isCommand) {
|
if (isCommand) {
|
||||||
props.commandManager.execute(cmd);
|
props.commandManager.execute(cmd);
|
||||||
@@ -332,6 +337,7 @@
|
|||||||
const finalState = computeAngleState(angle, obj, initialState);
|
const finalState = computeAngleState(angle, obj, initialState);
|
||||||
transformObject(obj, initialState, finalState, false);
|
transformObject(obj, initialState, finalState, false);
|
||||||
if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState;
|
if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState;
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeAngle = (angle, obj) => {
|
const changeAngle = (angle, obj) => {
|
||||||
var initialState;
|
var initialState;
|
||||||
@@ -424,6 +430,7 @@
|
|||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillAngle = (angle, obj) => {
|
const changeFillAngle = (angle, obj) => {
|
||||||
const fill = obj.get("fill");
|
const fill = obj.get("fill");
|
||||||
@@ -433,21 +440,22 @@
|
|||||||
};
|
};
|
||||||
changeFill(obj, pattern);
|
changeFill(obj, pattern);
|
||||||
};
|
};
|
||||||
// 改变填充便宜
|
// 改变填充偏移
|
||||||
const inputFillOffset = (value, obj) => {
|
const inputFillOffset = (value, obj) => {
|
||||||
if (!obj.oldPattern) obj.oldPattern = obj.get("fill");
|
if (!obj.oldPattern) obj.oldPattern = obj.get("fill");
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
...obj.get("fill"),
|
...obj.get("fill"),
|
||||||
offsetX: (value.left / 100) * obj.width,
|
offsetX: value.x,
|
||||||
offsetY: (value.top / 100) * obj.height,
|
offsetY: value.y,
|
||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillOffset = (value, obj) => {
|
const changeFillOffset = (value, obj) => {
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
offsetX: (value.left / 100) * obj.width,
|
offsetX: value.x,
|
||||||
offsetY: (value.top / 100) * obj.height,
|
offsetY: value.y,
|
||||||
});
|
});
|
||||||
changeFill(obj, pattern);
|
changeFill(obj, pattern);
|
||||||
};
|
};
|
||||||
@@ -462,6 +470,7 @@
|
|||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillScale = (scale, obj) => {
|
const changeFillScale = (scale, obj) => {
|
||||||
const fill = obj.get("fill");
|
const fill = obj.get("fill");
|
||||||
@@ -483,7 +492,7 @@
|
|||||||
props.commandManager.execute(cmd);
|
props.commandManager.execute(cmd);
|
||||||
};
|
};
|
||||||
// 改变填充间隙
|
// 改变填充间隙
|
||||||
const inputFill_Gap = (gapX, gapY, obj) => {
|
const inputFillGap = (gapX, gapY, obj) => {
|
||||||
const cmd = new FillRepeatGapChangeCommand({
|
const cmd = new FillRepeatGapChangeCommand({
|
||||||
canvas: props.canvas,
|
canvas: props.canvas,
|
||||||
layers: layers,
|
layers: layers,
|
||||||
@@ -494,9 +503,10 @@
|
|||||||
newGapY: gapY,
|
newGapY: gapY,
|
||||||
record: true,
|
record: true,
|
||||||
});
|
});
|
||||||
cmd.execute();
|
cmd.execute(false);
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFill_Gap = (gapX, gapY, obj) => {
|
const changeFillGap = (gapX, gapY, obj) => {
|
||||||
if (obj.oldFill_) {
|
if (obj.oldFill_) {
|
||||||
obj.fill_ = { ...obj.oldFill_ };
|
obj.fill_ = { ...obj.oldFill_ };
|
||||||
delete obj.oldFill_;
|
delete obj.oldFill_;
|
||||||
@@ -760,7 +770,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tool-content {
|
.tool-content {
|
||||||
overflow-y: auto;
|
// overflow-y: auto;
|
||||||
max-height: 20rem;
|
max-height: 20rem;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
|
|||||||
@@ -29,8 +29,11 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
clothingMinIOPath: {
|
||||||
|
type: String,
|
||||||
|
default: "", // 衣服底图URL-线稿
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const commandManager = inject("commandManager");
|
const commandManager = inject("commandManager");
|
||||||
const layerManager = inject("layerManager"); // 图层管理器
|
const layerManager = inject("layerManager"); // 图层管理器
|
||||||
|
|
||||||
@@ -52,6 +55,7 @@ commandManager.setChangeCallback((info) => {
|
|||||||
emit("undo-redo-status-changed", {
|
emit("undo-redo-status-changed", {
|
||||||
canUndo: canUndo.value,
|
canUndo: canUndo.value,
|
||||||
canRedo: canRedo.value,
|
canRedo: canRedo.value,
|
||||||
|
type: info.type,
|
||||||
commandManager,
|
commandManager,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -249,7 +253,13 @@ const redGreenToolsList = ref([
|
|||||||
|
|
||||||
// 根据模式选择工具列表
|
// 根据模式选择工具列表
|
||||||
const toolsList = computed(() => {
|
const toolsList = computed(() => {
|
||||||
return props.isRedGreenMode ? redGreenToolsList.value : normalToolsList.value;
|
const list = props.isRedGreenMode ? redGreenToolsList.value : normalToolsList.value;
|
||||||
|
return list.filter(tool => {
|
||||||
|
if(tool.id === OperationType.PART){
|
||||||
|
return !!props.clothingMinIOPath;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function selectTool(tool, isRedGreenMode = false) {
|
function selectTool(tool, isRedGreenMode = false) {
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ export class BrushIndicator {
|
|||||||
// this.show(e.e);
|
// this.show(e.e);
|
||||||
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
||||||
} else {
|
} else {
|
||||||
// requestIdleCallback(() => {
|
// setTimeout(() => {
|
||||||
// this.updatePosition(e.e);
|
// this.updatePosition(e.e);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
isGroupLayer,
|
isGroupLayer,
|
||||||
OperationType,
|
OperationType,
|
||||||
OperationTypes,
|
OperationTypes,
|
||||||
findLayer,
|
|
||||||
createLayer,
|
createLayer,
|
||||||
LayerType,
|
LayerType,
|
||||||
SpecialLayerId,
|
SpecialLayerId,
|
||||||
@@ -20,7 +19,6 @@ import { AnimationManager } from "./animation/AnimationManager";
|
|||||||
import { createCanvas } from "../utils/canvasFactory";
|
import { createCanvas } from "../utils/canvasFactory";
|
||||||
import { CanvasEventManager } from "./events/CanvasEventManager";
|
import { CanvasEventManager } from "./events/CanvasEventManager";
|
||||||
import CanvasConfig from "../config/canvasConfig";
|
import CanvasConfig from "../config/canvasConfig";
|
||||||
import { RedGreenModeManager } from "./RedGreenModeManager";
|
|
||||||
import { EraserStateManager } from "./EraserStateManager";
|
import { EraserStateManager } from "./EraserStateManager";
|
||||||
import {
|
import {
|
||||||
deepClone,
|
deepClone,
|
||||||
@@ -31,9 +29,11 @@ import {
|
|||||||
fillToCssStyle,
|
fillToCssStyle,
|
||||||
calculateRotatedTopLeftDeg,
|
calculateRotatedTopLeftDeg,
|
||||||
calculateCenterPoint,
|
calculateCenterPoint,
|
||||||
|
calculateTopLeftPoint,
|
||||||
createPatternTransform,
|
createPatternTransform,
|
||||||
getTransformScaleAngle,
|
getTransformScaleAngle,
|
||||||
base64ToCanvas,
|
base64ToCanvas,
|
||||||
|
imageAddGapToCanvas,
|
||||||
} from "../utils/helper";
|
} from "../utils/helper";
|
||||||
import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands";
|
import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands";
|
||||||
import { isFunction } from "lodash-es";
|
import { isFunction } from "lodash-es";
|
||||||
@@ -47,7 +47,7 @@ import { getObjectAlphaToCanvas } from "../utils/objectHelper";
|
|||||||
import { AddLayerCommand, RemoveLayerCommand, ToggleChildLayerVisibilityCommand } from "../commands/LayerCommands";
|
import { AddLayerCommand, RemoveLayerCommand, ToggleChildLayerVisibilityCommand } from "../commands/LayerCommands";
|
||||||
import { fa, id } from "element-plus/es/locales.mjs";
|
import { fa, id } from "element-plus/es/locales.mjs";
|
||||||
import i18n from "@/lang/index.ts";
|
import i18n from "@/lang/index.ts";
|
||||||
const {t} = i18n.global;
|
const { t } = i18n.global;
|
||||||
|
|
||||||
export class CanvasManager {
|
export class CanvasManager {
|
||||||
constructor(canvasElement, options) {
|
constructor(canvasElement, options) {
|
||||||
@@ -68,8 +68,11 @@ export class CanvasManager {
|
|||||||
this.isFixedErasable = options.isFixedErasable || false; // 是否允许擦除固定图层
|
this.isFixedErasable = options.isFixedErasable || false; // 是否允许擦除固定图层
|
||||||
this.eraserStateManager = null; // 橡皮擦状态管理器引用
|
this.eraserStateManager = null; // 橡皮擦状态管理器引用
|
||||||
this.handleCanvasInit = null; // 画布初始化回调函数
|
this.handleCanvasInit = null; // 画布初始化回调函数
|
||||||
|
this.partManager = options.partManager || null;
|
||||||
this.props = options.props || {};
|
this.props = options.props || {};
|
||||||
this.emit = options.emit || (() => {});
|
this.emit = options.emit || (() => { });
|
||||||
|
this.awaitCanvasRun = null;
|
||||||
|
this.canvasChangeing = false;
|
||||||
// 初始化画布
|
// 初始化画布
|
||||||
this.initializeCanvas();
|
this.initializeCanvas();
|
||||||
}
|
}
|
||||||
@@ -172,7 +175,12 @@ export class CanvasManager {
|
|||||||
_initCanvasEvents() {
|
_initCanvasEvents() {
|
||||||
// 添加笔刷图像转换处理回调
|
// 添加笔刷图像转换处理回调
|
||||||
this.canvas.onBrushImageConverted = async (fabricImage) => {
|
this.canvas.onBrushImageConverted = async (fabricImage) => {
|
||||||
|
const activeTool = this.toolManager?.activeTool?.value;
|
||||||
|
if (activeTool === OperationType.PART_BRUSH) {
|
||||||
|
this.partManager?.addDrawPartImage(fabricImage);
|
||||||
|
} else {
|
||||||
await this.addImageToLayer({ fabricImage, targetLayerId: null });
|
await this.addImageToLayer({ fabricImage, targetLayerId: null });
|
||||||
|
}
|
||||||
// 返回false表示使用默认行为(直接添加到画布)
|
// 返回false表示使用默认行为(直接添加到画布)
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -194,6 +202,10 @@ export class CanvasManager {
|
|||||||
console.log("擦除完成", e.targets);
|
console.log("擦除完成", e.targets);
|
||||||
// 可以在这里保存状态到命令管理器
|
// 可以在这里保存状态到命令管理器
|
||||||
const affectedObjects = e.targets || [];
|
const affectedObjects = e.targets || [];
|
||||||
|
const activeTool = this.toolManager?.activeTool?.value;
|
||||||
|
if (activeTool === OperationType.PART_ERASER) {
|
||||||
|
return this.partManager?.onErasingEnd(affectedObjects);
|
||||||
|
}
|
||||||
const command = this.eraserStateManager.endErasing(affectedObjects);
|
const command = this.eraserStateManager.endErasing(affectedObjects);
|
||||||
if (command && this.commandManager) {
|
if (command && this.commandManager) {
|
||||||
await this.commandManager?.executeCommand?.(command);
|
await this.commandManager?.executeCommand?.(command);
|
||||||
@@ -325,6 +337,7 @@ export class CanvasManager {
|
|||||||
setupCanvasEvents(activeElementId, layerManager) {
|
setupCanvasEvents(activeElementId, layerManager) {
|
||||||
// 创建画布事件管理器
|
// 创建画布事件管理器
|
||||||
this.eventManager = new CanvasEventManager(this.canvas, {
|
this.eventManager = new CanvasEventManager(this.canvas, {
|
||||||
|
canvasManager: this,
|
||||||
toolManager: this.toolManager,
|
toolManager: this.toolManager,
|
||||||
animationManager: this.animationManager,
|
animationManager: this.animationManager,
|
||||||
thumbnailManager: this.thumbnailManager,
|
thumbnailManager: this.thumbnailManager,
|
||||||
@@ -442,12 +455,41 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 居中所有画布元素,包括背景层和其他元素
|
// 居中所有画布元素,包括背景层和其他元素
|
||||||
this.centerAllObjects();
|
await this.centerAllObjects();
|
||||||
|
|
||||||
// // 重新渲染画布使变更生效
|
// // 重新渲染画布使变更生效
|
||||||
// this.canvas.renderAll();
|
// this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
|
// 重置画布大小参照固定图层
|
||||||
|
async resetCanvasSizeByFixedLayer() {
|
||||||
|
// 重置画布大小为固定图层的大小
|
||||||
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
|
const backgroundObject = this.getBackgroundLayerObject();
|
||||||
|
if (!fixedLayerObj || !backgroundObject) return
|
||||||
|
const fwidth = fixedLayerObj.width * fixedLayerObj.scaleX
|
||||||
|
const fheight = fixedLayerObj.height * fixedLayerObj.scaleY
|
||||||
|
const bwidth = backgroundObject.width * backgroundObject.scaleX
|
||||||
|
const bheight = backgroundObject.height * backgroundObject.scaleY
|
||||||
|
console.log(fixedLayerObj.width,
|
||||||
|
fixedLayerObj.scaleX,
|
||||||
|
fixedLayerObj.height,
|
||||||
|
fixedLayerObj.scaleY,
|
||||||
|
backgroundObject.width,
|
||||||
|
backgroundObject.scaleX,
|
||||||
|
backgroundObject.height,
|
||||||
|
backgroundObject.scaleY, 'CanvasManager resetCanvasSizeByFixedLayer')
|
||||||
|
if (Math.abs(fwidth / bwidth - fheight / bheight) < 0.1) return;
|
||||||
|
this.canvasWidth.value = fwidth
|
||||||
|
this.canvasHeight.value = fheight
|
||||||
|
backgroundObject.set({
|
||||||
|
width: this.canvasWidth.value,
|
||||||
|
height: this.canvasHeight.value,
|
||||||
|
})
|
||||||
|
this.canvas?.clipPath?.set?.({
|
||||||
|
width: this.canvasWidth.value,
|
||||||
|
height: this.canvasHeight.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 重置视图变换,使元素回到原始位置
|
* 重置视图变换,使元素回到原始位置
|
||||||
* @private
|
* @private
|
||||||
@@ -467,7 +509,6 @@ export class CanvasManager {
|
|||||||
*/
|
*/
|
||||||
async centerAllObjects() {
|
async centerAllObjects() {
|
||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
|
|
||||||
// 获取所有可见对象(不是背景元素的对象)
|
// 获取所有可见对象(不是背景元素的对象)
|
||||||
const allObjects = this.canvas.getObjects();
|
const allObjects = this.canvas.getObjects();
|
||||||
if (allObjects.length === 0) return;
|
if (allObjects.length === 0) return;
|
||||||
@@ -482,9 +523,6 @@ export class CanvasManager {
|
|||||||
// 获取背景对象
|
// 获取背景对象
|
||||||
const backgroundObject = visibleObjects.find((obj) => obj.isBackground);
|
const backgroundObject = visibleObjects.find((obj) => obj.isBackground);
|
||||||
|
|
||||||
// !this.canvas?.clipPath &&
|
|
||||||
// this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
|
||||||
|
|
||||||
this.canvas?.clipPath?.set?.({
|
this.canvas?.clipPath?.set?.({
|
||||||
left: this.width / 2,
|
left: this.width / 2,
|
||||||
top: this.height / 2,
|
top: this.height / 2,
|
||||||
@@ -577,22 +615,15 @@ export class CanvasManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
!this.canvas?.clipPath &&
|
||||||
|
this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||||
|
|
||||||
// 如果有背景层,更新蒙层位置
|
// 如果有背景层,更新蒙层位置
|
||||||
if (backgroundObject && CanvasConfig.isCropBackground) {
|
if (backgroundObject && CanvasConfig.isCropBackground) {
|
||||||
this.updateMaskPosition(backgroundObject);
|
this.updateMaskPosition(backgroundObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新颜色层信息
|
this.setSpecialCliptInfo(false, true)
|
||||||
// const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
|
||||||
// if(colorObject){
|
|
||||||
// await this.setObjecCliptInfo(colorObject);
|
|
||||||
// }
|
|
||||||
const groupLayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
|
||||||
if(groupLayer){
|
|
||||||
const groupRect = new fabric.Rect({});
|
|
||||||
await this.setObjecCliptInfo(groupRect);
|
|
||||||
groupLayer.clippingMask = groupRect.toObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新渲染画布
|
// 重新渲染画布
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
@@ -827,9 +858,9 @@ export class CanvasManager {
|
|||||||
|
|
||||||
return layerObjectByLayerId;
|
return layerObjectByLayerId;
|
||||||
}
|
}
|
||||||
getObjectsByIds(ids){
|
getObjectsByIdOrLayerId(ids) {
|
||||||
const objects = this.canvas.getObjects().filter((obj) => {
|
const objects = this.canvas.getObjects().filter((obj) => {
|
||||||
return ids.includes(obj.id);
|
return ids.includes(obj.id) || ids.includes(obj.layerId);
|
||||||
});
|
});
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
@@ -841,7 +872,6 @@ export class CanvasManager {
|
|||||||
updateMaskPosition(backgroundLayerObject) {
|
updateMaskPosition(backgroundLayerObject) {
|
||||||
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
|
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
|
||||||
return;
|
return;
|
||||||
console.log("backgroundLayerObject");
|
|
||||||
const left = backgroundLayerObject.left;
|
const left = backgroundLayerObject.left;
|
||||||
const top = backgroundLayerObject.top;
|
const top = backgroundLayerObject.top;
|
||||||
|
|
||||||
@@ -938,6 +968,7 @@ export class CanvasManager {
|
|||||||
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
||||||
* @param {Boolean} options.isPrintTrimsNoRepeat 是否包含印花图层的不平铺
|
* @param {Boolean} options.isPrintTrimsNoRepeat 是否包含印花图层的不平铺
|
||||||
* @param {Boolean} options.isPrintTrimsRepeat 是否包含印花图层的平铺
|
* @param {Boolean} options.isPrintTrimsRepeat 是否包含印花图层的平铺
|
||||||
|
* @param {Boolean} options.isContainNormalLayer 是否包含普通图层
|
||||||
* @param {String} options.layerId 导出具体图层ID
|
* @param {String} options.layerId 导出具体图层ID
|
||||||
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
||||||
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
||||||
@@ -960,6 +991,7 @@ export class CanvasManager {
|
|||||||
const enhancedOptions = {
|
const enhancedOptions = {
|
||||||
isPrintTrimsNoRepeat: true,
|
isPrintTrimsNoRepeat: true,
|
||||||
isPrintTrimsRepeat: true,
|
isPrintTrimsRepeat: true,
|
||||||
|
isContainNormalLayer: true,
|
||||||
...options,
|
...options,
|
||||||
// 如果没有明确指定,则根据当前模式自动设置
|
// 如果没有明确指定,则根据当前模式自动设置
|
||||||
restoreOpacityInRedGreen:
|
restoreOpacityInRedGreen:
|
||||||
@@ -993,16 +1025,16 @@ export class CanvasManager {
|
|||||||
|
|
||||||
// 处理特殊图层的显示状态
|
// 处理特殊图层的显示状态
|
||||||
const ptlids = [];
|
const ptlids = [];
|
||||||
if(!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat){
|
if (!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat) {
|
||||||
let layers = this.layers?.value?.find((layer) => layer.isPrintTrimsGroup)?.children || [];
|
let layers = this.layers?.value?.find((layer) => layer.isPrintTrimsGroup)?.children || [];
|
||||||
for(let layer of layers){
|
for (let layer of layers) {
|
||||||
if(!layer.visible) continue;
|
if (!layer.visible) continue;
|
||||||
let repeat = layer.fabricObjects?.[0]?.fill?.repeat || "no-repeat";
|
let repeat = layer.fabricObjects?.[0]?.fill?.repeat || "no-repeat";
|
||||||
if(typeof repeat !== "string") repeat = "no-repeat";
|
if (typeof repeat !== "string") repeat = "no-repeat";
|
||||||
if(repeat === "no-repeat"){
|
if (repeat === "no-repeat") {
|
||||||
if(enhancedOptions.isPrintTrimsNoRepeat) continue;
|
if (enhancedOptions.isPrintTrimsNoRepeat) continue;
|
||||||
}else{
|
} else {
|
||||||
if(enhancedOptions.isPrintTrimsRepeat) continue;
|
if (enhancedOptions.isPrintTrimsRepeat) continue;
|
||||||
}
|
}
|
||||||
ptlids.push(layer.id);
|
ptlids.push(layer.id);
|
||||||
const command = new ToggleChildLayerVisibilityCommand({
|
const command = new ToggleChildLayerVisibilityCommand({
|
||||||
@@ -1017,8 +1049,8 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
const res = await this.exportManager.exportImage(enhancedOptions);
|
const res = await this.exportManager.exportImage(enhancedOptions);
|
||||||
// 恢复特殊图层的显示状态
|
// 恢复特殊图层的显示状态
|
||||||
if(ptlids.length > 0){
|
if (ptlids.length > 0) {
|
||||||
for(let id of ptlids){
|
for (let id of ptlids) {
|
||||||
const command = new ToggleChildLayerVisibilityCommand({
|
const command = new ToggleChildLayerVisibilityCommand({
|
||||||
canvas: this.canvas,
|
canvas: this.canvas,
|
||||||
layers: this.layers,
|
layers: this.layers,
|
||||||
@@ -1044,12 +1076,14 @@ export class CanvasManager {
|
|||||||
// 导出颜色图层信息
|
// 导出颜色图层信息
|
||||||
const color = await this.exportColorLayer().catch(() => (null));
|
const color = await this.exportColorLayer().catch(() => (null));
|
||||||
// 导出印花和元素图层信息
|
// 导出印花和元素图层信息
|
||||||
const printTrimsData = await this.exportPrintTrimsLayers().catch(() => ({prints: null, trims: null}));
|
const printTrimsData = await this.exportPrintTrimsLayers().catch(() => ({ prints: null, trims: null }));
|
||||||
|
|
||||||
return {
|
const obj = {
|
||||||
color,
|
color,
|
||||||
...printTrimsData,
|
...printTrimsData,
|
||||||
};
|
};
|
||||||
|
console.log("==========exportExtraInfo:", obj);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1062,7 +1096,7 @@ export class CanvasManager {
|
|||||||
return Promise.reject("颜色图层不存在");
|
return Promise.reject("颜色图层不存在");
|
||||||
}
|
}
|
||||||
const object = this.getLayerObjectById(SpecialLayerId.COLOR);
|
const object = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||||
if(!object){
|
if (!object) {
|
||||||
console.warn("颜色图层不存在,请确保已添加颜色图层");
|
console.warn("颜色图层不存在,请确保已添加颜色图层");
|
||||||
return Promise.reject("颜色图层不存在");
|
return Promise.reject("颜色图层不存在");
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1127,7 @@ export class CanvasManager {
|
|||||||
});
|
});
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
const color = object.originColor;
|
const color = object.originColor;
|
||||||
return {css, base64, color};
|
return { css, base64, color };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1101,11 +1135,11 @@ export class CanvasManager {
|
|||||||
*/
|
*/
|
||||||
async exportPrintTrimsLayers() {
|
async exportPrintTrimsLayers() {
|
||||||
const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
||||||
if(!glayer) return Promise.reject("印花和元素图层组不存在");
|
if (!glayer) return Promise.reject("印花和元素图层组不存在");
|
||||||
const ids = glayer.children.map((v) => v.id);
|
const ids = glayer.children.map((v) => v.id);
|
||||||
const objects = this.getObjectsByIds(ids);
|
const objects = this.getObjectsByIdOrLayerId(ids);
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
if(!fixedLayerObj) return Promise.reject("固定图层不存在");
|
if (!fixedLayerObj) return Promise.reject("固定图层不存在");
|
||||||
const flWidth = fixedLayerObj.width
|
const flWidth = fixedLayerObj.width
|
||||||
const flHeight = fixedLayerObj.height
|
const flHeight = fixedLayerObj.height
|
||||||
const flTop = fixedLayerObj.top
|
const flTop = fixedLayerObj.top
|
||||||
@@ -1114,9 +1148,10 @@ export class CanvasManager {
|
|||||||
const flScaleY = fixedLayerObj.scaleY
|
const flScaleY = fixedLayerObj.scaleY
|
||||||
const prints = [];
|
const prints = [];
|
||||||
const trims = [];
|
const trims = [];
|
||||||
objects.forEach((v) => {
|
objects.forEach((v, i) => {
|
||||||
const sourceData = glayer.children.find((v_) => v_.id === v.id)?.metadata?.sourceData;
|
const label = glayer.children.find((v_) => (v_.id === v.layerId || v_.id === v.id));
|
||||||
if(!sourceData) return;
|
const sourceData = label?.metadata?.sourceData;
|
||||||
|
if (!sourceData) return;
|
||||||
const obj = {
|
const obj = {
|
||||||
ifSingle: typeof v.fill === "string",
|
ifSingle: typeof v.fill === "string",
|
||||||
level2Type: sourceData.level2Type,
|
level2Type: sourceData.level2Type,
|
||||||
@@ -1127,44 +1162,51 @@ export class CanvasManager {
|
|||||||
scale: [0, 0],
|
scale: [0, 0],
|
||||||
angle: v.angle,
|
angle: v.angle,
|
||||||
name: sourceData.name,
|
name: sourceData.name,
|
||||||
priority: sourceData.priority,
|
priority: i + 1,
|
||||||
object:{
|
object: {
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
scaleX: 0,//对象的缩放比例
|
scaleX: 0,//对象的缩放比例
|
||||||
scaleY: 0,//对象的缩放比例
|
scaleY: 0,//对象的缩放比例
|
||||||
opacity: v.opacity,
|
opacity: v.opacity,
|
||||||
angle: v.angle,
|
angle: v.angle,
|
||||||
flipX: v.flipX,//是否水平翻转
|
flipX: v.flipX,
|
||||||
flipY: v.flipY,//是否垂直翻转
|
flipY: v.flipY,
|
||||||
blendMode: v.globalCompositeOperation,// 混合模式
|
blendMode: v.globalCompositeOperation,
|
||||||
gapX: 0,// 平铺模式下的间距
|
gapX: 0,// 平铺模式下的间距
|
||||||
gapY: 0,// 平铺模式下的间距
|
gapY: 0,// 平铺模式下的间距
|
||||||
|
fill_repeat: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let left = (v.left - (flLeft - flWidth * flScaleX / 2));
|
let left = (v.left - (flLeft - flWidth * flScaleX / 2));
|
||||||
let top = (v.top - (flTop - flHeight * flScaleY / 2));
|
let top = (v.top - (flTop - flHeight * flScaleY / 2));
|
||||||
let width = (v.width * v.scaleX);
|
let width = (v.width * v.scaleX);
|
||||||
let height = (v.height * v.scaleY);
|
let height = (v.height * v.scaleY);
|
||||||
let {x:cx, y:cy} = calculateCenterPoint(width, height, left, top, v.angle);
|
if (v.originX === "center" && v.originY === "center") {
|
||||||
let oX = (cx-width/2) / flScaleX;
|
let { x: cx, y: cy } = calculateTopLeftPoint(width, height, left, top, v.angle);
|
||||||
let oY = (cy-height/2) / flScaleY;
|
left = cx;
|
||||||
|
top = cy;
|
||||||
|
}
|
||||||
|
let oX = left / flScaleX;
|
||||||
|
let oY = top / flScaleY;
|
||||||
let oScaleX = (v.width * v.scaleX) / (flWidth * flScaleX);
|
let oScaleX = (v.width * v.scaleX) / (flWidth * flScaleX);
|
||||||
let oScaleY = (v.height * v.scaleY) / (flHeight * flScaleY);
|
let oScaleY = (v.height * v.scaleY) / (flHeight * flScaleY);
|
||||||
// obj.object.width = width;
|
|
||||||
// obj.object.height = height;
|
|
||||||
obj.object.top = oY;
|
obj.object.top = oY;
|
||||||
obj.object.left = oX;
|
obj.object.left = oX;
|
||||||
obj.object.scaleX = oScaleX;
|
obj.object.scaleX = oScaleX;
|
||||||
obj.object.scaleY = oScaleY;
|
obj.object.scaleY = oScaleY;
|
||||||
if(obj.ifSingle){
|
if (obj.ifSingle) {
|
||||||
|
// 单个的是从中心计算的
|
||||||
|
let { x: cx, y: cy } = calculateCenterPoint(width, height, left, top, v.angle);
|
||||||
|
let oX = (cx - width / 2) / flScaleX;
|
||||||
|
let oY = (cy - height / 2) / flScaleY;
|
||||||
obj.location = [oX, oY];
|
obj.location = [oX, oY];
|
||||||
obj.scale = [oScaleX, oScaleY];
|
obj.scale = [oScaleX, oScaleY];
|
||||||
}else{
|
} else {
|
||||||
let fill = v.fill;
|
let fill = v.fill;
|
||||||
let fill_ = v.fill_;
|
let fill_ = v.fill_;
|
||||||
if(!fill || !fill_) return console.warn("印花元素不存在fill或fill_属性");
|
if (!fill || !fill_) return console.warn("印花元素不存在fill或fill_属性");
|
||||||
let {scale, angle} = getTransformScaleAngle(fill.patternTransform);
|
let { scale, angle } = getTransformScaleAngle(fill.patternTransform);
|
||||||
let scaleX = scale * 5 * v.fill_.width / flWidth;
|
let scaleX = scale * 5 * v.fill_.width / flWidth;
|
||||||
let scaleY = scale * 5 * v.fill_.height / flHeight;
|
let scaleY = scale * 5 * v.fill_.height / flHeight;
|
||||||
let scaleXY = flWidth > flHeight ? scaleX : scaleY;
|
let scaleXY = flWidth > flHeight ? scaleX : scaleY;
|
||||||
@@ -1175,18 +1217,20 @@ export class CanvasManager {
|
|||||||
obj.scale = [scaleXY, scaleXY];
|
obj.scale = [scaleXY, scaleXY];
|
||||||
obj.angle = angle;
|
obj.angle = angle;
|
||||||
obj.location = [left, top];
|
obj.location = [left, top];
|
||||||
obj.gap = [fill_.gapX, fill_.gapY];
|
obj.object.gapX = fill_.gapX;
|
||||||
|
obj.object.gapY = fill_.gapY;
|
||||||
|
obj.object.fill_repeat = fill.repeat;
|
||||||
}
|
}
|
||||||
if(obj.level2Type === "Pattern"){
|
if (sourceData.type === "print") {
|
||||||
prints.push(obj);
|
prints.push(obj);
|
||||||
}else if(obj.level2Type === "Embroidery"){
|
} else if (sourceData.type === "trims") {
|
||||||
trims.push(obj);
|
trims.push(obj);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
|
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
|
||||||
prints.forEach((v, i) => v.priority = i + 1);
|
// prints.forEach((v, i) => v.priority = i + 1);
|
||||||
trims.forEach((v, i) => v.priority = i + 1);
|
// trims.forEach((v, i) => v.priority = i + 1);
|
||||||
return {prints, trims};
|
return { prints, trims };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1229,7 +1273,7 @@ export class CanvasManager {
|
|||||||
// 排除颜色图层和特殊组图层
|
// 排除颜色图层和特殊组图层
|
||||||
const excludedLayers = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
|
const excludedLayers = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
|
||||||
this.layers.value.forEach((layer) => {
|
this.layers.value.forEach((layer) => {
|
||||||
if(excludedLayers.includes(layer.id)){
|
if (excludedLayers.includes(layer.id)) {
|
||||||
excludedLayers.push(...layer.children?.map((child) => child.id));
|
excludedLayers.push(...layer.children?.map((child) => child.id));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1272,6 +1316,7 @@ export class CanvasManager {
|
|||||||
canvasColor: this.canvasColor.value,
|
canvasColor: this.canvasColor.value,
|
||||||
activeLayerId: this.layerManager?.activeLayerId?.value,
|
activeLayerId: this.layerManager?.activeLayerId?.value,
|
||||||
};
|
};
|
||||||
|
this.FixJsonIdLoss(data);
|
||||||
console.log("获取画布JSON数据...", data);
|
console.log("获取画布JSON数据...", data);
|
||||||
return JSON.stringify(data);
|
return JSON.stringify(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1279,10 +1324,8 @@ export class CanvasManager {
|
|||||||
throw new Error("获取画布JSON失败");
|
throw new Error("获取画布JSON失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadJSON(json, calllBack) {
|
loadJSON(json, calllBack) {
|
||||||
console.log("加载画布JSON数据:", json);
|
this.canvas.loading.value = true;
|
||||||
|
|
||||||
// 确保传入的json是字符串格式
|
// 确保传入的json是字符串格式
|
||||||
if (typeof json === "object") {
|
if (typeof json === "object") {
|
||||||
json = JSON.stringify(json);
|
json = JSON.stringify(json);
|
||||||
@@ -1291,7 +1334,9 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
// 解析JSON字符串
|
// 解析JSON字符串
|
||||||
try {
|
try {
|
||||||
const parsedJson = JSON.parse(json);
|
const parsedJson = window.testCanvasJson || JSON.parse(json);
|
||||||
|
console.log("加载画布JSON数据:", parsedJson);
|
||||||
|
this.FixJsonIdLoss(parsedJson);
|
||||||
this.canvasWidth.value = parsedJson.canvasWidth || this.width;
|
this.canvasWidth.value = parsedJson.canvasWidth || this.width;
|
||||||
this.canvasHeight.value = parsedJson.canvasHeight || this.height;
|
this.canvasHeight.value = parsedJson.canvasHeight || this.height;
|
||||||
this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
|
this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
|
||||||
@@ -1317,7 +1362,7 @@ export class CanvasManager {
|
|||||||
// this.canvasHeight.value = parsedJson.canvasHeight || this.height;
|
// this.canvasHeight.value = parsedJson.canvasHeight || this.height;
|
||||||
// this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
|
// this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
|
||||||
|
|
||||||
console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode);
|
// console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode);
|
||||||
|
|
||||||
// 重置视图变换以确保元素位置正确
|
// 重置视图变换以确保元素位置正确
|
||||||
this._resetViewportTransform(1);
|
this._resetViewportTransform(1);
|
||||||
@@ -1329,7 +1374,7 @@ export class CanvasManager {
|
|||||||
|
|
||||||
// 清除当前画布内容
|
// 清除当前画布内容
|
||||||
// this.canvas.clear(); // 清除画布内容 可以先去掉 这样加载闪动的情况就比较少 如果有问题 可以再打开
|
// this.canvas.clear(); // 清除画布内容 可以先去掉 这样加载闪动的情况就比较少 如果有问题 可以再打开
|
||||||
console.log("清除当前画布内容", canvasData);
|
// console.log("清除当前画布内容", canvasData);
|
||||||
delete canvasData.clipPath; // 删除当前裁剪路径
|
delete canvasData.clipPath; // 删除当前裁剪路径
|
||||||
// 加载画布数据
|
// 加载画布数据
|
||||||
this.canvas.loadFromJSON(canvasData, async () => {
|
this.canvas.loadFromJSON(canvasData, async () => {
|
||||||
@@ -1358,7 +1403,7 @@ export class CanvasManager {
|
|||||||
// 重置画布数据
|
// 重置画布数据
|
||||||
await this.setCanvasSize(this.canvas.width, this.canvas.height);
|
await this.setCanvasSize(this.canvas.width, this.canvas.height);
|
||||||
await this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
await this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
|
||||||
await this.createOtherLayers(this.props.otherData);
|
await this.resetCanvasSizeByFixedLayer();
|
||||||
// 重新构建对象关系
|
// 重新构建对象关系
|
||||||
// restoreObjectLayerAssociations(this.layers.value, this.canvas.getObjects());
|
// restoreObjectLayerAssociations(this.layers.value, this.canvas.getObjects());
|
||||||
// 验证图层关联关系 - 稳定后可以注释
|
// 验证图层关联关系 - 稳定后可以注释
|
||||||
@@ -1370,7 +1415,7 @@ export class CanvasManager {
|
|||||||
// console.log("图层关联验证结果:", isValidate);
|
// console.log("图层关联验证结果:", isValidate);
|
||||||
// 排序
|
// 排序
|
||||||
// 使用LayerSort工具重新排列画布对象(如果可用)
|
// 使用LayerSort工具重新排列画布对象(如果可用)
|
||||||
await this?.layerManager?.layerSort?.rearrangeObjects();
|
await this?.layerManager?.layerSort?.rearrangeObjectsAsync();
|
||||||
|
|
||||||
this.layerManager.activeLayerId.value = this.layers.value[0]
|
this.layerManager.activeLayerId.value = this.layers.value[0]
|
||||||
.children?.length
|
.children?.length
|
||||||
@@ -1388,7 +1433,6 @@ export class CanvasManager {
|
|||||||
await this.layerManager?.updateLayersObjectsInteractivity?.();
|
await this.layerManager?.updateLayersObjectsInteractivity?.();
|
||||||
|
|
||||||
await calllBack?.();
|
await calllBack?.();
|
||||||
this.emit("canvas-load-json-success");
|
|
||||||
// 更新所有缩略图
|
// 更新所有缩略图
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.updateAllThumbnails();
|
this.updateAllThumbnails();
|
||||||
@@ -1410,64 +1454,122 @@ export class CanvasManager {
|
|||||||
throw new Error("解析JSON失败,请检查输入格式: " + error.message);
|
throw new Error("解析JSON失败,请检查输入格式: " + error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 修复JSON数据中的ID丢失问题 */
|
||||||
|
FixJsonIdLoss(json) {
|
||||||
|
const layerIds = [];
|
||||||
|
const layers = json?.layers || [];
|
||||||
|
const objects = json?.canvas?.objects || [];
|
||||||
|
layers.forEach((layer) => {
|
||||||
|
layerIds.push(layer.id);
|
||||||
|
layer.children?.forEach((child) => layerIds.push(child.id));
|
||||||
|
if (!layer.fabricObjects?.[0]?.id && !layer.fabricObject?.id) {
|
||||||
|
const obj = objects?.find((o) => o.layerId === layer.id);
|
||||||
|
if (obj) {
|
||||||
|
layer.fabricObjects = [{
|
||||||
|
id: obj.id,
|
||||||
|
type: obj.type,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 排序
|
||||||
|
objects.sort((a, b) => {
|
||||||
|
if (a.isBackground) return -1;
|
||||||
|
if (b.isBackground) return 1;
|
||||||
|
})
|
||||||
|
// 排除的对象id
|
||||||
|
const excludedObjects = [SpecialLayerId.PART_SELECTOR];
|
||||||
|
json.canvas.objects = objects.filter((v) => {
|
||||||
|
// 指定ID排除
|
||||||
|
if (excludedObjects.includes(v.id)) return false;
|
||||||
|
|
||||||
|
if (v.isBackground || v.isFixed) return true;
|
||||||
|
// 当前图层不存在当前对象
|
||||||
|
if (!layerIds.includes(v.layerId)) return false;
|
||||||
|
return true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建其他图层:印花、颜色、元素...
|
* 创建其他图层:印花、颜色、元素...
|
||||||
* @param {Object} otherData - 其他图层数据
|
* @param {Object} otherData - 其他图层数据
|
||||||
*/
|
*/
|
||||||
async createOtherLayers(otherData, isUpdate = false) {
|
async createOtherLayers(otherData) {
|
||||||
if (!otherData) return console.warn("otherData 为空不需要添加");
|
if (!otherData) return console.warn("otherData 为空不需要添加");
|
||||||
|
let resolve = () => { };
|
||||||
|
this.awaitCanvasRun = () => (new Promise((v) => resolve = v))
|
||||||
const otherData_ = JSON.parse(JSON.stringify(otherData));
|
const otherData_ = JSON.parse(JSON.stringify(otherData));
|
||||||
console.log("==========创建其他图层", otherData_);
|
console.log("==========创建其他图层", otherData_);
|
||||||
|
|
||||||
const updateColor = !!otherData_.color;
|
|
||||||
const updateSpecialGroup = !!otherData_.printObject || !!otherData_.trims;
|
|
||||||
// 删除颜色图层和特殊组图层
|
// 删除颜色图层和特殊组图层
|
||||||
const ids = [];
|
const ids = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
|
||||||
if(isUpdate){
|
|
||||||
updateColor && ids.push(SpecialLayerId.COLOR)
|
|
||||||
updateSpecialGroup && ids.push(SpecialLayerId.SPECIAL_GROUP)
|
|
||||||
}else{
|
|
||||||
ids.push(SpecialLayerId.COLOR)
|
|
||||||
ids.push(SpecialLayerId.SPECIAL_GROUP)
|
|
||||||
}
|
|
||||||
this.layers.value = this.layers.value.filter((layer) => {
|
this.layers.value = this.layers.value.filter((layer) => {
|
||||||
if(ids.includes(layer.id)){
|
if (ids.includes(layer.id)) {
|
||||||
ids.push(...layer.children?.map((child) => child.id));
|
ids.push(...layer.children?.map((child) => child.id));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
this.canvas.getObjects().forEach((v) => ids.includes(v.id) && this.canvas.remove(v))
|
this.canvas.getObjects().forEach((v) => {
|
||||||
|
if (ids.includes(v.id) || ids.includes(v.layerId)) {
|
||||||
|
this.canvas.remove(v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// 创建颜色图层
|
// 创建颜色图层
|
||||||
otherData_.color && await this.createColorLayer(otherData_.color);
|
await this.createColorLayer(otherData_.color);
|
||||||
|
|
||||||
const printTrimsLayers = [];// 印花和元素图层
|
const printTrimsLayers = [];// 印花和元素图层
|
||||||
const singleLayers = [];// 平铺图层
|
const singleLayers = [];// 平铺图层
|
||||||
otherData_.printObject?.prints?.forEach((print, index) => {
|
otherData_.printObject?.prints?.forEach((print, index) => {// 印花
|
||||||
print.name = t("Canvas.Print") + (index + 1);
|
print.name = t("Canvas.Print") + (index + 1);
|
||||||
if(print.ifSingle){
|
print.type = "print";
|
||||||
printTrimsLayers.unshift({...print});
|
if (print.ifSingle) {
|
||||||
}else{
|
printTrimsLayers.unshift({ ...print });
|
||||||
singleLayers.unshift({...print});
|
} else {
|
||||||
|
singleLayers.unshift({ ...print });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
otherData_.trims?.prints?.forEach((trims, index) => {
|
otherData_.trims?.prints?.forEach((trims, index) => {// 元素
|
||||||
trims.name = t("Canvas.Elements") + (index + 1);
|
trims.name = t("Canvas.Elements") + (index + 1);
|
||||||
printTrimsLayers.unshift({...trims});
|
trims.type = "trims";
|
||||||
|
printTrimsLayers.unshift({ ...trims });
|
||||||
})
|
})
|
||||||
if(isUpdate ? updateSpecialGroup : true){
|
if (printTrimsLayers.length || singleLayers.length) {
|
||||||
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
|
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
|
||||||
}
|
}
|
||||||
await this.changeCanvas();
|
await this.changeCanvas();
|
||||||
|
console.log("==========创建其他图层成功");
|
||||||
|
resolve();
|
||||||
|
this.awaitCanvasRun = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置印花元素颜色的裁剪信息
|
||||||
|
async setSpecialCliptInfo(isColor = true, isGroup = true) {
|
||||||
|
// 更新颜色层信息
|
||||||
|
if (isColor) {
|
||||||
|
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||||
|
if (colorObject) {
|
||||||
|
await this.setObjecCliptInfo(colorObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 更新特殊组图层信息
|
||||||
|
if (isGroup) {
|
||||||
|
const groupLayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
||||||
|
if (groupLayer) {
|
||||||
|
const groupRect = new fabric.Rect({});
|
||||||
|
await this.setObjecCliptInfo(groupRect);
|
||||||
|
groupLayer.clippingMask = groupRect.toObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 设置画布对象的裁剪信息
|
// 设置画布对象的裁剪信息
|
||||||
async setObjecCliptInfo(tagObject, data){
|
async setObjecCliptInfo(tagObject, data) {
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
if(!fixedLayerObj) return console.warn("固定图层为空");
|
if (!fixedLayerObj) return console.warn("固定图层为空");
|
||||||
tagObject.set({
|
tagObject.set({
|
||||||
top: fixedLayerObj.top,
|
top: fixedLayerObj.top,
|
||||||
left: fixedLayerObj.left,
|
left: fixedLayerObj.left,
|
||||||
@@ -1480,7 +1582,7 @@ export class CanvasManager {
|
|||||||
});
|
});
|
||||||
var object = fixedLayerObj;
|
var object = fixedLayerObj;
|
||||||
const imageUrl = this.props.clothingImageUrl2;
|
const imageUrl = this.props.clothingImageUrl2;
|
||||||
if(imageUrl){
|
if (imageUrl) {
|
||||||
object = await new Promise((resolve, reject) => {
|
object = await new Promise((resolve, reject) => {
|
||||||
fabric.Image.fromURL(imageUrl, (imgObject) => {
|
fabric.Image.fromURL(imageUrl, (imgObject) => {
|
||||||
tagObject.set({
|
tagObject.set({
|
||||||
@@ -1500,8 +1602,8 @@ export class CanvasManager {
|
|||||||
});
|
});
|
||||||
tagObject.set('clipPath', transparentMask);
|
tagObject.set('clipPath', transparentMask);
|
||||||
}
|
}
|
||||||
async createColorLayer(color_){
|
async createColorLayer(color_) {
|
||||||
const color = color_ || {r:0,g:0,b:0,a:0};
|
const color = color_ || { r: 0, g: 0, b: 0, a: 0 };
|
||||||
// if(findLayer(this.layers.value, SpecialLayerId.COLOR)) {
|
// if(findLayer(this.layers.value, SpecialLayerId.COLOR)) {
|
||||||
// return console.warn("画布中已存在颜色图层");
|
// return console.warn("画布中已存在颜色图层");
|
||||||
// }
|
// }
|
||||||
@@ -1545,7 +1647,7 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建印花和元素图层
|
// 创建印花和元素图层
|
||||||
async createPrintTrimsLayers(printTrimsLayers, singleLayers){
|
async createPrintTrimsLayers(printTrimsLayers, singleLayers) {
|
||||||
// if(findLayer(this.layers.value, SpecialLayerId.SPECIAL_GROUP)) {
|
// if(findLayer(this.layers.value, SpecialLayerId.SPECIAL_GROUP)) {
|
||||||
// return console.warn("画布中已存在印花和元素组图层");
|
// return console.warn("画布中已存在印花和元素组图层");
|
||||||
// }
|
// }
|
||||||
@@ -1559,31 +1661,50 @@ export class CanvasManager {
|
|||||||
const flScaleY = fixedLayerObj.scaleY
|
const flScaleY = fixedLayerObj.scaleY
|
||||||
const children = [];
|
const children = [];
|
||||||
// 添加印花和元素图层
|
// 添加印花和元素图层
|
||||||
for(let index = 0; index < printTrimsLayers.length; index++){
|
for (let index = 0; index < printTrimsLayers.length; index++) {
|
||||||
let item = printTrimsLayers[index];
|
let item = printTrimsLayers[index];
|
||||||
let id = generateId("layer_image_");
|
let id = generateId("layer_image_");
|
||||||
let name = item.name;
|
let name = item.name;
|
||||||
let image = await new Promise(resolve => {
|
let image = await new Promise(resolve => {
|
||||||
fabric.Image.fromURL(item.path, (fabricImage)=>{
|
fabric.Image.fromURL(item.path, (fabricImage) => {
|
||||||
const left = flLeft - flWidth * flScaleX / 2 + (item.location?.[0] || 0) * flScaleX
|
resolve(fabricImage);
|
||||||
const top = flTop - flHeight * flScaleY / 2 + (item.location?.[1] || 0) * flScaleY
|
}, { crossOrigin: "anonymous" });
|
||||||
const scaleX = flWidth * (item.scale?.[0] || 1) / fabricImage.width * flScaleX
|
})
|
||||||
const scaleY = flHeight * (item.scale?.[1] || 1) / fabricImage.height * flScaleY
|
let left = flLeft - flWidth * flScaleX / 2 + (item.location?.[0] || 0) * flScaleX
|
||||||
const {x, y} = calculateRotatedTopLeftDeg(
|
let top = flTop - flHeight * flScaleY / 2 + (item.location?.[1] || 0) * flScaleY
|
||||||
fabricImage.width * scaleX,
|
let scaleX = flWidth * (item.scale?.[0] || 1) / image.width * flScaleX
|
||||||
fabricImage.height * scaleY,
|
let scaleY = flHeight * (item.scale?.[1] || 1) / image.height * flScaleY
|
||||||
|
let { x, y } = calculateRotatedTopLeftDeg(
|
||||||
|
image.width * scaleX,
|
||||||
|
image.height * scaleY,
|
||||||
left,
|
left,
|
||||||
top,
|
top,
|
||||||
0,
|
0,
|
||||||
item.angle || 0
|
item.angle || 0
|
||||||
)
|
)
|
||||||
const angle = item.angle || 0
|
let angle = item.angle || 0
|
||||||
fabricImage.set({
|
|
||||||
|
let opacity = 1
|
||||||
|
let flipX = false;
|
||||||
|
let flipY = false;
|
||||||
|
let blendMode = BlendMode.NORMAL;
|
||||||
|
// if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常
|
||||||
|
if (item.object) {
|
||||||
|
opacity = item.object.opacity
|
||||||
|
flipX = item.object.flipX
|
||||||
|
flipY = item.object.flipY
|
||||||
|
if (item.object.blendMode) blendMode = item.object.blendMode;
|
||||||
|
}
|
||||||
|
image.set({
|
||||||
left: x,
|
left: x,
|
||||||
top: y,
|
top: y,
|
||||||
scaleX: scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: scaleY,
|
scaleY: scaleY,
|
||||||
angle: angle,
|
angle: angle,
|
||||||
|
opacity: opacity,
|
||||||
|
flipX: flipX,
|
||||||
|
flipY: flipY,
|
||||||
|
globalCompositeOperation: blendMode,
|
||||||
id: id,
|
id: id,
|
||||||
layerId: id,
|
layerId: id,
|
||||||
layerName: name,
|
layerName: name,
|
||||||
@@ -1591,33 +1712,30 @@ export class CanvasManager {
|
|||||||
hasControls: true,
|
hasControls: true,
|
||||||
hasBorders: true,
|
hasBorders: true,
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
globalCompositeOperation: BlendMode.MULTIPLY,
|
|
||||||
});
|
});
|
||||||
resolve(fabricImage);
|
// this.canvas.add(image);
|
||||||
}, { crossOrigin: "anonymous" });
|
|
||||||
})
|
|
||||||
this.canvas.add(image);
|
|
||||||
let layer = createLayer({
|
let layer = createLayer({
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
type: LayerType.BITMAP,
|
type: LayerType.BITMAP,
|
||||||
visible: true,
|
visible: true,
|
||||||
locked: false,
|
locked: false,
|
||||||
opacity: 1.0,
|
opacity: opacity,
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
blendMode: BlendMode.MULTIPLY,
|
blendMode: blendMode,
|
||||||
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: {sourceData: item},
|
metadata: { sourceData: item },
|
||||||
|
object: image,
|
||||||
})
|
})
|
||||||
children.push(layer);
|
children.push(layer);
|
||||||
};
|
};
|
||||||
// 添加平铺图层
|
// 添加平铺图层
|
||||||
for(let index = 0; index < singleLayers.length; index++){
|
for (let index = 0; index < singleLayers.length; index++) {
|
||||||
let item = singleLayers[index];
|
let item = singleLayers[index];
|
||||||
let id = generateId("layer_image_");
|
let id = generateId("layer_image_");
|
||||||
let name = item.name;
|
let name = item.name;
|
||||||
let image = await new Promise(resolve => {
|
let image = await new Promise(resolve => {
|
||||||
fabric.Image.fromURL(item.path, (fabricImage)=>{
|
fabric.Image.fromURL(item.path, (fabricImage) => {
|
||||||
const imgElement = fabricImage.getElement();
|
const imgElement = fabricImage.getElement();
|
||||||
const tcanvas = document.createElement('canvas');
|
const tcanvas = document.createElement('canvas');
|
||||||
tcanvas.width = imgElement.width;
|
tcanvas.width = imgElement.width;
|
||||||
@@ -1628,50 +1746,83 @@ export class CanvasManager {
|
|||||||
resolve(tcanvas);
|
resolve(tcanvas);
|
||||||
}, { crossOrigin: "anonymous" });
|
}, { crossOrigin: "anonymous" });
|
||||||
})
|
})
|
||||||
let scaleX = fixedLayerObj.width / image.width * (item.scale?.[0] || 1) / 5;
|
let scaleX_ = flWidth / image.width * (item.scale?.[0] || 1) / 5;
|
||||||
let scaleY = fixedLayerObj.height / image.height * (item.scale?.[1] || 1) / 5;
|
let scaleY_ = flHeight / image.height * (item.scale?.[1] || 1) / 5;
|
||||||
let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX : scaleY;
|
let scale = flWidth > flHeight ? scaleX_ : scaleY_;
|
||||||
let left = (item.location?.[0] || 0) - image.width * scale / 2
|
let offsetX = (item.location?.[0] || 0) - image.width * scale / 2
|
||||||
let top = (item.location?.[1] || 0) - image.height * scale / 2
|
let offsetY = (item.location?.[1] || 0) - image.height * scale / 2
|
||||||
|
let top = flTop - flHeight * flScaleY / 2
|
||||||
|
let left = flLeft - flWidth * flScaleX / 2
|
||||||
|
let scaleX = flScaleX
|
||||||
|
let scaleY = flScaleY
|
||||||
|
let opacity = 1
|
||||||
|
let angle = 0
|
||||||
|
let gapX = 0
|
||||||
|
let gapY = 0
|
||||||
|
let fillSource = image
|
||||||
|
let flipX = false;
|
||||||
|
let flipY = false;
|
||||||
|
let blendMode = BlendMode.NORMAL;
|
||||||
|
let fill_repeat = "repeat"
|
||||||
|
if (item.object) {
|
||||||
|
top += item.object.top * flScaleY
|
||||||
|
left += item.object.left * flScaleX
|
||||||
|
scaleX *= item.object.scaleX
|
||||||
|
scaleY *= item.object.scaleY
|
||||||
|
opacity = item.object.opacity
|
||||||
|
angle = item.object.angle
|
||||||
|
flipX = item.object.flipX
|
||||||
|
flipY = item.object.flipY
|
||||||
|
if (item.object.blendMode) blendMode = item.object.blendMode;
|
||||||
|
gapX = item.object.gapX
|
||||||
|
gapY = item.object.gapY
|
||||||
|
fillSource = imageAddGapToCanvas(image, gapX, gapY);
|
||||||
|
if (item.object.fill_repeat) fill_repeat = item.object.fill_repeat;
|
||||||
|
}
|
||||||
let rect = new fabric.Rect({
|
let rect = new fabric.Rect({
|
||||||
id: id,
|
id: id,
|
||||||
layerId: id,
|
layerId: id,
|
||||||
layerName: name,
|
layerName: name,
|
||||||
width: fixedLayerObj.width,
|
width: flWidth,
|
||||||
height: fixedLayerObj.height,
|
height: flHeight,
|
||||||
top: fixedLayerObj.top - fixedLayerObj.height * fixedLayerObj.scaleY / 2,
|
top: top,
|
||||||
left: fixedLayerObj.left - fixedLayerObj.width * fixedLayerObj.scaleX / 2,
|
left: left,
|
||||||
scaleX: fixedLayerObj.scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: fixedLayerObj.scaleY,
|
scaleY: scaleY,
|
||||||
globalCompositeOperation: BlendMode.MULTIPLY,
|
opacity: opacity,
|
||||||
|
angle: angle,
|
||||||
|
flipX: flipX,
|
||||||
|
flipY: flipY,
|
||||||
|
globalCompositeOperation: blendMode,
|
||||||
fill: new fabric.Pattern({
|
fill: new fabric.Pattern({
|
||||||
source: image,
|
source: fillSource,
|
||||||
repeat: "repeat",
|
repeat: fill_repeat,
|
||||||
patternTransform: createPatternTransform(scale, item.angle || 0),
|
patternTransform: createPatternTransform(scale, item.angle || 0),
|
||||||
offsetX: left, // 水平偏移
|
offsetX: offsetX, // 水平偏移
|
||||||
offsetY: top, // 垂直偏移
|
offsetY: offsetY, // 垂直偏移
|
||||||
}),
|
}),
|
||||||
fill_ : {
|
fill_: {
|
||||||
source: item.path,
|
source: item.path,
|
||||||
gapX: 0,
|
gapX: gapX,
|
||||||
gapY: 0,
|
gapY: gapY,
|
||||||
width: image.width,
|
width: image.width,
|
||||||
height: image.height,
|
height: image.height,
|
||||||
},
|
},
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
});
|
});
|
||||||
this.canvas.add(rect);
|
// this.canvas.add(rect);
|
||||||
let layer = createLayer({
|
let layer = createLayer({
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
type: LayerType.BITMAP,
|
type: LayerType.BITMAP,
|
||||||
visible: true,
|
visible: true,
|
||||||
locked: true,
|
locked: false,
|
||||||
opacity: 1,
|
opacity: opacity,
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
blendMode: BlendMode.MULTIPLY,
|
blendMode: blendMode,
|
||||||
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: {sourceData: item},
|
metadata: { sourceData: item },
|
||||||
|
object: rect,
|
||||||
})
|
})
|
||||||
children.push(layer);
|
children.push(layer);
|
||||||
};
|
};
|
||||||
@@ -1687,7 +1838,14 @@ export class CanvasManager {
|
|||||||
// })
|
// })
|
||||||
// children.push(layer);
|
// children.push(layer);
|
||||||
// }
|
// }
|
||||||
if(children.length === 0) return;
|
if (children.length === 0) return;
|
||||||
|
// 印花元素排序
|
||||||
|
if (new Set(children.map(v => v.metadata.sourceData.priority)).size === children.length) {
|
||||||
|
children.sort((a, b) => b.metadata.sourceData.priority - a.metadata.sourceData.priority);
|
||||||
|
}
|
||||||
|
children.forEach(layer => {
|
||||||
|
this.canvas.add(layer.object);
|
||||||
|
});
|
||||||
const groupRect = new fabric.Rect({});
|
const groupRect = new fabric.Rect({});
|
||||||
await this.setObjecCliptInfo(groupRect);
|
await this.setObjecCliptInfo(groupRect);
|
||||||
// 插入组图层
|
// 插入组图层
|
||||||
@@ -1710,20 +1868,21 @@ export class CanvasManager {
|
|||||||
/**
|
/**
|
||||||
* 画布事件变更后
|
* 画布事件变更后
|
||||||
*/
|
*/
|
||||||
async changeCanvas(){
|
async changeCanvas(fids = [], isBeforeChange = false) {
|
||||||
|
if (!isBeforeChange) this.canvasChangeing = false;
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
if(!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
|
if (!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
|
||||||
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||||
if(colorObject){
|
if (colorObject) {
|
||||||
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP);
|
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP).filter(id => !fids.includes(id));
|
||||||
if(ids.length === 0){
|
if (ids.length === 0) {
|
||||||
ids.unshift(SpecialLayerId.SPECIAL_GROUP);
|
ids.unshift(SpecialLayerId.SPECIAL_GROUP);
|
||||||
await this.setObjecCliptInfo(colorObject);
|
await this.setObjecCliptInfo(colorObject);
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const base64 = await this.exportManager.exportImage({layerIdArray2: ids, isEnhanceImg: true});
|
const base64 = await this.exportManager.exportImage({ layerIdArray2: ids, isEnhanceImg: true });
|
||||||
if(!base64) return console.warn("导出图片失败", base64)
|
if (!base64) return console.warn("导出图片失败", base64)
|
||||||
const canvas = await base64ToCanvas(base64, fixedLayerObj.scaleX * 2, true);
|
const canvas = await base64ToCanvas(base64, fixedLayerObj.scaleX * 2, true);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
const width = fixedLayerObj.width;
|
const width = fixedLayerObj.width;
|
||||||
@@ -1735,6 +1894,24 @@ export class CanvasManager {
|
|||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 画布变更之前 */
|
||||||
|
async beforeChangeCanvas(objects) {
|
||||||
|
if (this.canvasChangeing) return;
|
||||||
|
const ids = objects.filter(v => {
|
||||||
|
return v.isPrintTrims && v.globalCompositeOperation && v.globalCompositeOperation !== BlendMode.NORMAL
|
||||||
|
}).map(v => v.layerId);
|
||||||
|
if (ids.length > 0) {
|
||||||
|
this.canvasChangeing = true;
|
||||||
|
this.canvas.getObjects().forEach(v => {
|
||||||
|
if (ids.includes(v.layerId)) {
|
||||||
|
v.globalCompositeOperation_ = v.globalCompositeOperation;
|
||||||
|
v.globalCompositeOperation = BlendMode.NORMAL;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.canvas.renderAll();
|
||||||
|
await this.changeCanvas(ids, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缩放红绿图模式内容以适应当前画布大小
|
* 缩放红绿图模式内容以适应当前画布大小
|
||||||
@@ -1936,13 +2113,13 @@ export class CanvasManager {
|
|||||||
moveActiveObject(direction, step = 1) {
|
moveActiveObject(direction, step = 1) {
|
||||||
const objects = [];
|
const objects = [];
|
||||||
const activeObject = this.canvas.getActiveObject();
|
const activeObject = this.canvas.getActiveObject();
|
||||||
if(!activeObject) return;
|
if (!activeObject) return;
|
||||||
const initPos = {
|
const initPos = {
|
||||||
id: activeObject.id,
|
id: activeObject.id,
|
||||||
left: activeObject.left,
|
left: activeObject.left,
|
||||||
top: activeObject.top,
|
top: activeObject.top,
|
||||||
};
|
};
|
||||||
switch(direction) {
|
switch (direction) {
|
||||||
case "up":
|
case "up":
|
||||||
activeObject.top -= step;
|
activeObject.top -= step;
|
||||||
break;
|
break;
|
||||||
@@ -1956,7 +2133,7 @@ export class CanvasManager {
|
|||||||
activeObject.left += step;
|
activeObject.left += step;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(!activeObject.id) return this.canvas.renderAll();
|
if (!activeObject.id) return this.canvas.renderAll();
|
||||||
const cmd = new ObjectMoveCommand({
|
const cmd = new ObjectMoveCommand({
|
||||||
canvas: this.canvas,
|
canvas: this.canvas,
|
||||||
initPos,
|
initPos,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} options.isContainBg 是否包含背景图层
|
* @param {Boolean} options.isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} options.isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} options.isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} options.isCropByBg 是否使用背景大小裁剪
|
||||||
* @param {String} options.layerId 导出具体图层ID
|
* @param {String} options.layerId 导出具体图层ID
|
||||||
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
||||||
@@ -35,6 +36,7 @@ export class ExportManager {
|
|||||||
isContainBg = false,
|
isContainBg = false,
|
||||||
isContainFixed = false,
|
isContainFixed = false,
|
||||||
isContainFixedOther = false, // 是否包含其他固定图层
|
isContainFixedOther = false, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer = true, // 是否包含普通图层
|
||||||
isCropByBg = false, // 是否使用背景大小裁剪
|
isCropByBg = false, // 是否使用背景大小裁剪
|
||||||
layerId = "",
|
layerId = "",
|
||||||
layerIdArray = [],
|
layerIdArray = [],
|
||||||
@@ -68,6 +70,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg,
|
isCropByBg,
|
||||||
@@ -81,6 +84,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg,
|
isCropByBg,
|
||||||
@@ -160,6 +164,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
||||||
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
||||||
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
||||||
@@ -173,6 +178,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer = true, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg, // 是否使用背景大小裁剪
|
isCropByBg, // 是否使用背景大小裁剪
|
||||||
@@ -188,6 +194,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
);
|
);
|
||||||
|
|
||||||
if (objectsToExport.length === 0) {
|
if (objectsToExport.length === 0) {
|
||||||
@@ -220,6 +227,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
||||||
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
||||||
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
||||||
@@ -233,6 +241,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg, // 是否使用背景大小裁剪
|
isCropByBg, // 是否使用背景大小裁剪
|
||||||
@@ -246,6 +255,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
excludedLayers,
|
excludedLayers,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -405,11 +415,12 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Array} excludedLayers 排除的图层ID数组
|
* @param {Array} excludedLayers 排除的图层ID数组
|
||||||
* @returns {Array} 按正确顺序排列的真实对象数组
|
* @returns {Array} 按正确顺序排列的真实对象数组
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_collectObjectsByLayerOrder(layerIdArray, isContainBg, isContainFixed, isContainFixedOther, excludedLayers) {
|
_collectObjectsByLayerOrder(layerIdArray, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer, excludedLayers) {
|
||||||
const objectsToExport = [];
|
const objectsToExport = [];
|
||||||
const allLayers = this._getAllLayersFlattened(excludedLayers); // 获取扁平化的图层列表
|
const allLayers = this._getAllLayersFlattened(excludedLayers); // 获取扁平化的图层列表
|
||||||
|
|
||||||
@@ -421,7 +432,7 @@ export class ExportManager {
|
|||||||
if (layerIdArray && !layerIdArray.includes(layer.id)) continue;
|
if (layerIdArray && !layerIdArray.includes(layer.id)) continue;
|
||||||
|
|
||||||
// 检查图层类型过滤条件
|
// 检查图层类型过滤条件
|
||||||
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther))
|
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (layer.visible) {
|
if (layer.visible) {
|
||||||
@@ -595,7 +606,9 @@ export class ExportManager {
|
|||||||
imageSmoothingEnabled: true,
|
imageSmoothingEnabled: true,
|
||||||
});
|
});
|
||||||
// tempFabricCanvas.setZoom(1);
|
// tempFabricCanvas.setZoom(1);
|
||||||
console.log("==========", fixedLayerObject)
|
const ox = fixedLayerObject.left - fixedLayerObject.width * fixedLayerObject.scaleX / 2
|
||||||
|
const oy = fixedLayerObject.top - fixedLayerObject.height * fixedLayerObject.scaleY / 2
|
||||||
|
// console.log("==========", fixedLayerObject, ox, oy)
|
||||||
try {
|
try {
|
||||||
// 克隆并添加所有对象到临时画布,需要调整位置相对于固定图层
|
// 克隆并添加所有对象到临时画布,需要调整位置相对于固定图层
|
||||||
for (let i = 0; i < objectsToExport.length; i++) {
|
for (let i = 0; i < objectsToExport.length; i++) {
|
||||||
@@ -605,15 +618,20 @@ export class ExportManager {
|
|||||||
restoreOpacityInRedGreen && true
|
restoreOpacityInRedGreen && true
|
||||||
);
|
);
|
||||||
if (cloned) {
|
if (cloned) {
|
||||||
|
let scaleX = cloned.scaleX / fixedLayerObject.scaleX
|
||||||
|
let scaleY = cloned.scaleY / fixedLayerObject.scaleY
|
||||||
|
let top = (cloned.top - oy) * scaleY
|
||||||
|
let left = (cloned.left - ox) * scaleX
|
||||||
|
if (cloned.originX === "center" && cloned.originY === "center") {
|
||||||
|
top = canvasHeight / 2
|
||||||
|
left = canvasWidth / 2
|
||||||
|
}
|
||||||
cloned.set({
|
cloned.set({
|
||||||
left: canvasWidth / 2,
|
left: left,
|
||||||
top: canvasHeight / 2,
|
top: top,
|
||||||
scaleX: cloned.scaleX / fixedLayerObject.scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: cloned.scaleY / fixedLayerObject.scaleY,
|
scaleY: scaleY,
|
||||||
originX: "center",
|
|
||||||
originY: "center",
|
|
||||||
});
|
});
|
||||||
console.log("==========", {...cloned})
|
|
||||||
// 更新对象坐标
|
// 更新对象坐标
|
||||||
cloned.setCoords();
|
cloned.setCoords();
|
||||||
tempFabricCanvas.add(cloned);
|
tempFabricCanvas.add(cloned);
|
||||||
@@ -670,7 +688,7 @@ export class ExportManager {
|
|||||||
isEnhanceImg, // 是否是增强图片
|
isEnhanceImg, // 是否是增强图片
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("导出图片数据URL:", dataURL);
|
// console.log("导出图片数据URL:", dataURL);
|
||||||
return dataURL;
|
return dataURL;
|
||||||
|
|
||||||
// // 创建与画布相同尺寸的临时画布
|
// // 创建与画布相同尺寸的临时画布
|
||||||
@@ -1040,10 +1058,11 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @returns {Boolean} 是否应该包含
|
* @returns {Boolean} 是否应该包含
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther) {
|
_shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer) {
|
||||||
if (!layer) return false;
|
if (!layer) return false;
|
||||||
|
|
||||||
// 检查背景图层
|
// 检查背景图层
|
||||||
@@ -1061,7 +1080,12 @@ export class ExportManager {
|
|||||||
return isContainFixedOther;
|
return isContainFixedOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通图层总是包含
|
// 印花图层始终导出
|
||||||
|
if (layer.isPrintTrims || layer.isPrintTrimsGroup) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 普通图层
|
||||||
|
return isContainNormalLayer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||