34 Commits

Author SHA1 Message Date
X1627315083@163.com
9c981a08ae fix 2026-05-20 15:53:12 +08:00
李志鹏
3ed5a37e5b 1 2026-05-15 16:25:08 +08:00
李志鹏
5546c71ec0 线稿图手动排序后更新bug 2026-05-15 15:01:17 +08:00
李志鹏
8a7776a4b6 去掉管理员界面的allUser编辑userName 2026-05-15 10:15:18 +08:00
X1627315083@163.com
a1281c8e3f fix 2026-05-14 18:06:01 +08:00
X1627315083@163.com
9a40e69081 fix 2026-05-14 09:27:06 +08:00
X1627315083@163.com
e27b43dc67 管理员页面增加globalAward流量页面 2026-05-13 17:29:05 +08:00
X1627315083@163.com
b6a55a8124 调整选择风格布局 2026-05-12 17:18:16 +08:00
6cace08a51 style: 去除底边距 2026-04-28 17:11:19 +08:00
6207095221 feat: 管理员页面 2026-04-28 17:11:10 +08:00
李志鹏
7bb38bf2e5 处理Safari 不支持requestIdleCallback方法 2026-04-24 17:11:48 +08:00
X1627315083@163.com
743fc762d6 fix 2026-04-23 16:57:03 +08:00
7297e4e7a4 bugfix 2026-04-23 14:08:59 +08:00
3bff1ebb66 feat: 工具函数 2026-04-23 14:05:00 +08:00
0d1656ee0a style: 字体间距 2026-04-23 13:56:54 +08:00
7d0873d874 style: 调整活动页样式 2026-04-23 13:56:47 +08:00
82941bca7c feat: 活动页 2026-04-23 11:22:21 +08:00
949ff9292d feat: 活动页面文案 2026-04-23 11:10:02 +08:00
X1627315083@163.com
11c9de8ced fix 2026-04-22 16:12:23 +08:00
X1627315083@163.com
fd518ad9b3 更新youtube地址 2026-04-22 13:24:23 +08:00
X1627315083@163.com
a2b45e2041 Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-04-17 16:35:14 +08:00
X1627315083@163.com
da64b57c1c 登录页路由加语言设置 2026-04-17 16:35:12 +08:00
李志鹏
7c14b1d831 Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-04-15 11:37:13 +08:00
李志鹏
8966b52430 红绿图b 2026-04-15 11:37:11 +08:00
X1627315083@163.com
5fa049f73d 隐藏brandDNA功能 2026-04-14 15:30:19 +08:00
X1627315083@163.com
575445f767 fix 2026-04-14 15:27:57 +08:00
李志鹏
f43c56236b 液化苹果浏览器闪屏问题 2026-04-14 10:02:06 +08:00
李志鹏
4352f7c2f4 111 2026-04-13 11:52:24 +08:00
李志鹏
c6b1bdbdf1 红绿图导出问题 2026-04-13 11:20:26 +08:00
X1627315083@163.com
f16aa6ea14 fix 2026-04-10 18:14:20 +08:00
X1627315083@163.com
a25abeb527 fix 2026-04-10 16:54:22 +08:00
X1627315083@163.com
d359cd7763 注释选择信用卡支付和支付宝支付的选项,改为默认信用卡自动续费支付 2026-03-30 10:43:27 +08:00
23085d9a9b Merge branch 'dev_vite' into StableVersion 2026-03-25 10:18:13 +08:00
X1627315083@163.com
35c6dfe29c 印花默认为正片叠底 2026-03-24 14:43:12 +08:00
79 changed files with 5583 additions and 9461 deletions

View File

@@ -13,11 +13,6 @@
font-weight: normal;
src: url('pingfang/pingfang-regular.ttf') format('truetype');
}
@font-face {
font-family: 'pingfang_heavy';
font-weight: normal;
src: url('pingfang/pingfang-heavy.ttf') format('truetype');
}
@font-face {
font-family: 'satoshi_light';
font-weight: normal;

View File

@@ -1,88 +0,0 @@
:deep(.ant-form) .form-group {
display: flex;
gap: 1.6rem;
}
:deep(.ant-form) .form-group .ant-form-item {
flex: 1;
}
:deep(.ant-form) .ant-form-item {
margin-bottom: 1.6rem;
position: relative;
}
:deep(.ant-form) .ant-form-item .tip-length {
user-select: none;
pointer-events: none;
position: absolute;
bottom: 1rem;
right: 1.6rem;
font-family: pingfang_regular;
font-size: 1rem;
color: #df2c2c;
}
:deep(.ant-form) .ant-form-item .ant-form-item-explain,
:deep(.ant-form) .ant-form-item .ant-form-item-explain-connected {
min-height: 0;
}
:deep(.ant-form) .ant-form-item .ant-form-item-explain-error {
font-size: 1.2rem;
}
:deep(.ant-form) .ant-form-item-label {
display: flex;
padding: 0 0 0.6rem 0;
}
:deep(.ant-form) .ant-form-item-label > label {
font-family: pingfang_medium;
font-size: 1.4rem;
line-height: 150%;
}
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
content: "";
}
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional):after {
display: inline-block;
color: #df2c2c;
font-size: 1.4rem;
content: "*";
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper,
:deep(.ant-form) .ant-form-item-control-input textarea,
:deep(.ant-form) .ant-form-item-control-input input {
border-radius: 1.2rem;
border: 0.16rem solid #d1d1d1;
font-family: pingfang_regular;
font-size: 1.4rem;
color: #000;
padding: 1.6rem;
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper::placeholder,
:deep(.ant-form) .ant-form-item-control-input textarea::placeholder,
:deep(.ant-form) .ant-form-item-control-input input::placeholder {
color: #999;
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper {
margin-bottom: 0.6rem;
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper:last-child {
margin-bottom: 0;
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper .ant-input-prefix {
width: 5.2rem;
font-size: 1.4rem;
line-height: 150%;
color: #000;
justify-content: center;
text-align: center;
}
:deep(.ant-form) .ant-form-item-control-input .ant-input-affix-wrapper input {
border: none;
height: 100%;
padding: 0 1.6rem;
border-radius: 0;
}
:deep(.ant-form) .ant-form-item-control-input input {
height: 5rem;
}
:deep(.ant-form) .ant-form-item-control-input textarea {
height: 11rem;
resize: none;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.1667 9.16667H10.8333V0.833333C10.8333 0.61232 10.7455 0.400358 10.5893 0.244078C10.433 0.0877974 10.221 0 10 0C9.77899 0 9.56702 0.0877974 9.41074 0.244078C9.25446 0.400358 9.16667 0.61232 9.16667 0.833333V9.16667H0.833333C0.61232 9.16667 0.400358 9.25446 0.244078 9.41074C0.0877974 9.56702 0 9.77899 0 10C0 10.221 0.0877974 10.433 0.244078 10.5893C0.400358 10.7455 0.61232 10.8333 0.833333 10.8333H9.16667V19.1667C9.16667 19.3877 9.25446 19.5996 9.41074 19.7559C9.56702 19.9122 9.77899 20 10 20C10.221 20 10.433 19.9122 10.5893 19.7559C10.7455 19.5996 10.8333 19.3877 10.8333 19.1667V10.8333H19.1667C19.3877 10.8333 19.5996 10.7455 19.7559 10.5893C19.9122 10.433 20 10.221 20 10C20 9.77899 19.9122 9.56702 19.7559 9.41074C19.5996 9.25446 19.3877 9.16667 19.1667 9.16667Z" fill="#B0B0B0"/>
</svg>

Before

Width:  |  Height:  |  Size: 906 B

View File

@@ -1,3 +0,0 @@
<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 4.46552C9.66667 4.85042 9.66667 5.81267 9 6.19757L1.5 10.5277C0.833332 10.9126 -1.90735e-06 10.4315 -1.90735e-06 9.66167V1.00142C-1.90735e-06 0.231615 0.833331 -0.24951 1.5 0.13539L9 4.46552Z" fill="#999999"/>
</svg>

Before

Width:  |  Height:  |  Size: 325 B

View File

@@ -1,3 +0,0 @@
<svg width="12" height="24" viewBox="0 0 12 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.3489 24C10.2173 24.0008 10.0869 23.9755 9.96503 23.9258C9.84319 23.876 9.73238 23.8027 9.63894 23.71L1.46894 15.54C1.00331 15.0755 0.633877 14.5238 0.381813 13.9163C0.129748 13.3089 0 12.6577 0 12C0 11.3423 0.129748 10.6911 0.381813 10.0837C0.633877 9.47621 1.00331 8.92446 1.46894 8.46L9.63894 0.290002C9.73218 0.196764 9.84287 0.122803 9.96469 0.0723426C10.0865 0.0218822 10.2171 -0.00408935 10.3489 -0.00408936C10.4808 -0.00408936 10.6114 0.0218822 10.7332 0.0723426C10.855 0.122803 10.9657 0.196764 11.0589 0.290002C11.1522 0.383241 11.2261 0.493931 11.2766 0.615753C11.3271 0.737575 11.353 0.868143 11.353 1C11.353 1.13186 11.3271 1.26243 11.2766 1.38425C11.2261 1.50607 11.1522 1.61676 11.0589 1.71L2.88894 9.88C2.32714 10.4425 2.01158 11.205 2.01158 12C2.01158 12.795 2.32714 13.5575 2.88894 14.12L11.0589 22.29C11.1527 22.383 11.2271 22.4936 11.2778 22.6154C11.3286 22.7373 11.3547 22.868 11.3547 23C11.3547 23.132 11.3286 23.2627 11.2778 23.3846C11.2271 23.5064 11.1527 23.617 11.0589 23.71C10.9655 23.8027 10.8547 23.876 10.7328 23.9258C10.611 23.9755 10.4805 24.0008 10.3489 24Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,35 +0,0 @@
<?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="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M92 5103 c-66 -32 -101 -105 -87 -180 6 -33 52 -84 376 -408 l369
-370 -75 -684 c-41 -377 -75 -716 -75 -753 0 -147 53 -312 140 -436 53 -76
1977 -1988 2079 -2067 298 -229 717 -269 1051 -100 126 64 198 127 611 542
446 447 493 503 560 665 57 137 73 226 73 393 -1 130 -4 164 -27 250 -34 127
-100 259 -177 355 -70 88 -2000 1999 -2068 2049 -63 45 -193 107 -267 126
-129 34 -199 31 -920 -44 l-680 -71 -365 364 c-201 201 -378 370 -393 376 -40
14 -87 12 -125 -7z m2380 -924 c29 -6 82 -25 118 -42 59 -29 152 -118 1062
-1020 918 -910 1034 -1030 1081 -1122 66 -129 83 -342 38 -485 -39 -127 -82
-192 -230 -345 -311 -322 -650 -659 -701 -699 -124 -97 -248 -139 -410 -140
-128 -1 -187 13 -309 71 l-94 45 -634 626 c-1451 1434 -1388 1370 -1423 1443
-60 127 -60 131 4 724 32 292 60 550 63 573 l6 44 127 -127 128 -127 -19 -54
c-77 -217 25 -464 232 -568 169 -85 340 -71 493 39 112 81 180 200 193 341 23
244 -161 471 -410 507 -63 9 -87 8 -149 -7 -40 -9 -84 -19 -98 -22 -21 -4 -43
13 -150 120 -118 119 -123 126 -95 127 17 0 255 24 530 54 552 58 571 60 647
44z m-685 -649 c42 -18 77 -61 89 -108 18 -66 -37 -153 -109 -173 -177 -47
-271 206 -104 282 53 23 71 23 124 -1z"/>
<path d="M3697 2450 c-26 -5 -76 -22 -110 -38 -54 -25 -95 -62 -312 -283 -516
-524 -522 -530 -557 -605 -31 -65 -33 -75 -33 -179 0 -105 2 -114 34 -180 29
-60 61 -97 230 -266 164 -165 206 -201 261 -228 148 -71 332 -53 450 45 19 16
197 193 396 394 325 329 364 372 395 435 33 67 34 74 34 185 0 174 -7 186
-262 442 -221 222 -259 250 -370 273 -75 16 -86 16 -156 5z m295 -498 c176
-175 178 -178 178 -221 0 -43 0 -43 -314 -364 -416 -427 -405 -417 -458 -417
-42 0 -45 3 -220 178 -162 162 -178 181 -178 212 0 19 9 49 20 65 10 17 173
186 362 378 l343 347 45 0 c44 0 45 -1 222 -178z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,11 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1572_2304)">
<path d="M19 4H18.492L16.308 1.168C16.0265 0.805806 15.6663 0.512417 15.2547 0.310054C14.843 0.107691 14.3907 0.00166304 13.932 0L10.068 0C9.6093 0.00166304 9.15699 0.107691 8.74533 0.310054C8.33368 0.512417 7.97347 0.805806 7.692 1.168L5.508 4H5C3.67441 4.00159 2.40356 4.52888 1.46622 5.46622C0.528882 6.40356 0.00158786 7.67441 0 9L0 19C0.00158786 20.3256 0.528882 21.5964 1.46622 22.5338C2.40356 23.4711 3.67441 23.9984 5 24H19C20.3256 23.9984 21.5964 23.4711 22.5338 22.5338C23.4711 21.5964 23.9984 20.3256 24 19V9C23.9984 7.67441 23.4711 6.40356 22.5338 5.46622C21.5964 4.52888 20.3256 4.00159 19 4ZM9.276 2.39C9.36967 2.26905 9.48969 2.17106 9.62693 2.10348C9.76418 2.0359 9.91502 2.00051 10.068 2H13.932C14.085 2.00066 14.2357 2.03611 14.373 2.10368C14.5102 2.17125 14.6302 2.26916 14.724 2.39L15.966 4H8.034L9.276 2.39ZM22 19C22 19.7956 21.6839 20.5587 21.1213 21.1213C20.5587 21.6839 19.7956 22 19 22H5C4.20435 22 3.44129 21.6839 2.87868 21.1213C2.31607 20.5587 2 19.7956 2 19V9C2 8.20435 2.31607 7.44129 2.87868 6.87868C3.44129 6.31607 4.20435 6 5 6H19C19.7956 6 20.5587 6.31607 21.1213 6.87868C21.6839 7.44129 22 8.20435 22 9V19Z" fill="white"/>
<path d="M12 8C10.8133 8 9.65328 8.35189 8.66658 9.01118C7.67989 9.67047 6.91085 10.6075 6.45673 11.7039C6.0026 12.8003 5.88378 14.0067 6.11529 15.1705C6.3468 16.3344 6.91825 17.4035 7.75736 18.2426C8.59648 19.0818 9.66558 19.6532 10.8295 19.8847C11.9933 20.1162 13.1997 19.9974 14.2961 19.5433C15.3925 19.0892 16.3295 18.3201 16.9888 17.3334C17.6481 16.3467 18 15.1867 18 14C17.9984 12.4092 17.3658 10.884 16.2409 9.75911C15.116 8.63424 13.5908 8.00159 12 8ZM12 18C11.2089 18 10.4355 17.7654 9.77772 17.3259C9.11993 16.8864 8.60723 16.2616 8.30448 15.5307C8.00173 14.7998 7.92252 13.9956 8.07686 13.2196C8.2312 12.4437 8.61217 11.731 9.17158 11.1716C9.73099 10.6122 10.4437 10.2312 11.2196 10.0769C11.9956 9.92252 12.7998 10.0017 13.5307 10.3045C14.2616 10.6072 14.8864 11.1199 15.3259 11.7777C15.7654 12.4355 16 13.2089 16 14C16 15.0609 15.5786 16.0783 14.8284 16.8284C14.0783 17.5786 13.0609 18 12 18Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1572_2304">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,24 +0,0 @@
<?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="512.000000pt" height="488.000000pt" viewBox="0 0 512.000000 488.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,488.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M2425 4873 c-518 -70 -923 -535 -929 -1063 0 -80 3 -102 21 -137 70
-131 234 -159 337 -57 45 46 58 81 67 190 17 195 89 349 218 466 120 108 254
161 411 161 184 0 307 -51 441 -183 71 -70 94 -100 127 -170 54 -112 85 -262
80 -381 -6 -131 -39 -191 -192 -345 -276 -277 -500 -453 -1656 -1307 -733
-541 -1115 -829 -1155 -871 -75 -78 -128 -167 -162 -271 -23 -69 -27 -98 -27
-205 -1 -90 4 -143 17 -189 55 -200 190 -362 372 -446 138 -64 -7 -60 2170
-60 1895 0 1993 1 2054 18 233 66 413 250 478 488 13 46 18 98 17 189 -1 107
-4 137 -27 205 -36 109 -89 196 -167 275 -40 40 -436 339 -1032 779 -533 393
-968 718 -968 722 0 3 64 62 142 130 347 301 481 474 539 694 41 154 25 417
-38 620 -121 387 -448 677 -838 740 -83 14 -229 18 -300 8z m1152 -3229 c549
-405 1015 -753 1037 -773 52 -49 76 -103 76 -176 0 -103 -58 -194 -147 -232
-44 -18 -3893 -20 -3954 -2 -93 28 -159 126 -159 234 0 73 24 127 76 176 74
69 2047 1520 2060 1515 8 -3 462 -337 1011 -742z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,22 +0,0 @@
<?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="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M207 953 c-4 -3 -7 -21 -7 -39 0 -31 -2 -33 -37 -36 l-38 -3 -3 -378
c-3 -418 -1 -429 60 -467 31 -19 46 -20 306 -18 l274 3 34 37 34 38 0 395 0
395 -40 0 -40 0 0 41 0 40 -37 -3 c-36 -3 -38 -5 -41 -40 -3 -36 -5 -38 -37
-38 -32 0 -34 2 -37 38 -3 36 -4 37 -43 37 -40 0 -40 0 -40 -38 0 -36 -1 -37
-37 -37 -38 0 -38 0 -38 40 l0 40 -40 0 -40 0 0 -40 0 -40 -40 0 -40 0 0 40
c0 39 -1 40 -33 40 -19 0 -37 -3 -40 -7z m543 -496 c0 -253 -3 -346 -12 -355
-9 -9 -79 -12 -254 -12 -133 0 -249 3 -258 6 -14 5 -16 46 -16 355 l0 349 270
0 270 0 0 -343z"/>
<path d="M280 640 l0 -40 198 2 197 3 3 38 3 37 -200 0 -201 0 0 -40z"/>
<path d="M280 485 l0 -45 198 2 197 3 0 40 0 40 -197 3 -198 2 0 -45z"/>
<path d="M280 330 l0 -40 120 0 120 0 0 40 0 40 -120 0 -120 0 0 -40z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,11 +0,0 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1572_2553)">
<path d="M47.5 0H12.5C9.18601 0.00396964 6.00889 1.3222 3.66555 3.66555C1.3222 6.00889 0.00396964 9.18601 0 12.5L0 47.5C0.00396964 50.814 1.3222 53.9911 3.66555 56.3345C6.00889 58.6778 9.18601 59.996 12.5 60H47.5C50.814 59.996 53.9911 58.6778 56.3345 56.3345C58.6778 53.9911 59.996 50.814 60 47.5V12.5C59.996 9.18601 58.6778 6.00889 56.3345 3.66555C53.9911 1.3222 50.814 0.00396964 47.5 0ZM12.5 5H47.5C49.4891 5 51.3968 5.79018 52.8033 7.1967C54.2098 8.60322 55 10.5109 55 12.5V47.5C54.9957 48.6137 54.7393 49.712 54.25 50.7125L31.3425 27.805C30.1817 26.6439 28.8036 25.7229 27.2868 25.0945C25.77 24.4661 24.1443 24.1427 22.5025 24.1427C20.8607 24.1427 19.235 24.4661 17.7182 25.0945C16.2014 25.7229 14.8233 26.6439 13.6625 27.805L5 36.465V12.5C5 10.5109 5.79018 8.60322 7.1967 7.1967C8.60322 5.79018 10.5109 5 12.5 5ZM12.5 55C10.5109 55 8.60322 54.2098 7.1967 52.8033C5.79018 51.3968 5 49.4891 5 47.5V43.535L17.195 31.34C17.8915 30.6431 18.7185 30.0902 19.6288 29.713C20.539 29.3358 21.5147 29.1416 22.5 29.1416C23.4853 29.1416 24.461 29.3358 25.3712 29.713C26.2815 30.0902 27.1085 30.6431 27.805 31.34L50.7125 54.25C49.712 54.7393 48.6137 54.9957 47.5 55H12.5Z" fill="#D0D0D0"/>
<path d="M40 26.25C41.7306 26.25 43.4223 25.7368 44.8612 24.7754C46.3002 23.8139 47.4217 22.4473 48.0839 20.8485C48.7462 19.2496 48.9195 17.4903 48.5819 15.793C48.2443 14.0956 47.4109 12.5365 46.1872 11.3128C44.9635 10.0891 43.4044 9.25575 41.707 8.91813C40.0097 8.58051 38.2504 8.75379 36.6515 9.41606C35.0527 10.0783 33.6861 11.1998 32.7246 12.6388C31.7632 14.0777 31.25 15.7694 31.25 17.5C31.25 19.8206 32.1719 22.0462 33.8128 23.6872C35.4538 25.3281 37.6794 26.25 40 26.25ZM40 13.75C40.7417 13.75 41.4667 13.9699 42.0834 14.382C42.7001 14.794 43.1807 15.3797 43.4645 16.0649C43.7484 16.7502 43.8226 17.5042 43.6779 18.2316C43.5333 18.959 43.1761 19.6272 42.6516 20.1517C42.1272 20.6761 41.459 21.0333 40.7316 21.1779C40.0042 21.3226 39.2502 21.2484 38.5649 20.9646C37.8797 20.6807 37.294 20.2001 36.882 19.5834C36.4699 18.9667 36.25 18.2417 36.25 17.5C36.25 16.5054 36.6451 15.5516 37.3483 14.8484C38.0516 14.1451 39.0054 13.75 40 13.75Z" fill="#D0D0D0"/>
</g>
<defs>
<clipPath id="clip0_1572_2553">
<rect width="60" height="60" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,3 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.9797 13.2649C14.0637 13.5764 13.8788 13.896 13.5673 13.9794C13.5166 13.9928 13.4658 13.9998 13.4157 13.9998C13.1584 13.9998 12.9228 13.8277 12.8528 13.5676C12.6451 12.7918 11.9171 12.25 11.083 12.25C10.2489 12.25 9.52088 12.7918 9.31322 13.5676C9.22922 13.8785 8.90956 14.0634 8.59866 13.98C8.28717 13.8966 8.10225 13.5769 8.18625 13.2655C8.53099 11.9805 9.72212 11.0834 11.083 11.0834C12.4439 11.0834 13.635 11.9805 13.9797 13.2655V13.2649ZM11.083 7.58318C10.2786 7.58318 9.62471 8.23704 9.62471 9.04138C9.62471 9.84572 10.2786 10.4996 11.083 10.4996C11.8874 10.4996 12.5413 9.84572 12.5413 9.04138C12.5413 8.23704 11.8874 7.58318 11.083 7.58318ZM2.33326 8.74974H2.91658C3.61656 8.74974 4.23837 8.4336 4.66653 7.94365C5.09468 8.4336 5.71649 8.74974 6.41647 8.74974H7.5831C7.85026 8.74974 8.11217 8.70483 8.36125 8.61617C8.66515 8.50826 8.82382 8.17521 8.7159 7.87132C8.60741 7.56744 8.27375 7.40995 7.97159 7.51669C7.84793 7.56044 7.71668 7.5826 7.5831 7.5826H6.41647C5.77308 7.5826 5.24984 7.0594 5.24984 6.41605C5.24984 6.09408 4.98852 5.83277 4.66653 5.83277C4.34454 5.83277 4.08321 6.09408 4.08321 6.41605C4.08321 7.0594 3.55998 7.5826 2.91658 7.5826H2.33326C1.70445 7.5826 1.19055 7.08273 1.16721 6.45921L1.83569 2.40602C2.0591 1.67517 2.74275 1.16655 3.50981 1.16655H4.08321V2.91638C4.08321 3.23835 4.34454 3.49966 4.66653 3.49966C4.98852 3.49966 5.24984 3.23835 5.24984 2.91638V1.16655H8.74973V2.91638C8.74973 3.23835 9.01048 3.49966 9.33305 3.49966C9.65562 3.49966 9.91637 3.23835 9.91637 2.91638V1.16655H10.4892C11.2557 1.16655 11.9399 1.67459 12.1633 2.40602L12.8318 6.45921C12.8271 6.57761 12.8049 6.69369 12.7659 6.80509C12.6585 7.10898 12.8184 7.44203 13.1217 7.54935C13.4262 7.65726 13.7587 7.49744 13.866 7.19356C13.9535 6.94391 13.999 6.68202 13.999 6.41605C13.999 6.38397 13.2996 2.13654 13.2932 2.11496C12.9374 0.869666 11.7836 0 10.4886 0H3.50981C2.21485 0.000583277 1.06163 0.870249 0.705229 2.11555C0.698812 2.13713 0 6.38455 0 6.41663C0 7.00282 0.224577 7.53302 0.583316 7.94365V11.6661C0.583316 12.9528 1.62978 13.9992 2.91658 13.9992H6.41647C6.73846 13.9992 6.99979 13.7379 6.99979 13.416C6.99979 13.094 6.73846 12.8327 6.41647 12.8327H2.91658C2.27318 12.8327 1.74995 12.3095 1.74995 11.6661V8.66691C1.93777 8.71591 2.13085 8.74974 2.33326 8.74974Z" fill="#585858"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,3 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.75 0.5C30.2139 0.50007 30.6592 0.684683 30.9873 1.0127C31.3153 1.34085 31.499 1.78607 31.499 2.25C31.499 2.71394 31.3153 3.15919 30.9873 3.4873L18.4746 16L30.9873 28.5127C31.3153 28.8409 31.499 29.2861 31.499 29.75C31.499 30.2139 31.3153 30.6592 30.9873 30.9873C30.6592 31.3153 30.2139 31.499 29.75 31.499C29.2861 31.499 28.8409 31.3153 28.5127 30.9873L16 18.4746L3.4873 30.9873C3.15919 31.3153 2.71394 31.499 2.25 31.499C1.78607 31.499 1.34085 31.3153 1.0127 30.9873C0.684683 30.6592 0.50007 30.2139 0.5 29.75C0.5 29.286 0.684623 28.8409 1.0127 28.5127L13.5254 16L1.0127 3.4873C0.684684 3.15919 0.500071 2.71394 0.5 2.25C0.5 1.78596 0.684621 1.34087 1.0127 1.0127C1.34087 0.684621 1.78596 0.5 2.25 0.5C2.71394 0.500071 3.15919 0.684684 3.4873 1.0127L16 13.5254L28.5127 1.0127C28.8409 0.684623 29.286 0.5 29.75 0.5Z" fill="black" stroke="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 963 B

View File

@@ -1,27 +0,0 @@
<?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="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M235 946 c-30 -13 -85 -69 -85 -86 0 -5 -30 -10 -66 -12 -51 -2 -70
-7 -78 -20 -21 -34 4 -52 77 -58 62 -5 67 -7 89 -40 27 -40 79 -70 123 -70 42
0 96 31 123 71 l23 34 251 5 c225 4 252 7 262 23 8 12 8 22 0 35 -10 15 -36
17 -267 20 l-255 2 -6 25 c-15 60 -125 101 -191 71z m103 -82 c47 -33 16 -124
-43 -124 -31 0 -75 41 -75 70 0 28 43 70 72 70 13 0 34 -7 46 -16z"/>
<path d="M600 611 c-19 -10 -45 -33 -58 -52 l-23 -34 -251 -5 c-225 -4 -252
-7 -262 -22 -8 -13 -8 -23 0 -35 10 -16 36 -18 267 -21 l255 -2 6 -25 c3 -13
23 -37 43 -52 29 -22 47 -28 89 -28 59 0 95 21 129 73 18 28 25 31 84 34 48 2
67 7 75 21 21 33 -4 51 -77 57 -62 5 -67 7 -89 40 -44 65 -122 87 -188 51z
m115 -86 c14 -13 25 -33 25 -45 0 -28 -43 -70 -72 -70 -40 0 -68 27 -68 66 0
68 68 97 115 49z"/>
<path d="M235 286 c-30 -13 -85 -69 -85 -86 0 -5 -30 -10 -66 -12 -51 -2 -70
-7 -78 -20 -21 -34 4 -52 77 -58 62 -5 67 -7 89 -40 27 -40 79 -70 123 -70 42
0 96 31 123 71 l23 34 251 5 c225 4 252 7 262 23 8 12 8 22 0 35 -10 15 -36
17 -267 20 l-255 2 -6 25 c-15 60 -125 101 -191 71z m103 -82 c47 -33 16 -124
-43 -124 -30 0 -75 41 -75 68 0 11 9 31 21 46 24 30 63 34 97 10z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,4 +0,0 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24 24C26.3734 24 28.6935 23.2962 30.6668 21.9776C32.6402 20.6591 34.1783 18.7849 35.0866 16.5922C35.9948 14.3995 36.2324 11.9867 35.7694 9.65892C35.3064 7.33115 34.1635 5.19295 32.4853 3.51472C30.8071 1.83649 28.6689 0.693605 26.3411 0.230582C24.0133 -0.232441 21.6005 0.00519943 19.4078 0.913451C17.2151 1.8217 15.3409 3.35977 14.0224 5.33316C12.7038 7.30655 12 9.62663 12 12C12.0032 15.1816 13.2685 18.232 15.5182 20.4818C17.768 22.7315 20.8184 23.9968 24 24ZM24 4.00001C25.5823 4.00001 27.129 4.4692 28.4446 5.34825C29.7602 6.2273 30.7855 7.47673 31.391 8.93854C31.9965 10.4003 32.155 12.0089 31.8463 13.5607C31.5376 15.1126 30.7757 16.538 29.6569 17.6569C28.538 18.7757 27.1126 19.5376 25.5607 19.8463C24.0089 20.155 22.4003 19.9965 20.9385 19.391C19.4767 18.7855 18.2273 17.7602 17.3482 16.4446C16.4692 15.129 16 13.5823 16 12C16 9.87827 16.8429 7.84344 18.3431 6.34315C19.8434 4.84286 21.8783 4.00001 24 4.00001Z" fill="#BBBBBB"/>
<path d="M24 28C19.2277 28.0053 14.6524 29.9034 11.2779 33.2779C7.90342 36.6524 6.00529 41.2277 6 46C6 46.5304 6.21071 47.0391 6.58579 47.4142C6.96086 47.7893 7.46957 48 8 48C8.53043 48 9.03914 47.7893 9.41421 47.4142C9.78929 47.0391 10 46.5304 10 46C10 42.287 11.475 38.726 14.1005 36.1005C16.726 33.475 20.287 32 24 32C27.713 32 31.274 33.475 33.8995 36.1005C36.525 38.726 38 42.287 38 46C38 46.5304 38.2107 47.0391 38.5858 47.4142C38.9609 47.7893 39.4696 48 40 48C40.5304 48 41.0391 47.7893 41.4142 47.4142C41.7893 47.0391 42 46.5304 42 46C41.9947 41.2277 40.0966 36.6524 36.7221 33.2779C33.3476 29.9034 28.7723 28.0053 24 28Z" fill="#BBBBBB"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -9,6 +9,11 @@
"id": 2,
"title": "AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png"
},
{
"id": 3,
"title": "AiDA Global Design Awards 2026",
"imgUrl": "/image/events/award-poster.gif"
}
],
"eventsItem": [
@@ -16,18 +21,19 @@
"id": 3,
"title": "AiDA Global Design Awards 2026",
"imgUrl": "/image/events/award-poster.gif",
"tips": "For inquiries: awards2026@code-create.com.hk",
"textList": [
{
"paragraph": [
{
"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 CodeCreate, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers from Hong Kong, China, Singapore, South Korea, and beyond, 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."
"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 CodeCreate, 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": "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 support provided, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
"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."
}
]
}

View File

@@ -9,6 +9,11 @@
"id": 2,
"title": "AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png"
},
{
"id": 3,
"title": "AiDA全球设计奖 2026",
"imgUrl": "/image/events/award-poster-zh.gif"
}
],
"eventsItem": [
@@ -16,18 +21,19 @@
"id": 3,
"title": "AiDA全球设计奖 2026",
"imgUrl": "/image/events/award-poster-zh.gif",
"tips": "如有疑问请联系awards2026@code-create.com.hk",
"textList": [
{
"paragraph": [
{
"text": "秉承推动 AI 赋能创意设计的初衷CodeCreate 举办了「AiDA 全球设计大奖 2026」面向来自香港、中国、新加坡、韩国及全球的设计师,鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
"text": "秉承推动 AI 赋能创意设计的初衷CodeCreate 举办了「AiDA 全球设计大奖 2026」面向来全球的设计师鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
}
]
},
{
"paragraph": [
{
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅支持,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅津贴,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
}
]
}

View File

@@ -1,110 +0,0 @@
:deep(.ant-form) {
.form-group {
display: flex;
gap: 1.6rem;
.ant-form-item {
flex: 1;
}
}
.ant-form-item {
margin-bottom: 1.6rem;
position: relative;
.tip-length {
user-select: none;
pointer-events: none;
position: absolute;
bottom: 1rem;
right: 1.6rem;
font-family: pingfang_regular;
font-size: 1rem;
color: #df2c2c;
}
.ant-form-item-explain,
.ant-form-item-explain-connected {
min-height: 0;
}
.ant-form-item-explain-error {
font-size: 1.2rem;
}
}
.ant-form-item-label {
display: flex;
padding: 0 0 0.6rem 0;
>label {
font-family: pingfang_medium;
font-size: 1.4rem;
line-height: 150%;
&.ant-form-item-required:not(.ant-form-item-required-mark-optional) {
&::before {
content: "";
}
&:after {
display: inline-block;
color: #df2c2c;
font-size: 1.4rem;
content: "*";
}
}
}
}
.ant-form-item-control-input {
.ant-input-affix-wrapper,
textarea,
input {
border-radius: 1.2rem;
border: 0.16rem solid #d1d1d1;
font-family: pingfang_regular;
font-size: 1.4rem;
color: #000;
padding: 1.6rem;
&::placeholder {
color: #999;
}
}
.ant-input-affix-wrapper {
margin-bottom: 0.6rem;
&:last-child {
margin-bottom: 0;
}
.ant-input-prefix {
width: 5.2rem;
font-size: 1.4rem;
line-height: 150%;
color: #000;
justify-content: center;
text-align: center;
}
input {
border: none;
height: 100%;
padding: 0 1.6rem;
border-radius: 0;
}
}
input {
height: 5rem;
}
textarea {
height: 11rem;
resize: none;
}
}
}

View File

@@ -2386,16 +2386,6 @@ textarea:focus{
// background: #ffffff;
}
}
// 迷你滚动条
.mini-scrollbar {
&::-webkit-scrollbar {
width: 0.4rem;
}
&::-webkit-scrollbar-thumb {
border-radius: 0.4rem;
background: rgba(0, 0, 0, 0.2);
}
}
//蒙层样式
.mark_loading{

View File

@@ -2,21 +2,36 @@
<div class="account_systemMessage">
<div class="account_generalMessage_title modal_title_text">
<!-- <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 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>
<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>
<div class="modal_title_text_intro">
{{ 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 class="account_generalMessage_item modal_title_text" style="display:flex;justify-content: center;" v-if="dataList.length == 0 && isNoData">
{{$t('account.dataNull')}}
<div
class="account_generalMessage_item modal_title_text"
style="display: flex; justify-content: center"
v-if="dataList.length == 0 && isNoData"
>
{{ $t("account.dataNull") }}
</div>
<div class="page_loading_box" v-show="!isNoData">
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
@@ -27,117 +42,135 @@
</div>
</template>
<script lang="ts">
import { defineComponent,computed,ref,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 {
defineComponent,
computed,
ref,
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({
components:{
},
components: {},
// emits:['putListData'],
props:['setReadStatus','setAllmessage','getHistory'],
setup(prop,{emit}) {
props: ["setReadStatus", "setAllmessage", "getHistory"],
setup(prop, { emit }) {
const router = useRouter()
const store = useStore();
const store = useStore()
let accountMessage = reactive({
dataList: [],
page:1,
size:10,
page: 1,
size: 10,
isNoData: false,
isShowMark: false,
isShowMark: false
})
let loadingDom:any = ref(null)
let setmessageList = ()=>{
let loadingDom: any = ref(null)
let setmessageList = () => {
accountMessage.isShowMark = true
let data = {
page: accountMessage.page,
size: accountMessage.size,
size: accountMessage.size
}
prop.getHistory(data).then((rv:any)=>{
prop.getHistory(data)
.then((rv: any) => {
accountMessage.isShowMark = false
if(rv.content.length == 0) {
if (rv.content.length == 0) {
accountMessage.isNoData = true
}else{
rv.content.forEach((item:any) => {
} else {
rv.content.forEach((item: any) => {
item.content = JSON.parse(item.content)
});
})
accountMessage.dataList.push(...rv.content)
}
}).catch(() => {
})
.catch(() => {
accountMessage.isShowMark = false
accountMessage.isNoData = true
})
}
let setRead = (item:any)=>{
prop.setReadStatus(item).then((rv:any)=>{
item.isRead = 1
}).catch((err:any)=>{
})
let setRead = (item: any) => {
let content = item.content.content
if (isValidUrl(content)) {
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
content += "&env=dev"
}
let allRead = ()=>{
// emit('setAllmessage')
prop.setAllmessage().then(()=>{
accountMessage.dataList.forEach((item:any)=>{
window.open(content, "_blank")
}
prop.setReadStatus(item)
.then((rv: any) => {
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)
onMounted (()=>{
onMounted(() => {
accountMessage.isNoData = false
accountMessage.page = 0
let imgParent:any = document.querySelector('.account_systemMessage .page_loading')
let imgParent: any = document.querySelector(".account_systemMessage .page_loading")
new IntersectionObserver(
(entries, observer) => {
// 如果不是相交,则直接返回
// console.log(entries[0]);
if (!entries[0].intersectionRatio) return;
accountMessage.page+=1
if (!entries[0].intersectionRatio) return
accountMessage.page += 1
setmessageList()
},
}
// { root:worksPage }
).observe(loadingDom.value);
).observe(loadingDom.value)
})
return{
return {
...toRefs(accountMessage),
setmessageList,
setRead,
allRead,
loadingDom,
loadingDom
}
},
data(){
return{
data() {
return {}
}
},
})
</script>
<style lang="less" scoped>
.account_systemMessage{
.account_systemMessage {
width: 100%;
.account_generalMessage_item{
.account_generalMessage_item {
font-size: var(--aida-fsize1-6);
.account_generalMessage_item_title{
.account_generalMessage_item_title {
display: flex;
align-items: center;
margin-bottom: 2rem;
.account_generalMessage_item_title_text{
.account_generalMessage_item_title_text {
max-width: 80%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.modal_title_text_intro{
.modal_title_text_intro {
margin-left: 4rem;
}
}
}
.modal_title_text_intro{
.modal_title_text_intro {
word-break: break-word;
white-space: pre-wrap;
font-family: Arial, sans-serif;

View File

@@ -1,6 +1,6 @@
<template>
<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_item">
<span>Create Time:</span>
@@ -8,16 +8,11 @@
style="width: 250px"
class="range_picker"
v-model:value="rangePickerValue"
:placeholder="[
$t('HistoryPage.StartDate'),
$t('HistoryPage.EndDate'),
]"
:placeholder="[$t('HistoryPage.StartDate'), $t('HistoryPage.EndDate')]"
valueFormat="YYYY-MM-DD"
>
<template #suffixIcon>
<span
class="icon iconfont range_picker_icon icon-rili"
></span>
<span class="icon iconfont range_picker_icon icon-rili"></span>
</template>
</a-range-picker>
</div>
@@ -63,38 +58,50 @@
show-search
></a-select>
</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 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
</div>
<div class="admin_search_item" @click="addhHistoryList">
Add
</div>
<div class="admin_search_item" @click="addhHistoryList">Add</div>
</div>
<div class="admin_state_list">
<div
class="admin_state_list_item"
@click="lastGeTrialList('year')"
>
<div class="admin_state_list_item" @click="lastGeTrialList('year')">
Nearly a year
</div>
<div
class="admin_state_list_item"
@click="lastGeTrialList('month')"
>
<div class="admin_state_list_item" @click="lastGeTrialList('month')">
Last month
</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 class="awayOrUnfold" :class="{active:isAwayOrUnfold}">
<span class="icon iconfont menu_icon icon-xiala" @click="()=>isAwayOrUnfold = !isAwayOrUnfold"></span>
<div class="awayOrUnfold" :class="{ active: isAwayOrUnfold }">
<span
class="icon iconfont menu_icon icon-xiala"
@click="() => (isAwayOrUnfold = !isAwayOrUnfold)"
></span>
</div>
<div class="admin_table_content" ref="historyTable">
<a-table
@@ -104,24 +111,19 @@
:data-source="dataList"
:scroll="{ y: historyTableHeight }"
@change="changePage"
:showSorterTooltip='false'
:showSorterTooltip="false"
:pagination="{
showSizeChanger: true,
current: currentPage,
pageSize: pageSize,
total: total,
showQuickJumper: true,
bordered: false,
bordered: false
}"
>
<template #bodyCell="{ column, text, record, index }">
<div class="operate_list" v-if="column?.Operations">
<div
class="operate_item"
@click="setAagree(record)"
>
Edit
</div>
<div class="operate_item" @click="setAagree(record)">Edit</div>
<!-- <div
class="operate_item"
@click="deleteGroup(record, index)"
@@ -132,34 +134,29 @@
</template>
</a-table>
</div>
<allUserPoerationsVue ref="allUserPoerationsVue" @searchHistoryList="searchHistoryList"></allUserPoerationsVue>
<allUserPoerationsVue
ref="allUserPoerationsVue"
@searchHistoryList="searchHistoryList"
/>
</div>
</template>
<script lang="ts">
import {
defineComponent,
ref,
createVNode,
computed,
reactive,
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'
import { defineComponent, ref, createVNode, computed, reactive, 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({
components: {allUserPoerationsVue,SelectUser},
components: { allUserPoerationsVue, SelectUser },
setup() {
const store:any = useStore()
const store: any = useStore()
let filter: any = reactive({
dataList: [],
tableLoading: false,
allCountry:[],
isAwayOrUnfold:false
});
allCountry: [],
isAwayOrUnfold: false
})
let filterData: any = reactive({
rangePickerValue: [],
currentPage: 1,
@@ -172,40 +169,41 @@ export default defineComponent({
occupation: "",
systemUser: "",
order: "", //'Ascending 升序 Descending 降序'
orderBy:'',
orderBy: "",
userName: "",
});
organizationId: null
})
let state: any = ref([
{
label: "all",
value: "",
value: ""
},
{
label:'visitor',
value:'0',
label: "visitor",
value: "0"
},
{
label:'yearly',
value:'1',
label: "yearly",
value: "1"
},
{
label:'monthly',
value:'2',
label: "monthly",
value: "2"
},
{
label:'trial',
value:'3',
label: "trial",
value: "3"
},
{
label: "userInEvent",
value: "4",
value: "4"
},
{
label: "Edu Admin",
value: "7",
},
]);
let renameData: any = ref({}); //修改名字选中的数据
value: "7"
}
])
let renameData: any = ref({}) //修改名字选中的数据
const columns: any = computed(() => {
return [
{
@@ -213,25 +211,25 @@ export default defineComponent({
align: "center",
dataIndex: "id",
key: "id",
width:100,
width: 100,
fixed: "left",
sorter: true,
sorter: true
},
{
title: "Email",
align: "center",
dataIndex: "userEmail",
key: "userEmail",
width:200,
ellipsis:true
width: 200,
ellipsis: true
},
{
title: "User Name",
align: "center",
dataIndex: "userName",
key: "userName",
width:150,
ellipsis:true
width: 150,
ellipsis: true
// customRender: (record: any) => {
// let time = formatTime(
// record.text / 1000,
@@ -245,77 +243,77 @@ export default defineComponent({
align: "center",
dataIndex: "language",
key: "language",
width:100,
ellipsis:true,
width: 100,
ellipsis: true
},
{
title: "Valid Start Time",
align: "center",
dataIndex: "validStartTime",
key: "validstartTime",
width:200,
ellipsis:true,
width: 200,
ellipsis: true,
customRender: (record: any) => {
let time = ''
if(record.text){
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
let time = ""
if (record.text) {
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
}
return time
},
}
},
{
title: "Valid End Time",
align: "center",
dataIndex: "validEndTime",
key: "validendTime",
width:200,
ellipsis:true,
width: 200,
ellipsis: true,
customRender: (record: any) => {
let time = ''
if(record.text){
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
let time = ""
if (record.text) {
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
}
return time
},
}
},
{
title: "Country or Region",
align: "center",
dataIndex: "country",
key: "country",
width:200,
width: 200
},
{
title: "Create Date",
align: "center",
dataIndex: "createDate",
key: "createDate",
width:200,
sorter: true,
width: 200,
sorter: true
},
{
title: "Is Beginner",
align: "center",
dataIndex: "isBeginner",
key: "isBeginner",
width:80,
ellipsis:true,
width: 80,
ellipsis: true,
customRender: (record: any) => {
let str;
let str
if (record.value == 1) {
str = "Yes";
str = "Yes"
} else {
str = "No";
str = "No"
}
return str
}
return str;
},
},
{
title: 'Machine Room Ip',
title: "Machine Room Ip",
align: "center",
dataIndex: "browserIdentifiers",
key: "browserIdentifiers",
width:200,
width: 200
},
{
title: "Credits",
@@ -326,11 +324,11 @@ export default defineComponent({
// resizable: true,
dataIndex: "credits",
key: "credits",
width:100,
sorter: true,
width: 100,
sorter: true
},
{
title: 'User Type',
title: "User Type",
align: "center",
// width: 150,
// minWidth: 100,
@@ -338,84 +336,84 @@ export default defineComponent({
// resizable: true,
dataIndex: "systemUser",
key: "systemUser",
width:100,
width: 100,
customRender: (record: any) => {
let str;
let str
if (record.value == 0) {
str = "visitor";
str = "visitor"
} else if (record.value == 1) {
str = "yearly";
str = "yearly"
} else if (record.value == 2) {
str = "monthly";
str = "monthly"
} else if (record.value == 3) {
str = "trial";
str = "trial"
} else if (record.value == 4) {
str = "userInEvent";
str = "userInEvent"
} else if (record.value == 7) {
str = "Edu Admin";
str = "Edu Admin"
}
return str
}
return str;
},
},
{
title: "Operations",
key: "operation",
width:120,
width: 120,
align: "center",
fixed: "right",
// slots:{customRender:'action'}
Operations: true,
},
];
});
Operations: true
}
]
})
//改变页码
let changePage = (e: any, filters:any, sorter:any) => {
filterData.currentPage = e.current;
filterData.pageSize = e.pageSize;
if(sorter.order){
if(sorter.columnKey == 'id'){
filterData.orderBy = 'id'
}else if(sorter.columnKey == "createDate"){
filterData.orderBy = 'time'
}else if(sorter.columnKey == "credits"){
filterData.orderBy = 'credits'
let changePage = (e: any, filters: any, sorter: any) => {
filterData.currentPage = e.current
filterData.pageSize = e.pageSize
if (sorter.order) {
if (sorter.columnKey == "id") {
filterData.orderBy = "id"
} else if (sorter.columnKey == "createDate") {
filterData.orderBy = "time"
} else if (sorter.columnKey == "credits") {
filterData.orderBy = "credits"
}
}
if(sorter.order){
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending";
}else{
filterData.order = ''
if (sorter.order) {
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending"
} else {
filterData.order = ""
}
gettrialList()
}
gettrialList();
};
//查询列表
let searchHistoryList = () => {
filterData.currentPage = 1;
gettrialList();
};
filterData.currentPage = 1
gettrialList()
}
let clearHistoryList = () => {
filterData.rangePickerValue = [],
filterData.currentPage = 1,
filterData.pageSize = 10,
filterData.total = 0,
filterData.country = "",
filterData.email = "",
filterData.userType = "",
filterData.ids = [],
filterData.occupation = "",
filterData.order = "", //'Ascending 升序 Descending 降序'
filterData.orderBy = "", //'Ascending 升序 Descending 降序'
filterData.systemUser = "",
filterData.userName = "";
};
;((filterData.rangePickerValue = []),
(filterData.currentPage = 1),
(filterData.pageSize = 10),
(filterData.total = 0),
(filterData.country = ""),
(filterData.email = ""),
(filterData.userType = ""),
(filterData.ids = []),
(filterData.occupation = ""),
(filterData.order = ""), //'Ascending 升序 Descending 降序'
(filterData.orderBy = ""), //'Ascending 升序 Descending 降序'
(filterData.systemUser = ""),
(filterData.userName = ""))
}
let setHistoryListData = () => {
let startDate: any = filterData.rangePickerValue?.[0]
? filterData.rangePickerValue[0] + " " + "00:00:00"
: "";
: ""
let endDate: any = filterData.rangePickerValue?.[1]
? filterData.rangePickerValue[1] + " " + "23:59:59"
: "";
: ""
let data = {
endTime: endDate,
startTime: startDate,
@@ -430,63 +428,118 @@ export default defineComponent({
order: filterData.order,
orderBy: filterData.orderBy,
userName: filterData.userName,
};
return data;
};
organizationId: filterData.organizationId
}
return data
}
//获取列表
let gettrialList = () => {
filter.tableLoading = true;
let data = setHistoryListData();
Https.axiosPost(Https.httpUrls.getUserInfo, data).then(
(rv: any) => {
filter.tableLoading = true
let data = setHistoryListData()
Https.axiosPost(Https.httpUrls.getUserInfo, data).then((rv: any) => {
if (rv) {
// this.dataList = rv
filter.dataList = rv.records;
filterData.total = rv.total;
filter.tableLoading = false;
filter.dataList = rv.records
filterData.total = rv.total
filter.tableLoading = false
// this.workspaceItem.position = this.singleTypeList[0].label
}
})
}
);
};
let lastGeTrialList = (str: string) => {
clearHistoryList();
let currentDate = new Date();
let currentTimestamp = Math.floor(currentDate.getTime() / 1000);
clearHistoryList()
let currentDate = new Date()
let currentTimestamp = Math.floor(currentDate.getTime() / 1000)
// 计算30天前的时间戳
let thirtyDaysAgoTimestamp;
let thirtyDaysAgoTimestamp
if (str == "year") {
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60;
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60
} else if (str == "month") {
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60;
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60
} 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) => {
// 使用 option.label 进行搜索
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
let addhHistoryList = () => {
allUserPoerationsVue.value.init('Add','')
};
allUserPoerationsVue.value.init("Add", "")
}
let allUserPoerationsVue = ref()
let setAagree = (data:any) =>{
allUserPoerationsVue.value.init('Edit',data)
let setAagree = (data: any) => {
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(() => {
let allCountry: any = sessionStorage.getItem("allCountry");
let allCountry: any = sessionStorage.getItem("allCountry")
if (allCountry) {
filter.allCountry = JSON.parse(allCountry);
filter.allCountry = JSON.parse(allCountry)
}
gettrialList();
});
gettrialList()
getOrganizationList()
})
return {
...toRefs(filter),
...toRefs(filterData),
@@ -501,29 +554,32 @@ export default defineComponent({
filterOption,
allUserPoerationsVue,
setAagree,
};
handleOrganizationScroll,
getOrganizationList,
organizationOptions,
organizationParams
}
},
data() {
return {
historyTableHeight: 0,
handleResizeColumn: (w: any, col: any) => {
col.width = w;
},
};
col.width = w
}
}
},
mounted() {
let historyTable: any = this.$refs.historyTable;
this.historyTableHeight = historyTable.clientHeight - 200;
let historyTable: any = this.$refs.historyTable
this.historyTableHeight = historyTable.clientHeight - 200
},
methods: {},
});
methods: {}
})
</script>
<style lang="less" scoped>
.admin_page .admin_table_search .admin_state {
display: flex;
flex-wrap: wrap;
}
.admin_page{
.admin_page {
}
</style>

View File

@@ -321,6 +321,7 @@ export default defineComponent({
data = setEditData()
if (!data.userName || !data.userEmail || !data.validEndTime || !data.systemUser)
return message.warning('Please check the input box marked with *')
delete data.userName
Https.axiosPost(Https.httpUrls.modifyUser, {}, { params: data }).then(rv => {
if (rv) {
cancelDsign()

View 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>

File diff suppressed because it is too large Load Diff

View File

@@ -55,6 +55,7 @@ commandManager.setChangeCallback((info) => {
emit("undo-redo-status-changed", {
canUndo: canUndo.value,
canRedo: canRedo.value,
type: info.type,
commandManager,
});
});

View File

@@ -907,7 +907,8 @@
}
emit("changeCanvas", commandData)
canvasManager.changeCanvas()
if ((command.canUndo || command.canRedo) && props.enabledRedGreenMode) {
const type = command.type
if (props.enabledRedGreenMode && (type === "undo" || type === "redo")) {
setTimeout(async () => {
try {
const imageData = await canvasManager.exportImage({
@@ -1040,6 +1041,7 @@
},
// 导出图片
exportImage: async ({
isFrontBackUpdata = false, // 更新红绿图时候需要用,直接更新红绿图
isContainBg = false, // 是否包含背景图层
isContainFixed = false, // 是否包含固定图层
isContainFixedOther = true, // 是否包含其他固定图层--颜色图层
@@ -1056,6 +1058,10 @@
} = {}) => {
loading.value = true
canvasManager?.canvas?.discardActiveObject()
if (isFrontBackUpdata) {
await canvasManager?.setSpecialCliptInfo(true, true)
canvasManager.canvas.renderAll()
}
var base64 = await canvasManager.exportImage({
isContainBg,
isContainFixed,

View File

@@ -409,7 +409,7 @@ export class BrushIndicator {
// this.show(e.e);
this._mouseEnterHandler && this._mouseEnterHandler(e)
} else {
// requestIdleCallback(() => {
// setTimeout(() => {
// this.updatePosition(e.e);
// });

View File

@@ -47,7 +47,7 @@ import { getObjectAlphaToCanvas } from "../utils/objectHelper";
import { AddLayerCommand, RemoveLayerCommand, ToggleChildLayerVisibilityCommand } from "../commands/LayerCommands";
import { fa, id } from "element-plus/es/locales.mjs";
import i18n from "@/lang/index.ts";
const {t} = i18n.global;
const { t } = i18n.global;
export class CanvasManager {
constructor(canvasElement, options) {
@@ -70,7 +70,7 @@ export class CanvasManager {
this.handleCanvasInit = null; // 画布初始化回调函数
this.partManager = options.partManager || null;
this.props = options.props || {};
this.emit = options.emit || (() => {});
this.emit = options.emit || (() => { });
this.awaitCanvasRun = null;
this.canvasChangeing = false;
// 初始化画布
@@ -176,9 +176,9 @@ export class CanvasManager {
// 添加笔刷图像转换处理回调
this.canvas.onBrushImageConverted = async (fabricImage) => {
const activeTool = this.toolManager?.activeTool?.value;
if(activeTool === OperationType.PART_BRUSH){
if (activeTool === OperationType.PART_BRUSH) {
this.partManager?.addDrawPartImage(fabricImage);
}else{
} else {
await this.addImageToLayer({ fabricImage, targetLayerId: null });
}
// 返回false表示使用默认行为直接添加到画布
@@ -203,7 +203,7 @@ export class CanvasManager {
// 可以在这里保存状态到命令管理器
const affectedObjects = e.targets || [];
const activeTool = this.toolManager?.activeTool?.value;
if(activeTool === OperationType.PART_ERASER){
if (activeTool === OperationType.PART_ERASER) {
return this.partManager?.onErasingEnd(affectedObjects);
}
const command = this.eraserStateManager.endErasing(affectedObjects);
@@ -461,7 +461,7 @@ export class CanvasManager {
// this.canvas.renderAll();
}
// 重置画布大小参照固定图层
async resetCanvasSizeByFixedLayer(){
async resetCanvasSizeByFixedLayer() {
// 重置画布大小为固定图层的大小
const fixedLayerObj = this.getFixedLayerObject();
const backgroundObject = this.getBackgroundLayerObject();
@@ -475,10 +475,10 @@ export class CanvasManager {
fixedLayerObj.height,
fixedLayerObj.scaleY,
backgroundObject.width,
backgroundObject.scaleX,
backgroundObject.height,
backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
if(Math.abs(fwidth/bwidth - fheight/bheight) < 0.1) return;
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({
@@ -489,7 +489,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
width: this.canvasWidth.value,
height: this.canvasHeight.value,
})
}
}
/**
* 重置视图变换,使元素回到原始位置
* @private
@@ -623,17 +623,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
this.updateMaskPosition(backgroundObject);
}
// 更新颜色层信息
// 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.setSpecialCliptInfo(false, true)
// 重新渲染画布
this.canvas.renderAll();
@@ -868,7 +858,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
return layerObjectByLayerId;
}
getObjectsByIdOrLayerId(ids){
getObjectsByIdOrLayerId(ids) {
const objects = this.canvas.getObjects().filter((obj) => {
return ids.includes(obj.id) || ids.includes(obj.layerId);
});
@@ -1035,16 +1025,16 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
// 处理特殊图层的显示状态
const ptlids = [];
if(!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat){
if (!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat) {
let layers = this.layers?.value?.find((layer) => layer.isPrintTrimsGroup)?.children || [];
for(let layer of layers){
if(!layer.visible) continue;
for (let layer of layers) {
if (!layer.visible) continue;
let repeat = layer.fabricObjects?.[0]?.fill?.repeat || "no-repeat";
if(typeof repeat !== "string") repeat = "no-repeat";
if(repeat === "no-repeat"){
if(enhancedOptions.isPrintTrimsNoRepeat) continue;
}else{
if(enhancedOptions.isPrintTrimsRepeat) continue;
if (typeof repeat !== "string") repeat = "no-repeat";
if (repeat === "no-repeat") {
if (enhancedOptions.isPrintTrimsNoRepeat) continue;
} else {
if (enhancedOptions.isPrintTrimsRepeat) continue;
}
ptlids.push(layer.id);
const command = new ToggleChildLayerVisibilityCommand({
@@ -1059,8 +1049,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
}
const res = await this.exportManager.exportImage(enhancedOptions);
// 恢复特殊图层的显示状态
if(ptlids.length > 0){
for(let id of ptlids){
if (ptlids.length > 0) {
for (let id of ptlids) {
const command = new ToggleChildLayerVisibilityCommand({
canvas: this.canvas,
layers: this.layers,
@@ -1086,7 +1076,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
// 导出颜色图层信息
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 }));
const obj = {
color,
@@ -1106,7 +1096,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
return Promise.reject("颜色图层不存在");
}
const object = this.getLayerObjectById(SpecialLayerId.COLOR);
if(!object){
if (!object) {
console.warn("颜色图层不存在,请确保已添加颜色图层");
return Promise.reject("颜色图层不存在");
}
@@ -1137,7 +1127,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
});
canvas.clear();
const color = object.originColor;
return {css, base64, color};
return { css, base64, color };
}
/**
@@ -1145,11 +1135,11 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
*/
async exportPrintTrimsLayers() {
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 objects = this.getObjectsByIdOrLayerId(ids);
const fixedLayerObj = this.getFixedLayerObject();
if(!fixedLayerObj) return Promise.reject("固定图层不存在");
if (!fixedLayerObj) return Promise.reject("固定图层不存在");
const flWidth = fixedLayerObj.width
const flHeight = fixedLayerObj.height
const flTop = fixedLayerObj.top
@@ -1161,7 +1151,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
objects.forEach((v, i) => {
const label = glayer.children.find((v_) => (v_.id === v.layerId || v_.id === v.id));
const sourceData = label?.metadata?.sourceData;
if(!sourceData) return;
if (!sourceData) return;
const obj = {
ifSingle: typeof v.fill === "string",
level2Type: sourceData.level2Type,
@@ -1173,7 +1163,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
angle: v.angle,
name: sourceData.name,
priority: i + 1,
object:{
object: {
top: 0,
left: 0,
scaleX: 0,//对象的缩放比例
@@ -1192,8 +1182,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
let top = (v.top - (flTop - flHeight * flScaleY / 2));
let width = (v.width * v.scaleX);
let height = (v.height * v.scaleY);
if(v.originX === "center" && v.originY === "center") {
let {x:cx, y:cy} = calculateTopLeftPoint(width, height, left, top, v.angle);
if (v.originX === "center" && v.originY === "center") {
let { x: cx, y: cy } = calculateTopLeftPoint(width, height, left, top, v.angle);
left = cx;
top = cy;
}
@@ -1205,18 +1195,18 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
obj.object.left = oX;
obj.object.scaleX = oScaleX;
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;
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.scale = [oScaleX, oScaleY];
}else{
} else {
let fill = v.fill;
let fill_ = v.fill_;
if(!fill || !fill_) return console.warn("印花元素不存在fill或fill_属性");
let {scale, angle} = getTransformScaleAngle(fill.patternTransform);
if (!fill || !fill_) return console.warn("印花元素不存在fill或fill_属性");
let { scale, angle } = getTransformScaleAngle(fill.patternTransform);
let scaleX = scale * 5 * v.fill_.width / flWidth;
let scaleY = scale * 5 * v.fill_.height / flHeight;
let scaleXY = flWidth > flHeight ? scaleX : scaleY;
@@ -1231,16 +1221,16 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
obj.object.gapY = fill_.gapY;
obj.object.fill_repeat = fill.repeat;
}
if(sourceData.type === "print"){
if (sourceData.type === "print") {
prints.push(obj);
}else if(sourceData.type === "trims"){
} else if (sourceData.type === "trims") {
trims.push(obj);
}
})
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
// prints.forEach((v, i) => v.priority = i + 1);
// trims.forEach((v, i) => v.priority = i + 1);
return {prints, trims};
return { prints, trims };
}
@@ -1283,7 +1273,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
// 排除颜色图层和特殊组图层
const excludedLayers = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
this.layers.value.forEach((layer) => {
if(excludedLayers.includes(layer.id)){
if (excludedLayers.includes(layer.id)) {
excludedLayers.push(...layer.children?.map((child) => child.id));
}
})
@@ -1465,16 +1455,16 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
}
}
/** 修复JSON数据中的ID丢失问题 */
FixJsonIdLoss(json){
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){
if (!layer.fabricObjects?.[0]?.id && !layer.fabricObject?.id) {
const obj = objects?.find((o) => o.layerId === layer.id);
if(obj) {
if (obj) {
layer.fabricObjects = [{
id: obj.id,
type: obj.type,
@@ -1491,11 +1481,11 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
const excludedObjects = [SpecialLayerId.PART_SELECTOR];
json.canvas.objects = objects.filter((v) => {
// 指定ID排除
if(excludedObjects.includes(v.id)) return false;
if (excludedObjects.includes(v.id)) return false;
if(v.isBackground || v.isFixed) return true;
if (v.isBackground || v.isFixed) return true;
// 当前图层不存在当前对象
if(!layerIds.includes(v.layerId)) return false;
if (!layerIds.includes(v.layerId)) return false;
return true
});
}
@@ -1507,22 +1497,22 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
*/
async createOtherLayers(otherData) {
if (!otherData) return console.warn("otherData 为空不需要添加");
let resolve = ()=>{};
this.awaitCanvasRun = ()=>(new Promise((v) => resolve = v))
let resolve = () => { };
this.awaitCanvasRun = () => (new Promise((v) => resolve = v))
const otherData_ = JSON.parse(JSON.stringify(otherData));
console.log("==========创建其他图层", otherData_);
// 删除颜色图层和特殊组图层
const ids = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
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));
return false;
}
return true;
})
this.canvas.getObjects().forEach((v) => {
if(ids.includes(v.id) || ids.includes(v.layerId)){
if (ids.includes(v.id) || ids.includes(v.layerId)) {
this.canvas.remove(v)
}
})
@@ -1536,18 +1526,18 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
otherData_.printObject?.prints?.forEach((print, index) => {// 印花
print.name = t("Canvas.Print") + (index + 1);
print.type = "print";
if(print.ifSingle){
printTrimsLayers.unshift({...print});
}else{
singleLayers.unshift({...print});
if (print.ifSingle) {
printTrimsLayers.unshift({ ...print });
} else {
singleLayers.unshift({ ...print });
}
})
otherData_.trims?.prints?.forEach((trims, index) => {// 元素
trims.name = t("Canvas.Elements") + (index + 1);
trims.type = "trims";
printTrimsLayers.unshift({...trims});
printTrimsLayers.unshift({ ...trims });
})
if(printTrimsLayers.length || singleLayers.length){
if (printTrimsLayers.length || singleLayers.length) {
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
}
await this.changeCanvas();
@@ -1556,10 +1546,30 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
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();
if(!fixedLayerObj) return console.warn("固定图层为空");
if (!fixedLayerObj) return console.warn("固定图层为空");
tagObject.set({
top: fixedLayerObj.top,
left: fixedLayerObj.left,
@@ -1572,7 +1582,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
});
var object = fixedLayerObj;
const imageUrl = this.props.clothingImageUrl2;
if(imageUrl){
if (imageUrl) {
object = await new Promise((resolve, reject) => {
fabric.Image.fromURL(imageUrl, (imgObject) => {
tagObject.set({
@@ -1592,8 +1602,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
});
tagObject.set('clipPath', transparentMask);
}
async createColorLayer(color_){
const color = color_ || {r:0,g:0,b:0,a:0};
async createColorLayer(color_) {
const color = color_ || { r: 0, g: 0, b: 0, a: 0 };
// if(findLayer(this.layers.value, SpecialLayerId.COLOR)) {
// return console.warn("画布中已存在颜色图层");
// }
@@ -1637,7 +1647,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
}
// 创建印花和元素图层
async createPrintTrimsLayers(printTrimsLayers, singleLayers){
async createPrintTrimsLayers(printTrimsLayers, singleLayers) {
// if(findLayer(this.layers.value, SpecialLayerId.SPECIAL_GROUP)) {
// return console.warn("画布中已存在印花和元素组图层");
// }
@@ -1651,12 +1661,12 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
const flScaleY = fixedLayerObj.scaleY
const children = [];
// 添加印花和元素图层
for(let index = 0; index < printTrimsLayers.length; index++){
for (let index = 0; index < printTrimsLayers.length; index++) {
let item = printTrimsLayers[index];
let id = generateId("layer_image_");
let name = item.name;
let image = await new Promise(resolve => {
fabric.Image.fromURL(item.path, (fabricImage)=>{
fabric.Image.fromURL(item.path, (fabricImage) => {
resolve(fabricImage);
}, { crossOrigin: "anonymous" });
})
@@ -1664,7 +1674,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
let top = flTop - flHeight * flScaleY / 2 + (item.location?.[1] || 0) * flScaleY
let scaleX = flWidth * (item.scale?.[0] || 1) / image.width * flScaleX
let scaleY = flHeight * (item.scale?.[1] || 1) / image.height * flScaleY
let {x, y} = calculateRotatedTopLeftDeg(
let { x, y } = calculateRotatedTopLeftDeg(
image.width * scaleX,
image.height * scaleY,
left,
@@ -1679,11 +1689,11 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
let flipY = false;
let blendMode = BlendMode.NORMAL;
// if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常
if(item.object){
if (item.object) {
opacity = item.object.opacity
flipX = item.object.flipX
flipY = item.object.flipY
if(item.object.blendMode) blendMode = item.object.blendMode;
if (item.object.blendMode) blendMode = item.object.blendMode;
}
image.set({
left: x,
@@ -1714,18 +1724,18 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
isPrintTrims: true,
blendMode: blendMode,
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
metadata: {sourceData: item},
metadata: { sourceData: item },
object: image,
})
children.push(layer);
};
// 添加平铺图层
for(let index = 0; index < singleLayers.length; index++){
for (let index = 0; index < singleLayers.length; index++) {
let item = singleLayers[index];
let id = generateId("layer_image_");
let name = item.name;
let image = await new Promise(resolve => {
fabric.Image.fromURL(item.path, (fabricImage)=>{
fabric.Image.fromURL(item.path, (fabricImage) => {
const imgElement = fabricImage.getElement();
const tcanvas = document.createElement('canvas');
tcanvas.width = imgElement.width;
@@ -1754,7 +1764,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
let flipY = false;
let blendMode = BlendMode.NORMAL;
let fill_repeat = "repeat"
if(item.object){
if (item.object) {
top += item.object.top * flScaleY
left += item.object.left * flScaleX
scaleX *= item.object.scaleX
@@ -1763,11 +1773,11 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
angle = item.object.angle
flipX = item.object.flipX
flipY = item.object.flipY
if(item.object.blendMode) blendMode = item.object.blendMode;
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;
if (item.object.fill_repeat) fill_repeat = item.object.fill_repeat;
}
let rect = new fabric.Rect({
id: id,
@@ -1791,7 +1801,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
offsetX: offsetX, // 水平偏移
offsetY: offsetY, // 垂直偏移
}),
fill_ : {
fill_: {
source: item.path,
gapX: gapX,
gapY: gapY,
@@ -1811,7 +1821,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
isPrintTrims: true,
blendMode: blendMode,
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
metadata: {sourceData: item},
metadata: { sourceData: item },
object: rect,
})
children.push(layer);
@@ -1828,9 +1838,9 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
// })
// 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){
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 => {
@@ -1858,21 +1868,21 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
/**
* 画布事件变更后
*/
async changeCanvas(fids = [], isBeforeChange = false){
if(!isBeforeChange) this.canvasChangeing = false;
async changeCanvas(fids = [], isBeforeChange = false) {
if (!isBeforeChange) this.canvasChangeing = false;
const fixedLayerObj = this.getFixedLayerObject();
if(!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
if (!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
if(colorObject){
if (colorObject) {
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);
await this.setObjecCliptInfo(colorObject);
this.canvas.renderAll();
return;
}
const base64 = await this.exportManager.exportImage({layerIdArray2: ids, isEnhanceImg: true});
if(!base64) return console.warn("导出图片失败", base64)
const base64 = await this.exportManager.exportImage({ layerIdArray2: ids, isEnhanceImg: true });
if (!base64) return console.warn("导出图片失败", base64)
const canvas = await base64ToCanvas(base64, fixedLayerObj.scaleX * 2, true);
const ctx = canvas.getContext('2d');
const width = fixedLayerObj.width;
@@ -1885,15 +1895,15 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
}
}
/** 画布变更之前 */
async beforeChangeCanvas(objects){
if(this.canvasChangeing) return;
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){
if (ids.length > 0) {
this.canvasChangeing = true;
this.canvas.getObjects().forEach(v => {
if(ids.includes(v.layerId)){
if (ids.includes(v.layerId)) {
v.globalCompositeOperation_ = v.globalCompositeOperation;
v.globalCompositeOperation = BlendMode.NORMAL;
}
@@ -2103,13 +2113,13 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
moveActiveObject(direction, step = 1) {
const objects = [];
const activeObject = this.canvas.getActiveObject();
if(!activeObject) return;
if (!activeObject) return;
const initPos = {
id: activeObject.id,
left: activeObject.left,
top: activeObject.top,
};
switch(direction) {
switch (direction) {
case "up":
activeObject.top -= step;
break;
@@ -2123,7 +2133,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
activeObject.left += step;
break;
}
if(!activeObject.id) return this.canvas.renderAll();
if (!activeObject.id) return this.canvas.renderAll();
const cmd = new ObjectMoveCommand({
canvas: this.canvas,
initPos,

View File

@@ -606,7 +606,9 @@ export class ExportManager {
imageSmoothingEnabled: true,
});
// 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 {
// 克隆并添加所有对象到临时画布,需要调整位置相对于固定图层
for (let i = 0; i < objectsToExport.length; i++) {
@@ -616,15 +618,20 @@ export class ExportManager {
restoreOpacityInRedGreen && true
);
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({
left: canvasWidth / 2,
top: canvasHeight / 2,
scaleX: cloned.scaleX / fixedLayerObject.scaleX,
scaleY: cloned.scaleY / fixedLayerObject.scaleY,
originX: "center",
originY: "center",
left: left,
top: top,
scaleX: scaleX,
scaleY: scaleY,
});
console.log("==========", {...cloned})
// 更新对象坐标
cloned.setCoords();
tempFabricCanvas.add(cloned);

View File

@@ -391,8 +391,8 @@ export class PartManager {
this.canvas.loading.value = true;
});
return new Promise((resolve, reject) => {
const user_id = store.state.UserHabit.userDetail.userId;
// const user_id = 24299;
// const user_id = store.state.UserHabit.userDetail.userId;
const user_id = 24299;
const data = {
image_path: this.props.clothingMinIOPath,
user_id,

View File

@@ -133,11 +133,12 @@ export class RedGreenModeManager {
this.canvas.on("mouse:up", (event) => {
// 可以在这里添加更多逻辑,比如生成图片或更新状态
nextTick(() => {
requestIdleCallback(async () => {
setTimeout(async () => {
if (!this.isInitialized) {
console.warn("红绿图模式未初始化,无法处理鼠标事件");
return;
}
console.log("鼠标抬起事件触发", this.onImageGenerated);
if (this.onImageGenerated) {
const imageData = await this.canvasManager.exportImage({
restoreOpacityInRedGreen: true, // 恢复红绿图模式下的透明度

View File

@@ -37,7 +37,6 @@ export class ThumbnailManager {
// 延迟执行避免阻塞UI
fabricObjects.length > 0 &&
requestIdleCallback(() => {
setTimeout(async () => {
const base64 = await this._generateLayerThumbnailNow(fabricObjects, layer);
// this.layerThumbnails.set(layerId, base64);
@@ -55,7 +54,6 @@ export class ThumbnailManager {
console.error("生成图层缩略图时出错:", error);
}
});
});
}
/**
@@ -65,7 +63,7 @@ export class ThumbnailManager {
generateAllLayerThumbnails(layers) {
if (!layers || !Array.isArray(layers)) return;
requestIdleCallback(() => {
setTimeout(() => {
setTimeout(() => {
layers.forEach((layer) => {
if (layer && layer.id) {

View File

@@ -180,7 +180,7 @@ export class CommandManager {
this._recordPerformance("execute", command.constructor.name, duration);
// 通知状态变化
this._notifyStateChange();
this._notifyStateChange("execute");
console.log(`✅ 命令执行成功: ${command.constructor.name}`);
return result;
@@ -219,7 +219,7 @@ export class CommandManager {
this._recordPerformance("undo", command.constructor.name, duration);
// 通知状态变化
this._notifyStateChange();
this._notifyStateChange("undo");
console.log(`✅ 命令撤销成功: ${command.constructor.name}`);
return result;
@@ -258,7 +258,7 @@ export class CommandManager {
this._recordPerformance("redo", command.constructor.name, duration);
// 通知状态变化
this._notifyStateChange();
this._notifyStateChange("redo");
console.log(`✅ 命令重做成功: ${command.constructor.name}`);
return result;
@@ -298,7 +298,7 @@ export class CommandManager {
this.undoStack = [];
this.redoStack = [];
this._notifyStateChange();
this._notifyStateChange("clear");
// console.log("📝 命令历史已清空");
}
@@ -417,10 +417,12 @@ export class CommandManager {
* 通知状态变化
* @private
*/
_notifyStateChange() {
_notifyStateChange(type) {
if (this.onStateChange) {
try {
this.onStateChange(this.getState());
const obj = this.getState();
obj.type = type;
this.onStateChange(obj);
} catch (error) {
console.error("状态变化回调执行失败:", error);
}

View File

@@ -85,7 +85,7 @@ export class LiquifyRealTimeUpdater {
if (isDrawing && this.config.useDirectUpdate) {
// 拖拽过程中使用快速更新(降低质量以提高性能)
this._fastUpdate(imageData);
await this._fastUpdate(imageData);
} else {
// 拖拽结束后使用完整更新(最高质量)
await this._fullUpdate(imageData);
@@ -124,7 +124,7 @@ export class LiquifyRealTimeUpdater {
* @param {ImageData} imageData 图像数据
* @private
*/
_fastUpdate(imageData) {
async _fastUpdate(imageData) {
if (!this.targetObject || !this.targetObject._element) {
return;
}
@@ -138,12 +138,14 @@ export class LiquifyRealTimeUpdater {
// 直接更新fabric对象的图像源使用PNG格式保持质量
const targetElement = this.targetObject._element;
// 方案1: 直接设置src属性最高性能
const dataURL = this.tempCanvas.toDataURL("image/png", quality);
if (targetElement.src !== dataURL) {
targetElement.src = dataURL;
// targetElement.src = dataURL;
const image = new Image();
image.src = dataURL;
await image.decode();
this.targetObject.setElement(image);
// 关键优化直接设置fabric对象为脏状态但不立即渲染
// this.targetObject.dirty = false; // 标记为不需要立即渲染
@@ -153,7 +155,7 @@ export class LiquifyRealTimeUpdater {
// 使用requestAnimationFrame进行批量渲染优化
// if (!this.renderingScheduled && !this.config.skipRenderDuringDrag) {
// this.renderingScheduled = true;
// requestIdleCallback(() => {
// setTimeout(() => {
// this.canvas.renderAll();
// this.renderingScheduled = false;
// });

View File

@@ -7,7 +7,6 @@ import { canvasConfig } from "../config/canvasConfig";
export const createCanvas = (elementId, options = {}) => {
// Create the canvas instance
const canvas = new fabric.Canvas(elementId, {
controlsAboveOverlay: true,// 控制面板在图层之上
enableRetinaScaling: canvasConfig.enableRetinaScaling,
renderOnAddRemove: false,
preserveObjectStacking: true, // 保持对象堆叠顺序

View File

@@ -447,6 +447,7 @@
</template>
</CanvasEditor>
</div>
<img src="" alt="" id="canvas-test-dom">
</div>
</template>
<style>
@@ -458,6 +459,13 @@
height: 600px !important;
z-index: 99999999;
}
#canvas-test-dom{
position: fixed;
z-index: 9999999999;
top: 0;
left: 0;
pointer-events: none;
}
</style>
<style scoped lang="less">
* {

View File

@@ -331,7 +331,6 @@ export default defineComponent({
store.commit('DesignDetail/setCurrentDetailType',str)
}
const setClothes = async (list:any,str:string)=>{
console.log(JSON.parse(JSON.stringify(list)))
let clothesList:any = []
if(detailData.isEditPattern.value == 'editSketch')await detailDom.canvasBox.submitBase64Data().then((rv)=>{
detailData.selectDetail.sketchString = rv
@@ -369,7 +368,6 @@ export default defineComponent({
// }else if(isCurrent){
// }
console.log(JSON.parse(JSON.stringify(detailData.selectDetail.color)),'=====')
color = list[i].color?.rgba?.r != null?`${list[i].color.rgba.r} ${list[i].color.rgba.g} ${list[i].color.rgba.b}`:''
gradient = list[i].gradient
if((detailData.currentDetailType == 'sketch' && newData?.sketch) || detailData.isEditPattern.value == 'editSketch'){
@@ -565,11 +563,14 @@ export default defineComponent({
}
}else{
//走画布合成图片并且直接分割
if(detailData.isEditPattern.value !== 'canvasEditor' && detailData.isEditPattern.value !== 'redGreenExample'){
if(detailData.isEditPattern.value !== 'canvasEditor'){
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
}
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
}
await detailDom.canvasBox.privewDetail()
await upDateFrontBackSketch()
await uploadSelectDetail()
@@ -625,7 +626,7 @@ export default defineComponent({
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
// await detailDom.canvasBox.saveCanvas()
await (detailDom.canvasBox as any).privewDetail()
if(detailData.isEditPattern.value == 'canvasEditor')await uploadSelectDetail()
if(detailData.isEditPattern.value == 'canvasEditor' || detailData.isEditPattern.value == 'redGreenExample')await uploadSelectDetail()
detailData.isEditPattern.value = ''
}else{
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
@@ -780,8 +781,7 @@ export default defineComponent({
color.gradient = canvasColor.gradient
}
}
if(detailData.isEditPattern.value == 'canvasEditor'){
if(detailData.isEditPattern.value == 'canvasEditor' || detailData.isEditPattern.value == 'redGreenExample'){
delete detailData.selectDetail.newDetail
detailData.selectDetail.trims.prints = allInfo.trims || []
detailData.selectDetail.printObject.prints = allInfo.prints || []
@@ -804,7 +804,6 @@ export default defineComponent({
if(detailData.currentDetailType == 'color'){
detailData.detailLeftColorKey++
}
}
const canvasReload = async ()=>{
if(detailData.isEditPattern.value){

View File

@@ -163,7 +163,6 @@ export default defineComponent({
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
// if(!detailDom.editCanvas)return
return new Promise(async (res,reject)=>{
console.log(detailDom.editCanvas)
await detailDom.editCanvas.exportImage({
isContainFixed:true,
width:props.sketchSize.width,
@@ -245,17 +244,27 @@ export default defineComponent({
const frontBackChange = async (value:any)=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
await nextTick()
if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){
await privewDetail()
}else{
await detailDom.editCanvas.exportImage({
isFrontBackUpdata: true,
isContainFixed:true,
width:props.sketchSize.width,
height:props.sketchSize.height,
}).then((rv)=>{
if(detailData.selectDetail?.partialDesign)detailData.selectDetail.partialDesign.partialDesignBase64 = rv
})
}
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath || detailData.selectDetail.path
let size = {
...detailData.canvasConfig,
}
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
segmentImage(value,full,size).then(async (rv)=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
@@ -267,7 +276,6 @@ export default defineComponent({
back.imageUrl = rv.targetBackUrl
// store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
})
}
const editSketchCanvasInit = async (value:any)=>{
detailData.canvasInstance = value

View File

@@ -393,8 +393,8 @@ export default defineComponent({
angle: 0,
flipX: false,
flipY: false,
// blendMode: "multiply",
blendMode: "source-over",
blendMode: "multiply",
// blendMode: "source-over",
gapX: 0,
gapY: 0,
}

View File

@@ -124,7 +124,11 @@ export default defineComponent({
const handleResize = ()=>{
clearTimeout(time)
time = setTimeout(()=>{
store.commit('DesignDetail/setDesignDetail',getDetailListData.designDetail)
let data = {
...getDetailListData.designDetail,
fromType:'resize',
}
store.commit('DesignDetail/setDesignDetail',data)
getDetailListDom.position?.updataPosition?.()
getDetailListDom.modelNav?.setItemPosition?.()
getDetailListDom.position?.updateRect?.()

View File

@@ -189,11 +189,11 @@ export default defineComponent({
}
return { scaleX, scaleY, rotate };
}
const initMoveableForSelected = () => {
const initMoveableForSelected = async (isDestroy:boolean = false) => {
// 销毁旧的实例
if(selectItem.imgDomIndex == -1)return
if (moveableInstance.value) {
moveableInstance.value.destroy();
if (moveableInstance?.value?.destroy && !isDestroy) {
moveableInstance?.value?.destroy();
}
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
@@ -509,7 +509,7 @@ export default defineComponent({
watch(()=>detailData.frontBack.front.length,(newValue,oldValue)=>{
if(selectItem.selectDetail?.id)selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == selectItem.selectDetail?.id)
setTimeout(()=>{
initMoveableForSelected()
initMoveableForSelected(oldValue == 0)
},100)
})
const setRevocation = async ()=>{

View File

@@ -21,7 +21,11 @@
{{ $t("event.detail") }}
</div>
</div>
<div class="modal_title_text content" v-for="item in eventsDetail.textList">
<div
class="modal_title_text content"
v-for="item in eventsDetail.textList"
:class="{ award: eventsDetail.id === 3 }"
>
<div class="eventsDetail_content_right_btn_box">
<div
class="eventsDetail_content_right_btn"
@@ -43,6 +47,7 @@
v-detailText="introItem.text"
></div>
</div>
<div class="tips" v-if="eventsDetail.tips">{{ eventsDetail.tips }}</div>
</div>
</div>
</div>
@@ -120,8 +125,13 @@ export default defineComponent({
})
}
const openDetail = () => {
let language = locale.value === "ENGLISH" ? "en" : "zh"
let language = locale.value === "ENGLISH" ? "en" : "cn"
let url = `https://aida-global-design-awards.com.hk/${language}`
// 如果是dev环境把域名换成http://192.168.31.198
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
url += "?env=dev"
}
window.open(url, "_blank")
// router.push("/award/index")
@@ -233,7 +243,7 @@ export default defineComponent({
}
.eventsDetail_content_right {
.modal_title_text {
letter-spacing: 0.4rem;
letter-spacing: 0.3rem;
font-weight: 600;
&-header {
display: flex;
@@ -265,18 +275,21 @@ export default defineComponent({
.eventsDetail_content_right_btn_box {
display: flex;
justify-content: space-evenly;
.eventsDetail_content_right_btn {
// .eventsDetail_content_right_btn {
// }
}
}
}
.modal_title_text:last-child {
}
// .modal_title_text:last-child {
// }
.modal_title_text:last-child::after {
content: "";
display: block;
border-top: 3px solid;
height: 6rem;
}
.modal_title_text.award:last-child:after {
display: none;
}
}
}
}
@@ -293,4 +306,13 @@ export default defineComponent({
white-space: nowrap;
cursor: pointer;
}
.tips{
color: rgba(0, 0, 0, 0.45);
font-size: var(--aida-fsize1-4);
font-weight: 400;
letter-spacing: 0.3rem;
}
.modal_title_text.content.award{
line-height: 1.3;
}
</style>

View File

@@ -531,7 +531,7 @@ export default defineComponent({
}
)
const setSpeed = (item: any) => {
speed.speedData = item
speed.speedData = {...item}
}
onMounted(() => {
if (props.msg == 'Sketchboard') {
@@ -734,6 +734,8 @@ export default defineComponent({
let maxImg = 8
if (this.type_.type2 == 'Sketchboard') {
maxImg = 20
}else if(this.type_.type2 == 'Printboard'){
maxImg = 16
}
let parent: any = this.$parent
if (parent.isUseGenerate) {

View File

@@ -7,7 +7,7 @@
:get-container="() => $refs.upgradePlan"
width="35%"
height="auto"
:zIndex="9999999"
zIndex="9999999"
:maskClosable="false"
:centered="true"
:closable="false"

View File

@@ -940,7 +940,8 @@ export default defineComponent({
// padding: 3rem 0;
justify-content: space-between;
position: relative;
user-select:none
user-select:none;
flex-direction: row;
&.active{
flex-direction: row;
}

View File

@@ -205,7 +205,7 @@
</div>
<div class="payment">
<div class="allocation">
<div class="selectType">
<!-- <div class="selectType">
<div class="text">{{ $t('Renew.Payment') }}:</div>
<label>
<input
@@ -227,7 +227,7 @@
/>
{{ $t('Renew.Alipay') }}
</label>
</div>
</div> -->
</div>
<div class="gallery_btn gallery_btn_radius" @click="payment">
{{ $t('upgradePlan.Continue') }}

View File

@@ -77,17 +77,10 @@ export default defineComponent({
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 80%;
height: auto;
max-height: 80vh;
position: absolute;
width: max-content;
video{
width: 100%;
max-height: 80vh;
height: 100%;
object-fit: contain;
width: max-content;
max-height:80vh;
max-width:80vw;
}
.general_video_btn{
color: #fff;

View File

@@ -745,6 +745,12 @@ export default defineComponent({
"userLikeId": likeItem.id
}
arrData.push(obj)
designData.selectLikeDesign.forEach((v:any)=>{
if(v.id === likeItem.id){
v.oldSort = v.sort
v.sort = likeItem.sort
}
})
})
let data = {
"userLikeGroupId": userGroupId.value,
@@ -1304,9 +1310,9 @@ export default defineComponent({
})
return
}
const parents = designData.selectLikeDesign.filter((item:any) => item.resultType === 'Design');
const parents = designData.selectLikeDesign.filter((item:any) => item.resultType === 'Design').filter((item:any) => likeDesignCollectionList.value.some((v:any) => (v.id === item.id)));
parents.map((parent:any) => {
parent.sort = parent.oldSort||parent.sort
parent.sort = likeDesignCollectionList.value.find((v:any) => v.id === parent.id)?.sort || parent.oldSort||parent.sort
delete parent.oldSort
return {
...parent,
@@ -1533,7 +1539,7 @@ export default defineComponent({
this.observerData.time = setTimeout(()=>{
this.setSystemDesigner(0)
this.setDesignItemStyle()
// this.setDesignItemStyle()
},100)
// const { width } = entry.contentRect;
}
@@ -1931,6 +1937,7 @@ export default defineComponent({
this.disLikeLoading = true;
Https.axiosPost(Https.httpUrls.designDislike, data)
.then((rv: any) => {
console.log(rv)
if (rv) {
this.recycleDomHidden = true
this.store.commit("addDesignCollectionList", [design]);

View File

@@ -41,10 +41,10 @@
<div class="center">{{ selectObject?.styleName?selectObject?.styleName:$t('Header.All') }}</div>
<div class="gallery_btn" @click="setStyle">{{ $t('Habit.Select') }}</div>
</div>
<div class="style brand marginBottom">
<!-- <div class="style brand marginBottom">
<div class="text">{{$t('Habit.Brand')}}:</div>
<div class="gallery_btn" @click="setBrandDNA">{{ $t('Habit.Select') }}</div>
</div>
</div> -->
<div class="brandImg" v-if="selectObject.userBrandDna"><img :src="selectObject.userBrandDnaImg"></div>
<div class="brandDNAStrenght marginBottom" v-if="selectObject.userBrandDna">
<div class="text" style="font-size: 1.6rem;">

View File

@@ -258,6 +258,7 @@ methods: {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
}
.content_bottom_item:nth-child(4n){

View File

@@ -24,8 +24,6 @@ export default {
SubscribeNow: '立即订阅',
TaskList: '任务列表',
ViewOrders: '查询订单',
BecomeSeller: '成为卖家',
SellerDashboard: '卖家中心',
toolsToProduct: '转产品图',
toolsRelight: '产品图编辑',
toolsToTransferPose: '产品图视频',
@@ -1721,19 +1719,5 @@ export default {
IncorrectEmailFormat: '请输入正确的邮箱格式',
CompleteVerificationCode: '请输入完整的验证码',
PleaseEnterYourAccountNumberOrPassword: '请输入您的账号或密码'
},
SellerToolTip: {
title: '如何上架你的设计',
titleInfo: '按照以下4个步骤将你的设计发布到市场。',
step1Title: '选择系列',
step1Info: '选择你要上架的设计系列。',
step2Title: '选择草图',
step2Info: '挑选你要上架的草图,可同时选择多个。',
step3Title: '编辑草图详情',
step3Info: '详情信息已从AiDA自动填充请检查并补充任何缺失的信息。',
step4Title: '上架发布',
step4Info: '发布后,你的设计将立即在市场上线。',
showAgain: '不再提示',
GetStarted: '开始体验',
}
}

View File

@@ -24,8 +24,6 @@ export default {
SubscribeNow: 'Subscribe now',
TaskList: 'Task List',
ViewOrders: 'View Orders',
BecomeSeller: 'Become a Seller',
SellerDashboard: 'Seller Dashboard',
toolsToProduct: 'To product image',
toolsRelight: 'Edit product image',
toolsToTransferPose: 'To product video',
@@ -1772,19 +1770,5 @@ export default {
IncorrectEmailFormat: 'The email format is incorrect',
CompleteVerificationCode: 'Please enter the complete verification code.',
PleaseEnterYourAccountNumberOrPassword: 'Please enter your account number or password'
},
SellerToolTip: {
title: 'How to List your Design',
titleInfo: 'Follow these 4 steps to publish your design to the marketplace.',
step1Title: 'Select Collection',
step1Info: 'Choose the design collection you want to list from.',
step2Title: 'Select Sketch',
step2Info: 'Pick the sketch you want to list. You can select multiple at a time.',
step3Title: 'Edit Sketch Details',
step3Info: 'Details are pre-filled from AiDA. Review and complete any missing information.',
step4Title: 'Listing Live',
step4Info: 'Publish and your design goes live on the marketplace.',
showAgain: 'Dont show me again',
GetStarted: 'Get Started',
}
}

View File

@@ -169,69 +169,6 @@ const routes: Array<RouteRecordRaw> = [
name: "otherUsers",
meta: { enter: "all" },
component: () => import("@/component/Account/otherUsers.vue"),
},
{
path: "becomeSeller",
name: "becomeSeller",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/BecomeSeller/index.vue"),
},
{
path: "seller",
name: "seller",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/index.vue"),
children:[
{
path: "brandProfile",
name: "brandProfile",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/BrandProfile/index.vue"),
},
{
path: "myListings",
name: "myListings",
meta: { enter: "all" },
children:[
{
path: "",
name: "myListingsChild",
meta: { enter: "all" },
redirect: "/home/seller/myListings/index",
},
{
path: "index",
name: "myListingsIndex",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/MyListings/main/index.vue"),
},
{
path: "select",
name: "myListingsSelect",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/MyListings/createSelect/index.vue"),
},
{
path: "select/:id",
name: "myListingsSelectItem",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/MyListings/createSelectItem/index.vue"),
},
]
},
{
path: "myOrders",
name: "myOrders",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/BrandProfile/index.vue"),
},
{
path: "settings",
name: "settings",
meta: { enter: "all" },
component: () => import("@/views/SellerDashboard/BrandProfile/index.vue"),
},
],
},
],
},
@@ -241,6 +178,12 @@ const routes: Array<RouteRecordRaw> = [
meta: { enter: "all" },
component: () => import("@/views/HomeRecommend.vue"),
},
{
path: "/Square/:lang",
name: "HomeRecommendLang",
meta: { enter: "all" },
component: () => import("@/views/HomeRecommend.vue"),
},
{
path: "/administrator",
name: "administrator",
@@ -394,6 +337,13 @@ const routes: Array<RouteRecordRaw> = [
meta: { enter: 3 },
component: () =>
import("@/component/Administrator/SE/getGenerateFrequency/index.vue"),
},
{
path: "globalAwardPopularity",
name: "globalAwardPopularity",
meta: { enter: 3 },
component: () =>
import("@/component/Administrator/globalAwardPopularity.vue"),
},
],
},

View File

@@ -87,8 +87,10 @@ const DesignDetail : Module<DesignDetail,RootState> = {
left:0,
top:0,
}
if(data?.fromType !== 'resize'){
v.maskMinioUrl = v.layersObject?.[0]?.maskMinioUrl
v.maskUrl = v.layersObject?.[0]?.maskUrl
}
v.layersObject[i].designOpenrtionBtn = false
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
front[index] = v.layersObject[i]

View File

@@ -198,6 +198,13 @@ const all = (t)=>{
route: '/administrator/subscriptionPlan',
key: 'sub14',
isShow: true
},
{
name: 'Global Award Popularity',
icon: 'usetime',
route: '/administrator/globalAwardPopularity',
key: 'sub15',
isShow: true
}
]
}

View File

@@ -346,6 +346,7 @@ export const Https = {
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
switchSubAccountSubscribePlan:
'/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
getGlobalAwardPopularity: '/api/global-award/page/visit/count', // 获取global award流量
//云生成
designCloud: `/api/design/designCloud`, //创建云生成

View File

@@ -340,12 +340,12 @@ const navTypeList = (t)=>{
value:'Models',
router:'library=Models'
},
{
icon:'fi-ss-gem',
label:t('LibraryPage.brandDNA'),
value:'MyBrand',
router:'library=MyBrand'
},
// {
// icon:'fi-ss-gem',
// label:t('LibraryPage.brandDNA'),
// value:'MyBrand',
// router:'library=MyBrand'
// },
]
},
// history:{

View File

@@ -672,6 +672,17 @@ function sketchToMask(sketchImage) {
img.src = sketchImage;
});
}
function isValidUrl(string) {
try {
const url = new URL(string)
// 通常我们只需要 http 或 https 协议
return url.protocol === "http:" || url.protocol === "https:"
} catch (err) {
return false
}
}
export {
isEmail,
getUploadUrl,
@@ -695,5 +706,6 @@ export {
calculateGradientCoordinate,
segmentImage,
UrlToFile,
sketchToMask
sketchToMask,
isValidUrl
}

View File

@@ -373,15 +373,6 @@
<i class="fi fi-rs-notebook"></i>
<span class="select_item_des">{{ $t('Header.ViewOrders') }}</span>
</div>
<div class="select_item" @click="onBecomeSeller">
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
<span class="select_item_des">{{ $t('Header.BecomeSeller') }}</span>
</div>
<div class="select_item" @click="onSellerDashboard">
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
<span class="select_item_des">{{ $t('Header.SellerDashboard') }}</span>
<a-badge :dot="true"></a-badge>
</div>
<router-link
class="select_item"
v-if="userDetail.systemList.indexOf(3) >= 0"
@@ -409,7 +400,7 @@
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
</a>
<a href="https://www.youtube.com/@AiDA-3.1" target="_blank" >
<a href="https://www.youtube.com/@Code-Create_AiDA" target="_blank" >
<img src="@/assets/images/socialMediaLogo/socialIcons.svg" alt="">
</a>
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
@@ -1254,12 +1245,6 @@ export default defineComponent({
let payOrder = this.$refs.payOrder
payOrder.init()
},
onBecomeSeller(){
this.$router.push({ name: 'becomeSeller' })
},
onSellerDashboard(){
this.$router.push({ name: 'brandProfile' })
},
//教程
getTutorial() {
let url = 'https://aida-user-manual-chinese.super.site/'
@@ -2132,7 +2117,7 @@ export default defineComponent({
}
> .routerView {
position: relative;
overflow-y: hidden;
overflow: hidden;
flex: 1;
display: flex;
> .router {

View File

@@ -62,7 +62,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { useStore } from 'vuex'
import { setLang } from '@/tool/guide'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { useRouter, useRoute } from 'vue-router'
import { gsap, TweenMax } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
export default defineComponent({
@@ -71,6 +71,7 @@ export default defineComponent({
const {t, locale} = useI18n()
const store = useStore()
const router = useRouter()
const route = useRoute()
let registerModel = ref()
let data = reactive({})
@@ -117,7 +118,14 @@ export default defineComponent({
onMounted(() => {
window.addEventListener('resize', updataIsMoblie)
// 初始化语言设置
const savedLang = localStorage.getItem('loginLanguage')
let savedLang = localStorage.getItem('loginLanguage')
if(route?.params?.lang == 'cn'){
savedLang = 'CHINESE_SIMPLIFIED'
localStorage.setItem('loginLanguage', savedLang)
}{
savedLang = 'ENGLISH'
localStorage.setItem('loginLanguage', savedLang)
}
if (savedLang) {
isChinese.value = savedLang === 'CHINESE_SIMPLIFIED'
locale.value = savedLang

View File

@@ -1,35 +0,0 @@
<template>
<div class="become-seller">
<seller-header
title="Apply to Become a Seller"
tip="Join the Stylish Parade and start selling your design work"
/>
<div class="content">
<seller-review v-if="isSubmit" />
<seller-apply v-else @submit="isSubmit = true" />
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue"
import sellerHeader from "../seller-header.vue"
import sellerReview from "./sellerReview.vue"
import sellerApply from "./sellerApply.vue"
const isSubmit = ref(false)
</script>
<style scoped lang="less">
.become-seller {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
> .content {
margin-top: 4rem;
flex: 1;
overflow: hidden;
}
}
</style>

View File

@@ -1,255 +0,0 @@
<template>
<div class="seller-apply">
<div class="session">
<div class="content mini-scrollbar">
<div class="title">Brand Information</div>
<div class="tip">Share a few details to set up your seller profile</div>
<div class="form">
<a-form :model="formData" :rules="formRules" layout="vertical" ref="formRef">
<a-form-item label="Store Name" name="storeName">
<a-input
v-model:value="formData.storeName"
placeholder="Enter the store name"
:maxlength="80"
/>
<span class="tip-length">{{ formData.storeName.length }}/80</span>
</a-form-item>
<a-form-item label="Owners Full Name" name="fullName">
<a-input
v-model:value="formData.fullName"
placeholder="Enter store owner's full name"
/>
</a-form-item>
<div class="form-group">
<a-form-item label="Email" name="email">
<a-input
type="email"
v-model:value="formData.email"
placeholder="Enter email"
/>
</a-form-item>
<a-form-item label="Phone Number" name="phoneNumber">
<a-input
type="tel"
v-model:value="formData.phoneNumber"
placeholder="Enter phone number"
/>
</a-form-item>
</div>
<a-form-item label="Store Description" name="description">
<a-textarea
v-model:value="formData.description"
placeholder="Briefly describe your design style and store features..."
:maxlength="500"
/>
<span class="tip-length">{{ formData.description.length }}/500</span>
</a-form-item>
<a-form-item label="Portfoilo/Social Media Links">
<a-input
placeholder="https://"
v-for="(v, i) in formData.links"
:key="i"
v-model:value="formData.links[i]"
>
<template #prefix>Link {{ i + 1 }}</template>
</a-input>
<a-input
placeholder="https://"
v-model:value="newLink"
@keyup.enter.prevent="addLink"
>
<template #prefix>
<span @click="addLink" style="cursor: pointer">
<svg-icon name="seller-add" size="20" />
</span>
</template>
</a-input>
</a-form-item>
</a-form>
</div>
</div>
</div>
<div class="session">
<div class="content">
<div class="title">Brand Information</div>
<div class="tip">Share a few details to set up your seller profile</div>
<div class="agreement">
<div class="title">AiDA Seller Agreement</div>
<div class="tip">
By checking the box below, you agree to comply with the following terms:
</div>
<ul>
<li>Provide accurate and truthful personal and store information</li>
<li>Only sell original designs or content with proper licensing</li>
<li>Maintain high quality standards for all products</li>
<li>Respond to customer inquiries within 48 hours</li>
<li>Ship orders within promised timeframes</li>
<li>Comply with AiDA's terms of service and community guidelines</li>
<li>Pay applicable platform fees and transaction charges</li>
<li>Handle customer disputes professionally and fairly</li>
</ul>
</div>
<a-checkbox class="agree-agreement" v-model:checked="isAgreement">
I have read and agree to the Seller Agreement, understanding my responsibilities
and obligations as a seller on the AiDA platform.
</a-checkbox>
</div>
<div class="btns">
<button class="cancel" @click="onCancel">Cancel</button>
<button class="submit" :disabled="!isAgreement" @click="onSubmit">
Submit Application
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from "vue"
import { useRoute, useRouter } from "vue-router"
const route = useRoute()
const router = useRouter()
const emit = defineEmits(["submit"])
const formRules = {
storeName: [{ required: true, message: "Enter the store name" }],
fullName: [{ required: true, message: "Enter store owner's full name" }],
email: [{ required: true, message: "Enter email" }],
phoneNumber: [{ required: true, message: "Enter phone number" }],
description: [{ required: true, message: "Enter store description" }]
}
const formRef = ref(null)
const formData = reactive({
storeName: "",
fullName: "",
email: "",
phoneNumber: "",
description: "",
links: ["", ""]
})
const isAgreement = ref(false)
const newLink = ref("")
const addLink = () => {
formData.links.push(newLink.value)
newLink.value = ""
}
const onCancel = () => {
router.back()
}
const onSubmit = () => {
formRef.value
.validate()
.then(() => {
console.log(formData)
emit("submit")
})
.catch(() => {
console.log("validate failed")
})
}
</script>
<style scoped lang="less">
@import "@/assets/style/ant-from-style.less";
.seller-apply {
width: 100%;
height: 100%;
overflow: hidden;
padding: 0 10rem;
display: flex;
gap: 6rem;
> .session {
flex: 1;
overflow: hidden;
> .content {
max-height: 100%;
padding: 2.4rem;
border: 1px solid #b0b0b0;
border-radius: 2.4rem;
overflow-y: auto;
> .title {
font-size: 2.2rem;
line-height: 130%;
color: #000;
margin-bottom: 0.8rem;
}
> .tip {
font-family: pingfang_regular;
font-size: 1.4rem;
line-height: 150%;
color: #b0b0b0;
}
> .form {
margin-top: 1.6rem;
}
> .agreement {
padding: 1.6rem;
border-radius: 1.2rem;
background-color: #f9f9f9;
margin-bottom: 2.4rem;
> .title {
font-size: 1.4rem;
color: #000;
margin-bottom: 1rem;
}
> ul > li,
> .tip {
font-family: pingfang_medium;
font-size: 1.4rem;
color: #737373;
}
> ul {
margin-top: 3rem;
padding-left: 2.5rem;
> li {
margin-bottom: 1rem;
list-style-type: disc;
}
}
&:deep(.agree-agreement) {
align-items: flex-start;
span {
font-family: pingfang_medium;
font-size: 1.2rem;
}
.ant-checkbox-inner,
.ant-checkbox-input {
width: 2rem;
height: 2rem;
}
.ant-checkbox-inner {
border-color: #000 !important;
}
}
}
}
> .btns {
margin-top: 3.9rem;
display: flex;
justify-content: flex-end;
gap: 1.6rem;
> button {
height: 6rem;
border-radius: 6rem;
padding: 0 4rem;
background-color: #000;
color: #fff;
font-size: 1.6rem;
border: none;
cursor: pointer;
&:active:not(:disabled) {
opacity: 0.8;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
> .cancel {
background-color: #fff;
color: #000;
border: 0.15rem solid #000;
}
}
}
}
</style>

View File

@@ -1,126 +0,0 @@
<template>
<div class="seller-review">
<img class="success" src="@/assets/images/seller/success-1.png" />
<div class="title">Application Submitted</div>
<div class="tip">
Our team will review your application and get back to you within 13 business days.
You'll receive a notification in your email once a decision has been made.
</div>
<div class="step-list">
<div v-for="v in list" :key="v.title" class="step-item">
<img v-show="!v.active" src="@/assets/images/seller/success-0.png" />
<img v-show="v.active" src="@/assets/images/seller/success-1.png" />
<div class="content">
<div class="title">{{ v.title }}</div>
<div class="tip">{{ v.tip }}</div>
</div>
</div>
</div>
<button class="home-btn" @click="onBackToHome">Back to Homepage</button>
</div>
</template>
<script setup>
import { ref, computed } from "vue"
import { useRoute, useRouter } from "vue-router"
const route = useRoute()
const router = useRouter()
const list = ref([
{
title: "Step 1: Submit Application",
tip: "Fill out the seller information form and agree to our terms",
active: true
},
{
title: "Step 2: Review & Verification",
tip: "Our team will review your application (typically 1-3 business days)",
active: false
},
{
title: "Step 3: Start Selling",
tip: "Once approved, access your seller dashboard and start listing products ",
active: false
}
])
const onBackToHome = () => {
router.push({ name: "home" })
}
</script>
<style scoped lang="less">
.seller-review {
margin: 0 auto;
width: 60rem;
height: 90%;
overflow-y: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 2.4rem;
> .success {
width: 10rem;
height: 10rem;
padding: 1.2rem;
}
> .title {
font-size: 2.2rem;
line-height: 130%;
text-align: center;
color: #000;
}
> .tip {
font-family: pingfang_medium;
font-size: 1.8rem;
line-height: 170%;
text-align: center;
color: #585858;
}
> .step-list {
margin: 2.6rem 0;
width: 100%;
padding: 1.6rem;
background-color: #f9f9f9;
display: flex;
flex-direction: column;
gap: 1.4rem;
border-radius: 1.2rem;
> .step-item {
display: flex;
> img {
width: 2rem;
height: 2rem;
margin: 0.2rem;
margin-right: 1.2rem;
}
> .content {
flex: 1;
font-size: 1.4rem;
> .title {
font-style: Bold;
color: #000;
line-height: 150%;
}
> .tip {
font-family: "pingfang_medium";
line-height: 170%;
color: #737373;
}
}
}
}
> .home-btn {
width: 31rem;
height: 6rem;
border-radius: 4rem;
font-size: 1.6rem;
color: #fff;
background-color: #000;
border: none;
cursor: pointer;
outline: none;
&:active {
opacity: 0.8;
}
}
}
</style>

View File

@@ -1,139 +0,0 @@
<template>
<div class="brand-info">
<a-form :model="formData" :rules="isEdit ? formRules : {}" layout="vertical" ref="formRef">
<div class="form-group">
<a-form-item label="Store Name" name="storeName">
<a-input
v-model:value="formData.storeName"
placeholder="Enter the store name"
:maxlength="80"
:readonly="!isEdit"
/>
<span v-show="isEdit" class="tip-length"
>{{ formData.storeName.length }}/80</span
>
</a-form-item>
<a-form-item label="Owners Full Name" name="fullName">
<a-input
v-model:value="formData.fullName"
placeholder="Enter store owner's full name"
:readonly="!isEdit"
/>
</a-form-item>
</div>
<div class="form-group">
<a-form-item label="Email" name="email">
<a-input
type="email"
v-model:value="formData.email"
placeholder="Enter email"
:readonly="!isEdit"
/>
</a-form-item>
<a-form-item label="Phone Number" name="phoneNumber">
<a-input
type="tel"
v-model:value="formData.phoneNumber"
placeholder="Enter phone number"
:readonly="!isEdit"
/>
</a-form-item>
</div>
<div class="form-group">
<a-form-item label="Portfoilo/Social Media Links">
<a-input
placeholder="https://"
v-for="(v, i) in formData.links"
:key="i"
v-model:value="formData.links[i]"
:readonly="!isEdit"
>
<template #prefix>Link {{ i + 1 }}</template>
</a-input>
<a-input
placeholder="https://"
v-model:value="newLink"
@keyup.enter.prevent="addLink"
v-if="isEdit"
>
<template #prefix>
<span @click="addLink" style="cursor: pointer">
<svg-icon name="seller-add" size="20" />
</span>
</template>
</a-input>
</a-form-item>
<a-form-item label="Store Description" name="description">
<a-textarea
v-model:value="formData.description"
placeholder="Briefly describe your design style and store features..."
:maxlength="500"
:readonly="!isEdit"
/>
<span v-show="isEdit" class="tip-length"
>{{ formData.description.length }}/500</span
>
</a-form-item>
</div>
</a-form>
</div>
</template>
<script setup>
import { ref, reactive, watch } from "vue"
import { useRoute, useRouter } from "vue-router"
const route = useRoute()
const router = useRouter()
const props = defineProps({
isEdit: {
type: Boolean,
default: false
}
})
const formRules = {
storeName: [{ required: true, message: "Enter the store name" }],
fullName: [{ required: true, message: "Enter store owner's full name" }],
email: [{ required: true, message: "Enter email" }],
phoneNumber: [{ required: true, message: "Enter phone number" }],
description: [{ required: true, message: "Enter store description" }]
}
const formRef = ref(null)
const formData = reactive({
storeName: "",
fullName: "",
email: "",
phoneNumber: "",
description: "",
links: ["", ""]
})
const newLink = ref("")
const addLink = () => {
formData.links.push(newLink.value)
newLink.value = ""
}
watch(
() => props.isEdit,
(v) => (v ? edit() : cancel())
)
const edit = () => {}
const cancel = () => {}
const submit = async () => {
const valid = await formRef.value.validate()
if (!valid) return Promise.reject(false)
console.log(valid)
return valid
}
defineExpose({
submit
})
</script>
<style scoped lang="less">
@import "@/assets/style/ant-from-style.less";
.brand-info {
// width: 100%;
// height: 100%;
// overflow: hidden;
// padding: 0 10rem;
}
</style>

View File

@@ -1,183 +0,0 @@
<template>
<div class="brand-profile-index">
<div class="header">
<div class="bg">
<img v-if="banner" :src="banner" />
<div v-else class="null">
<span class="icon"><svg-icon name="seller-picture" size="60" /></span>
<span class="tip">Your brand banner has not been set up yet.</span>
</div>
<button>Change Brand Banner</button>
</div>
<!-- 头像 -->
<div class="avatar">
<img v-if="avatar" :src="avatar" />
<div v-else class="null">
<svg-icon name="seller-user" size="48" />
</div>
<span class="icon">
<svg-icon name="seller-camera" size="24" />
</span>
</div>
</div>
<brand-info :is-edit="isEdit" ref="brandInfoRef" />
</div>
<div class="and-profile-footer">
<template v-if="isEdit">
<div class="btns">
<button class="cancel" @click="onCancel">Cancel</button>
<button class="submit" @click="onSubmit">Save Change</button>
</div>
<p class="tip">Changes will be reflected on your Stylish Parade brand page.</p>
</template>
<template v-else>
<div class="btns">
<button class="edit" @click="onEdit">Edit</button>
</div>
<p class="tip">&nbsp;</p>
</template>
</div>
</template>
<script setup>
import { ref } from "vue"
import BrandInfo from "./brand-info.vue"
const banner = ref("http://118.31.39.42:3000/falls/5bd8065cbb396eb5a8ef0a142605139358734e57.png")
const avatar = ref("http://118.31.39.42:3000/falls/20251024140128_10355_1.jpg")
const isEdit = ref(false)
const brandInfoRef = ref(null)
const onEdit = () => {
isEdit.value = true
}
const onCancel = () => {
isEdit.value = false
}
const onSubmit = () => {
brandInfoRef.value
.submit()
.then(() => {
isEdit.value = false
})
.catch(() => {})
}
</script>
<style scoped lang="less">
.brand-profile-index {
flex: 1;
overflow-y: auto;
padding: 0 8rem;
margin: 0 7rem;
> .header {
position: relative;
margin-bottom: 6rem;
> .bg {
position: relative;
> img {
width: 100%;
height: auto;
border-radius: 1.2rem;
}
> .null {
width: 100%;
height: 23rem;
border-radius: 1.2rem;
border: 1px dashed #b0b0b0;
background: #f9f9f9;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
> .tip {
margin-top: 1.2rem;
font-family: pingfang_medium;
font-size: 1.6rem;
color: rgba(153, 153, 153, 0.6);
}
}
> button {
position: absolute;
bottom: 1.6rem;
right: 1.6rem;
padding: 0 2.7rem;
border-radius: 4rem;
height: 4.5rem;
border: none;
background-color: #fff;
box-shadow: 0.2rem 0.2rem 1.2rem 0 rgba(0, 0, 0, 0.1);
font-family: pingfang_medium;
font-size: 1.6rem;
cursor: pointer;
color: #000;
&:active {
opacity: 0.8;
}
}
}
> .avatar {
position: absolute;
left: 6rem;
bottom: -4rem;
> img,
> .null {
width: 12rem;
height: 12rem;
border-radius: 1.2rem;
border: 0.15rem solid #919191;
}
> .null {
background-color: #f2f1f1;
}
> .icon {
position: absolute;
width: 5rem;
height: 5rem;
border-radius: 50%;
background: rgba(146, 146, 146, 0.96);
right: -1.6rem;
bottom: -1.6rem;
cursor: pointer;
}
}
}
}
.and-profile-footer {
margin: 0 15rem;
> .btns {
margin-top: 3rem;
display: flex;
justify-content: flex-end;
padding-right: 1.6rem;
gap: 1.3rem;
> button {
height: 6rem;
border-radius: 6rem;
padding: 0 4rem;
background-color: #000;
color: #fff;
font-size: 1.6rem;
border: none;
cursor: pointer;
&:active:not(:disabled) {
opacity: 0.8;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
> .cancel {
background-color: #fff;
color: #000;
border: 0.15rem solid #000;
}
}
> .tip {
padding-right: 1.6rem;
margin-top: 0.7rem;
font-family: pingfang_regular;
font-size: 1.4rem;
text-align: right;
color: #999;
}
}
</style>

View File

@@ -1,47 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import sellerHeader from "../../seller-header.vue"
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="myListings-seller">
<seller-header
title="Select Collection"
:breadcrumbs="[
{title:'My Listings', name:'myListingsIndex'},
{title:'Select Collection', name: 'myListingsSelect' }
]"
>
</seller-header>
<div class="content">
1231222aaa
</div>
</div>
</template>
<style scoped lang="less">
.myListings-seller {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
> .content {
margin-top: 2rem;
flex: 1;
overflow: hidden;
}
}
</style>

View File

@@ -1,48 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import sellerHeader from "../../seller-header.vue"
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="myListings-seller">
<seller-header
title="Select Collection"
:breadcrumbs="[
{title:'My Listings', name:'myListingsIndex'},
{title:'Select Collection', name: 'myListingsSelect' },
{title:'Select Sketch', name: 'myListingsSelectItem' }
]"
>
</seller-header>
<div class="content">
1231222aaa
</div>
</div>
</template>
<style scoped lang="less">
.myListings-seller {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
> .content {
margin-top: 2rem;
flex: 1;
overflow: hidden;
}
}
</style>

View File

@@ -1,229 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { VueDraggable } from "vue-draggable-plus"
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
showDrafts: false,
})
const list = ref([
{ id: "1" },
{ id: "2" },
{ id: "3" },
{ id: "4" },
{ id: "5" },
{ id: "6" },
{ id: "7" },
{ id: "8" },
{ id: "9" },
{ id: "9" },
{ id: "9" },
{ id: "9" },
{ id: "9" },
{ id: "9" },
{ id: "10" }
])
const list2 = ref([
{ id: "1" },
{ id: "2" },
{ id: "3" },
{ id: "4" },
{ id: "5" },
{ id: "6" },
{ id: "7" },
{ id: "8" },
{ id: "9" },
{ id: "10" }
])
const config = ref({
"data-container-type": "root",
"data-parent-id": "null",
animation: 250,
handle: ".item", // 可拖动的元素
"ghost-class": "ghost", // 拖动时的类名
"chosen-class": "chosen", // 选中时的类名
"drag-class": "drag", // 拖动时的类名
"swap-threshold": 0.5,
"empty-insert-threshold": 5,
"force-fallback": false,
"fallback-tolerance": 3,
"scroll-sensitivity": 100,
"scroll-speed": 10,
onEnd: (e) => {}
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const { showDrafts } = toRefs(data);
</script>
<template>
<div class="listings">
<div class="listingsBox listingsBox1">
<div class="box">
<div class="title">
<div class="left">
<i class="fi fi-rs-comments"></i>
<span>Active Listings</span>
</div>
<div class="right">
</div>
</div>
<VueDraggable
v-model="list"
class="list"
v-bind="config"
:group="{
name: 'sortable',
pull: false,
put: true
}"
>
<div class="item" v-for="v in list" :key="v.id" :draging="true">
{{ v.id }}
</div>
</VueDraggable>
</div>
<div class="openOrCloseDrafts" :class="{'active': showDrafts}" @click="showDrafts = !showDrafts">
<span class="icon iconfont icon-xiala"></span>
</div>
</div>
<!-- <div class="listingsBox listingsBox2" :class="{'active': showDrafts}">
<div class="box">
<VueDraggable
v-model="list2"
class="list"
v-bind="config"
:group="{
name: 'sortable',
pull: true,
put: true
}"
>
<div class="item" v-for="v in list" :key="v.id" :draging="true">
{{ v.id }}
</div>
</VueDraggable>
</div>
</div> -->
</div>
</template>
<style lang="less" scoped>
.listings{
position: absolute;
width: 100%;
height: 100%;
display: flex;
gap: 2rem;
.listingsBox{
background-color: #f9fafa;
border-radius: 2rem;
flex: 1;
position: relative;
// overflow: hidden;
display: flex;
.box{
width: 100%;
padding: 2.4rem 4rem;
padding-bottom: 0;
flex-direction: column;
flex: 1;
> .title{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
> .left{
display: flex;
justify-content: space-between;
align-items: center;
font-family: pingfang_heavy;
font-weight: 400;
font-size: 1.8rem;
line-height: 130%;
letter-spacing: 0%;
gap: 1.2rem;
> i{
display: flex;
justify-content: space-between;
align-items: center;
font-size: 2.4rem;
}
}
}
.list{
display: flex;
flex-wrap: wrap;
gap: 20px;
.item{
width: 197px;
height: 249px;
border-radius: 20px;
border: 1.5px solid #C7C7C7;
&:hover{
border: 2px solid #000000;
}
}
}
}
}
.listingsBox1{
flex: 1;
.box{
.list{
justify-content: center;
}
}
}
.listingsBox2{
width: 48.8rem;
transition: all .3s;
overflow: hidden;
&.active{
width: 0;
}
.box{
width: 48.8rem;
}
}
.openOrCloseDrafts{
position: absolute;
width: 3.4rem;
height: 8rem;
border-top-right-radius: 2rem;
border-bottom-right-radius: 2rem;
border-width: 1.5px, 1.5px, 1.5px, 0px;
border-style: solid;
border-color: #000000;
right: 1.5px;
top: 50%;
transform: translate(100%,-50%);
cursor: pointer;
transition: all 0.3s ease-in-out;
border-left: none;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
z-index: 2;
> span{
transform: rotate(-90deg);
transition: all .3s;
}
&.active{
> span{
transform: rotate(90deg);
}
}
&:hover{
width: 4.5rem;
}
}
}
</style>

View File

@@ -1,79 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import sellerHeader from "../../seller-header.vue"
import sellerContent from "./content.vue"
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="myListings-seller">
<seller-header
title="My Listings"
tip="Active listings and unpublished inventory."
>
<template #right>
<div class="button">
<span>New Listing</span>
<div class="icon">
<i class="fi fi-br-plus"></i>
</div>
</div>
</template>
</seller-header>
<div class="content">
<sellerContent></sellerContent>
</div>
</div>
</template>
<style scoped lang="less">
.myListings-seller {
flex: 1;
// overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
.button {
width: 16rem;
height: 6rem;
border-radius: 4rem;
display: flex;
border: 1.5px solid #000000;
background-color: #000;
color: #fff;
transition: all .3s;
gap: .8rem;
align-items: center;
justify-content: center;
font-size: 1.6rem;
cursor: pointer;
i{
color: #fff;
display: flex;
font-size: 1.6rem;
}
&:hover{
background-color: #fff;
color: #000;
i{
color: #000;
}
}
}
> .content {
margin-top: 2rem;
flex: 1;
position: relative;
}
}
</style>

View File

@@ -1,102 +0,0 @@
<template>
<div class="seller-dashboard-index">
<div class="nav">
<div
v-for="v in list"
:key="v.path"
:class="{ active: v.path === activePath }"
@click="handleClick(v.path)"
>
<div class="icon"><svg-icon :name="v.icon" size="20" /></div>
<span class="layer">{{ v.layer }}</span>
</div>
</div>
<router-view></router-view>
<toolTipBox v-model:visible="visible" @close="() => {}"></toolTipBox>
</div>
</template>
<script setup>
import { ref, computed } from "vue"
import { useRoute, useRouter } from "vue-router"
import toolTipBox from "./toolTipBox.vue"
const route = useRoute()
const router = useRouter()
const visible = ref(false)
const list = ref([
{
icon: "seller-brandProfile",
layer: "Brand Profile",
path: "/home/seller/brandProfile"
},
{
icon: "seller-myListings",
layer: "My Listings",
path: "/home/seller/myListings"
},
{
icon: "seller-myOrders",
layer: "My Orders",
path: "/home/seller/myOrders"
},
{
icon: "seller-settings",
layer: "Settings",
path: "/home/seller/settings"
}
])
const activePath = computed(() => route.path)
const handleClick = (path) => {
if (path === activePath.value) return
router.push(path)
}
</script>
<style scoped lang="less">
.seller-dashboard-index {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
> .nav {
width: 100%;
display: flex;
align-items: center;
gap: 3.6rem;
margin-bottom: 4rem;
> div {
width: 18rem;
height: 6rem;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
> .icon {
margin-right: 1rem;
color: #b0b0b0;
}
> .layer {
font-size: 2rem;
color: #999999;
}
&.active {
> .icon,
> .layer {
color: #000;
}
&::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 0.4rem;
background-color: #000;
}
}
}
}
}
</style>

View File

@@ -1,96 +0,0 @@
<template>
<div class="seller-header">
<div class="back" @click="() => router.back()">
<svg-icon name="seller-back" size="24" />
</div>
<div class="content">
<span class="title" v-show="title">{{ title }}</span>
<span class="tip" v-show="tip">{{ tip }}</span>
<div class="breadcrumbs" v-show="breadcrumbs.length > 0">
<template v-for="(v, i) in breadcrumbs" :key="i">
<span
class="title"
:class="{
last: i === breadcrumbs.length - 1
}"
@click="() => router.push({ name: v.name })"
>{{ v.title }}</span
>
<span class="icon" v-show="i < breadcrumbs.length - 1">
<svg-icon name="seller-arrow_right_solid" size="10" />
</span>
</template>
</div>
</div>
<div class="right">
<slot name="right"></slot>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue"
import { useRoute, useRouter } from "vue-router"
const props = defineProps({
title: {
type: String,
default: ""
},
tip: {
type: String,
default: ""
},
breadcrumbs: {
type: Array, // { title: string, name: string }
default: () => []
}
})
const route = useRoute()
const router = useRouter()
</script>
<style scoped lang="less">
.seller-header {
width: 100%;
min-height: 6rem;
display: flex;
align-items: center;
gap: 2.4rem;
> .back {
width: 5rem;
height: 5rem;
border-radius: 1.2rem;
border: 1px solid #d7d7d7;
cursor: pointer;
}
> .content {
flex: 1;
display: flex;
flex-direction: column;
> .title {
line-height: 130%;
font-size: 2.4rem;
color: #000;
}
> .tip {
font-family: "pingfang_medium";
font-size: 1.4rem;
line-height: 150%;
color: #888;
}
> .breadcrumbs {
display: flex;
align-items: center;
gap: 1rem;
> .title {
font-family: "pingfang_regular";
color: #999;
font-size: 1.4rem;
cursor: pointer;
&:not(.last) {
text-decoration: underline;
}
}
}
}
}
</style>

View File

@@ -1,266 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import sellerToolTipImg1 from '@/assets/images/seller/sellerToolTip-1.png'
import sellerToolTipImg2 from '@/assets/images/seller/sellerToolTip-2.png'
import sellerToolTipImg3 from '@/assets/images/seller/sellerToolTip-3.png'
import { useI18n } from 'vue-i18n'
const props = defineProps({
visible: {
type: Boolean,
default: false,
}
})
const emit = defineEmits([
'update:visible','close'
])
const {t} = useI18n()
let data = reactive({
visible: props.visible,
stepList: [
{
img: sellerToolTipImg1,
title: t('SellerToolTip.step1Title'),
info: t('SellerToolTip.step1Info'),
},{
img: sellerToolTipImg2,
title: t('SellerToolTip.step2Title'),
info: t('SellerToolTip.step2Info'),
},{
img: sellerToolTipImg3,
title: t('SellerToolTip.step3Title'),
info: t('SellerToolTip.step3Info'),
},{
title: t('SellerToolTip.step4Title'),
info: t('SellerToolTip.step4Info'),
}
],
showAgain: false,
})
let toolTipBoxRef = ref(null)
const cleardata = ()=>{
emit('update:visible', false)
emit('close', data.showAgain)
}
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const { showAgain } = toRefs(data);
</script>
<template>
<div ref="toolTipBoxRef" class="toolTipBox" v-if="visible">
<a-modal
class="collection generalModel"
v-model:visible="data.visible"
:footer="null"
:get-container="() => toolTipBoxRef"
width="126.2rem"
:maskClosable="false"
:centered="true"
:closable="false"
:mask="true"
:keyboard="false"
:destroyOnClose="false"
:zIndex="1000"
>
<div class="generalModel_btn">
<div class="generalModel_closeIcon" @click.stop="cleardata()">
<SvgIcon name="seller-sellerToolTipClose" size="30"></SvgIcon>
</div>
</div>
<div class="titleBox">
<div class="title">
{{t('SellerToolTip.title')}}
</div>
<div class="info">
{{t('SellerToolTip.titleInfo')}}
</div>
</div>
<div class="stepBox">
<div class="step" v-for="(item, index) in data.stepList" :key="index" :class="{'active': index === 2}">
<div class="stepNum">
<div class="num">
{{index}}
</div>
</div>
<div class="title">
{{item.title}}
</div>
<div class="info">
{{item.info}}
</div>
<div class="imgBox" v-if="item.img">
<img :src="item.img" alt="">
</div>
</div>
</div>
<div class="bottom">
<div class="showAgain">
<label>
<input type="checkbox" v-model="showAgain">
{{t('SellerToolTip.showAgain')}}
</label>
</div>
<div class="gallery_btn" @click="cleardata()">
{{t('SellerToolTip.GetStarted')}}
<i class="fi fi-rr-arrow-small-right"></i>
</div>
</div>
</a-modal>
</div>
</template>
<style lang="less" scoped>
.toolTipBox{
width: 100%;
height: 100%;
position: relative;
:deep(.generalModel){
height: auto;
.ant-modal-body{
padding: 6.2rem 8rem;
.generalModel_btn{
.generalModel_closeIcon{
transform: translate(0%, 0%);
top: 4rem;
right: 4rem;
}
}
}
}
.titleBox{
margin-bottom: 5.2rem;
.title{
font-size: 3.2rem;
font-weight: 400;
color:#000000;
line-height: 130%;
font-family: pingfang_heavy;
margin-bottom: 1.2rem;
}
.info{
font-weight: 400;
font-size: 2.4rem;
line-height: 130%;
color: #979797;
}
}
.stepBox{
margin: 0 1.3rem;
display: flex;
gap: 7rem;
margin-bottom: 9.7rem;
.step{
--itemWidth: 21.2rem;
--textColor: #585858;
--indexBgColor: #f6f6f6;
--indexTextColor: #000000;
--indexBorderColor: #C7C7C7;
&:hover{
--textColor: #000;
--indexBgColor: #000;
--indexTextColor: #fff;
--indexBorderColor: #000;
}
width: var(--itemWidth);
> div{
transition: all .3s;
}
&.active{
--itemWidth: 23.2rem;
}
.stepNum{
width: 6.4rem;
height: 6.4rem;
margin-bottom: 2.6rem;
position: relative;
font-weight: 500;
font-size: 2.8rem;
> .num{
position: relative;
z-index: 2;
color: var(--indexTextColor);
background-color: var(--indexBgColor);
width: 100%;
height: 100%;
border-radius: 50%;
border: 2px solid var(--indexBorderColor);
display: flex;
justify-content: center;
align-items: center;
transition: all .3s;
}
&::after{
content: '';
display: block;
width: calc(var(--itemWidth) + 8px);
height: 1.5px;
background-color: #C7C7C7;
position: absolute;
top: 50%;
left: 100%;
transform: translate(0%,-50%);
}
}
&:last-child .stepNum::after{
display: none;
}
.title{
font-weight: 500;
font-size: 2.4rem;
line-height: 130%;
color: var(--textColor);
font-family: pingfang_heavy;
margin-bottom: 2.6rem;
}
.info{
font-weight: 400;
font-size: 1.8rem;
line-height: 120%;
letter-spacing: -1%;
color: var(--textColor);
margin-bottom: 2.6rem;
}
.imgBox{
width: 21.2rem;
img{
width: 100%;
object-fit: contain;
}
}
}
}
.bottom{
display: flex;
margin: 0 1.3rem;
align-items: center;
justify-content: space-between;
.showAgain{
> label{
cursor: pointer;
font-family: pingfang_regular;
font-weight: 400;
font-size: 1.4rem;
line-height: 150%;
letter-spacing: -1%;
display: flex;
gap: 1.1rem;
}
}
> .gallery_btn{
padding: 0 3rem;
display: flex;
> i{
margin-left: 1.2rem;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>