Compare commits
161 Commits
de78bfc051
...
StableVers
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ed5a37e5b | ||
|
|
5546c71ec0 | ||
|
|
8a7776a4b6 | ||
|
|
a1281c8e3f | ||
|
|
9a40e69081 | ||
|
|
e27b43dc67 | ||
|
|
b6a55a8124 | ||
| 6cace08a51 | |||
| 6207095221 | |||
|
|
7bb38bf2e5 | ||
|
|
743fc762d6 | ||
| 7297e4e7a4 | |||
| 3bff1ebb66 | |||
| 0d1656ee0a | |||
| 7d0873d874 | |||
| 82941bca7c | |||
| 949ff9292d | |||
|
|
11c9de8ced | ||
|
|
fd518ad9b3 | ||
|
|
a2b45e2041 | ||
|
|
da64b57c1c | ||
|
|
7c14b1d831 | ||
|
|
8966b52430 | ||
|
|
5fa049f73d | ||
|
|
575445f767 | ||
|
|
f43c56236b | ||
|
|
4352f7c2f4 | ||
|
|
c6b1bdbdf1 | ||
|
|
f16aa6ea14 | ||
|
|
a25abeb527 | ||
|
|
d359cd7763 | ||
| 23085d9a9b | |||
| bb021ae9ac | |||
| bfb4e128f5 | |||
| 2f9b33e4ca | |||
|
|
35c6dfe29c | ||
|
|
48c37e0810 | ||
| b869a82fae | |||
| e61a8e372d | |||
|
|
f5a74991c9 | ||
|
|
e58e8540c9 | ||
| e75ed7684e | |||
| 918d71072b | |||
|
|
242bc7a01d | ||
|
|
02ad8a340a | ||
|
|
0c250a21b4 | ||
|
|
f781060e7b | ||
|
|
832c9101ab | ||
|
|
c48e836f8e | ||
|
|
6f0780ac2e | ||
|
|
5acb91e584 | ||
|
|
f66ba9e6fa | ||
| 7a90cb8db9 | |||
| dafe87fad8 | |||
| c44747e2c2 | |||
|
|
341c765c73 | ||
|
|
ed6cc294a5 | ||
|
|
a77dc718f9 | ||
|
|
86953a91a1 | ||
| cabbb653bd | |||
| 99533c12b6 | |||
|
|
59da67e4b4 | ||
|
|
1428f191dd | ||
|
|
13024cdd99 | ||
|
|
fd85ea02c1 | ||
|
|
c196ab6678 | ||
|
|
c005b85c06 | ||
|
|
b50dbbc246 | ||
|
|
01d09f4c34 | ||
|
|
79c9a66296 | ||
|
|
761b1b3512 | ||
|
|
b2cb7378d6 | ||
| 4d9ea75146 | |||
| f7e6926ee9 | |||
| 7aba4e30c9 | |||
| dc1ab330cf | |||
|
|
18c70fe6a3 | ||
|
|
5c746aca4d | ||
|
|
72c4898101 | ||
|
|
a905971dae | ||
| 69643dbc83 | |||
| f3a707d6d8 | |||
| 8f4a43db14 | |||
| 186a158114 | |||
| 3da4a97400 | |||
|
|
96b3636aea | ||
| 228e3d56b5 | |||
| 99ea7eedc7 | |||
| d4fb435db9 | |||
| 0c8b3ee8f1 | |||
| ca782d0aff | |||
|
|
3dfb607b91 | ||
|
|
981b4dad5c | ||
|
|
181e6a87b8 | ||
| 287825b4bf | |||
| 1ffc303721 | |||
|
|
bdf1bb2669 | ||
|
|
1fe79ffcf9 | ||
| 758f63615a | |||
| 20145742c5 | |||
| 8ec9b1bcea | |||
| a9cb6e16e9 | |||
|
|
5690fc6c5b | ||
|
|
9db6a589f0 | ||
|
|
896490e57b | ||
| fca04ba44b | |||
| 25e4fc06c6 | |||
|
|
4bd7740753 | ||
|
|
c428bfd93b | ||
|
|
2a29c6b2cc | ||
|
|
e9d7203804 | ||
|
|
5d7cec520b | ||
|
|
fe72df0c07 | ||
|
|
7c04332290 | ||
|
|
73d912d3cd | ||
|
|
b320294764 | ||
|
|
4913d02c93 | ||
|
|
56916c8d10 | ||
|
|
393a06eceb | ||
|
|
fdb6a87ab4 | ||
| 6d868c7c7a | |||
| 89a89ea5ef | |||
|
|
811e179889 | ||
|
|
0e0eed2566 | ||
|
|
8588c74ffd | ||
|
|
62e7f34c98 | ||
|
|
8f0a56965f | ||
|
|
59422e54d8 | ||
|
|
012f0ef1b5 | ||
|
|
ec4ae4a259 | ||
|
|
8da66d54c0 | ||
|
|
2839953d8e | ||
|
|
2d5d1b7a5e | ||
|
|
33aaf0b600 | ||
|
|
bf4d7bdba8 | ||
|
|
944071201d | ||
|
|
f6556ec9a9 | ||
|
|
8967439d4e | ||
|
|
85ae158952 | ||
|
|
813d2e9645 | ||
|
|
d94ade6641 | ||
|
|
eda893ce10 | ||
|
|
c8cb2de9ab | ||
|
|
7cda2cce27 | ||
| 41893cab86 | |||
| b23531f18b | |||
|
|
a18dead4ff | ||
|
|
76047b763d | ||
|
|
9f09a2f31b | ||
|
|
1e0bf83d12 | ||
|
|
b7f7aea0b7 | ||
|
|
4dfa9433fd | ||
|
|
03a9e2f52c | ||
|
|
fb1d09d98e | ||
|
|
65323febee | ||
|
|
b158341d6e | ||
|
|
06fa763f26 | ||
|
|
9b0ec12738 | ||
|
|
07b7a6f1d7 | ||
| bff3ea8459 | |||
|
|
920d01a972 |
@@ -5,4 +5,3 @@ VITE_USER_NODE_ENV = 'development'
|
|||||||
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
||||||
|
|
||||||
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
||||||
|
|
||||||
|
|||||||
33
.prettierrc.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/** @type {import('prettier').Config} */
|
||||||
|
module.exports = {
|
||||||
|
// 打印宽度
|
||||||
|
printWidth: 100,
|
||||||
|
// 使用 4 空格缩进
|
||||||
|
tabWidth: 4,
|
||||||
|
// 使用 4 空格缩进,不使用制表符
|
||||||
|
useTabs: true,
|
||||||
|
// 行尾使用 LF (Unix 风格)
|
||||||
|
endOfLine: 'lf',
|
||||||
|
// 语句末尾使用分号
|
||||||
|
semi: false,
|
||||||
|
// 使用单引号
|
||||||
|
singleQuote: false,
|
||||||
|
// 对象和数组末尾不添加尾随逗号
|
||||||
|
trailingComma: 'none',
|
||||||
|
// JSX 引号使用单引号
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
// 括号内侧空格
|
||||||
|
bracketSpacing: true,
|
||||||
|
// JSX 标签不换行
|
||||||
|
bracketSameLine: false,
|
||||||
|
// 箭头函数参数始终使用括号
|
||||||
|
arrowParens: 'always',
|
||||||
|
// HTML、Vue、Angular 和 Markdown 使用 LF
|
||||||
|
htmlWhitespaceSensitivity: 'css',
|
||||||
|
// Vue 文件脚本和样式缩进
|
||||||
|
vueIndentScriptAndStyle: false,
|
||||||
|
// 行注释位置在注释上方,不加空格
|
||||||
|
proseWrap: 'preserve',
|
||||||
|
// 根据文件类型自动推断
|
||||||
|
embeddedLanguageFormatting: 'auto',
|
||||||
|
};
|
||||||
BIN
public/css/fonts/InstrumentSans-Bold.ttf
Normal file
BIN
public/css/fonts/InstrumentSans-Regular.ttf
Normal file
@@ -1,31 +1,41 @@
|
|||||||
/* 字体定义 */
|
/* 字体定义 */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
src: url('./fonts/ARIAL.ttf') format('ttf');
|
src: url('./fonts/ARIAL.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'ArialBold';
|
font-family: 'ArialBold';
|
||||||
src: url('./fonts/ARIALBD.ttf') format('ttf');
|
src: url('./fonts/ARIALBD.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'ArialMedium';
|
font-family: 'ArialMedium';
|
||||||
src: url('./fonts/ArialMdm.ttf') format('ttf');
|
src: url('./fonts/ArialMdm.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Poppins';
|
font-family: 'Poppins';
|
||||||
src: url('./fonts/Poppins-Regular.ttf') format('ttf');
|
src: url('./fonts/Poppins-Regular.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'PoppinsMedium';
|
font-family: 'PoppinsMedium';
|
||||||
src: url('./fonts/Poppins-Medium.ttf') format('ttf');
|
src: url('./fonts/Poppins-Medium.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'PoppinsBold';
|
font-family: 'PoppinsBold';
|
||||||
src: url('./fonts/Poppins-SemiBold.ttf') format('ttf');
|
src: url('./fonts/Poppins-SemiBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Instrument';
|
||||||
|
src: url('./InstrumentSans-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'InstrumentBold';
|
||||||
|
src: url('./InstrumentSans-Bold.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/image/events/award-poster-zh.gif
Normal file
|
After Width: | Height: | Size: 15 MiB |
BIN
public/image/events/award-poster.gif
Normal file
|
After Width: | Height: | Size: 15 MiB |
1
src/assets/icons/CFile.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="#00000073" aria-hidden="true" viewBox="64 64 896 896"><path d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 985 B |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 327 B |
BIN
src/assets/images/award/banner.mp4
Normal file
|
Before Width: | Height: | Size: 5.0 MiB |
BIN
src/assets/images/award/banner_chinese.mp4
Normal file
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 492 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 7.5 KiB |
BIN
src/assets/images/award/upload_video_icon.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
@@ -4,13 +4,41 @@
|
|||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
||||||
"imgUrl": "/image/events/workshop-En.jpg"
|
"imgUrl": "/image/events/workshop-En.jpg"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "AiDA X SFT AI Fashion Award 2024",
|
"title": "AiDA X SFT AI Fashion Award 2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA Global Design Awards 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem": [
|
"eventsItem": [
|
||||||
|
{
|
||||||
|
"id": 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 Code‑Create, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers worldwide the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "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."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
"title": "Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face!",
|
||||||
@@ -22,45 +50,53 @@
|
|||||||
"text": "🎨AiDA Workshop!"
|
"text": "🎨AiDA Workshop!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
|
"text": "The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "<b>⚠️ATTENTION❗❗</b>"
|
"text": "<b>⚠️ATTENTION❗❗</b>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "1. Add the tag in the work description #AiDAworkshop_2024"
|
"text": "1. Add the tag in the work description #AiDAworkshop_2024"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"text": "2. One winner only"
|
"text": "2. One winner only"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
|
"text": "<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "✅Round-trip transportation fee (only within China)"
|
"text": "✅Round-trip transportation fee (only within China)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "✅One night accommodation fee"
|
"text": "✅One night accommodation fee"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "⌛️Deadline: October 31, 2024"
|
"text": "⌛️Deadline: October 31, 2024"
|
||||||
@@ -80,7 +116,8 @@
|
|||||||
"text": "With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion."
|
"text": "With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "The competition is open to all SFT students, with the winners having the chance to win cash prizes (up to 20,000 HKD), internship opportunity at BESFXXK (will work with the renowned designer, Mr Jae Hyuk Lim, for the BESFXXK collection, that will be featured at NY Fashion Week and Paris Fashion Week) and more surprises! Scan the QR code to learn more."
|
"text": "The competition is open to all SFT students, with the winners having the chance to win cash prizes (up to 20,000 HKD), internship opportunity at BESFXXK (will work with the renowned designer, Mr Jae Hyuk Lim, for the BESFXXK collection, that will be featured at NY Fashion Week and Paris Fashion Week) and more surprises! Scan the QR code to learn more."
|
||||||
|
|||||||
@@ -4,13 +4,41 @@
|
|||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
||||||
"imgUrl": "/image/events/workshop-Cn.jpg"
|
"imgUrl": "/image/events/workshop-Cn.jpg"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "AiDA X SFT AI时尚设计比赛2024",
|
"title": "AiDA X SFT AI时尚设计比赛2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA全球设计奖 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster-zh.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem": [
|
"eventsItem": [
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA全球设计奖 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster-zh.gif",
|
||||||
|
"tips": "如有疑问,请联系:awards2026@code-create.com.hk",
|
||||||
|
"textList": [
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "秉承推动 AI 赋能创意设计的初衷,Code‑Create 举办了「AiDA 全球设计大奖 2026」,面向来全球的设计师,鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paragraph": [
|
||||||
|
{
|
||||||
|
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅津贴,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
|
||||||
@@ -22,45 +50,53 @@
|
|||||||
"text": "🎨这是一趟艺术巅峰之旅!AiDA Workshop!"
|
"text": "🎨这是一趟艺术巅峰之旅!AiDA Workshop!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "参与过程很简单,利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞)将被邀请至11月14日 举办的AiDA Workshop香港线下活动,与英国皇家艺术学院(RCA)、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流!(名额仅限1名)"
|
"text": "参与过程很简单,利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞)将被邀请至11月14日 举办的AiDA Workshop香港线下活动,与英国皇家艺术学院(RCA)、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流!(名额仅限1名)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "<b>⚠️注意❗❗</b>"
|
"text": "<b>⚠️注意❗❗</b>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "1. 作品描述添加tag: #AiDAworkshop_2024"
|
"text": "1. 作品描述添加tag: #AiDAworkshop_2024"
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"text": "2. 一个冠军名额"
|
"text": "2. 一个冠军名额"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "<b>🤩Code-Create将提供(适用条款条规):</b>"
|
"text": "<b>🤩Code-Create将提供(适用条款条规):</b>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "✅往返机票/动车费用(仅限中国地区)"
|
"text": "✅往返机票/动车费用(仅限中国地区)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "✅一晚酒店住宿费用"
|
"text": "✅一晚酒店住宿费用"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "⌛️截止时间:2024.10.31"
|
"text": "⌛️截止时间:2024.10.31"
|
||||||
@@ -80,7 +116,8 @@
|
|||||||
"text": "秉承着激发学生使用AI进行时尚设计的创新能力的初衷,Code-Create和香港理工大学时装及纺织学院(SFT)共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验,为未来的时尚设计行业打下了坚实的基础,成为时尚界的AI先锋。"
|
"text": "秉承着激发学生使用AI进行时尚设计的创新能力的初衷,Code-Create和香港理工大学时装及纺织学院(SFT)共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验,为未来的时尚设计行业打下了坚实的基础,成为时尚界的AI先锋。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": " 此次比赛面向全体SFT 学生,最终获奖者将赢取丰厚奖金(最高可达2万港币),获得在BESFXXK的实习机会(将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
|
"text": " 此次比赛面向全体SFT 学生,最终获奖者将赢取丰厚奖金(最高可达2万港币),获得在BESFXXK的实习机会(将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
|
||||||
|
|||||||
@@ -2507,3 +2507,6 @@ textarea:focus {
|
|||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.flex-1{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -2425,3 +2425,6 @@ textarea:focus{
|
|||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.flex-1{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -2,21 +2,36 @@
|
|||||||
<div class="account_systemMessage">
|
<div class="account_systemMessage">
|
||||||
<div class="account_generalMessage_title modal_title_text">
|
<div class="account_generalMessage_title modal_title_text">
|
||||||
<!-- <span>系统消息</span> -->
|
<!-- <span>系统消息</span> -->
|
||||||
<div class="account_generalMessage_title_setting" @click="allRead">{{$t('account.AllRead')}}</div>
|
<div class="account_generalMessage_title_setting" @click="allRead">
|
||||||
|
{{ $t("account.AllRead") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" v-for="item in dataList" :key="item.id" @click="setRead(item)">
|
</div>
|
||||||
|
<div
|
||||||
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
v-for="item in dataList"
|
||||||
|
:key="item.id"
|
||||||
|
@click="setRead(item)"
|
||||||
|
>
|
||||||
<a-badge :dot="item.isRead == 0"></a-badge>
|
<a-badge :dot="item.isRead == 0"></a-badge>
|
||||||
<div class="account_generalMessage_item_title">
|
<div class="account_generalMessage_item_title">
|
||||||
<div class="account_generalMessage_item_title_text" :title="item.content">{{ item.content.title }}</div>
|
<div class="account_generalMessage_item_title_text" :title="item.content">
|
||||||
|
{{ item.content.title }}
|
||||||
|
</div>
|
||||||
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal_title_text_intro">
|
<div class="modal_title_text_intro">
|
||||||
{{ item.content.content }}
|
{{ item.content.content }}
|
||||||
<span v-if="item.content.link" class="account_generalMessage_item_link">{{ item.content.link }}</span>
|
<span v-if="item.content.link" class="account_generalMessage_item_link">{{
|
||||||
|
item.content.link
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" style="display:flex;justify-content: center;" v-if="dataList.length == 0 && isNoData">
|
<div
|
||||||
{{$t('account.dataNull')}}
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
style="display: flex; justify-content: center"
|
||||||
|
v-if="dataList.length == 0 && isNoData"
|
||||||
|
>
|
||||||
|
{{ $t("account.dataNull") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="page_loading_box" v-show="!isNoData">
|
<div class="page_loading_box" v-show="!isNoData">
|
||||||
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
||||||
@@ -27,34 +42,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent,computed,ref,reactive,nextTick,toRefs,createVNode, onMounted} from 'vue'
|
import {
|
||||||
import { Https } from "@/tool/https";
|
defineComponent,
|
||||||
import { useRouter,useRoute } from 'vue-router'
|
computed,
|
||||||
import { useStore } from "vuex";
|
ref,
|
||||||
import { useI18n } from 'vue-i18n'
|
reactive,
|
||||||
|
nextTick,
|
||||||
|
toRefs,
|
||||||
|
createVNode,
|
||||||
|
onMounted
|
||||||
|
} from "vue"
|
||||||
|
import { Https } from "@/tool/https"
|
||||||
|
import { useRouter, useRoute } from "vue-router"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
import { isValidUrl } from "@/tool/util"
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components: {},
|
||||||
},
|
|
||||||
// emits:['putListData'],
|
// emits:['putListData'],
|
||||||
props:['setReadStatus','setAllmessage','getHistory'],
|
props: ["setReadStatus", "setAllmessage", "getHistory"],
|
||||||
setup(prop, { emit }) {
|
setup(prop, { emit }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
let accountMessage = reactive({
|
let accountMessage = reactive({
|
||||||
dataList: [],
|
dataList: [],
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
isNoData: false,
|
isNoData: false,
|
||||||
isShowMark: false,
|
isShowMark: false
|
||||||
})
|
})
|
||||||
let loadingDom: any = ref(null)
|
let loadingDom: any = ref(null)
|
||||||
let setmessageList = () => {
|
let setmessageList = () => {
|
||||||
accountMessage.isShowMark = true
|
accountMessage.isShowMark = true
|
||||||
let data = {
|
let data = {
|
||||||
page: accountMessage.page,
|
page: accountMessage.page,
|
||||||
size: accountMessage.size,
|
size: accountMessage.size
|
||||||
}
|
}
|
||||||
prop.getHistory(data).then((rv:any)=>{
|
prop.getHistory(data)
|
||||||
|
.then((rv: any) => {
|
||||||
accountMessage.isShowMark = false
|
accountMessage.isShowMark = false
|
||||||
|
|
||||||
if (rv.content.length == 0) {
|
if (rv.content.length == 0) {
|
||||||
@@ -62,58 +87,67 @@ export default defineComponent({
|
|||||||
} else {
|
} else {
|
||||||
rv.content.forEach((item: any) => {
|
rv.content.forEach((item: any) => {
|
||||||
item.content = JSON.parse(item.content)
|
item.content = JSON.parse(item.content)
|
||||||
});
|
})
|
||||||
accountMessage.dataList.push(...rv.content)
|
accountMessage.dataList.push(...rv.content)
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
})
|
||||||
|
.catch(() => {
|
||||||
accountMessage.isShowMark = false
|
accountMessage.isShowMark = false
|
||||||
accountMessage.isNoData = true
|
accountMessage.isNoData = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let setRead = (item: any) => {
|
let setRead = (item: any) => {
|
||||||
prop.setReadStatus(item).then((rv:any)=>{
|
let content = item.content.content
|
||||||
|
if (isValidUrl(content)) {
|
||||||
|
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
|
||||||
|
content += "&env=dev"
|
||||||
|
}
|
||||||
|
window.open(content, "_blank")
|
||||||
|
}
|
||||||
|
|
||||||
|
prop.setReadStatus(item)
|
||||||
|
.then((rv: any) => {
|
||||||
item.isRead = 1
|
item.isRead = 1
|
||||||
}).catch((err:any)=>{
|
|
||||||
})
|
})
|
||||||
|
.catch((err: any) => {})
|
||||||
}
|
}
|
||||||
let allRead = () => {
|
let allRead = () => {
|
||||||
// emit('setAllmessage')
|
// emit('setAllmessage')
|
||||||
prop.setAllmessage().then(()=>{
|
prop.setAllmessage()
|
||||||
|
.then(() => {
|
||||||
accountMessage.dataList.forEach((item: any) => {
|
accountMessage.dataList.forEach((item: any) => {
|
||||||
item.isRead = 1
|
item.isRead = 1
|
||||||
})
|
})
|
||||||
}).catch((err:any)=>{
|
|
||||||
})
|
})
|
||||||
|
.catch((err: any) => {})
|
||||||
}
|
}
|
||||||
// provide('exhibitionList',exhibitionList)
|
// provide('exhibitionList',exhibitionList)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
accountMessage.isNoData = false
|
accountMessage.isNoData = false
|
||||||
accountMessage.page = 0
|
accountMessage.page = 0
|
||||||
let imgParent:any = document.querySelector('.account_systemMessage .page_loading')
|
let imgParent: any = document.querySelector(".account_systemMessage .page_loading")
|
||||||
new IntersectionObserver(
|
new IntersectionObserver(
|
||||||
(entries, observer) => {
|
(entries, observer) => {
|
||||||
// 如果不是相交,则直接返回
|
// 如果不是相交,则直接返回
|
||||||
// console.log(entries[0]);
|
// console.log(entries[0]);
|
||||||
if (!entries[0].intersectionRatio) return;
|
if (!entries[0].intersectionRatio) return
|
||||||
accountMessage.page += 1
|
accountMessage.page += 1
|
||||||
setmessageList()
|
setmessageList()
|
||||||
},
|
}
|
||||||
// { root:worksPage }
|
// { root:worksPage }
|
||||||
).observe(loadingDom.value);
|
).observe(loadingDom.value)
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
...toRefs(accountMessage),
|
...toRefs(accountMessage),
|
||||||
setmessageList,
|
setmessageList,
|
||||||
setRead,
|
setRead,
|
||||||
allRead,
|
allRead,
|
||||||
loadingDom,
|
loadingDom
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return{
|
return {}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -133,7 +167,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
.modal_title_text_intro {
|
.modal_title_text_intro {
|
||||||
margin-left: 4rem;
|
margin-left: 4rem;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,7 @@
|
|||||||
total: total,
|
total: total,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
bordered: false,
|
bordered: false,
|
||||||
|
showTotal: (total) => `Total Transaction: ${total}`
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, text, record, index }">
|
<template #bodyCell="{ column, text, record, index }">
|
||||||
@@ -465,13 +466,16 @@ export default defineComponent({
|
|||||||
(rv: any) => {
|
(rv: any) => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
// this.dataList = rv
|
// this.dataList = rv
|
||||||
|
// console.log('rv----',rv);
|
||||||
|
|
||||||
filter.dataList = rv.content;
|
filter.dataList = rv.content;
|
||||||
filterData.total = rv.total;
|
filterData.total = rv.total;
|
||||||
filter.tableLoading = false;
|
filter.tableLoading = false;
|
||||||
filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
|
filterData.totalPayer = rv.totalAmount;
|
||||||
const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
|
// filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
|
||||||
return total + (isNaN(value) ? 0 : value);
|
// const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
|
||||||
}, 0);
|
// return total + (isNaN(value) ? 0 : value);
|
||||||
|
// }, 0);
|
||||||
|
|
||||||
// this.workspaceItem.position = this.singleTypeList[0].label
|
// this.workspaceItem.position = this.singleTypeList[0].label
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,11 @@
|
|||||||
style="width: 250px"
|
style="width: 250px"
|
||||||
class="range_picker"
|
class="range_picker"
|
||||||
v-model:value="rangePickerValue"
|
v-model:value="rangePickerValue"
|
||||||
:placeholder="[
|
:placeholder="[$t('HistoryPage.StartDate'), $t('HistoryPage.EndDate')]"
|
||||||
$t('HistoryPage.StartDate'),
|
|
||||||
$t('HistoryPage.EndDate'),
|
|
||||||
]"
|
|
||||||
valueFormat="YYYY-MM-DD"
|
valueFormat="YYYY-MM-DD"
|
||||||
>
|
>
|
||||||
<template #suffixIcon>
|
<template #suffixIcon>
|
||||||
<span
|
<span class="icon iconfont range_picker_icon icon-rili"></span>
|
||||||
class="icon iconfont range_picker_icon icon-rili"
|
|
||||||
></span>
|
|
||||||
</template>
|
</template>
|
||||||
</a-range-picker>
|
</a-range-picker>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,38 +58,50 @@
|
|||||||
show-search
|
show-search
|
||||||
></a-select>
|
></a-select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Orgnization:</span>
|
||||||
|
<a-select
|
||||||
|
v-model:value="organizationId"
|
||||||
|
placeholder="Select the organization"
|
||||||
|
allow-clear
|
||||||
|
style="width: 250px"
|
||||||
|
@popupScroll="handleOrganizationScroll"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in organizationOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_search">
|
<div class="admin_search">
|
||||||
<div class="admin_search_item" @click="searchHistoryList" :style="{height:isAwayOrUnfold?'4rem':''}">
|
<div
|
||||||
|
class="admin_search_item"
|
||||||
|
@click="searchHistoryList"
|
||||||
|
:style="{ height: isAwayOrUnfold ? '4rem' : '' }"
|
||||||
|
>
|
||||||
Search
|
Search
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_search_item" @click="addhHistoryList">
|
<div class="admin_search_item" @click="addhHistoryList">Add</div>
|
||||||
Add
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_state_list">
|
<div class="admin_state_list">
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('year')">
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('year')"
|
|
||||||
>
|
|
||||||
Nearly a year
|
Nearly a year
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('month')">
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('month')"
|
|
||||||
>
|
|
||||||
Last month
|
Last month
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="admin_state_list_item" @click="lastGeTrialList('week')">Last week</div>
|
||||||
class="admin_state_list_item"
|
|
||||||
@click="lastGeTrialList('week')"
|
|
||||||
>
|
|
||||||
Last week
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="awayOrUnfold" :class="{ active: isAwayOrUnfold }">
|
<div class="awayOrUnfold" :class="{ active: isAwayOrUnfold }">
|
||||||
<span class="icon iconfont menu_icon icon-xiala" @click="()=>isAwayOrUnfold = !isAwayOrUnfold"></span>
|
<span
|
||||||
|
class="icon iconfont menu_icon icon-xiala"
|
||||||
|
@click="() => (isAwayOrUnfold = !isAwayOrUnfold)"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_table_content" ref="historyTable">
|
<div class="admin_table_content" ref="historyTable">
|
||||||
<a-table
|
<a-table
|
||||||
@@ -104,24 +111,19 @@
|
|||||||
:data-source="dataList"
|
:data-source="dataList"
|
||||||
:scroll="{ y: historyTableHeight }"
|
:scroll="{ y: historyTableHeight }"
|
||||||
@change="changePage"
|
@change="changePage"
|
||||||
:showSorterTooltip='false'
|
:showSorterTooltip="false"
|
||||||
:pagination="{
|
:pagination="{
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
current: currentPage,
|
current: currentPage,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
total: total,
|
total: total,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
bordered: false,
|
bordered: false
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, text, record, index }">
|
<template #bodyCell="{ column, text, record, index }">
|
||||||
<div class="operate_list" v-if="column?.Operations">
|
<div class="operate_list" v-if="column?.Operations">
|
||||||
<div
|
<div class="operate_item" @click="setAagree(record)">Edit</div>
|
||||||
class="operate_item"
|
|
||||||
@click="setAagree(record)"
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</div>
|
|
||||||
<!-- <div
|
<!-- <div
|
||||||
class="operate_item"
|
class="operate_item"
|
||||||
@click="deleteGroup(record, index)"
|
@click="deleteGroup(record, index)"
|
||||||
@@ -132,24 +134,19 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</div>
|
</div>
|
||||||
<allUserPoerationsVue ref="allUserPoerationsVue" @searchHistoryList="searchHistoryList"></allUserPoerationsVue>
|
<allUserPoerationsVue
|
||||||
|
ref="allUserPoerationsVue"
|
||||||
|
@searchHistoryList="searchHistoryList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import { defineComponent, ref, createVNode, computed, reactive, toRefs, onMounted } from "vue"
|
||||||
defineComponent,
|
import { formatTime } from "@/tool/util"
|
||||||
ref,
|
import { useStore } from "vuex"
|
||||||
createVNode,
|
import { Https } from "@/tool/https"
|
||||||
computed,
|
import allUserPoerationsVue from "./allUserPoerations.vue"
|
||||||
reactive,
|
import SelectUser from "@/component/common/SelectUser.vue"
|
||||||
toRefs,
|
|
||||||
onMounted,
|
|
||||||
} from "vue";
|
|
||||||
import { formatTime } from "@/tool/util";
|
|
||||||
import { useStore } from "vuex";
|
|
||||||
import { Https } from "@/tool/https";
|
|
||||||
import allUserPoerationsVue from "./allUserPoerations.vue";
|
|
||||||
import SelectUser from '@/component/common/SelectUser.vue'
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { allUserPoerationsVue, SelectUser },
|
components: { allUserPoerationsVue, SelectUser },
|
||||||
setup() {
|
setup() {
|
||||||
@@ -159,7 +156,7 @@ export default defineComponent({
|
|||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
allCountry: [],
|
allCountry: [],
|
||||||
isAwayOrUnfold: false
|
isAwayOrUnfold: false
|
||||||
});
|
})
|
||||||
let filterData: any = reactive({
|
let filterData: any = reactive({
|
||||||
rangePickerValue: [],
|
rangePickerValue: [],
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
@@ -172,40 +169,41 @@ export default defineComponent({
|
|||||||
occupation: "",
|
occupation: "",
|
||||||
systemUser: "",
|
systemUser: "",
|
||||||
order: "", //'Ascending 升序 Descending 降序'
|
order: "", //'Ascending 升序 Descending 降序'
|
||||||
orderBy:'',
|
orderBy: "",
|
||||||
userName: "",
|
userName: "",
|
||||||
});
|
organizationId: null
|
||||||
|
})
|
||||||
let state: any = ref([
|
let state: any = ref([
|
||||||
{
|
{
|
||||||
label: "all",
|
label: "all",
|
||||||
value: "",
|
value: ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'visitor',
|
label: "visitor",
|
||||||
value:'0',
|
value: "0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'yearly',
|
label: "yearly",
|
||||||
value:'1',
|
value: "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'monthly',
|
label: "monthly",
|
||||||
value:'2',
|
value: "2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'trial',
|
label: "trial",
|
||||||
value:'3',
|
value: "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "userInEvent",
|
label: "userInEvent",
|
||||||
value: "4",
|
value: "4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Edu Admin",
|
label: "Edu Admin",
|
||||||
value: "7",
|
value: "7"
|
||||||
},
|
}
|
||||||
]);
|
])
|
||||||
let renameData: any = ref({}); //修改名字选中的数据
|
let renameData: any = ref({}) //修改名字选中的数据
|
||||||
const columns: any = computed(() => {
|
const columns: any = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -215,7 +213,7 @@ export default defineComponent({
|
|||||||
key: "id",
|
key: "id",
|
||||||
width: 100,
|
width: 100,
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Email",
|
title: "Email",
|
||||||
@@ -246,7 +244,7 @@ export default defineComponent({
|
|||||||
dataIndex: "language",
|
dataIndex: "language",
|
||||||
key: "language",
|
key: "language",
|
||||||
width: 100,
|
width: 100,
|
||||||
ellipsis:true,
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Valid Start Time",
|
title: "Valid Start Time",
|
||||||
@@ -256,12 +254,12 @@ export default defineComponent({
|
|||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let time = ''
|
let time = ""
|
||||||
if (record.text) {
|
if (record.text) {
|
||||||
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
|
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
}
|
}
|
||||||
return time
|
return time
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Valid End Time",
|
title: "Valid End Time",
|
||||||
@@ -271,19 +269,19 @@ export default defineComponent({
|
|||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let time = ''
|
let time = ""
|
||||||
if (record.text) {
|
if (record.text) {
|
||||||
time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
|
time = formatTime(record.text / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
}
|
}
|
||||||
return time
|
return time
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Country or Region",
|
title: "Country or Region",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "country",
|
dataIndex: "country",
|
||||||
key: "country",
|
key: "country",
|
||||||
width:200,
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Create Date",
|
title: "Create Date",
|
||||||
@@ -291,7 +289,7 @@ export default defineComponent({
|
|||||||
dataIndex: "createDate",
|
dataIndex: "createDate",
|
||||||
key: "createDate",
|
key: "createDate",
|
||||||
width: 200,
|
width: 200,
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Is Beginner",
|
title: "Is Beginner",
|
||||||
@@ -301,21 +299,21 @@ export default defineComponent({
|
|||||||
width: 80,
|
width: 80,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let str;
|
let str
|
||||||
if (record.value == 1) {
|
if (record.value == 1) {
|
||||||
str = "Yes";
|
str = "Yes"
|
||||||
} else {
|
} else {
|
||||||
str = "No";
|
str = "No"
|
||||||
|
}
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
return str;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Machine Room Ip',
|
title: "Machine Room Ip",
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "browserIdentifiers",
|
dataIndex: "browserIdentifiers",
|
||||||
key: "browserIdentifiers",
|
key: "browserIdentifiers",
|
||||||
width:200,
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Credits",
|
title: "Credits",
|
||||||
@@ -327,10 +325,10 @@ export default defineComponent({
|
|||||||
dataIndex: "credits",
|
dataIndex: "credits",
|
||||||
key: "credits",
|
key: "credits",
|
||||||
width: 100,
|
width: 100,
|
||||||
sorter: true,
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'User Type',
|
title: "User Type",
|
||||||
align: "center",
|
align: "center",
|
||||||
// width: 150,
|
// width: 150,
|
||||||
// minWidth: 100,
|
// minWidth: 100,
|
||||||
@@ -340,22 +338,22 @@ export default defineComponent({
|
|||||||
key: "systemUser",
|
key: "systemUser",
|
||||||
width: 100,
|
width: 100,
|
||||||
customRender: (record: any) => {
|
customRender: (record: any) => {
|
||||||
let str;
|
let str
|
||||||
if (record.value == 0) {
|
if (record.value == 0) {
|
||||||
str = "visitor";
|
str = "visitor"
|
||||||
} else if (record.value == 1) {
|
} else if (record.value == 1) {
|
||||||
str = "yearly";
|
str = "yearly"
|
||||||
} else if (record.value == 2) {
|
} else if (record.value == 2) {
|
||||||
str = "monthly";
|
str = "monthly"
|
||||||
} else if (record.value == 3) {
|
} else if (record.value == 3) {
|
||||||
str = "trial";
|
str = "trial"
|
||||||
} else if (record.value == 4) {
|
} else if (record.value == 4) {
|
||||||
str = "userInEvent";
|
str = "userInEvent"
|
||||||
} else if (record.value == 7) {
|
} else if (record.value == 7) {
|
||||||
str = "Edu Admin";
|
str = "Edu Admin"
|
||||||
|
}
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
return str;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Operations",
|
title: "Operations",
|
||||||
@@ -364,58 +362,58 @@ export default defineComponent({
|
|||||||
align: "center",
|
align: "center",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
// slots:{customRender:'action'}
|
// slots:{customRender:'action'}
|
||||||
Operations: true,
|
Operations: true
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
});
|
})
|
||||||
//改变页码
|
//改变页码
|
||||||
let changePage = (e: any, filters: any, sorter: any) => {
|
let changePage = (e: any, filters: any, sorter: any) => {
|
||||||
filterData.currentPage = e.current;
|
filterData.currentPage = e.current
|
||||||
filterData.pageSize = e.pageSize;
|
filterData.pageSize = e.pageSize
|
||||||
if (sorter.order) {
|
if (sorter.order) {
|
||||||
if(sorter.columnKey == 'id'){
|
if (sorter.columnKey == "id") {
|
||||||
filterData.orderBy = 'id'
|
filterData.orderBy = "id"
|
||||||
} else if (sorter.columnKey == "createDate") {
|
} else if (sorter.columnKey == "createDate") {
|
||||||
filterData.orderBy = 'time'
|
filterData.orderBy = "time"
|
||||||
} else if (sorter.columnKey == "credits") {
|
} else if (sorter.columnKey == "credits") {
|
||||||
filterData.orderBy = 'credits'
|
filterData.orderBy = "credits"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sorter.order) {
|
if (sorter.order) {
|
||||||
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending";
|
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending"
|
||||||
} else {
|
} else {
|
||||||
filterData.order = ''
|
filterData.order = ""
|
||||||
|
}
|
||||||
|
gettrialList()
|
||||||
}
|
}
|
||||||
gettrialList();
|
|
||||||
};
|
|
||||||
|
|
||||||
//查询列表
|
//查询列表
|
||||||
let searchHistoryList = () => {
|
let searchHistoryList = () => {
|
||||||
filterData.currentPage = 1;
|
filterData.currentPage = 1
|
||||||
gettrialList();
|
gettrialList()
|
||||||
};
|
}
|
||||||
let clearHistoryList = () => {
|
let clearHistoryList = () => {
|
||||||
filterData.rangePickerValue = [],
|
;((filterData.rangePickerValue = []),
|
||||||
filterData.currentPage = 1,
|
(filterData.currentPage = 1),
|
||||||
filterData.pageSize = 10,
|
(filterData.pageSize = 10),
|
||||||
filterData.total = 0,
|
(filterData.total = 0),
|
||||||
filterData.country = "",
|
(filterData.country = ""),
|
||||||
filterData.email = "",
|
(filterData.email = ""),
|
||||||
filterData.userType = "",
|
(filterData.userType = ""),
|
||||||
filterData.ids = [],
|
(filterData.ids = []),
|
||||||
filterData.occupation = "",
|
(filterData.occupation = ""),
|
||||||
filterData.order = "", //'Ascending 升序 Descending 降序'
|
(filterData.order = ""), //'Ascending 升序 Descending 降序'
|
||||||
filterData.orderBy = "", //'Ascending 升序 Descending 降序'
|
(filterData.orderBy = ""), //'Ascending 升序 Descending 降序'
|
||||||
filterData.systemUser = "",
|
(filterData.systemUser = ""),
|
||||||
filterData.userName = "";
|
(filterData.userName = ""))
|
||||||
};
|
}
|
||||||
let setHistoryListData = () => {
|
let setHistoryListData = () => {
|
||||||
let startDate: any = filterData.rangePickerValue?.[0]
|
let startDate: any = filterData.rangePickerValue?.[0]
|
||||||
? filterData.rangePickerValue[0] + " " + "00:00:00"
|
? filterData.rangePickerValue[0] + " " + "00:00:00"
|
||||||
: "";
|
: ""
|
||||||
let endDate: any = filterData.rangePickerValue?.[1]
|
let endDate: any = filterData.rangePickerValue?.[1]
|
||||||
? filterData.rangePickerValue[1] + " " + "23:59:59"
|
? filterData.rangePickerValue[1] + " " + "23:59:59"
|
||||||
: "";
|
: ""
|
||||||
let data = {
|
let data = {
|
||||||
endTime: endDate,
|
endTime: endDate,
|
||||||
startTime: startDate,
|
startTime: startDate,
|
||||||
@@ -430,63 +428,118 @@ export default defineComponent({
|
|||||||
order: filterData.order,
|
order: filterData.order,
|
||||||
orderBy: filterData.orderBy,
|
orderBy: filterData.orderBy,
|
||||||
userName: filterData.userName,
|
userName: filterData.userName,
|
||||||
};
|
organizationId: filterData.organizationId
|
||||||
return data;
|
}
|
||||||
};
|
return data
|
||||||
|
}
|
||||||
//获取列表
|
//获取列表
|
||||||
let gettrialList = () => {
|
let gettrialList = () => {
|
||||||
filter.tableLoading = true;
|
filter.tableLoading = true
|
||||||
let data = setHistoryListData();
|
let data = setHistoryListData()
|
||||||
Https.axiosPost(Https.httpUrls.getUserInfo, data).then(
|
Https.axiosPost(Https.httpUrls.getUserInfo, data).then((rv: any) => {
|
||||||
(rv: any) => {
|
|
||||||
if (rv) {
|
if (rv) {
|
||||||
// this.dataList = rv
|
// this.dataList = rv
|
||||||
filter.dataList = rv.records;
|
filter.dataList = rv.records
|
||||||
filterData.total = rv.total;
|
filterData.total = rv.total
|
||||||
filter.tableLoading = false;
|
filter.tableLoading = false
|
||||||
|
|
||||||
// this.workspaceItem.position = this.singleTypeList[0].label
|
// this.workspaceItem.position = this.singleTypeList[0].label
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
let lastGeTrialList = (str: string) => {
|
let lastGeTrialList = (str: string) => {
|
||||||
clearHistoryList();
|
clearHistoryList()
|
||||||
let currentDate = new Date();
|
let currentDate = new Date()
|
||||||
let currentTimestamp = Math.floor(currentDate.getTime() / 1000);
|
let currentTimestamp = Math.floor(currentDate.getTime() / 1000)
|
||||||
// 计算30天前的时间戳
|
// 计算30天前的时间戳
|
||||||
let thirtyDaysAgoTimestamp;
|
let thirtyDaysAgoTimestamp
|
||||||
if (str == "year") {
|
if (str == "year") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60
|
||||||
} else if (str == "month") {
|
} else if (str == "month") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60
|
||||||
} else if (str == "week") {
|
} else if (str == "week") {
|
||||||
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60;
|
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60
|
||||||
|
}
|
||||||
|
filterData.rangePickerValue[0] = formatTime(thirtyDaysAgoTimestamp, "YYYY-MM-DD")
|
||||||
|
gettrialList()
|
||||||
}
|
}
|
||||||
filterData.rangePickerValue[0] = formatTime(
|
|
||||||
thirtyDaysAgoTimestamp,
|
|
||||||
"YYYY-MM-DD"
|
|
||||||
);
|
|
||||||
gettrialList();
|
|
||||||
};
|
|
||||||
let filterOption = (input: any, option: any) => {
|
let filterOption = (input: any, option: any) => {
|
||||||
// 使用 option.label 进行搜索
|
// 使用 option.label 进行搜索
|
||||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
};
|
}
|
||||||
let addhHistoryList = () => {
|
let addhHistoryList = () => {
|
||||||
allUserPoerationsVue.value.init('Add','')
|
allUserPoerationsVue.value.init("Add", "")
|
||||||
};
|
}
|
||||||
let allUserPoerationsVue = ref()
|
let allUserPoerationsVue = ref()
|
||||||
let setAagree = (data: any) => {
|
let setAagree = (data: any) => {
|
||||||
allUserPoerationsVue.value.init('Edit',data)
|
allUserPoerationsVue.value.init("Edit", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const organizationOptions = ref([])
|
||||||
|
const organizationParams = reactive({
|
||||||
|
page: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
const organizationLoading = ref(false)
|
||||||
|
const getOrganizationList = async (isLoadMore = false) => {
|
||||||
|
console.log("111111")
|
||||||
|
if (organizationLoading.value) return
|
||||||
|
if (isLoadMore) {
|
||||||
|
const loaded = organizationParams.page * organizationParams.size
|
||||||
|
if (organizationParams.total && loaded >= organizationParams.total) return
|
||||||
|
organizationParams.page += 1
|
||||||
|
} else {
|
||||||
|
organizationParams.page = 1
|
||||||
|
organizationOptions.value = []
|
||||||
|
}
|
||||||
|
organizationLoading.value = true
|
||||||
|
try {
|
||||||
|
const { total, ...requestParams } = organizationParams
|
||||||
|
const rv: any = await Https.axiosPost(
|
||||||
|
Https.httpUrls.queryOrganization,
|
||||||
|
requestParams
|
||||||
|
)
|
||||||
|
if (rv) {
|
||||||
|
const newRecords = rv.records || []
|
||||||
|
// 遍历新数据,如果已存在则覆盖,不存在则追加
|
||||||
|
newRecords.forEach((newOrg: any) => {
|
||||||
|
const newOrgId = String(newOrg.id)
|
||||||
|
const existingIndex = organizationOptions.value.findIndex(
|
||||||
|
(org: any) => String(org.id) === newOrgId
|
||||||
|
)
|
||||||
|
if (existingIndex !== -1) {
|
||||||
|
// 如果已存在,用新数据覆盖旧项
|
||||||
|
organizationOptions.value[existingIndex] = newOrg
|
||||||
|
} else {
|
||||||
|
// 如果不存在,追加到末尾
|
||||||
|
organizationOptions.value.push(newOrg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
organizationParams.total = rv.total || 0
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
organizationLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOrganizationScroll = (e: any) => {
|
||||||
|
const target = e?.target
|
||||||
|
if (!target) return
|
||||||
|
const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 20
|
||||||
|
if (nearBottom) {
|
||||||
|
getOrganizationList(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let allCountry: any = sessionStorage.getItem("allCountry");
|
let allCountry: any = sessionStorage.getItem("allCountry")
|
||||||
if (allCountry) {
|
if (allCountry) {
|
||||||
filter.allCountry = JSON.parse(allCountry);
|
filter.allCountry = JSON.parse(allCountry)
|
||||||
}
|
}
|
||||||
gettrialList();
|
gettrialList()
|
||||||
});
|
getOrganizationList()
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
...toRefs(filter),
|
...toRefs(filter),
|
||||||
...toRefs(filterData),
|
...toRefs(filterData),
|
||||||
@@ -501,22 +554,26 @@ export default defineComponent({
|
|||||||
filterOption,
|
filterOption,
|
||||||
allUserPoerationsVue,
|
allUserPoerationsVue,
|
||||||
setAagree,
|
setAagree,
|
||||||
};
|
handleOrganizationScroll,
|
||||||
|
getOrganizationList,
|
||||||
|
organizationOptions,
|
||||||
|
organizationParams
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
historyTableHeight: 0,
|
historyTableHeight: 0,
|
||||||
handleResizeColumn: (w: any, col: any) => {
|
handleResizeColumn: (w: any, col: any) => {
|
||||||
col.width = w;
|
col.width = w
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let historyTable: any = this.$refs.historyTable;
|
let historyTable: any = this.$refs.historyTable
|
||||||
this.historyTableHeight = historyTable.clientHeight - 200;
|
this.historyTableHeight = historyTable.clientHeight - 200
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.admin_page .admin_table_search .admin_state {
|
.admin_page .admin_table_search .admin_state {
|
||||||
@@ -524,6 +581,5 @@ export default defineComponent({
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.admin_page {
|
.admin_page {
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -321,6 +321,7 @@ export default defineComponent({
|
|||||||
data = setEditData()
|
data = setEditData()
|
||||||
if (!data.userName || !data.userEmail || !data.validEndTime || !data.systemUser)
|
if (!data.userName || !data.userEmail || !data.validEndTime || !data.systemUser)
|
||||||
return message.warning('Please check the input box marked with *')
|
return message.warning('Please check the input box marked with *')
|
||||||
|
delete data.userName
|
||||||
Https.axiosPost(Https.httpUrls.modifyUser, {}, { params: data }).then(rv => {
|
Https.axiosPost(Https.httpUrls.modifyUser, {}, { params: data }).then(rv => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
cancelDsign()
|
cancelDsign()
|
||||||
|
|||||||
99
src/component/Administrator/globalAwardPopularity.vue
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div class="admin_page globalAwardPopularity" ref="adminPage">
|
||||||
|
<div class="admin_table_search">
|
||||||
|
<div class="admin_state">
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Current Time:</span>
|
||||||
|
<span>{{ currentTimeStr }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Raw Visi Count:</span>
|
||||||
|
<span>{{ rawVisitCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="admin_state_item">
|
||||||
|
<span>Unique Visit Count:</span>
|
||||||
|
<span>{{ uniqueVisitCount }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="admin_search">
|
||||||
|
<div class="admin_search_item" @click="getGlobalAwardPopularity">
|
||||||
|
<i class="fi fi-br-refresh"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="admin_table_content" ref="questionnaireTable">
|
||||||
|
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, createVNode,toRefs, computed,reactive, onMounted, nextTick } from "vue";
|
||||||
|
import { Https } from "@/tool/https";
|
||||||
|
import type { TableColumnsType } from 'ant-design-vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {},
|
||||||
|
setup() {
|
||||||
|
const currentTime = ref(new Date())
|
||||||
|
const currentTimeStr = computed(()=>{
|
||||||
|
return currentTime.value.toLocaleString()
|
||||||
|
})
|
||||||
|
const rawVisitCount = ref(0)
|
||||||
|
const uniqueVisitCount = ref(0)
|
||||||
|
const getGlobalAwardPopularity = () => {
|
||||||
|
Https.axiosGet(Https.httpUrls.getGlobalAwardPopularity,).then((rv)=>{
|
||||||
|
currentTime.value = new Date()
|
||||||
|
rawVisitCount.value = rv.rawVisitCount
|
||||||
|
uniqueVisitCount.value = rv.uniqueVisitCount
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(()=>{
|
||||||
|
getGlobalAwardPopularity()
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
currentTimeStr,
|
||||||
|
getGlobalAwardPopularity,
|
||||||
|
rawVisitCount,
|
||||||
|
uniqueVisitCount,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.admin_page.globalAwardPopularity{
|
||||||
|
.admin_table_search{
|
||||||
|
// flex: 1;
|
||||||
|
width: min-content;
|
||||||
|
justify-content: flex-start;
|
||||||
|
border-radius: 2rem;
|
||||||
|
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2);
|
||||||
|
margin-left: 2rem;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
.admin_state{
|
||||||
|
flex-direction: column;
|
||||||
|
width: auto;
|
||||||
|
cursor: auto;
|
||||||
|
.admin_state_item{
|
||||||
|
> span{
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.admin_search{
|
||||||
|
i{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
class="search-form"
|
class="search-form"
|
||||||
layout="inline"
|
layout="inline"
|
||||||
:model="searchForm"
|
:model="searchForm"
|
||||||
:label-col="{ style: { width: '12rem' } }"
|
:label-col="{ style: { width: '14rem' } }"
|
||||||
:wrapper-col="{ style: { width: '22rem' } }"
|
:wrapper-col="{ style: { width: '20rem' } }"
|
||||||
>
|
>
|
||||||
<a-form-item label="ID">
|
<a-form-item label="ID">
|
||||||
<a-input v-model:value="searchForm.id" allow-clear placeholder="Input the id" />
|
<a-input v-model:value="searchForm.id" allow-clear placeholder="Input the id" />
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
:options="countryList"
|
:options="countryList"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item class="search-form__actions">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click="handleSearch">Search</a-button>
|
<a-button type="primary" @click="handleSearch">Search</a-button>
|
||||||
<a-button @click="handleReset">Reset</a-button>
|
<a-button @click="handleReset">Reset</a-button>
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
:loading="tableLoading"
|
:loading="tableLoading"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
|
:customRow="customPlanRow"
|
||||||
@change="changePage"
|
@change="changePage"
|
||||||
@resizeColumn="handleResizeColumn"
|
@resizeColumn="handleResizeColumn"
|
||||||
:scroll="{ y: historyTableHeight }"
|
:scroll="{ y: historyTableHeight }"
|
||||||
@@ -107,10 +108,11 @@
|
|||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
column.key === 'currentPeriodStart' || column.key === 'currentPeriodEnd'
|
column.key === 'currentPeriodStart' ||
|
||||||
|
column.key === 'currentPeriodEnd'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
|
{{ formatTime(record[column.key], "YYYY-MM-DD hh:mm:ss") }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="column.key === 'status'">
|
<template v-if="column.key === 'status'">
|
||||||
@@ -120,15 +122,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="column.key === 'actions'">
|
<template v-else-if="column.key === 'actions'">
|
||||||
<a-space>
|
<a-space class="plan-row-actions" @click.stop>
|
||||||
<a @click="openEdit(record)">Edit</a>
|
<a @click.stop="openEdit(record)">Edit</a>
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
title="Confirm to delete this subscription plan?"
|
title="Confirm to delete this subscription plan?"
|
||||||
ok-text="Confirm"
|
ok-text="Confirm"
|
||||||
cancel-text="Cancel"
|
cancel-text="Cancel"
|
||||||
@confirm="removePlan(record.id)"
|
@confirm="removePlan(record.id)"
|
||||||
>
|
>
|
||||||
<a class="danger-text">Delete</a>
|
<a class="danger-text" @click.stop>Delete</a>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
@@ -137,6 +139,50 @@
|
|||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="userInfoModalVisible"
|
||||||
|
title="User Info"
|
||||||
|
width="80%"
|
||||||
|
:footer="null"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
class="user-info-modal"
|
||||||
|
>
|
||||||
|
<a-table
|
||||||
|
:columns="userInfoColumns"
|
||||||
|
:data-source="userInfoList"
|
||||||
|
:loading="userInfoLoading"
|
||||||
|
:pagination="{
|
||||||
|
showSizeChanger: true,
|
||||||
|
current: userInfoPage.current,
|
||||||
|
pageSize: userInfoPage.size,
|
||||||
|
total: userInfoPage.total,
|
||||||
|
showQuickJumper: true,
|
||||||
|
bordered: false
|
||||||
|
}"
|
||||||
|
row-key="id"
|
||||||
|
:scroll="{ x: 1280, y: 420 }"
|
||||||
|
@change="changeUserInfoPage"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
column.key === 'validStartTime' ||
|
||||||
|
column.key === 'validEndTime' ||
|
||||||
|
column.key === 'createDate'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ formatUserTime(record[column.key]) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'systemUser'">
|
||||||
|
{{ getSystemUserLabel(record.systemUser) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'isBeginner'">
|
||||||
|
{{ record.isBeginner == 1 ? "Yes" : "No" }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
<div class="subscriptionPlanModal" ref="subscriptionPlanModal"></div>
|
<div class="subscriptionPlanModal" ref="subscriptionPlanModal"></div>
|
||||||
<a-modal
|
<a-modal
|
||||||
class="subscriptionPlan_modal generalModel"
|
class="subscriptionPlan_modal generalModel"
|
||||||
@@ -213,7 +259,10 @@
|
|||||||
@select="handleOrganizationSelect"
|
@select="handleOrganizationSelect"
|
||||||
@change="handleOrganizationChange"
|
@change="handleOrganizationChange"
|
||||||
>
|
>
|
||||||
<a-select-option value="ADD_ORGANIZATION" class="add-organization-option">
|
<a-select-option
|
||||||
|
value="ADD_ORGANIZATION"
|
||||||
|
class="add-organization-option"
|
||||||
|
>
|
||||||
+ Create Organization
|
+ Create Organization
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
@@ -393,27 +442,30 @@ import {
|
|||||||
ref,
|
ref,
|
||||||
onMounted,
|
onMounted,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
|
onActivated,
|
||||||
computed,
|
computed,
|
||||||
nextTick,
|
nextTick,
|
||||||
useTemplateRef
|
useTemplateRef
|
||||||
} from 'vue'
|
} from "vue"
|
||||||
import SelectUser from '@/component/common/SelectUser.vue'
|
import SelectUser from "@/component/common/SelectUser.vue"
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from "ant-design-vue"
|
||||||
import { Https } from '@/tool/https'
|
import { Https } from "@/tool/https"
|
||||||
import { formatTime } from '@/tool/util'
|
import { formatTime } from "@/tool/util"
|
||||||
import store from '@/store'
|
import store from "@/store"
|
||||||
import type { FormInstance, Rule } from 'ant-design-vue/es/form'
|
import type { FormInstance, Rule } from "ant-design-vue/es/form"
|
||||||
import { debounce } from 'lodash-es'
|
import { debounce } from "lodash-es"
|
||||||
import dayjs, { Dayjs } from 'dayjs'
|
import dayjs, { Dayjs } from "dayjs"
|
||||||
|
|
||||||
type PlanStatus = 'PENDING' | 'ACTIVE' | 'EXPIRED'
|
type PlanStatus = "PENDING" | "ACTIVE" | "EXPIRED"
|
||||||
interface SubscriptionPlan {
|
interface SubscriptionPlan {
|
||||||
id: number
|
id: number
|
||||||
|
userId?: string | number
|
||||||
name: string
|
name: string
|
||||||
currentPeriodStart: string
|
currentPeriodStart: string
|
||||||
currentPeriodEnd: string
|
currentPeriodEnd: string
|
||||||
organizationId: string
|
organizationId: string
|
||||||
adminAccId: string
|
adminAccId: string
|
||||||
|
adminAccEmail?: string
|
||||||
status: PlanStatus
|
status: PlanStatus
|
||||||
creditLimit: number
|
creditLimit: number
|
||||||
accountNum?: number
|
accountNum?: number
|
||||||
@@ -421,17 +473,32 @@ interface SubscriptionPlan {
|
|||||||
endStamp: number
|
endStamp: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UserInfoRecord {
|
||||||
|
id: number
|
||||||
|
userEmail?: string
|
||||||
|
userName?: string
|
||||||
|
language?: string
|
||||||
|
validStartTime?: number | string
|
||||||
|
validEndTime?: number | string
|
||||||
|
country?: string
|
||||||
|
createDate?: number | string
|
||||||
|
isBeginner?: number
|
||||||
|
browserIdentifiers?: string
|
||||||
|
credits?: number
|
||||||
|
systemUser?: number | string
|
||||||
|
}
|
||||||
|
|
||||||
const countryList = ref([])
|
const countryList = ref([])
|
||||||
const userRef = ref(null)
|
const userRef = ref(null)
|
||||||
|
|
||||||
const searchForm = reactive({
|
const searchForm = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
startTime: '',
|
startTime: "",
|
||||||
endTime: '',
|
endTime: "",
|
||||||
organizationId: undefined as string | undefined,
|
organizationId: undefined as string | undefined,
|
||||||
adminAccId: undefined as string | undefined,
|
adminAccId: undefined as string | undefined,
|
||||||
status: [] as PlanStatus[] | [],
|
status: [] as PlanStatus[] | [],
|
||||||
id: '',
|
id: "",
|
||||||
countryOrRegion: null,
|
countryOrRegion: null,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
@@ -442,15 +509,24 @@ const toSeconds = (dateStr: string) => Math.floor(new Date(dateStr).getTime() /
|
|||||||
|
|
||||||
const tableData = ref<SubscriptionPlan[]>([])
|
const tableData = ref<SubscriptionPlan[]>([])
|
||||||
const tableLoading = ref(false)
|
const tableLoading = ref(false)
|
||||||
|
const userInfoModalVisible = ref(false)
|
||||||
|
const userInfoLoading = ref(false)
|
||||||
|
const userInfoList = ref<UserInfoRecord[]>([])
|
||||||
|
const currentUserInfoPlanId = ref<string | number | null>(null)
|
||||||
|
const userInfoPage = reactive({
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
const modalVisible = ref(false)
|
const modalVisible = ref(false)
|
||||||
const confirmLoading = ref(false)
|
const confirmLoading = ref(false)
|
||||||
const modalTitle = ref('New Subscription Plan')
|
const modalTitle = ref("New Subscription Plan")
|
||||||
const isEditMode = ref(false)
|
const isEditMode = ref(false)
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
currentPeriodStart: '',
|
currentPeriodStart: "",
|
||||||
currentPeriodEnd: '',
|
currentPeriodEnd: "",
|
||||||
organizationId: undefined as string | undefined,
|
organizationId: undefined as string | undefined,
|
||||||
adminAccId: undefined as string | undefined,
|
adminAccId: undefined as string | undefined,
|
||||||
creditLimit: null as number | null,
|
creditLimit: null as number | null,
|
||||||
@@ -461,44 +537,44 @@ const formState = reactive({
|
|||||||
|
|
||||||
const organizationModalVisible = ref(false)
|
const organizationModalVisible = ref(false)
|
||||||
const organizationForm = reactive({
|
const organizationForm = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
type: undefined as string | undefined
|
type: undefined as string | undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
const statusLabelMap: Record<PlanStatus, string> = {
|
const statusLabelMap: Record<PlanStatus, string> = {
|
||||||
PENDING: 'Pending',
|
PENDING: "Pending",
|
||||||
ACTIVE: 'Active',
|
ACTIVE: "Active",
|
||||||
EXPIRED: 'Expired'
|
EXPIRED: "Expired"
|
||||||
}
|
}
|
||||||
const statusColorMap: Record<PlanStatus, string> = {
|
const statusColorMap: Record<PlanStatus, string> = {
|
||||||
PENDING: 'blue',
|
PENDING: "blue",
|
||||||
ACTIVE: 'green',
|
ACTIVE: "green",
|
||||||
EXPIRED: 'red'
|
EXPIRED: "red"
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusOption = ref([
|
const statusOption = ref([
|
||||||
{
|
{
|
||||||
label: 'Pending',
|
label: "Pending",
|
||||||
value: 'PENDING'
|
value: "PENDING"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Active',
|
label: "Active",
|
||||||
value: 'ACTIVE'
|
value: "ACTIVE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Expired',
|
label: "Expired",
|
||||||
value: 'EXPIRED'
|
value: "EXPIRED"
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const disabledDate = (current: Dayjs) => {
|
const disabledDate = (current: Dayjs) => {
|
||||||
return current && current < dayjs().subtract(1, 'days').endOf('day')
|
return current && current < dayjs().subtract(1, "days").endOf("day")
|
||||||
}
|
}
|
||||||
|
|
||||||
const disableEndDate = (current: Dayjs) => {
|
const disableEndDate = (current: Dayjs) => {
|
||||||
if (isEditMode.value) {
|
if (isEditMode.value) {
|
||||||
const specificTime = dayjs(formState.currentPeriodEnd)
|
const specificTime = dayjs(formState.currentPeriodEnd)
|
||||||
return current && current < dayjs(formState.currentPeriodEnd * 1000).startOf('day')
|
return current && current < dayjs(formState.currentPeriodEnd * 1000).startOf("day")
|
||||||
}
|
}
|
||||||
return disabledDate(current)
|
return disabledDate(current)
|
||||||
}
|
}
|
||||||
@@ -509,7 +585,7 @@ const range = (start: number, end: number) => {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const disableEndTime = date => {
|
const disableEndTime = (date) => {
|
||||||
if (!formState.currentPeriodEnd || !isEditMode.value)
|
if (!formState.currentPeriodEnd || !isEditMode.value)
|
||||||
return {
|
return {
|
||||||
disabledHours: () => [],
|
disabledHours: () => [],
|
||||||
@@ -519,7 +595,7 @@ const disableEndTime = date => {
|
|||||||
|
|
||||||
const specificTime = dayjs.unix(formState.currentPeriodEnd)
|
const specificTime = dayjs.unix(formState.currentPeriodEnd)
|
||||||
|
|
||||||
if (date && date.isSame(specificTime, 'day')) {
|
if (date && date.isSame(specificTime, "day")) {
|
||||||
// 如果是指定日期当天,禁用时间戳之前的时间
|
// 如果是指定日期当天,禁用时间戳之前的时间
|
||||||
const hour = specificTime.hour()
|
const hour = specificTime.hour()
|
||||||
const minute = specificTime.minute()
|
const minute = specificTime.minute()
|
||||||
@@ -527,7 +603,7 @@ const disableEndTime = date => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
disabledHours: () => Array.from({ length: hour }, (_, i) => i), // 禁用小时之前
|
disabledHours: () => Array.from({ length: hour }, (_, i) => i), // 禁用小时之前
|
||||||
disabledMinutes: selectedHour => {
|
disabledMinutes: (selectedHour) => {
|
||||||
if (selectedHour === hour) {
|
if (selectedHour === hour) {
|
||||||
return Array.from({ length: minute }, (_, i) => i) // 同小时,禁用分钟之前
|
return Array.from({ length: minute }, (_, i) => i) // 同小时,禁用分钟之前
|
||||||
}
|
}
|
||||||
@@ -555,114 +631,328 @@ const normalizeStatus = (status?: string): PlanStatus | undefined => {
|
|||||||
return upper
|
return upper
|
||||||
}
|
}
|
||||||
const getStatusColor = (status?: string) =>
|
const getStatusColor = (status?: string) =>
|
||||||
statusColorMap[normalizeStatus(status) as PlanStatus] || 'default'
|
statusColorMap[normalizeStatus(status) as PlanStatus] || "default"
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ title: 'Name', dataIndex: 'name', key: 'name', align: 'center', width: 180 },
|
{ title: "Name", dataIndex: "name", key: "name", align: "center", width: 180 },
|
||||||
{ title: 'ID', dataIndex: 'id', key: 'id', align: 'center', width: 80 },
|
{ title: "ID", dataIndex: "id", key: "id", align: "center", width: 80 },
|
||||||
{
|
{
|
||||||
title: 'Organization',
|
title: "Organization",
|
||||||
dataIndex: 'organizationName',
|
dataIndex: "organizationName",
|
||||||
key: 'organizationName',
|
key: "organizationName",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 180
|
width: 180
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Admin Account',
|
title: "Admin Account",
|
||||||
dataIndex: 'adminAccEmail',
|
dataIndex: "adminAccEmail",
|
||||||
key: 'adminAccEmail',
|
key: "adminAccEmail",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 180,
|
width: 180,
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Sub-Account Num',
|
title: "Sub-Account Num",
|
||||||
dataIndex: 'accountNum',
|
dataIndex: "accountNum",
|
||||||
key: 'accountNum',
|
key: "accountNum",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 120,
|
width: 120,
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Country or Region',
|
title: "Country or Region",
|
||||||
dataIndex: 'countryOrRegion',
|
dataIndex: "countryOrRegion",
|
||||||
key: 'countryOrRegion',
|
key: "countryOrRegion",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 120,
|
width: 120,
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Start Time',
|
title: "Start Time",
|
||||||
dataIndex: 'currentPeriodStart',
|
dataIndex: "currentPeriodStart",
|
||||||
key: 'currentPeriodStart',
|
key: "currentPeriodStart",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 200
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'End Time',
|
title: "End Time",
|
||||||
dataIndex: 'currentPeriodEnd',
|
dataIndex: "currentPeriodEnd",
|
||||||
key: 'currentPeriodEnd',
|
key: "currentPeriodEnd",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 200
|
width: 200
|
||||||
},
|
},
|
||||||
{ title: 'Status', dataIndex: 'status', key: 'status', align: 'center', width: 100 },
|
{ title: "Status", dataIndex: "status", key: "status", align: "center", width: 100 },
|
||||||
{
|
{
|
||||||
title: 'Credit Limit',
|
title: "Credit Limit",
|
||||||
dataIndex: 'creditLimit',
|
dataIndex: "creditLimit",
|
||||||
key: 'creditLimit',
|
key: "creditLimit",
|
||||||
align: 'center',
|
align: "center",
|
||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
{ title: 'Operations', key: 'actions', width: 160, align: 'center', fixed: 'right' }
|
{ title: "Operations", key: "actions", width: 160, align: "center", fixed: "right" }
|
||||||
]
|
]
|
||||||
|
|
||||||
const historyTable = ref()
|
const userInfoColumns = [
|
||||||
|
{ title: "User Id", dataIndex: "id", key: "id", align: "center", width: 100 },
|
||||||
|
{
|
||||||
|
title: "Email",
|
||||||
|
dataIndex: "userEmail",
|
||||||
|
key: "userEmail",
|
||||||
|
align: "center",
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "User Name",
|
||||||
|
dataIndex: "userName",
|
||||||
|
key: "userName",
|
||||||
|
align: "center",
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "Valid Start Time",
|
||||||
|
dataIndex: "validStartTime",
|
||||||
|
key: "validStartTime",
|
||||||
|
align: "center",
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Valid End Time",
|
||||||
|
dataIndex: "validEndTime",
|
||||||
|
key: "validEndTime",
|
||||||
|
align: "center",
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Country or Region",
|
||||||
|
dataIndex: "country",
|
||||||
|
key: "country",
|
||||||
|
align: "center",
|
||||||
|
width: 180,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Credits",
|
||||||
|
dataIndex: "credits",
|
||||||
|
key: "credits",
|
||||||
|
align: "center",
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "User Type",
|
||||||
|
dataIndex: "systemUser",
|
||||||
|
key: "systemUser",
|
||||||
|
align: "center",
|
||||||
|
width: 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const systemUserLabelMap: Record<string, string> = {
|
||||||
|
"0": "visitor",
|
||||||
|
"1": "yearly",
|
||||||
|
"2": "monthly",
|
||||||
|
"3": "trial",
|
||||||
|
"4": "userInEvent",
|
||||||
|
"7": "Edu Admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSystemUserLabel = (systemUser?: number | string) => {
|
||||||
|
if (systemUser === undefined || systemUser === null) return ""
|
||||||
|
return systemUserLabelMap[String(systemUser)] || String(systemUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatUserTime = (value?: number | string) => {
|
||||||
|
if (!value) return ""
|
||||||
|
if (typeof value === "number") {
|
||||||
|
return formatTime(value / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
|
}
|
||||||
|
if (/^\d+$/.test(value)) {
|
||||||
|
return formatTime(Number(value) / 1000, "YYYY-MM-DD hh:mm:ss")
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizeUserInfoList = (res: any): UserInfoRecord[] => {
|
||||||
|
if (Array.isArray(res)) return res
|
||||||
|
if (Array.isArray(res?.records)) return res.records
|
||||||
|
if (res) return [res]
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildUserInfoParams = (id: string | number) => ({
|
||||||
|
endTime: "",
|
||||||
|
startTime: "",
|
||||||
|
size: userInfoPage.size,
|
||||||
|
page: userInfoPage.current,
|
||||||
|
systemUser: "",
|
||||||
|
country: "",
|
||||||
|
email: "",
|
||||||
|
userType: "",
|
||||||
|
ids: [],
|
||||||
|
occupation: "",
|
||||||
|
order: "",
|
||||||
|
orderBy: "",
|
||||||
|
userName: "",
|
||||||
|
subscriptionPlanId: id
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchUserInfo = async () => {
|
||||||
|
if (currentUserInfoPlanId.value === null) return
|
||||||
|
userInfoLoading.value = true
|
||||||
|
userInfoList.value = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await Https.axiosPost(
|
||||||
|
Https.httpUrls.getUserInfo,
|
||||||
|
buildUserInfoParams(currentUserInfoPlanId.value)
|
||||||
|
)
|
||||||
|
const records = normalizeUserInfoList(res)
|
||||||
|
userInfoList.value = records
|
||||||
|
userInfoPage.total = Number(res?.total ?? records.length)
|
||||||
|
} catch (error: any) {
|
||||||
|
message.error(error.message || "Failed to load user info")
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
userInfoLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const openUserInfo = async (record: SubscriptionPlan) => {
|
||||||
|
console.log(record)
|
||||||
|
// debugger
|
||||||
|
|
||||||
|
currentUserInfoPlanId.value = record.id
|
||||||
|
userInfoPage.current = 1
|
||||||
|
userInfoModalVisible.value = true
|
||||||
|
await fetchUserInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeUserInfoPage = (pagination: any) => {
|
||||||
|
userInfoPage.current = pagination.current
|
||||||
|
userInfoPage.size = pagination.pageSize
|
||||||
|
fetchUserInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
const customPlanRow = (record: SubscriptionPlan) => {
|
||||||
|
return {
|
||||||
|
onClick: (event: MouseEvent) => {
|
||||||
|
const target = event.target as HTMLElement | null
|
||||||
|
if (target?.closest(".plan-row-actions")) return
|
||||||
|
openUserInfo(record)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const historyTable = ref<HTMLElement | null>(null)
|
||||||
const historyTableHeight = ref(0)
|
const historyTableHeight = ref(0)
|
||||||
|
const minTableBodyHeight = 120
|
||||||
|
let tableResizeObserver: ResizeObserver | null = null
|
||||||
|
let tableResizeTimer: ReturnType<typeof window.setTimeout> | null = null
|
||||||
|
|
||||||
const handleResizeColumn = (w: any, col: any) => {
|
const handleResizeColumn = (w: any, col: any) => {
|
||||||
col.width = w
|
col.width = w
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateTableHeight = () => {
|
const getElementOuterHeight = (element: Element | null) => {
|
||||||
nextTick(() => {
|
if (!element) return 0
|
||||||
if (historyTable.value) {
|
const htmlElement = element as HTMLElement
|
||||||
historyTableHeight.value = historyTable.value.clientHeight - 200
|
const style = window.getComputedStyle(htmlElement)
|
||||||
|
return (
|
||||||
|
htmlElement.offsetHeight +
|
||||||
|
Number.parseFloat(style.marginTop || "0") +
|
||||||
|
Number.parseFloat(style.marginBottom || "0")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const calculateTableHeight = () => {
|
||||||
|
if (tableResizeTimer) {
|
||||||
|
window.clearTimeout(tableResizeTimer)
|
||||||
|
}
|
||||||
|
tableResizeTimer = window.setTimeout(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
const tableWrapper = historyTable.value
|
||||||
|
if (!tableWrapper) {
|
||||||
|
tableResizeTimer = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableHead = tableWrapper.querySelector(".ant-table-thead") ?? null
|
||||||
|
const pagination = tableWrapper.querySelector(".ant-pagination") ?? null
|
||||||
|
const tableHeadHeight = getElementOuterHeight(tableHead) || 55
|
||||||
|
const paginationHeight = getElementOuterHeight(pagination) || 48
|
||||||
|
const reservedHeight = tableHeadHeight + paginationHeight + 8
|
||||||
|
|
||||||
|
historyTableHeight.value = Math.max(
|
||||||
|
minTableBodyHeight,
|
||||||
|
tableWrapper.clientHeight - reservedHeight
|
||||||
|
)
|
||||||
|
tableResizeTimer = null
|
||||||
})
|
})
|
||||||
|
}, 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
calculateTableHeight()
|
calculateTableHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setupTableResizeObserver = () => {
|
||||||
|
if (!historyTable.value || typeof ResizeObserver === "undefined") return
|
||||||
|
tableResizeObserver?.disconnect()
|
||||||
|
tableResizeObserver = new ResizeObserver(() => {
|
||||||
|
calculateTableHeight()
|
||||||
|
})
|
||||||
|
tableResizeObserver.observe(historyTable.value)
|
||||||
|
|
||||||
|
const searchCard = historyTable.value
|
||||||
|
.closest(".subscription-plan")
|
||||||
|
?.querySelector(".search-card")
|
||||||
|
if (searchCard) {
|
||||||
|
tableResizeObserver.observe(searchCard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getOrganizationList()
|
await getOrganizationList()
|
||||||
await handleSearch()
|
await handleSearch()
|
||||||
calculateTableHeight()
|
calculateTableHeight()
|
||||||
window.addEventListener('resize', handleResize)
|
setupTableResizeObserver()
|
||||||
const list = sessionStorage.getItem('allCountry')
|
window.addEventListener("resize", handleResize)
|
||||||
|
const list = sessionStorage.getItem("allCountry")
|
||||||
countryList.value = list ? JSON.parse(list) : []
|
countryList.value = list ? JSON.parse(list) : []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
calculateTableHeight()
|
||||||
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('resize', handleResize)
|
window.removeEventListener("resize", handleResize)
|
||||||
|
tableResizeObserver?.disconnect()
|
||||||
|
if (tableResizeTimer) {
|
||||||
|
window.clearTimeout(tableResizeTimer)
|
||||||
|
tableResizeTimer = null
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFetchTableData = async () => {
|
const handleFetchTableData = async () => {
|
||||||
tableLoading.value = true
|
tableLoading.value = true
|
||||||
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
|
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
|
||||||
.then(res => {
|
.then((res) => {
|
||||||
tableData.value = res.records
|
tableData.value = res.records
|
||||||
searchForm.total = res.total
|
searchForm.total = res.total
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
tableLoading.value = false
|
tableLoading.value = false
|
||||||
|
calculateTableHeight()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetFormState = () => {
|
const resetFormState = () => {
|
||||||
formState.name = ''
|
formState.name = ""
|
||||||
formState.currentPeriodStart = ''
|
formState.currentPeriodStart = ""
|
||||||
formState.currentPeriodEnd = ''
|
formState.currentPeriodEnd = ""
|
||||||
formState.organizationId = undefined
|
formState.organizationId = undefined
|
||||||
formState.adminAccId = undefined
|
formState.adminAccId = undefined
|
||||||
formState.creditLimit = null
|
formState.creditLimit = null
|
||||||
@@ -683,26 +973,26 @@ const handleSearch = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
searchForm.name = ''
|
searchForm.name = ""
|
||||||
searchForm.startTime = ''
|
searchForm.startTime = ""
|
||||||
searchForm.endTime = ''
|
searchForm.endTime = ""
|
||||||
searchForm.organizationId = undefined
|
searchForm.organizationId = undefined
|
||||||
searchForm.adminAccId = undefined
|
searchForm.adminAccId = undefined
|
||||||
searchForm.status = []
|
searchForm.status = []
|
||||||
searchForm.id = ''
|
searchForm.id = ""
|
||||||
searchForm.countryOrRegion = null
|
searchForm.countryOrRegion = null
|
||||||
handleSearch()
|
handleSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
const openCreate = () => {
|
const openCreate = () => {
|
||||||
modalTitle.value = 'New Subscription Plan'
|
modalTitle.value = "New Subscription Plan"
|
||||||
isEditMode.value = false
|
isEditMode.value = false
|
||||||
resetFormState()
|
resetFormState()
|
||||||
modalVisible.value = true
|
modalVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const openEdit = (record: SubscriptionPlan) => {
|
const openEdit = (record: SubscriptionPlan) => {
|
||||||
modalTitle.value = 'Edit Subscription Plan'
|
modalTitle.value = "Edit Subscription Plan"
|
||||||
isEditMode.value = true
|
isEditMode.value = true
|
||||||
formState.name = record.name
|
formState.name = record.name
|
||||||
formState.currentPeriodStart = String(record.currentPeriodStart)
|
formState.currentPeriodStart = String(record.currentPeriodStart)
|
||||||
@@ -755,25 +1045,25 @@ const validateForm = (): boolean => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requiredFields: FieldRule[] = [
|
const requiredFields: FieldRule[] = [
|
||||||
{ value: formState.currentPeriodStart, message: 'Please select the start time' },
|
{ value: formState.currentPeriodStart, message: "Please select the start time" },
|
||||||
{ value: formState.currentPeriodEnd, message: 'Please select the end time' },
|
{ value: formState.currentPeriodEnd, message: "Please select the end time" },
|
||||||
{ value: formState.adminAccId, message: 'Please select the admin account' },
|
{ value: formState.adminAccId, message: "Please select the admin account" },
|
||||||
{
|
{
|
||||||
value: formState.creditLimit,
|
value: formState.creditLimit,
|
||||||
message: 'Please input credit limit',
|
message: "Please input credit limit",
|
||||||
checkNull: true
|
checkNull: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: formState.accountNum,
|
value: formState.accountNum,
|
||||||
message: 'Please input account number',
|
message: "Please input account number",
|
||||||
checkNull: true
|
checkNull: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
if (!isEditMode.value) {
|
if (!isEditMode.value) {
|
||||||
requiredFields.push(
|
requiredFields.push(
|
||||||
{ value: formState.name, message: 'Please input the name' },
|
{ value: formState.name, message: "Please input the name" },
|
||||||
{ value: formState.organizationId, message: 'Please select organization' }
|
{ value: formState.organizationId, message: "Please select organization" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,7 +1096,7 @@ const handleSubmit = async () => {
|
|||||||
res = await Https.axiosPost(Https.httpUrls.createSubscribePlan, params)
|
res = await Https.axiosPost(Https.httpUrls.createSubscribePlan, params)
|
||||||
}
|
}
|
||||||
message.success(
|
message.success(
|
||||||
`${isEditMode.value ? 'Subscription plan updated' : 'Subscription plan created'}`
|
`${isEditMode.value ? "Subscription plan updated" : "Subscription plan created"}`
|
||||||
)
|
)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message)
|
message.error(error.message)
|
||||||
@@ -835,8 +1125,8 @@ const cancelModal = () => {
|
|||||||
const removePlan = (id: number) => {
|
const removePlan = (id: number) => {
|
||||||
tableLoading.value = true
|
tableLoading.value = true
|
||||||
Https.axiosGet(Https.httpUrls.deleteSubscribePlan, { params: { id } })
|
Https.axiosGet(Https.httpUrls.deleteSubscribePlan, { params: { id } })
|
||||||
.then(res => {
|
.then((res) => {
|
||||||
message.success('Subscription plan deleted')
|
message.success("Subscription plan deleted")
|
||||||
handleReset()
|
handleReset()
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
@@ -901,15 +1191,15 @@ const handleOrganizationScroll = (e: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleOrganizationSelect = (value: string) => {
|
const handleOrganizationSelect = (value: string) => {
|
||||||
if (value === 'ADD_ORGANIZATION') {
|
if (value === "ADD_ORGANIZATION") {
|
||||||
// 打开添加组织弹窗
|
// 打开添加组织弹窗
|
||||||
organizationModalVisible.value = true
|
organizationModalVisible.value = true
|
||||||
// 使用nextTick确保值被重置,使其不被选中
|
// 使用nextTick确保值被重置,使其不被选中
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (searchForm.organizationId === 'ADD_ORGANIZATION') {
|
if (searchForm.organizationId === "ADD_ORGANIZATION") {
|
||||||
searchForm.organizationId = undefined
|
searchForm.organizationId = undefined
|
||||||
}
|
}
|
||||||
if (formState.organizationId === 'ADD_ORGANIZATION') {
|
if (formState.organizationId === "ADD_ORGANIZATION") {
|
||||||
formState.organizationId = undefined
|
formState.organizationId = undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -918,12 +1208,12 @@ const handleOrganizationSelect = (value: string) => {
|
|||||||
|
|
||||||
const handleOrganizationChange = (value: string) => {
|
const handleOrganizationChange = (value: string) => {
|
||||||
// 如果change事件触发时值是"添加组织",立即重置
|
// 如果change事件触发时值是"添加组织",立即重置
|
||||||
if (value === 'ADD_ORGANIZATION') {
|
if (value === "ADD_ORGANIZATION") {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (searchForm.organizationId === 'ADD_ORGANIZATION') {
|
if (searchForm.organizationId === "ADD_ORGANIZATION") {
|
||||||
searchForm.organizationId = undefined
|
searchForm.organizationId = undefined
|
||||||
}
|
}
|
||||||
if (formState.organizationId === 'ADD_ORGANIZATION') {
|
if (formState.organizationId === "ADD_ORGANIZATION") {
|
||||||
formState.organizationId = undefined
|
formState.organizationId = undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -932,13 +1222,13 @@ const handleOrganizationChange = (value: string) => {
|
|||||||
|
|
||||||
const cancelOrganizationModal = () => {
|
const cancelOrganizationModal = () => {
|
||||||
organizationModalVisible.value = false
|
organizationModalVisible.value = false
|
||||||
organizationForm.name = ''
|
organizationForm.name = ""
|
||||||
organizationForm.type = undefined
|
organizationForm.type = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCreateOrganization = async () => {
|
const handleCreateOrganization = async () => {
|
||||||
if (!organizationForm.name || !organizationForm.type) {
|
if (!organizationForm.name || !organizationForm.type) {
|
||||||
message.warning('Please fill in name and type')
|
message.warning("Please fill in name and type")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -948,7 +1238,7 @@ const handleCreateOrganization = async () => {
|
|||||||
type: organizationForm.type
|
type: organizationForm.type
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
message.success('Organization created successfully')
|
message.success("Organization created successfully")
|
||||||
cancelOrganizationModal()
|
cancelOrganizationModal()
|
||||||
// 刷新组织列表
|
// 刷新组织列表
|
||||||
await getOrganizationList()
|
await getOrganizationList()
|
||||||
@@ -960,26 +1250,28 @@ const handleCreateOrganization = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message || 'Failed to create organization')
|
message.error(error.message || "Failed to create organization")
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterOption = (input: string, option: any) => {
|
const filterOption = (input: string, option: any) => {
|
||||||
const label = option?.label ?? option?.children ?? option?.key?.label ?? ''
|
const label = option?.label ?? option?.children ?? option?.key?.label ?? ""
|
||||||
return String(label).toLowerCase().includes(input.toLowerCase())
|
return String(label).toLowerCase().includes(input.toLowerCase())
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.subscription-plan {
|
.subscription-plan {
|
||||||
padding: 2rem 2.4rem 3.2rem 0;
|
padding: 2rem 2.4rem 0 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.search-card {
|
.search-card {
|
||||||
margin-bottom: 1.6rem;
|
margin-bottom: 1.6rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-card {
|
.table-card {
|
||||||
@@ -987,13 +1279,15 @@ const filterOption = (input: string, option: any) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
min-height: 0;
|
||||||
|
|
||||||
:deep(.ant-card-body) {
|
:deep(.ant-card-body) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 2.4rem;
|
padding: 2.4rem 2.4rem 0;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-card__header {
|
.table-card__header {
|
||||||
@@ -1007,6 +1301,42 @@ const filterOption = (input: string, option: any) => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
||||||
|
:deep(.ant-table-wrapper),
|
||||||
|
:deep(.ant-spin-nested-loading),
|
||||||
|
:deep(.ant-spin-container) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-container) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-container) {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-content) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-body) {
|
||||||
|
overflow-y: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-pagination) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.danger-text {
|
.danger-text {
|
||||||
@@ -1026,8 +1356,23 @@ const filterOption = (input: string, option: any) => {
|
|||||||
:deep(.ant-table-tbody > tr:hover > td) {
|
:deep(.ant-table-tbody > tr:hover > td) {
|
||||||
background: rgb(202, 202, 202);
|
background: rgb(202, 202, 202);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-tbody > tr) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.plan-row-actions) {
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info-modal {
|
||||||
|
:deep(.ant-modal-body) {
|
||||||
|
padding: 2.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.subscriptionPlan_modal) {
|
:deep(.subscriptionPlan_modal) {
|
||||||
.ant-modal-body {
|
.ant-modal-body {
|
||||||
// height: calc(65rem * 1.2);
|
// height: calc(65rem * 1.2);
|
||||||
@@ -1079,11 +1424,69 @@ const filterOption = (input: string, option: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.search-form) {
|
:deep(.search-form) {
|
||||||
column-gap: 2rem;
|
--search-label-width: 14rem;
|
||||||
row-gap: 2rem;
|
--search-control-width: 20rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
column-gap: 1.8rem;
|
||||||
|
row-gap: 1.8rem;
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
min-width: calc(var(--search-label-width) + var(--search-control-width));
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item-label {
|
||||||
|
flex: 0 0 var(--search-label-width);
|
||||||
|
max-width: var(--search-label-width);
|
||||||
|
overflow: visible;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item-control {
|
||||||
|
flex: 0 0 var(--search-control-width);
|
||||||
|
max-width: var(--search-control-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input,
|
||||||
|
.ant-input-affix-wrapper,
|
||||||
|
.ant-picker,
|
||||||
.ant-select {
|
.ant-select {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-form__actions {
|
||||||
|
min-width: auto;
|
||||||
|
|
||||||
|
.ant-form-item-control {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1600px) {
|
||||||
|
:deep(.search-form) {
|
||||||
|
--search-control-width: 22rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
:deep(.search-form) {
|
||||||
|
.ant-form-item {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item-control {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
max-width: calc(100% - var(--search-label-width));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-select-dropdown) {
|
:deep(.ant-select-dropdown) {
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ import {
|
|||||||
insertObjectAtZIndex,
|
insertObjectAtZIndex,
|
||||||
removeCanvasObjectByObject,
|
removeCanvasObjectByObject,
|
||||||
createPatternTransform,
|
createPatternTransform,
|
||||||
|
getTransformScaleAngle,
|
||||||
imageAddGapToCanvas,
|
imageAddGapToCanvas,
|
||||||
} from "../utils/helper";
|
} from "../utils/helper";
|
||||||
import { restoreFabricObject } from "../utils/objectHelper";
|
import { restoreFabricObject } from "../utils/objectHelper";
|
||||||
|
|
||||||
const scale = 0.3;// 默认缩放比例
|
|
||||||
|
|
||||||
export const FillSourceToBase64 = (source) => {
|
export const FillSourceToBase64 = (source) => {
|
||||||
if (source?.toDataURL) {
|
if (source?.toDataURL) {
|
||||||
return source.toDataURL?.();
|
return source.toDataURL?.();
|
||||||
@@ -39,7 +38,6 @@ export class FillRepeatCommand extends Command {
|
|||||||
this.fillRepeat = options.fillRepeat;
|
this.fillRepeat = options.fillRepeat;
|
||||||
this.oldObjects = null;
|
this.oldObjects = null;
|
||||||
this.oldLocked = null;
|
this.oldLocked = null;
|
||||||
this.oldIsDisableUnlock = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute() {
|
async execute() {
|
||||||
@@ -64,17 +62,15 @@ export class FillRepeatCommand extends Command {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
image.set({
|
image.set({
|
||||||
id: object.id,
|
...this.copyObjectProperties(object),
|
||||||
layerId: object.layerId,
|
|
||||||
layerName: object.layerName,
|
|
||||||
...(fill_.originalInfo || {
|
...(fill_.originalInfo || {
|
||||||
top: object.top,
|
top: object.top,
|
||||||
left: object.left,
|
left: object.left,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
|
||||||
this.oldLocked = layer.locked;
|
// this.oldLocked = layer.locked;
|
||||||
layer.locked = false;
|
// layer.locked = false;
|
||||||
|
|
||||||
this.canvas.add(image);
|
this.canvas.add(image);
|
||||||
this.canvas.remove(object);
|
this.canvas.remove(object);
|
||||||
@@ -113,23 +109,32 @@ export class FillRepeatCommand extends Command {
|
|||||||
const fdObject = this.canvasManager.getFixedLayerObject();
|
const fdObject = this.canvasManager.getFixedLayerObject();
|
||||||
const bgObject = this.canvasManager.getBackgroundLayerObject();
|
const bgObject = this.canvasManager.getBackgroundLayerObject();
|
||||||
const tObject = fdObject || bgObject;
|
const tObject = fdObject || bgObject;
|
||||||
|
const tWidth = tObject.width;
|
||||||
|
const tHeight = tObject.height;
|
||||||
|
|
||||||
|
// const offsetX = object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2;
|
||||||
|
// const offsetY = object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2;
|
||||||
|
const scaleX_ = tWidth / img.width / 5;
|
||||||
|
const scaleY_ = tHeight / img.height / 5;
|
||||||
|
const scale_ = tWidth > tHeight ? scaleX_ : scaleY_;
|
||||||
|
|
||||||
|
const patternTransform = object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale_, 0);
|
||||||
|
const scale = getTransformScaleAngle(patternTransform).scale;
|
||||||
|
const offsetX = tWidth / 2 - img.width * scale / 2;
|
||||||
|
const offsetY = tHeight / 2 - img.height * scale / 2;
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
source: img,
|
source: img,
|
||||||
repeat: this.fillRepeat,
|
repeat: this.fillRepeat,
|
||||||
patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0),
|
patternTransform,
|
||||||
offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2, // 水平偏移
|
offsetX, // 水平偏移
|
||||||
offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2, // 垂直偏移
|
offsetY, // 垂直偏移
|
||||||
});
|
});
|
||||||
const rect = new fabric.Rect({
|
const rect = new fabric.Rect({
|
||||||
id: object.id,
|
...this.copyObjectProperties(object),
|
||||||
layerId: object.layerId,
|
|
||||||
layerName: object.layerName,
|
|
||||||
fill_,
|
fill_,
|
||||||
});
|
});
|
||||||
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
|
||||||
this.oldLocked = layer.locked;
|
// this.oldLocked = layer.locked;
|
||||||
// this.oldIsDisableUnlock = layer.isDisableUnlock;
|
|
||||||
// layer.isDisableUnlock = true;
|
|
||||||
if (this.oldObjects.type === "rect") {
|
if (this.oldObjects.type === "rect") {
|
||||||
rect.set({
|
rect.set({
|
||||||
width: object.width,
|
width: object.width,
|
||||||
@@ -148,14 +153,14 @@ export class FillRepeatCommand extends Command {
|
|||||||
let scaleX = tObject.scaleX || 1;
|
let scaleX = tObject.scaleX || 1;
|
||||||
let scaleY = tObject.scaleY || 1;
|
let scaleY = tObject.scaleY || 1;
|
||||||
rect.set({
|
rect.set({
|
||||||
width: tObject.width,
|
width: tWidth,
|
||||||
height: tObject.height,
|
height: tHeight,
|
||||||
top: tObject.top - tObject.height * scaleY / 2,
|
top: tObject.top - tHeight * scaleY / 2,
|
||||||
left: tObject.left - tObject.width * scaleX / 2,
|
left: tObject.left - tWidth * scaleX / 2,
|
||||||
scaleX,
|
scaleX,
|
||||||
scaleY,
|
scaleY,
|
||||||
});
|
});
|
||||||
layer.locked = true;
|
// layer.locked = true;
|
||||||
}
|
}
|
||||||
rect.set("fill", pattern);
|
rect.set("fill", pattern);
|
||||||
this.canvas.add(rect);
|
this.canvas.add(rect);
|
||||||
@@ -184,14 +189,23 @@ export class FillRepeatCommand extends Command {
|
|||||||
this.canvas.remove(object);
|
this.canvas.remove(object);
|
||||||
this.canvas.add(this.oldObjects);
|
this.canvas.add(this.oldObjects);
|
||||||
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
|
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
|
||||||
layer.locked = this.oldLocked;
|
// layer.locked = this.oldLocked;
|
||||||
// layer.isDisableUnlock = this.oldIsDisableUnlock;
|
|
||||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||||
await this.layerManager?.sortLayersWithTool?.();
|
await this.layerManager?.sortLayersWithTool?.();
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
|
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 复制原对象的属性
|
||||||
|
copyObjectProperties(object) {
|
||||||
|
return {
|
||||||
|
id: object.id,
|
||||||
|
layerId: object.layerId,
|
||||||
|
layerName: object.layerName,
|
||||||
|
isPrintTrims: object.isPrintTrims,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -230,6 +244,10 @@ export class FillRepeatChangeCommand extends Command {
|
|||||||
...this.newPattern,
|
...this.newPattern,
|
||||||
});
|
});
|
||||||
object.set("fill", pattern);
|
object.set("fill", pattern);
|
||||||
|
if (object.globalCompositeOperation_) {
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -276,7 +294,7 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
this.oldGapY = null;
|
this.oldGapY = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(isUndo = false) {
|
async execute(isCommand = true, isUndo = false) {
|
||||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||||
console.warn("图层不存在或没有 fabric 对象");
|
console.warn("图层不存在或没有 fabric 对象");
|
||||||
@@ -315,6 +333,10 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
const fill = object.get("fill");
|
const fill = object.get("fill");
|
||||||
fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY);
|
fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY);
|
||||||
object.set("fill", new fabric.Pattern(fill));
|
object.set("fill", new fabric.Pattern(fill));
|
||||||
|
if (isCommand && object.globalCompositeOperation_) {
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -324,7 +346,7 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
console.warn("没有旧间隙可恢复");
|
console.warn("没有旧间隙可恢复");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await this.execute(true);
|
await this.execute(true, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -280,8 +280,13 @@ export class PasteLayerCommand extends Command {
|
|||||||
isCut: undefined,
|
isCut: undefined,
|
||||||
serializedObjects: undefined,
|
serializedObjects: undefined,
|
||||||
};
|
};
|
||||||
|
if(this.newLayer.isPrintTrims){
|
||||||
if (this.insertIndex !== undefined && this.insertIndex !== null) {
|
this.layers.value.forEach((layer) => {
|
||||||
|
if (layer.isPrintTrimsGroup) {
|
||||||
|
layer.children.unshift(this.newLayer);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else if (this.insertIndex !== undefined && this.insertIndex !== null) {
|
||||||
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
|
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
|
||||||
} else {
|
} else {
|
||||||
this.layers.value.push(this.newLayer);
|
this.layers.value.push(this.newLayer);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class TransformCommand extends Command {
|
|||||||
this.layerManager = options.layerManager;
|
this.layerManager = options.layerManager;
|
||||||
this.layers = options.layers || null;
|
this.layers = options.layers || null;
|
||||||
this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID
|
this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID
|
||||||
|
this.isCommand = options.isCommand == undefined ? true : options.isCommand
|
||||||
const targetObject =
|
const targetObject =
|
||||||
findObjectById(this.canvas, this.objectId)?.object || null;
|
findObjectById(this.canvas, this.objectId)?.object || null;
|
||||||
|
|
||||||
@@ -189,6 +189,11 @@ export class TransformCommand extends Command {
|
|||||||
object.set(key, value);
|
object.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.isCommand && object.globalCompositeOperation_){
|
||||||
|
object.globalCompositeOperation = object.globalCompositeOperation_;
|
||||||
|
object.globalCompositeOperation_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 确保对象更新
|
// 确保对象更新
|
||||||
object.setCoords();
|
object.setCoords();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,8 +132,8 @@
|
|||||||
const offsetY = object.fill?.offsetY;
|
const offsetY = object.fill?.offsetY;
|
||||||
const twidth = object.fill_?.width;
|
const twidth = object.fill_?.width;
|
||||||
const theight = object.fill_?.height;
|
const theight = object.fill_?.height;
|
||||||
const x = ((offsetX - (twidth * scale) / 2) * 100) / object.width;
|
const x = ((offsetX + (twidth * scale) / 2) * 100) / object.width;
|
||||||
const y = ((offsetY - (theight * scale) / 2) * 100) / object.height;
|
const y = ((offsetY + (theight * scale) / 2) * 100) / object.height;
|
||||||
return { x, y };
|
return { x, y };
|
||||||
});
|
});
|
||||||
const inputFillOffset = (e) => setFillOffset(e, true);
|
const inputFillOffset = (e) => setFillOffset(e, true);
|
||||||
@@ -143,8 +143,8 @@
|
|||||||
const object = props.object;
|
const object = props.object;
|
||||||
const patternTransform = object.fill?.patternTransform;
|
const patternTransform = object.fill?.patternTransform;
|
||||||
const scale = getTransformScaleAngle(patternTransform).scale;
|
const scale = getTransformScaleAngle(patternTransform).scale;
|
||||||
const x = (left / 100) * object.width + (object.fill_?.width * scale) / 2;
|
const x = (left / 100) * object.width - (object.fill_?.width * scale) / 2;
|
||||||
const y = (top / 100) * object.height + (object.fill_?.height * scale) / 2;
|
const y = (top / 100) * object.height - (object.fill_?.height * scale) / 2;
|
||||||
emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y });
|
emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y });
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -126,8 +126,8 @@
|
|||||||
:options="selectOptions"
|
:options="selectOptions"
|
||||||
@change="(e) => changeFillRepeat(e, v)"
|
@change="(e) => changeFillRepeat(e, v)"
|
||||||
:disabled="
|
:disabled="
|
||||||
v.layer?.metadata?.level2Type ===
|
v.layer?.metadata?.sourceData?.type ===
|
||||||
'Embroidery'
|
'trims'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -315,6 +315,7 @@
|
|||||||
layerManager: props.layerManager,
|
layerManager: props.layerManager,
|
||||||
layers: layers,
|
layers: layers,
|
||||||
lastSelectLayerId: lastSelectLayerId,
|
lastSelectLayerId: lastSelectLayerId,
|
||||||
|
isCommand,
|
||||||
});
|
});
|
||||||
if (isCommand) {
|
if (isCommand) {
|
||||||
props.commandManager.execute(cmd);
|
props.commandManager.execute(cmd);
|
||||||
@@ -336,6 +337,7 @@
|
|||||||
const finalState = computeAngleState(angle, obj, initialState);
|
const finalState = computeAngleState(angle, obj, initialState);
|
||||||
transformObject(obj, initialState, finalState, false);
|
transformObject(obj, initialState, finalState, false);
|
||||||
if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState;
|
if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState;
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeAngle = (angle, obj) => {
|
const changeAngle = (angle, obj) => {
|
||||||
var initialState;
|
var initialState;
|
||||||
@@ -428,6 +430,7 @@
|
|||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillAngle = (angle, obj) => {
|
const changeFillAngle = (angle, obj) => {
|
||||||
const fill = obj.get("fill");
|
const fill = obj.get("fill");
|
||||||
@@ -447,6 +450,7 @@
|
|||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillOffset = (value, obj) => {
|
const changeFillOffset = (value, obj) => {
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
@@ -466,6 +470,7 @@
|
|||||||
});
|
});
|
||||||
obj.set("fill", pattern);
|
obj.set("fill", pattern);
|
||||||
props.canvas.renderAll();
|
props.canvas.renderAll();
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillScale = (scale, obj) => {
|
const changeFillScale = (scale, obj) => {
|
||||||
const fill = obj.get("fill");
|
const fill = obj.get("fill");
|
||||||
@@ -498,7 +503,8 @@
|
|||||||
newGapY: gapY,
|
newGapY: gapY,
|
||||||
record: true,
|
record: true,
|
||||||
});
|
});
|
||||||
cmd.execute();
|
cmd.execute(false);
|
||||||
|
props.canvasManager.beforeChangeCanvas([obj]);
|
||||||
};
|
};
|
||||||
const changeFillGap = (gapX, gapY, obj) => {
|
const changeFillGap = (gapX, gapY, obj) => {
|
||||||
if (obj.oldFill_) {
|
if (obj.oldFill_) {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ commandManager.setChangeCallback((info) => {
|
|||||||
emit("undo-redo-status-changed", {
|
emit("undo-redo-status-changed", {
|
||||||
canUndo: canUndo.value,
|
canUndo: canUndo.value,
|
||||||
canRedo: canRedo.value,
|
canRedo: canRedo.value,
|
||||||
|
type: info.type,
|
||||||
commandManager,
|
commandManager,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ export class BrushIndicator {
|
|||||||
// this.show(e.e);
|
// this.show(e.e);
|
||||||
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
||||||
} else {
|
} else {
|
||||||
// requestIdleCallback(() => {
|
// setTimeout(() => {
|
||||||
// this.updatePosition(e.e);
|
// this.updatePosition(e.e);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
isGroupLayer,
|
isGroupLayer,
|
||||||
OperationType,
|
OperationType,
|
||||||
OperationTypes,
|
OperationTypes,
|
||||||
findLayer,
|
|
||||||
createLayer,
|
createLayer,
|
||||||
LayerType,
|
LayerType,
|
||||||
SpecialLayerId,
|
SpecialLayerId,
|
||||||
@@ -20,7 +19,6 @@ import { AnimationManager } from "./animation/AnimationManager";
|
|||||||
import { createCanvas } from "../utils/canvasFactory";
|
import { createCanvas } from "../utils/canvasFactory";
|
||||||
import { CanvasEventManager } from "./events/CanvasEventManager";
|
import { CanvasEventManager } from "./events/CanvasEventManager";
|
||||||
import CanvasConfig from "../config/canvasConfig";
|
import CanvasConfig from "../config/canvasConfig";
|
||||||
import { RedGreenModeManager } from "./RedGreenModeManager";
|
|
||||||
import { EraserStateManager } from "./EraserStateManager";
|
import { EraserStateManager } from "./EraserStateManager";
|
||||||
import {
|
import {
|
||||||
deepClone,
|
deepClone,
|
||||||
@@ -74,6 +72,7 @@ export class CanvasManager {
|
|||||||
this.props = options.props || {};
|
this.props = options.props || {};
|
||||||
this.emit = options.emit || (() => { });
|
this.emit = options.emit || (() => { });
|
||||||
this.awaitCanvasRun = null;
|
this.awaitCanvasRun = null;
|
||||||
|
this.canvasChangeing = false;
|
||||||
// 初始化画布
|
// 初始化画布
|
||||||
this.initializeCanvas();
|
this.initializeCanvas();
|
||||||
}
|
}
|
||||||
@@ -338,6 +337,7 @@ export class CanvasManager {
|
|||||||
setupCanvasEvents(activeElementId, layerManager) {
|
setupCanvasEvents(activeElementId, layerManager) {
|
||||||
// 创建画布事件管理器
|
// 创建画布事件管理器
|
||||||
this.eventManager = new CanvasEventManager(this.canvas, {
|
this.eventManager = new CanvasEventManager(this.canvas, {
|
||||||
|
canvasManager: this,
|
||||||
toolManager: this.toolManager,
|
toolManager: this.toolManager,
|
||||||
animationManager: this.animationManager,
|
animationManager: this.animationManager,
|
||||||
thumbnailManager: this.thumbnailManager,
|
thumbnailManager: this.thumbnailManager,
|
||||||
@@ -623,17 +623,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
this.updateMaskPosition(backgroundObject);
|
this.updateMaskPosition(backgroundObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新颜色层信息
|
this.setSpecialCliptInfo(false, true)
|
||||||
// const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
|
||||||
// if(colorObject){
|
|
||||||
// await this.setObjecCliptInfo(colorObject);
|
|
||||||
// }
|
|
||||||
const groupLayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
|
||||||
if(groupLayer){
|
|
||||||
const groupRect = new fabric.Rect({});
|
|
||||||
await this.setObjecCliptInfo(groupRect);
|
|
||||||
groupLayer.clippingMask = groupRect.toObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新渲染画布
|
// 重新渲染画布
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
@@ -868,9 +858,9 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
|
|
||||||
return layerObjectByLayerId;
|
return layerObjectByLayerId;
|
||||||
}
|
}
|
||||||
getObjectsByIds(ids){
|
getObjectsByIdOrLayerId(ids) {
|
||||||
const objects = this.canvas.getObjects().filter((obj) => {
|
const objects = this.canvas.getObjects().filter((obj) => {
|
||||||
return ids.includes(obj.id);
|
return ids.includes(obj.id) || ids.includes(obj.layerId);
|
||||||
});
|
});
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
@@ -1147,7 +1137,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
||||||
if (!glayer) return Promise.reject("印花和元素图层组不存在");
|
if (!glayer) return Promise.reject("印花和元素图层组不存在");
|
||||||
const ids = glayer.children.map((v) => v.id);
|
const ids = glayer.children.map((v) => v.id);
|
||||||
const objects = this.getObjectsByIds(ids);
|
const objects = this.getObjectsByIdOrLayerId(ids);
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
if (!fixedLayerObj) return Promise.reject("固定图层不存在");
|
if (!fixedLayerObj) return Promise.reject("固定图层不存在");
|
||||||
const flWidth = fixedLayerObj.width
|
const flWidth = fixedLayerObj.width
|
||||||
@@ -1158,8 +1148,9 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
const flScaleY = fixedLayerObj.scaleY
|
const flScaleY = fixedLayerObj.scaleY
|
||||||
const prints = [];
|
const prints = [];
|
||||||
const trims = [];
|
const trims = [];
|
||||||
objects.forEach((v) => {
|
objects.forEach((v, i) => {
|
||||||
const sourceData = glayer.children.find((v_) => v_.id === v.id)?.metadata?.sourceData;
|
const label = glayer.children.find((v_) => (v_.id === v.layerId || v_.id === v.id));
|
||||||
|
const sourceData = label?.metadata?.sourceData;
|
||||||
if (!sourceData) return;
|
if (!sourceData) return;
|
||||||
const obj = {
|
const obj = {
|
||||||
ifSingle: typeof v.fill === "string",
|
ifSingle: typeof v.fill === "string",
|
||||||
@@ -1171,7 +1162,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
scale: [0, 0],
|
scale: [0, 0],
|
||||||
angle: v.angle,
|
angle: v.angle,
|
||||||
name: sourceData.name,
|
name: sourceData.name,
|
||||||
priority: sourceData.priority,
|
priority: i + 1,
|
||||||
object: {
|
object: {
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -1220,8 +1211,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
let scaleY = scale * 5 * v.fill_.height / flHeight;
|
let scaleY = scale * 5 * v.fill_.height / flHeight;
|
||||||
let scaleXY = flWidth > flHeight ? scaleX : scaleY;
|
let scaleXY = flWidth > flHeight ? scaleX : scaleY;
|
||||||
|
|
||||||
let left = fill.offsetX - v.fill_.width * scale / 2;
|
let left = fill.offsetX + v.fill_.width * scale / 2;
|
||||||
let top = fill.offsetY - v.fill_.height * scale / 2;
|
let top = fill.offsetY + v.fill_.height * scale / 2;
|
||||||
|
|
||||||
obj.scale = [scaleXY, scaleXY];
|
obj.scale = [scaleXY, scaleXY];
|
||||||
obj.angle = angle;
|
obj.angle = angle;
|
||||||
@@ -1237,8 +1228,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
|
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
|
||||||
prints.forEach((v, i) => v.priority = i + 1);
|
// prints.forEach((v, i) => v.priority = i + 1);
|
||||||
trims.forEach((v, i) => v.priority = i + 1);
|
// trims.forEach((v, i) => v.priority = i + 1);
|
||||||
return { prints, trims };
|
return { prints, trims };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1334,7 +1325,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadJSON(json, calllBack) {
|
loadJSON(json, calllBack) {
|
||||||
|
this.canvas.loading.value = true;
|
||||||
// 确保传入的json是字符串格式
|
// 确保传入的json是字符串格式
|
||||||
if (typeof json === "object") {
|
if (typeof json === "object") {
|
||||||
json = JSON.stringify(json);
|
json = JSON.stringify(json);
|
||||||
@@ -1465,9 +1456,12 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
}
|
}
|
||||||
/** 修复JSON数据中的ID丢失问题 */
|
/** 修复JSON数据中的ID丢失问题 */
|
||||||
FixJsonIdLoss(json) {
|
FixJsonIdLoss(json) {
|
||||||
|
const layerIds = [];
|
||||||
const layers = json?.layers || [];
|
const layers = json?.layers || [];
|
||||||
const objects = json?.canvas?.objects || [];
|
const objects = json?.canvas?.objects || [];
|
||||||
layers.forEach((layer) => {
|
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);
|
const obj = objects?.find((o) => o.layerId === layer.id);
|
||||||
if (obj) {
|
if (obj) {
|
||||||
@@ -1483,6 +1477,17 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
if (a.isBackground) return -1;
|
if (a.isBackground) return -1;
|
||||||
if (b.isBackground) return 1;
|
if (b.isBackground) return 1;
|
||||||
})
|
})
|
||||||
|
// 排除的对象id
|
||||||
|
const excludedObjects = [SpecialLayerId.PART_SELECTOR];
|
||||||
|
json.canvas.objects = objects.filter((v) => {
|
||||||
|
// 指定ID排除
|
||||||
|
if (excludedObjects.includes(v.id)) return false;
|
||||||
|
|
||||||
|
if (v.isBackground || v.isFixed) return true;
|
||||||
|
// 当前图层不存在当前对象
|
||||||
|
if (!layerIds.includes(v.layerId)) return false;
|
||||||
|
return true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1490,25 +1495,15 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
* 创建其他图层:印花、颜色、元素...
|
* 创建其他图层:印花、颜色、元素...
|
||||||
* @param {Object} otherData - 其他图层数据
|
* @param {Object} otherData - 其他图层数据
|
||||||
*/
|
*/
|
||||||
async createOtherLayers(otherData, isUpdate = false) {
|
async createOtherLayers(otherData) {
|
||||||
if (!otherData) return console.warn("otherData 为空不需要添加");
|
if (!otherData) return console.warn("otherData 为空不需要添加");
|
||||||
this.canvas.loading.value = true;
|
|
||||||
let resolve = () => { };
|
let resolve = () => { };
|
||||||
this.awaitCanvasRun = () => (new Promise((v) => resolve = v))
|
this.awaitCanvasRun = () => (new Promise((v) => resolve = v))
|
||||||
const otherData_ = JSON.parse(JSON.stringify(otherData));
|
const otherData_ = JSON.parse(JSON.stringify(otherData));
|
||||||
console.log("==========创建其他图层", otherData_);
|
console.log("==========创建其他图层", otherData_);
|
||||||
|
|
||||||
const updateColor = !!otherData_.color;
|
|
||||||
const updateSpecialGroup = !!otherData_.printObject || !!otherData_.trims;
|
|
||||||
// 删除颜色图层和特殊组图层
|
// 删除颜色图层和特殊组图层
|
||||||
const ids = [];
|
const ids = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
|
||||||
if(isUpdate){
|
|
||||||
updateColor && ids.push(SpecialLayerId.COLOR)
|
|
||||||
updateSpecialGroup && ids.push(SpecialLayerId.SPECIAL_GROUP)
|
|
||||||
}else{
|
|
||||||
ids.push(SpecialLayerId.COLOR)
|
|
||||||
ids.push(SpecialLayerId.SPECIAL_GROUP)
|
|
||||||
}
|
|
||||||
this.layers.value = this.layers.value.filter((layer) => {
|
this.layers.value = this.layers.value.filter((layer) => {
|
||||||
if (ids.includes(layer.id)) {
|
if (ids.includes(layer.id)) {
|
||||||
ids.push(...layer.children?.map((child) => child.id));
|
ids.push(...layer.children?.map((child) => child.id));
|
||||||
@@ -1516,11 +1511,15 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
this.canvas.getObjects().forEach((v) => ids.includes(v.id) && this.canvas.remove(v))
|
this.canvas.getObjects().forEach((v) => {
|
||||||
|
if (ids.includes(v.id) || ids.includes(v.layerId)) {
|
||||||
|
this.canvas.remove(v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// 创建颜色图层
|
// 创建颜色图层
|
||||||
otherData_.color && await this.createColorLayer(otherData_.color);
|
await this.createColorLayer(otherData_.color);
|
||||||
|
|
||||||
const printTrimsLayers = [];// 印花和元素图层
|
const printTrimsLayers = [];// 印花和元素图层
|
||||||
const singleLayers = [];// 平铺图层
|
const singleLayers = [];// 平铺图层
|
||||||
@@ -1538,16 +1537,35 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
trims.type = "trims";
|
trims.type = "trims";
|
||||||
printTrimsLayers.unshift({ ...trims });
|
printTrimsLayers.unshift({ ...trims });
|
||||||
})
|
})
|
||||||
if(isUpdate ? updateSpecialGroup : true){
|
if (printTrimsLayers.length || singleLayers.length) {
|
||||||
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
|
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
|
||||||
}
|
}
|
||||||
await this.changeCanvas();
|
await this.changeCanvas();
|
||||||
console.log("==========创建其他图层成功");
|
console.log("==========创建其他图层成功");
|
||||||
resolve();
|
resolve();
|
||||||
this.awaitCanvasRun = null;
|
this.awaitCanvasRun = null;
|
||||||
this.canvas.loading.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置印花元素颜色的裁剪信息
|
||||||
|
async setSpecialCliptInfo(isColor = true, isGroup = true) {
|
||||||
|
// 更新颜色层信息
|
||||||
|
if (isColor) {
|
||||||
|
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||||
|
if (colorObject) {
|
||||||
|
await this.setObjecCliptInfo(colorObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 更新特殊组图层信息
|
||||||
|
if (isGroup) {
|
||||||
|
const groupLayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
|
||||||
|
if (groupLayer) {
|
||||||
|
const groupRect = new fabric.Rect({});
|
||||||
|
await this.setObjecCliptInfo(groupRect);
|
||||||
|
groupLayer.clippingMask = groupRect.toObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 设置画布对象的裁剪信息
|
// 设置画布对象的裁剪信息
|
||||||
async setObjecCliptInfo(tagObject, data) {
|
async setObjecCliptInfo(tagObject, data) {
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
@@ -1669,8 +1687,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
let opacity = 1
|
let opacity = 1
|
||||||
let flipX = false;
|
let flipX = false;
|
||||||
let flipY = false;
|
let flipY = false;
|
||||||
let blendMode = BlendMode.MULTIPLY;
|
let blendMode = BlendMode.NORMAL;
|
||||||
if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常
|
// if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常
|
||||||
if (item.object) {
|
if (item.object) {
|
||||||
opacity = item.object.opacity
|
opacity = item.object.opacity
|
||||||
flipX = item.object.flipX
|
flipX = item.object.flipX
|
||||||
@@ -1695,7 +1713,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
hasBorders: true,
|
hasBorders: true,
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
});
|
});
|
||||||
this.canvas.add(image);
|
// this.canvas.add(image);
|
||||||
let layer = createLayer({
|
let layer = createLayer({
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
@@ -1706,7 +1724,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
blendMode: blendMode,
|
blendMode: blendMode,
|
||||||
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: {sourceData: item, level2Type: item.level2Type},
|
metadata: { sourceData: item },
|
||||||
|
object: image,
|
||||||
})
|
})
|
||||||
children.push(layer);
|
children.push(layer);
|
||||||
};
|
};
|
||||||
@@ -1730,8 +1749,8 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
let scaleX_ = flWidth / image.width * (item.scale?.[0] || 1) / 5;
|
let scaleX_ = flWidth / image.width * (item.scale?.[0] || 1) / 5;
|
||||||
let scaleY_ = flHeight / image.height * (item.scale?.[1] || 1) / 5;
|
let scaleY_ = flHeight / image.height * (item.scale?.[1] || 1) / 5;
|
||||||
let scale = flWidth > flHeight ? scaleX_ : scaleY_;
|
let scale = flWidth > flHeight ? scaleX_ : scaleY_;
|
||||||
let offsetX = (item.location?.[0] || 0) + image.width * scale / 2
|
let offsetX = (item.location?.[0] || 0) - image.width * scale / 2
|
||||||
let offsetY = (item.location?.[1] || 0) + image.height * scale / 2
|
let offsetY = (item.location?.[1] || 0) - image.height * scale / 2
|
||||||
let top = flTop - flHeight * flScaleY / 2
|
let top = flTop - flHeight * flScaleY / 2
|
||||||
let left = flLeft - flWidth * flScaleX / 2
|
let left = flLeft - flWidth * flScaleX / 2
|
||||||
let scaleX = flScaleX
|
let scaleX = flScaleX
|
||||||
@@ -1743,7 +1762,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
let fillSource = image
|
let fillSource = image
|
||||||
let flipX = false;
|
let flipX = false;
|
||||||
let flipY = false;
|
let flipY = false;
|
||||||
let blendMode = BlendMode.MULTIPLY;
|
let blendMode = BlendMode.NORMAL;
|
||||||
let fill_repeat = "repeat"
|
let fill_repeat = "repeat"
|
||||||
if (item.object) {
|
if (item.object) {
|
||||||
top += item.object.top * flScaleY
|
top += item.object.top * flScaleY
|
||||||
@@ -1754,7 +1773,7 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
angle = item.object.angle
|
angle = item.object.angle
|
||||||
flipX = item.object.flipX
|
flipX = item.object.flipX
|
||||||
flipY = item.object.flipY
|
flipY = item.object.flipY
|
||||||
blendMode = item.object.blendMode || BlendMode.MULTIPLY;
|
if (item.object.blendMode) blendMode = item.object.blendMode;
|
||||||
gapX = item.object.gapX
|
gapX = item.object.gapX
|
||||||
gapY = item.object.gapY
|
gapY = item.object.gapY
|
||||||
fillSource = imageAddGapToCanvas(image, gapX, gapY);
|
fillSource = imageAddGapToCanvas(image, gapX, gapY);
|
||||||
@@ -1791,18 +1810,19 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
},
|
},
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
});
|
});
|
||||||
this.canvas.add(rect);
|
// this.canvas.add(rect);
|
||||||
let layer = createLayer({
|
let layer = createLayer({
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
type: LayerType.BITMAP,
|
type: LayerType.BITMAP,
|
||||||
visible: true,
|
visible: true,
|
||||||
locked: true,
|
locked: false,
|
||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
isPrintTrims: true,
|
isPrintTrims: true,
|
||||||
blendMode: BlendMode.MULTIPLY,
|
blendMode: blendMode,
|
||||||
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: { sourceData: item },
|
metadata: { sourceData: item },
|
||||||
|
object: rect,
|
||||||
})
|
})
|
||||||
children.push(layer);
|
children.push(layer);
|
||||||
};
|
};
|
||||||
@@ -1819,6 +1839,13 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
// children.push(layer);
|
// children.push(layer);
|
||||||
// }
|
// }
|
||||||
if (children.length === 0) return;
|
if (children.length === 0) return;
|
||||||
|
// 印花元素排序
|
||||||
|
if (new Set(children.map(v => v.metadata.sourceData.priority)).size === children.length) {
|
||||||
|
children.sort((a, b) => b.metadata.sourceData.priority - a.metadata.sourceData.priority);
|
||||||
|
}
|
||||||
|
children.forEach(layer => {
|
||||||
|
this.canvas.add(layer.object);
|
||||||
|
});
|
||||||
const groupRect = new fabric.Rect({});
|
const groupRect = new fabric.Rect({});
|
||||||
await this.setObjecCliptInfo(groupRect);
|
await this.setObjecCliptInfo(groupRect);
|
||||||
// 插入组图层
|
// 插入组图层
|
||||||
@@ -1841,12 +1868,13 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
/**
|
/**
|
||||||
* 画布事件变更后
|
* 画布事件变更后
|
||||||
*/
|
*/
|
||||||
async changeCanvas(){
|
async changeCanvas(fids = [], isBeforeChange = false) {
|
||||||
|
if (!isBeforeChange) this.canvasChangeing = false;
|
||||||
const fixedLayerObj = this.getFixedLayerObject();
|
const fixedLayerObj = this.getFixedLayerObject();
|
||||||
if (!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
|
if (!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
|
||||||
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
|
||||||
if (colorObject) {
|
if (colorObject) {
|
||||||
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP);
|
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP).filter(id => !fids.includes(id));
|
||||||
if (ids.length === 0) {
|
if (ids.length === 0) {
|
||||||
ids.unshift(SpecialLayerId.SPECIAL_GROUP);
|
ids.unshift(SpecialLayerId.SPECIAL_GROUP);
|
||||||
await this.setObjecCliptInfo(colorObject);
|
await this.setObjecCliptInfo(colorObject);
|
||||||
@@ -1866,6 +1894,24 @@ backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
|
|||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 画布变更之前 */
|
||||||
|
async beforeChangeCanvas(objects) {
|
||||||
|
if (this.canvasChangeing) return;
|
||||||
|
const ids = objects.filter(v => {
|
||||||
|
return v.isPrintTrims && v.globalCompositeOperation && v.globalCompositeOperation !== BlendMode.NORMAL
|
||||||
|
}).map(v => v.layerId);
|
||||||
|
if (ids.length > 0) {
|
||||||
|
this.canvasChangeing = true;
|
||||||
|
this.canvas.getObjects().forEach(v => {
|
||||||
|
if (ids.includes(v.layerId)) {
|
||||||
|
v.globalCompositeOperation_ = v.globalCompositeOperation;
|
||||||
|
v.globalCompositeOperation = BlendMode.NORMAL;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.canvas.renderAll();
|
||||||
|
await this.changeCanvas(ids, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缩放红绿图模式内容以适应当前画布大小
|
* 缩放红绿图模式内容以适应当前画布大小
|
||||||
|
|||||||
@@ -606,7 +606,9 @@ export class ExportManager {
|
|||||||
imageSmoothingEnabled: true,
|
imageSmoothingEnabled: true,
|
||||||
});
|
});
|
||||||
// tempFabricCanvas.setZoom(1);
|
// tempFabricCanvas.setZoom(1);
|
||||||
console.log("==========", fixedLayerObject)
|
const ox = fixedLayerObject.left - fixedLayerObject.width * fixedLayerObject.scaleX / 2
|
||||||
|
const oy = fixedLayerObject.top - fixedLayerObject.height * fixedLayerObject.scaleY / 2
|
||||||
|
// console.log("==========", fixedLayerObject, ox, oy)
|
||||||
try {
|
try {
|
||||||
// 克隆并添加所有对象到临时画布,需要调整位置相对于固定图层
|
// 克隆并添加所有对象到临时画布,需要调整位置相对于固定图层
|
||||||
for (let i = 0; i < objectsToExport.length; i++) {
|
for (let i = 0; i < objectsToExport.length; i++) {
|
||||||
@@ -616,15 +618,20 @@ export class ExportManager {
|
|||||||
restoreOpacityInRedGreen && true
|
restoreOpacityInRedGreen && true
|
||||||
);
|
);
|
||||||
if (cloned) {
|
if (cloned) {
|
||||||
|
let scaleX = cloned.scaleX / fixedLayerObject.scaleX
|
||||||
|
let scaleY = cloned.scaleY / fixedLayerObject.scaleY
|
||||||
|
let top = (cloned.top - oy) * scaleY
|
||||||
|
let left = (cloned.left - ox) * scaleX
|
||||||
|
if (cloned.originX === "center" && cloned.originY === "center") {
|
||||||
|
top = canvasHeight / 2
|
||||||
|
left = canvasWidth / 2
|
||||||
|
}
|
||||||
cloned.set({
|
cloned.set({
|
||||||
left: canvasWidth / 2,
|
left: left,
|
||||||
top: canvasHeight / 2,
|
top: top,
|
||||||
scaleX: cloned.scaleX / fixedLayerObject.scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: cloned.scaleY / fixedLayerObject.scaleY,
|
scaleY: scaleY,
|
||||||
originX: "center",
|
|
||||||
originY: "center",
|
|
||||||
});
|
});
|
||||||
console.log("==========", {...cloned})
|
|
||||||
// 更新对象坐标
|
// 更新对象坐标
|
||||||
cloned.setCoords();
|
cloned.setCoords();
|
||||||
tempFabricCanvas.add(cloned);
|
tempFabricCanvas.add(cloned);
|
||||||
|
|||||||
@@ -1580,7 +1580,7 @@ export class LayerManager {
|
|||||||
/**
|
/**
|
||||||
* 排序图层,确保图层顺序: 普通图层 > 固定图层 > 背景图层
|
* 排序图层,确保图层顺序: 普通图层 > 固定图层 > 背景图层
|
||||||
*/
|
*/
|
||||||
sortLayers() {
|
async sortLayers() {
|
||||||
// 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间
|
// 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间
|
||||||
this.layers.value.sort((a, b) => {
|
this.layers.value.sort((a, b) => {
|
||||||
// 如果a是背景图层,它应该排在后面(最底层)
|
// 如果a是背景图层,它应该排在后面(最底层)
|
||||||
@@ -1604,17 +1604,17 @@ export class LayerManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 更新画布对象顺序
|
// 更新画布对象顺序
|
||||||
this._rearrangeObjects();
|
await this._rearrangeObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重新排列画布上的对象以匹配图层顺序
|
* 重新排列画布上的对象以匹配图层顺序
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_rearrangeObjects() {
|
async _rearrangeObjects() {
|
||||||
if (this.layerSort) {
|
if (this.layerSort) {
|
||||||
// 使用LayerSort的高级排序
|
// 使用LayerSort的高级排序
|
||||||
this.layerSort.rearrangeObjects();
|
await this.layerSort.rearrangeObjects();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1750,7 +1750,7 @@ export class LayerManager {
|
|||||||
layer.serializedObjects = layer.fabricObjects
|
layer.serializedObjects = layer.fabricObjects
|
||||||
.map((obj) => {
|
.map((obj) => {
|
||||||
if (typeof obj.toObject === "function") {
|
if (typeof obj.toObject === "function") {
|
||||||
return obj.toObject(["id", "layerId", "layerName"]);
|
return obj.toObject(["id", "layerId", "layerName", "fill_"]);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
@@ -1763,7 +1763,7 @@ export class LayerManager {
|
|||||||
if (layer.fabricObject) {
|
if (layer.fabricObject) {
|
||||||
layer.serializedBackgroundObject =
|
layer.serializedBackgroundObject =
|
||||||
typeof layer.fabricObject.toObject === "function"
|
typeof layer.fabricObject.toObject === "function"
|
||||||
? layer.fabricObject.toObject(["id", "layerId", "layerName"])
|
? layer.fabricObject.toObject(["id", "layerId", "layerName", "fill_"])
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
delete layer.fabricObject;
|
delete layer.fabricObject;
|
||||||
@@ -1793,7 +1793,7 @@ export class LayerManager {
|
|||||||
return layer.fabricObjects
|
return layer.fabricObjects
|
||||||
.map((obj) => {
|
.map((obj) => {
|
||||||
const { object } = findObjectById(this.canvas, obj.id);
|
const { object } = findObjectById(this.canvas, obj.id);
|
||||||
if (object) return object.toObject(["id", "layerId", "layerName"]);
|
if (object) return object.toObject(["id", "layerId", "layerName", "fill_"]);
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -1839,6 +1839,7 @@ export class LayerManager {
|
|||||||
|
|
||||||
// 存储到剪贴板
|
// 存储到剪贴板
|
||||||
this.clipboardData = layerCopy;
|
this.clipboardData = layerCopy;
|
||||||
|
console.log("复制图层:", layerCopy);
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.value = "aida_copy_canvas_layer: " + layer.name;
|
input.value = "aida_copy_canvas_layer: " + layer.name;
|
||||||
document.body.appendChild(input);
|
document.body.appendChild(input);
|
||||||
@@ -1884,7 +1885,7 @@ export class LayerManager {
|
|||||||
layerCopy.serializedObjects = layer.fabricObjects
|
layerCopy.serializedObjects = layer.fabricObjects
|
||||||
.map((obj) =>
|
.map((obj) =>
|
||||||
typeof obj.toObject === "function"
|
typeof obj.toObject === "function"
|
||||||
? obj.toObject(["id", "layerId", "layerName"])
|
? obj.toObject(["id", "layerId", "layerName", "fill_"])
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -1935,10 +1936,6 @@ export class LayerManager {
|
|||||||
return this.clipboardData;
|
return this.clipboardData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 粘贴图层
|
|
||||||
* @returns {string} 新创建的图层ID
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* 粘贴图层
|
* 粘贴图层
|
||||||
* @returns {string} 新创建的图层ID
|
* @returns {string} 新创建的图层ID
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { fabric } from "fabric-with-all";
|
import { fabric } from "fabric-with-all";
|
||||||
import { traceImageContour, imageToCanvas } from "../utils/helper";
|
import { traceImageContour, imageToCanvas } from "../utils/helper";
|
||||||
import { OperationType } from "../utils/layerHelper";
|
import { OperationType, SpecialLayerId } from "../utils/layerHelper";
|
||||||
import { LassoCutoutCommand } from "../commands/LassoCutoutCommand";
|
import { LassoCutoutCommand } from "../commands/LassoCutoutCommand";
|
||||||
import addIcon from "@/assets/images/canvas/add.png";
|
import addIcon from "@/assets/images/canvas/add.png";
|
||||||
import removeIcon from "@/assets/images/canvas/remove.png";
|
import removeIcon from "@/assets/images/canvas/remove.png";
|
||||||
@@ -72,7 +72,7 @@ export class PartManager {
|
|||||||
this.activeTool = this.toolManager.activeTool;
|
this.activeTool = this.toolManager.activeTool;
|
||||||
|
|
||||||
this.rgba = { r: 0, g: 255, b: 0, a: 200 };
|
this.rgba = { r: 0, g: 255, b: 0, a: 200 };
|
||||||
this.partId = "part_selector";
|
this.partId = SpecialLayerId.PART_SELECTOR;
|
||||||
this.partGroup = null; // 当前选区对象
|
this.partGroup = null; // 当前选区对象
|
||||||
this.partCanvas = null;// 选区画布
|
this.partCanvas = null;// 选区画布
|
||||||
this.rectangleObject = null; // 矩形对象
|
this.rectangleObject = null; // 矩形对象
|
||||||
@@ -90,16 +90,17 @@ export class PartManager {
|
|||||||
|
|
||||||
if (toolId === OperationType.PART_ERASER) {
|
if (toolId === OperationType.PART_ERASER) {
|
||||||
this.setEraserTool();
|
this.setEraserTool();
|
||||||
} else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) {
|
|
||||||
this.clearPointData();
|
|
||||||
this.resetPartObject();
|
|
||||||
}
|
|
||||||
if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) {
|
|
||||||
if (this.pointList.length > 0) {
|
|
||||||
this.clearPointData();
|
|
||||||
this.resetPartObject();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) {
|
||||||
|
// this.clearPointData();
|
||||||
|
// this.resetPartObject();
|
||||||
|
// }
|
||||||
|
// if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) {
|
||||||
|
// if (this.pointList.length > 0) {
|
||||||
|
// this.clearPointData();
|
||||||
|
// this.resetPartObject();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// 如果从非选区工具切换到选区工具,初始化事件
|
// 如果从非选区工具切换到选区工具,初始化事件
|
||||||
if (!wasActive && this.isActive) {
|
if (!wasActive && this.isActive) {
|
||||||
@@ -380,7 +381,8 @@ export class PartManager {
|
|||||||
box: [...this.pointList],
|
box: [...this.pointList],
|
||||||
});
|
});
|
||||||
const image = await this.loadImageToObject(url);
|
const image = await this.loadImageToObject(url);
|
||||||
const canvas = getObjectAlphaToCanvas(image, null, 0, this.rgba);
|
const data = this.partCanvas?.getContext("2d")?.getImageData(0, 0, this.partCanvas.width, this.partCanvas.height);
|
||||||
|
const canvas = getObjectAlphaToCanvas(image, data, 0, this.rgba, !!data);
|
||||||
this.partDrawCommand(canvas);
|
this.partDrawCommand(canvas);
|
||||||
}
|
}
|
||||||
/** 获取分隔后图片 */
|
/** 获取分隔后图片 */
|
||||||
|
|||||||
@@ -133,11 +133,12 @@ export class RedGreenModeManager {
|
|||||||
this.canvas.on("mouse:up", (event) => {
|
this.canvas.on("mouse:up", (event) => {
|
||||||
// 可以在这里添加更多逻辑,比如生成图片或更新状态
|
// 可以在这里添加更多逻辑,比如生成图片或更新状态
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
requestIdleCallback(async () => {
|
setTimeout(async () => {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
console.warn("红绿图模式未初始化,无法处理鼠标事件");
|
console.warn("红绿图模式未初始化,无法处理鼠标事件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("鼠标抬起事件触发", this.onImageGenerated);
|
||||||
if (this.onImageGenerated) {
|
if (this.onImageGenerated) {
|
||||||
const imageData = await this.canvasManager.exportImage({
|
const imageData = await this.canvasManager.exportImage({
|
||||||
restoreOpacityInRedGreen: true, // 恢复红绿图模式下的透明度
|
restoreOpacityInRedGreen: true, // 恢复红绿图模式下的透明度
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export class ThumbnailManager {
|
|||||||
|
|
||||||
// 延迟执行,避免阻塞UI
|
// 延迟执行,避免阻塞UI
|
||||||
fabricObjects.length > 0 &&
|
fabricObjects.length > 0 &&
|
||||||
requestIdleCallback(() => {
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const base64 = await this._generateLayerThumbnailNow(fabricObjects, layer);
|
const base64 = await this._generateLayerThumbnailNow(fabricObjects, layer);
|
||||||
// this.layerThumbnails.set(layerId, base64);
|
// this.layerThumbnails.set(layerId, base64);
|
||||||
@@ -55,7 +54,6 @@ export class ThumbnailManager {
|
|||||||
console.error("生成图层缩略图时出错:", error);
|
console.error("生成图层缩略图时出错:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +63,7 @@ export class ThumbnailManager {
|
|||||||
generateAllLayerThumbnails(layers) {
|
generateAllLayerThumbnails(layers) {
|
||||||
if (!layers || !Array.isArray(layers)) return;
|
if (!layers || !Array.isArray(layers)) return;
|
||||||
|
|
||||||
requestIdleCallback(() => {
|
setTimeout(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layers.forEach((layer) => {
|
layers.forEach((layer) => {
|
||||||
if (layer && layer.id) {
|
if (layer && layer.id) {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("execute", command.constructor.name, duration);
|
this._recordPerformance("execute", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("execute");
|
||||||
|
|
||||||
console.log(`✅ 命令执行成功: ${command.constructor.name}`);
|
console.log(`✅ 命令执行成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -219,7 +219,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("undo", command.constructor.name, duration);
|
this._recordPerformance("undo", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("undo");
|
||||||
|
|
||||||
console.log(`✅ 命令撤销成功: ${command.constructor.name}`);
|
console.log(`✅ 命令撤销成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -258,7 +258,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("redo", command.constructor.name, duration);
|
this._recordPerformance("redo", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("redo");
|
||||||
|
|
||||||
console.log(`✅ 命令重做成功: ${command.constructor.name}`);
|
console.log(`✅ 命令重做成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -298,7 +298,7 @@ export class CommandManager {
|
|||||||
|
|
||||||
this.undoStack = [];
|
this.undoStack = [];
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("clear");
|
||||||
// console.log("📝 命令历史已清空");
|
// console.log("📝 命令历史已清空");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,10 +417,12 @@ export class CommandManager {
|
|||||||
* 通知状态变化
|
* 通知状态变化
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_notifyStateChange() {
|
_notifyStateChange(type) {
|
||||||
if (this.onStateChange) {
|
if (this.onStateChange) {
|
||||||
try {
|
try {
|
||||||
this.onStateChange(this.getState());
|
const obj = this.getState();
|
||||||
|
obj.type = type;
|
||||||
|
this.onStateChange(obj);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("状态变化回调执行失败:", error);
|
console.error("状态变化回调执行失败:", error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { OperationType, OperationTypes } from "../../utils/layerHelper";
|
|||||||
export class CanvasEventManager {
|
export class CanvasEventManager {
|
||||||
constructor(canvas, options = {}) {
|
constructor(canvas, options = {}) {
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
this.canvasManager = options.canvasManager;
|
||||||
this.toolManager = options.toolManager || null;
|
this.toolManager = options.toolManager || null;
|
||||||
this.animationManager = options.animationManager;
|
this.animationManager = options.animationManager;
|
||||||
this.thumbnailManager = options.thumbnailManager;
|
this.thumbnailManager = options.thumbnailManager;
|
||||||
@@ -691,6 +692,8 @@ export class CanvasEventManager {
|
|||||||
// 清除临时状态记录
|
// 清除临时状态记录
|
||||||
delete activeObj._initialTransformState;
|
delete activeObj._initialTransformState;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
this.canvasManager.changeCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.thumbnailManager && e.target) {
|
if (this.thumbnailManager && e.target) {
|
||||||
@@ -975,6 +978,13 @@ export class CanvasEventManager {
|
|||||||
// 添加调试日志(可选)
|
// 添加调试日志(可选)
|
||||||
// console.log(`捕获对象 ${obj.id} (${obj.type}) 的初始变换状态`);
|
// console.log(`捕获对象 ${obj.id} (${obj.type}) 的初始变换状态`);
|
||||||
}
|
}
|
||||||
|
const arrs = [];
|
||||||
|
if (e.target._objects) {
|
||||||
|
e.target._objects.forEach((v) => arrs.push(v));
|
||||||
|
} else {
|
||||||
|
arrs.push(e.target);
|
||||||
|
}
|
||||||
|
this.canvasManager.beforeChangeCanvas(arrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
|
|
||||||
if (isDrawing && this.config.useDirectUpdate) {
|
if (isDrawing && this.config.useDirectUpdate) {
|
||||||
// 拖拽过程中使用快速更新(降低质量以提高性能)
|
// 拖拽过程中使用快速更新(降低质量以提高性能)
|
||||||
this._fastUpdate(imageData);
|
await this._fastUpdate(imageData);
|
||||||
} else {
|
} else {
|
||||||
// 拖拽结束后使用完整更新(最高质量)
|
// 拖拽结束后使用完整更新(最高质量)
|
||||||
await this._fullUpdate(imageData);
|
await this._fullUpdate(imageData);
|
||||||
@@ -124,7 +124,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
* @param {ImageData} imageData 图像数据
|
* @param {ImageData} imageData 图像数据
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_fastUpdate(imageData) {
|
async _fastUpdate(imageData) {
|
||||||
if (!this.targetObject || !this.targetObject._element) {
|
if (!this.targetObject || !this.targetObject._element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,12 +138,14 @@ export class LiquifyRealTimeUpdater {
|
|||||||
|
|
||||||
// 直接更新fabric对象的图像源(使用PNG格式保持质量)
|
// 直接更新fabric对象的图像源(使用PNG格式保持质量)
|
||||||
const targetElement = this.targetObject._element;
|
const targetElement = this.targetObject._element;
|
||||||
|
|
||||||
// 方案1: 直接设置src属性(最高性能)
|
// 方案1: 直接设置src属性(最高性能)
|
||||||
const dataURL = this.tempCanvas.toDataURL("image/png", quality);
|
const dataURL = this.tempCanvas.toDataURL("image/png", quality);
|
||||||
|
|
||||||
if (targetElement.src !== dataURL) {
|
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对象为脏状态,但不立即渲染
|
// 关键优化:直接设置fabric对象为脏状态,但不立即渲染
|
||||||
// this.targetObject.dirty = false; // 标记为不需要立即渲染
|
// this.targetObject.dirty = false; // 标记为不需要立即渲染
|
||||||
@@ -153,7 +155,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
// 使用requestAnimationFrame进行批量渲染优化
|
// 使用requestAnimationFrame进行批量渲染优化
|
||||||
// if (!this.renderingScheduled && !this.config.skipRenderDuringDrag) {
|
// if (!this.renderingScheduled && !this.config.skipRenderDuringDrag) {
|
||||||
// this.renderingScheduled = true;
|
// this.renderingScheduled = true;
|
||||||
// requestIdleCallback(() => {
|
// setTimeout(() => {
|
||||||
// this.canvas.renderAll();
|
// this.canvas.renderAll();
|
||||||
// this.renderingScheduled = false;
|
// this.renderingScheduled = false;
|
||||||
// });
|
// });
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export class LayerSort {
|
|||||||
if (canvasObjects.length === 0) return;
|
if (canvasObjects.length === 0) return;
|
||||||
|
|
||||||
// 使用画布渲染优化
|
// 使用画布渲染优化
|
||||||
await optimizeCanvasRendering(this.canvas, () => {
|
await new Promise((resolve) => {
|
||||||
|
optimizeCanvasRendering(this.canvas, () => {
|
||||||
// 计算每个对象应该在的 z-index 位置
|
// 计算每个对象应该在的 z-index 位置
|
||||||
const objectZIndexMap = this.calculateObjectZIndexes();
|
const objectZIndexMap = this.calculateObjectZIndexes();
|
||||||
|
|
||||||
@@ -51,6 +52,8 @@ export class LayerSort {
|
|||||||
this.canvas.moveTo(item.object, index);
|
this.canvas.moveTo(item.object, index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const LayerType = {
|
|||||||
export const SpecialLayerId = {
|
export const SpecialLayerId = {
|
||||||
SPECIAL_GROUP: "group_special", // 特殊组
|
SPECIAL_GROUP: "group_special", // 特殊组
|
||||||
COLOR: "special_color", // 颜色图层
|
COLOR: "special_color", // 颜色图层
|
||||||
|
PART_SELECTOR: "part_selector", // 部件选择器图层
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,10 @@ export async function restoreFabricObject(serializedObject, canvas) {
|
|||||||
* @param {ImageData} revData - 相反的ImageData,白通道的相同位置是否为透明,revData为白色为透明,黑色为不透明
|
* @param {ImageData} revData - 相反的ImageData,白通道的相同位置是否为透明,revData为白色为透明,黑色为不透明
|
||||||
* @param {number} diff - 差值,默认 25
|
* @param {number} diff - 差值,默认 25
|
||||||
* @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 }
|
* @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 }
|
||||||
|
* @param {boolean} isMerge - 是否合并,true=合并revData,false=反转revData
|
||||||
* @returns {HTMLCanvasElement|null} 包含黑白通道的画布,或 null 如果失败
|
* @returns {HTMLCanvasElement|null} 包含黑白通道的画布,或 null 如果失败
|
||||||
*/
|
*/
|
||||||
export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }) {
|
export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }, isMerge = false) {
|
||||||
const image = object.getElement();
|
const image = object.getElement();
|
||||||
if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") {
|
if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") {
|
||||||
console.warn("对象不是图片");
|
console.warn("对象不是图片");
|
||||||
@@ -93,18 +94,20 @@ export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 2
|
|||||||
const revG = revData?.data[i + 1] || 0;
|
const revG = revData?.data[i + 1] || 0;
|
||||||
const revB = revData?.data[i + 2] || 0;
|
const revB = revData?.data[i + 2] || 0;
|
||||||
const revA = revData?.data[i + 3] || 0;
|
const revA = revData?.data[i + 3] || 0;
|
||||||
|
let isHave = false;
|
||||||
if (r || g || b || a) {
|
if (r || g || b || a) {
|
||||||
if (revR > diff || revG > diff || revB > diff || revA > diff) {
|
if (revR > diff || revG > diff || revB > diff || revA > diff) {
|
||||||
data.data[i + 0] = 0;
|
isHave = false;
|
||||||
data.data[i + 1] = 0;
|
|
||||||
data.data[i + 2] = 0;
|
|
||||||
data.data[i + 3] = 0;
|
|
||||||
} else {
|
} else {
|
||||||
|
isHave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isMerge && (revR || revG || revB || revA)) isHave = true;
|
||||||
|
if (isHave) {
|
||||||
data.data[i + 0] = rgba.r;
|
data.data[i + 0] = rgba.r;
|
||||||
data.data[i + 1] = rgba.g;
|
data.data[i + 1] = rgba.g;
|
||||||
data.data[i + 2] = rgba.b;
|
data.data[i + 2] = rgba.b;
|
||||||
data.data[i + 3] = rgba.a;
|
data.data[i + 3] = rgba.a;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
data.data[i + 0] = 0;
|
data.data[i + 0] = 0;
|
||||||
data.data[i + 1] = 0;
|
data.data[i + 1] = 0;
|
||||||
|
|||||||
@@ -184,16 +184,17 @@ const createClippedDataURLByCanvas = async ({
|
|||||||
// console.log("🖼️ 使用图像遮罩裁剪方法生成DataURL");
|
// console.log("🖼️ 使用图像遮罩裁剪方法生成DataURL");
|
||||||
|
|
||||||
// 使用优化后的边界计算,确保包含描边区域
|
// 使用优化后的边界计算,确保包含描边区域
|
||||||
// const optimizedBounds = calculateOptimizedBounds(
|
const optimizedBounds = calculateOptimizedBounds(
|
||||||
// clippingObject,
|
clippingObject,
|
||||||
// fabricObjects
|
fabricObjects
|
||||||
// );
|
);
|
||||||
const optimizedBounds = {
|
console.log("📐 优化后的选区边界框:", optimizedBounds);
|
||||||
left: clippingObject.left - clippingObject.width / 2,
|
// const optimizedBounds = {
|
||||||
top: clippingObject.top - clippingObject.height / 2,
|
// left: clippingObject.left - clippingObject.width / 2,
|
||||||
width: clippingObject.width,
|
// top: clippingObject.top - clippingObject.height / 2,
|
||||||
height: clippingObject.height,
|
// width: clippingObject.width,
|
||||||
}
|
// height: clippingObject.height,
|
||||||
|
// }
|
||||||
|
|
||||||
// 使用高分辨率以保证质量
|
// 使用高分辨率以保证质量
|
||||||
const pixelRatio = window.devicePixelRatio || 1;
|
const pixelRatio = window.devicePixelRatio || 1;
|
||||||
|
|||||||
@@ -375,6 +375,7 @@ const confirm = ()=>{
|
|||||||
/* 图片网格 */
|
/* 图片网格 */
|
||||||
.image-grid {
|
.image-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
align-content: start;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
min-height: 20rem;
|
min-height: 20rem;
|
||||||
|
|||||||
@@ -203,9 +203,9 @@
|
|||||||
let scaleY = ((cheight / image.height) * item.scale[1]) / 5;
|
let scaleY = ((cheight / image.height) * item.scale[1]) / 5;
|
||||||
let scale = cwidth > cheight ? scaleX : scaleY;
|
let scale = cwidth > cheight ? scaleX : scaleY;
|
||||||
let offsetX =
|
let offsetX =
|
||||||
(item.location[0] * cwidth) / props.width + (image.width * scale) / 2;
|
(item.location[0] * cwidth) / props.width - (image.width * scale) / 2;
|
||||||
let offsetY =
|
let offsetY =
|
||||||
(item.location[1] * cheight) / props.height +
|
(item.location[1] * cheight) / props.height -
|
||||||
(image.height * scale) / 2;
|
(image.height * scale) / 2;
|
||||||
let angle = item.angle;
|
let angle = item.angle;
|
||||||
let gapX = item.object.gapX;
|
let gapX = item.object.gapX;
|
||||||
|
|||||||
@@ -333,6 +333,7 @@
|
|||||||
]);
|
]);
|
||||||
const canvasLoadJsonSuccess = () => {
|
const canvasLoadJsonSuccess = () => {
|
||||||
console.log("画布加载JSON成功");
|
console.log("画布加载JSON成功");
|
||||||
|
return;
|
||||||
canvasEditor.value?.updateOtherLayers({
|
canvasEditor.value?.updateOtherLayers({
|
||||||
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
|
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
|
||||||
printObject: {
|
printObject: {
|
||||||
@@ -342,32 +343,34 @@
|
|||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
path: "/src/assets/images/canvas/yinhua1.jpg",
|
path: "/src/assets/images/canvas/yinhua1.jpg",
|
||||||
location: [250, 780],
|
location: [800, 600],
|
||||||
scale: [1.2, 1.6],
|
scale: [1, 1],
|
||||||
angle: 0,
|
angle: 0,
|
||||||
|
priority: 1,
|
||||||
object: {
|
object: {
|
||||||
top: 600,
|
top: 300,
|
||||||
left: 800,
|
left: 400,
|
||||||
scaleX: 0.5,
|
scaleX: 0.5,
|
||||||
scaleY: 0.5,
|
scaleY: 0.5,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
angle: 45,
|
angle: 0,
|
||||||
flipX: false,
|
flipX: false,
|
||||||
flipY: false,
|
flipY: false,
|
||||||
blendMode: "multiply",
|
// blendMode: "multiply",
|
||||||
gapX: 0,
|
gapX: 0,
|
||||||
gapY: 0,
|
gapY: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// ifSingle: true,
|
ifSingle: true,
|
||||||
// level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
// designType: "Library",
|
designType: "Library",
|
||||||
// path: "/src/assets/images/canvas/yinhua1.jpg",
|
path: "/src/assets/images/canvas/yinhua1.jpg",
|
||||||
// location: [550, 650],
|
location: [550, 650],
|
||||||
// scale: [0.15, 0.2],
|
scale: [0.15, 0.2],
|
||||||
// angle: 0,
|
angle: 0,
|
||||||
// },
|
priority: 2,
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// ifSingle: true,
|
// ifSingle: true,
|
||||||
// level2Type: "Pattern",
|
// level2Type: "Pattern",
|
||||||
@@ -376,6 +379,7 @@
|
|||||||
// location: [700, 400],
|
// location: [700, 400],
|
||||||
// scale: [0.1, 0.133],
|
// scale: [0.1, 0.133],
|
||||||
// angle: 0,
|
// angle: 0,
|
||||||
|
// priority: 3,
|
||||||
// },
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -411,6 +415,7 @@
|
|||||||
:clothingMinIOPath="clothingMinIOPath"
|
:clothingMinIOPath="clothingMinIOPath"
|
||||||
:clothingImageUrl="clothingImageUrl"
|
:clothingImageUrl="clothingImageUrl"
|
||||||
:clothingImageUrl2="clothingImageUrlInit"
|
:clothingImageUrl2="clothingImageUrlInit"
|
||||||
|
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
|
||||||
:config="editorConfig"
|
:config="editorConfig"
|
||||||
:clothing-image-opts="{
|
:clothing-image-opts="{
|
||||||
imageMode: 'contains', // 设置底图包含在画布内
|
imageMode: 'contains', // 设置底图包含在画布内
|
||||||
@@ -442,6 +447,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</CanvasEditor>
|
</CanvasEditor>
|
||||||
</div>
|
</div>
|
||||||
|
<img src="" alt="" id="canvas-test-dom">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
@@ -453,6 +459,13 @@
|
|||||||
height: 600px !important;
|
height: 600px !important;
|
||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
}
|
}
|
||||||
|
#canvas-test-dom{
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999999999;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
:enabledRedGreenMode="false"
|
:enabledRedGreenMode="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn">123
|
<div class="btn">
|
||||||
<div class="gallery_btn" @click="exportElement">Export</div>
|
<div class="gallery_btn" @click="exportElement">Export</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -371,7 +371,13 @@ export default defineComponent({
|
|||||||
color = list[i].color?.rgba?.r != null?`${list[i].color.rgba.r} ${list[i].color.rgba.g} ${list[i].color.rgba.b}`:''
|
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
|
gradient = list[i].gradient
|
||||||
if((detailData.currentDetailType == 'sketch' && newData?.sketch) || detailData.isEditPattern.value == 'editSketch'){
|
if((detailData.currentDetailType == 'sketch' && newData?.sketch) || detailData.isEditPattern.value == 'editSketch'){
|
||||||
|
if(detailData.isEditPattern.value == 'editSketch'){
|
||||||
|
color = detailData.selectDetail?.color?.rgba?.r != null?`${detailData.selectDetail.color.rgba.r} ${detailData.selectDetail.color.rgba.g} ${detailData.selectDetail.color.rgba.b}`:''
|
||||||
|
gradient = detailData.selectDetail?.gradient || null
|
||||||
|
}else{
|
||||||
color = detailData.designDetail.clothes?.[0]?.color?.rgba?.r?`${detailData.designDetail.clothes?.[0].color.rgba.r} ${detailData.designDetail.clothes[0].color.rgba.g} ${detailData.designDetail.clothes[0].color.rgba.b}`:''
|
color = detailData.designDetail.clothes?.[0]?.color?.rgba?.r?`${detailData.designDetail.clothes?.[0].color.rgba.r} ${detailData.designDetail.clothes[0].color.rgba.g} ${detailData.designDetail.clothes[0].color.rgba.b}`:''
|
||||||
|
gradient = detailData.designDetail.clothes?.[0]?.gradient || null
|
||||||
|
}
|
||||||
detailData.selectDetail.maskUrl = ''
|
detailData.selectDetail.maskUrl = ''
|
||||||
detailData.selectDetail.maskMinioUrl = ''
|
detailData.selectDetail.maskMinioUrl = ''
|
||||||
}
|
}
|
||||||
@@ -492,7 +498,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const submit = async ()=>{
|
const submit = async ()=>{
|
||||||
detailData.loadingShow = true
|
detailData.loadingShow = true
|
||||||
if(detailData.isEditPattern.value !== 'canvasEditor'){
|
if(detailData.isEditPattern.value !== 'canvasEditor' && detailDom.canvasBox){
|
||||||
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
||||||
let otherData = await updateOtherLayers('single')
|
let otherData = await updateOtherLayers('single')
|
||||||
await detailDom.canvasBox.updateOtherLayers(otherData)
|
await detailDom.canvasBox.updateOtherLayers(otherData)
|
||||||
@@ -547,6 +553,7 @@ export default defineComponent({
|
|||||||
if((detailData.currentDetailType == 'models' && !detailData.isEditPattern.value) || (detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
|
if((detailData.currentDetailType == 'models' && !detailData.isEditPattern.value) || (detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
|
||||||
await getSubmitData('preview')
|
await getSubmitData('preview')
|
||||||
if(detailData.currentDetailType == 'models')return detailData.loadingShow = false
|
if(detailData.currentDetailType == 'models')return detailData.loadingShow = false
|
||||||
|
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == detailData.selectDetail.id)
|
||||||
await getSketchSize()
|
await getSketchSize()
|
||||||
detailDom.canvasBox.changeSketchUpdateFrontBack = async ()=>{
|
detailDom.canvasBox.changeSketchUpdateFrontBack = async ()=>{
|
||||||
await detailDom.canvasBox.privewDetail()
|
await detailDom.canvasBox.privewDetail()
|
||||||
@@ -556,11 +563,14 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//走画布合成图片并且直接分割
|
//走画布合成图片并且直接分割
|
||||||
|
if(detailData.isEditPattern.value !== 'canvasEditor' && detailData.isEditPattern.value !== 'redGreenExample'){
|
||||||
if(detailData.isEditPattern.value !== 'canvasEditor'){
|
if(detailData.isEditPattern.value !== 'canvasEditor'){
|
||||||
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
||||||
|
}
|
||||||
let otherData = await updateOtherLayers('single')
|
let otherData = await updateOtherLayers('single')
|
||||||
await detailDom.canvasBox.updateOtherLayers(otherData)
|
await detailDom.canvasBox.updateOtherLayers(otherData)
|
||||||
}
|
}
|
||||||
|
|
||||||
await detailDom.canvasBox.privewDetail()
|
await detailDom.canvasBox.privewDetail()
|
||||||
await upDateFrontBackSketch()
|
await upDateFrontBackSketch()
|
||||||
await uploadSelectDetail()
|
await uploadSelectDetail()
|
||||||
@@ -581,9 +591,9 @@ export default defineComponent({
|
|||||||
let front = detailData.frontBack.front[detailData.imgDomIndex]
|
let front = detailData.frontBack.front[detailData.imgDomIndex]
|
||||||
let back = detailData.frontBack.back[detailData.imgDomIndex]
|
let back = detailData.frontBack.back[detailData.imgDomIndex]
|
||||||
|
|
||||||
front.oldImageUrl = ''
|
if(front?.oldImageUrl)front.oldImageUrl = ''
|
||||||
front.oldMaskUrl = ''
|
if(front?.oldMaskUrl)front.oldMaskUrl = ''
|
||||||
back.oldImageUrl = ''
|
if(back?.oldImageUrl)back.oldImageUrl = ''
|
||||||
front.imageUrl = rv.targetFrontUrl
|
front.imageUrl = rv.targetFrontUrl
|
||||||
back.imageUrl = rv.targetBackUrl
|
back.imageUrl = rv.targetBackUrl
|
||||||
store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation})
|
store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation})
|
||||||
@@ -616,7 +626,7 @@ export default defineComponent({
|
|||||||
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
|
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
|
||||||
// await detailDom.canvasBox.saveCanvas()
|
// await detailDom.canvasBox.saveCanvas()
|
||||||
await (detailDom.canvasBox as any).privewDetail()
|
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 = ''
|
detailData.isEditPattern.value = ''
|
||||||
}else{
|
}else{
|
||||||
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
|
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
|
||||||
@@ -678,7 +688,7 @@ export default defineComponent({
|
|||||||
let color = detailData.selectDetail.newDetail?.color
|
let color = detailData.selectDetail.newDetail?.color
|
||||||
// let colorData:any = await getColorName(color?.rgba)
|
// let colorData:any = await getColorName(color?.rgba)
|
||||||
if(detailData.selectDetail.newDetail?.color){
|
if(detailData.selectDetail.newDetail?.color){
|
||||||
if(color.r){
|
if(color.r != null){
|
||||||
color.rgba = {r:color.r,g:color.g,b:color.b,a:color.a}
|
color.rgba = {r:color.r,g:color.g,b:color.b,a:color.a}
|
||||||
}else{
|
}else{
|
||||||
color.rgba = {}
|
color.rgba = {}
|
||||||
@@ -750,7 +760,6 @@ export default defineComponent({
|
|||||||
const uploadSelectDetail = async ()=>{//更新选中的detail
|
const uploadSelectDetail = async ()=>{//更新选中的detail
|
||||||
// await detailDom.canvasBox.saveCanvas()
|
// await detailDom.canvasBox.saveCanvas()
|
||||||
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
|
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
|
||||||
console.log(allInfo)
|
|
||||||
let color:any = {}
|
let color:any = {}
|
||||||
if(allInfo.color?.color?.rgba || allInfo.color?.color?.gradient){
|
if(allInfo.color?.color?.rgba || allInfo.color?.color?.gradient){
|
||||||
let canvasColor = allInfo.color.color;
|
let canvasColor = allInfo.color.color;
|
||||||
@@ -771,10 +780,8 @@ export default defineComponent({
|
|||||||
if(canvasColor?.gradient){
|
if(canvasColor?.gradient){
|
||||||
color.gradient = canvasColor.gradient
|
color.gradient = canvasColor.gradient
|
||||||
}
|
}
|
||||||
console.log(color,'color')
|
|
||||||
}
|
}
|
||||||
|
if(detailData.isEditPattern.value == 'canvasEditor' || detailData.isEditPattern.value == 'redGreenExample'){
|
||||||
if(detailData.isEditPattern.value == 'canvasEditor'){
|
|
||||||
delete detailData.selectDetail.newDetail
|
delete detailData.selectDetail.newDetail
|
||||||
detailData.selectDetail.trims.prints = allInfo.trims || []
|
detailData.selectDetail.trims.prints = allInfo.trims || []
|
||||||
detailData.selectDetail.printObject.prints = allInfo.prints || []
|
detailData.selectDetail.printObject.prints = allInfo.prints || []
|
||||||
@@ -797,7 +804,6 @@ export default defineComponent({
|
|||||||
if(detailData.currentDetailType == 'color'){
|
if(detailData.currentDetailType == 'color'){
|
||||||
detailData.detailLeftColorKey++
|
detailData.detailLeftColorKey++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const canvasReload = async ()=>{
|
const canvasReload = async ()=>{
|
||||||
if(detailData.isEditPattern.value){
|
if(detailData.isEditPattern.value){
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
@canvasInit="editSketchCanvasInit"
|
@canvasInit="editSketchCanvasInit"
|
||||||
is-edit
|
is-edit
|
||||||
:clothingImageUrl="selectDetail.path"
|
:clothingImageUrl="selectDetail.path"
|
||||||
:clothingImageUrl2="selectDetail.layersObject[0].maskUrl"
|
:clothingImageUrl2="selectDetail.maskUrl || selectDetail.layersObject[0].maskUrl"
|
||||||
:clothingMinIOPath="selectDetail.minIOPath"
|
|
||||||
showFixedLayer
|
showFixedLayer
|
||||||
:canvasJSON="canvasJSON"
|
:canvasJSON="canvasJSON"
|
||||||
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
|
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
|
||||||
@@ -52,9 +51,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mark_loading" v-show="isShowMark">
|
<!-- <div class="mark_loading" v-show="isShowMark">
|
||||||
<a-spin size="large" />
|
<a-spin size="large" />
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@@ -164,7 +163,6 @@ export default defineComponent({
|
|||||||
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
||||||
// if(!detailDom.editCanvas)return
|
// if(!detailDom.editCanvas)return
|
||||||
return new Promise(async (res,reject)=>{
|
return new Promise(async (res,reject)=>{
|
||||||
console.log(detailDom.editCanvas)
|
|
||||||
await detailDom.editCanvas.exportImage({
|
await detailDom.editCanvas.exportImage({
|
||||||
isContainFixed:true,
|
isContainFixed:true,
|
||||||
width:props.sketchSize.width,
|
width:props.sketchSize.width,
|
||||||
@@ -245,15 +243,28 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const frontBackChange = (value:any)=>{
|
const frontBackChange = async (value:any)=>{
|
||||||
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.path
|
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 = {
|
let size = {
|
||||||
...detailData.canvasConfig,
|
...detailData.canvasConfig,
|
||||||
}
|
}
|
||||||
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
|
||||||
segmentImage(value,full,size).then(async (rv)=>{
|
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?.oldImageUrl)front.oldImageUrl = front.imageUrl
|
||||||
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
|
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
|
||||||
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
|
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
|
||||||
@@ -265,7 +276,6 @@ export default defineComponent({
|
|||||||
back.imageUrl = rv.targetBackUrl
|
back.imageUrl = rv.targetBackUrl
|
||||||
// store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
// store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
const editSketchCanvasInit = async (value:any)=>{
|
const editSketchCanvasInit = async (value:any)=>{
|
||||||
detailData.canvasInstance = value
|
detailData.canvasInstance = value
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
watch(()=>colorData.selectColor,async (newVal,oldVal)=>{
|
watch(()=>colorData.selectColor,async (newVal,oldVal)=>{
|
||||||
if((newVal.rgba && newVal.rgba?.r != null) || newVal.gradient != null){
|
if((newVal.rgba && newVal.rgba?.r != null) || newVal.gradient != null){
|
||||||
console.log('=======',123)
|
|
||||||
let data :any = {}
|
let data :any = {}
|
||||||
if(newVal.rgba?.r != null){
|
if(newVal.rgba?.r != null){
|
||||||
data = await getColorName(newVal.rgba)
|
data = await getColorName(newVal.rgba)
|
||||||
@@ -119,7 +118,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
store.commit('DesignDetail/setNewDetail',value)
|
store.commit('DesignDetail/setNewDetail',value)
|
||||||
}else{
|
}else{
|
||||||
console.log('=======',123)
|
|
||||||
let value = {
|
let value = {
|
||||||
data:{},
|
data:{},
|
||||||
str:'color'
|
str:'color'
|
||||||
@@ -144,14 +142,13 @@ export default defineComponent({
|
|||||||
let color = colorData.allBoardData.colorBoards?.[index]
|
let color = colorData.allBoardData.colorBoards?.[index]
|
||||||
if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue
|
if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue
|
||||||
if(
|
if(
|
||||||
(colorData.allBoardData.colorBoards?.[index] &&
|
(colorData.allBoardData.colorBoards?.[index] && color?.rgba &&
|
||||||
colorData.selectDetail.color.rgba?.r == color?.rgba?.r &&
|
colorData.selectDetail.color.rgba?.r == color?.rgba?.r &&
|
||||||
colorData.selectDetail.color.rgba?.g == color?.rgba?.g &&
|
colorData.selectDetail.color.rgba?.g == color?.rgba?.g &&
|
||||||
colorData.selectDetail.color.rgba?.b == color?.rgba?.b) ||
|
colorData.selectDetail.color.rgba?.b == color?.rgba?.b) ||
|
||||||
(JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient)
|
((JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient))
|
||||||
){
|
){
|
||||||
isNoSelect = true
|
isNoSelect = true
|
||||||
console.log('=======',123)
|
|
||||||
colorData.selectColor = item
|
colorData.selectColor = item
|
||||||
colorData.colorList.index = index
|
colorData.colorList.index = index
|
||||||
}else if(color?.rgba?.r){
|
}else if(color?.rgba?.r){
|
||||||
@@ -175,7 +172,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
colorData.colorList.list[newVal].push(item)
|
colorData.colorList.list[newVal].push(item)
|
||||||
}
|
}
|
||||||
console.log('=======',isNoSelect)
|
|
||||||
if(!isNoSelect){
|
if(!isNoSelect){
|
||||||
let color = colorData.selectDetail.newDetail?.color?.rgba?.r != null?colorData.selectDetail.newDetail?.color:colorData.selectDetail.color
|
let color = colorData.selectDetail.newDetail?.color?.rgba?.r != null?colorData.selectDetail.newDetail?.color:colorData.selectDetail.color
|
||||||
let item:any = {}
|
let item:any = {}
|
||||||
|
|||||||
@@ -40,11 +40,29 @@ export default defineComponent({
|
|||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
const updateCatecory = (arr)=>{
|
||||||
|
arr.forEach((v:any) => {
|
||||||
|
if(props.catecoryList)props.catecoryList.forEach((item:any) => {
|
||||||
|
if(v.level2Type == item.value && !v.category){
|
||||||
|
v.category=item.name
|
||||||
|
v.categoryValue=item.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
const detailData = reactive({
|
const detailData = reactive({
|
||||||
allBoardData:computed(()=>store.state.UploadFilesModule.allBoardData),
|
allBoardData:computed(()=>store.state.UploadFilesModule.allBoardData),
|
||||||
currentList:{
|
currentList:{
|
||||||
sketch:computed(()=>store.state.UploadFilesModule.allBoardData.sketchboardFiles),
|
sketch:computed(()=>{
|
||||||
print:computed(()=>store.state.UploadFilesModule.allBoardData.printboardFiles),
|
let sketch = store.state.UploadFilesModule.allBoardData.sketchboardFiles
|
||||||
|
updateCatecory(sketch)
|
||||||
|
return sketch
|
||||||
|
}),
|
||||||
|
print:computed(()=>{
|
||||||
|
let print = store.state.UploadFilesModule.allBoardData.printboardFiles
|
||||||
|
updateCatecory(print)
|
||||||
|
return print
|
||||||
|
}),
|
||||||
color:computed(()=>store.state.UploadFilesModule.allBoardData.colorBoards),
|
color:computed(()=>store.state.UploadFilesModule.allBoardData.colorBoards),
|
||||||
models:computed(()=>store.state.Workspace.probjects.model),
|
models:computed(()=>store.state.Workspace.probjects.model),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export default defineComponent({
|
|||||||
selectImgItem(data)
|
selectImgItem(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
data.id = id
|
||||||
if(data?.imgUrl)data.url = data.imgUrl
|
if(data?.imgUrl)data.url = data.imgUrl
|
||||||
let value = {
|
let value = {
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -89,8 +89,8 @@
|
|||||||
<img crossOrigin="anonymous" :src="item?.path" :style="{transform:`rotateZ(${item.pattern?.transform?.rotateZ}deg)`}" class="designOpenrtion_imgItme" draggable="false">
|
<img crossOrigin="anonymous" :src="item?.path" :style="{transform:`rotateZ(${item.pattern?.transform?.rotateZ}deg)`}" class="designOpenrtion_imgItme" draggable="false">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg"> -->
|
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true"> -->
|
||||||
<img :src="stateOverallSingle == 'single'?(selectDetail.undividedLayer||selectDetail.path):(selectDetail.undividedLayerColor || selectDetail.path)" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
|
<img :src="(selectDetail.path)" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
|
||||||
<img :src="selectDetail.sketchMask" alt="" class="designOpenrtion_sketchMask" ref="sketchMask">
|
<img :src="selectDetail.sketchMask" alt="" class="designOpenrtion_sketchMask" ref="sketchMask">
|
||||||
<div class="designOpenrtion_btn" v-if="stateOverallSingle == 'single'" >
|
<div class="designOpenrtion_btn" v-if="stateOverallSingle == 'single'" >
|
||||||
<ul v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
|
<ul v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
|
||||||
@@ -160,7 +160,6 @@ export default defineComponent({
|
|||||||
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
||||||
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
|
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
|
||||||
currentPrintElement:computed(()=>store.state.DesignDetail.currentPrintElement),
|
currentPrintElement:computed(()=>store.state.DesignDetail.currentPrintElement),
|
||||||
systemDesignerPercentage:0,
|
|
||||||
printStyleList:{
|
printStyleList:{
|
||||||
print:{
|
print:{
|
||||||
single:[],
|
single:[],
|
||||||
@@ -174,7 +173,6 @@ export default defineComponent({
|
|||||||
type:props.type,
|
type:props.type,
|
||||||
imgDomIndex:-1,
|
imgDomIndex:-1,
|
||||||
direction:'',//判断点的那条边
|
direction:'',//判断点的那条边
|
||||||
printZIndex:2,//印花优先级
|
|
||||||
sketchWH:{
|
sketchWH:{
|
||||||
width:0,
|
width:0,
|
||||||
height:0,
|
height:0,
|
||||||
@@ -225,6 +223,7 @@ export default defineComponent({
|
|||||||
img.onload = ()=>{
|
img.onload = ()=>{
|
||||||
let imgScale = img.width / img.height
|
let imgScale = img.width / img.height
|
||||||
let zoom = 2
|
let zoom = 2
|
||||||
|
console.log(editPrintElementData.sketchWH)
|
||||||
let width = editPrintElementData.sketchWH.width / zoom
|
let width = editPrintElementData.sketchWH.width / zoom
|
||||||
let height = width / editPrintElementData.sketchWH.height
|
let height = width / editPrintElementData.sketchWH.height
|
||||||
|
|
||||||
@@ -234,29 +233,47 @@ export default defineComponent({
|
|||||||
let sketchH = editPrintElementData.sketchWH.height * editPrintElementData.sketchWH.scale[1]
|
let sketchH = editPrintElementData.sketchWH.height * editPrintElementData.sketchWH.scale[1]
|
||||||
let x = sketchW / 2 - (sketchW * (width / editPrintElementData.sketchWH.width)/2)
|
let x = sketchW / 2 - (sketchW * (width / editPrintElementData.sketchWH.width)/2)
|
||||||
let y = sketchH / 2 -(sketchH * height/2)
|
let y = sketchH / 2 -(sketchH * height/2)
|
||||||
if(!editPrintElementData.stateOverallSingle == 'single'){
|
if(editPrintElementData.stateOverallSingle !== 'single'){
|
||||||
x = sketchW / 2
|
x = sketchW / 2
|
||||||
y = sketchH / 2
|
y = sketchH / 2
|
||||||
}
|
}
|
||||||
let location = [x,y]
|
let location = [x,y]
|
||||||
resolve({scale,location})
|
resolve({scale,location})
|
||||||
}
|
}
|
||||||
img.src = item.url
|
img.src = item.url || item.path
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const addPrintELement = async (data:any)=>{
|
const addPrintELement = async (data:any)=>{
|
||||||
if(!editPrintElementData.isSketchLoad)return
|
if(!editPrintElementData.isSketchLoad)return
|
||||||
let {scale,location} = await setScaleLocation(data)
|
let {scale,location} = await setScaleLocation(data)
|
||||||
|
let printIndex = 1
|
||||||
|
let allElementPrint = []
|
||||||
|
if(props.type == 'print'){
|
||||||
|
allElementPrint = [
|
||||||
|
...(editPrintElementData.printStyleList.print.single || []),
|
||||||
|
...(editPrintElementData.printStyleList.print.overall || []),
|
||||||
|
...(editPrintElementData.selectDetail.trims.prints || []),
|
||||||
|
]
|
||||||
|
}else{
|
||||||
|
allElementPrint = [
|
||||||
|
...(editPrintElementData.printStyleList.element.single || []),
|
||||||
|
...(editPrintElementData.selectDetail.printObject.prints || []),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if(allElementPrint.length >= 1){
|
||||||
|
printIndex = Math.max(...allElementPrint.map(item => Number(item.priority))) + 1
|
||||||
|
}
|
||||||
let item = {
|
let item = {
|
||||||
angle:0,
|
angle:0,
|
||||||
designType:data.designType,
|
designType:data.designType,
|
||||||
ifSingle:editPrintElementData.stateOverallSingle == 'single',
|
ifSingle:editPrintElementData.stateOverallSingle == 'single',
|
||||||
level2Type:data.level2Type,
|
level2Type:data.level2Type,
|
||||||
location:editPrintElementData.stateOverallSingle == 'single'?location:[0,0],
|
location:location,
|
||||||
|
// location:editPrintElementData.stateOverallSingle == 'single'?location:[0,0],
|
||||||
minIOPath:data.minIOPath || data.originalUrl,
|
minIOPath:data.minIOPath || data.originalUrl,
|
||||||
path:data.url,
|
path:data.url,
|
||||||
priority:editPrintElementData.printZIndex,
|
priority:printIndex,
|
||||||
scale,
|
scale:editPrintElementData.stateOverallSingle == 'single'?scale:[1,1],
|
||||||
globalCompositeOperation:'',
|
globalCompositeOperation:'',
|
||||||
}
|
}
|
||||||
getItemPosition(item)
|
getItemPosition(item)
|
||||||
@@ -283,10 +300,10 @@ export default defineComponent({
|
|||||||
// location = [item.pattern.style.left,item.pattern.style.top]
|
// location = [item.pattern.style.left,item.pattern.style.top]
|
||||||
}
|
}
|
||||||
let value ={
|
let value ={
|
||||||
angle : item.pattern.transform.rotateZ,
|
angle:0,
|
||||||
// angle : !this.overallSingle ? 0:item.pattern.transform.rotateZ,
|
// angle : !this.overallSingle ? 0:item.pattern.transform.rotateZ,
|
||||||
location : location,
|
location : location,
|
||||||
priority:index,
|
priority:item.priority,
|
||||||
scale: scale,
|
scale: scale,
|
||||||
designType:item.designType,
|
designType:item.designType,
|
||||||
level2Type:item.level2Type,
|
level2Type:item.level2Type,
|
||||||
@@ -295,16 +312,22 @@ export default defineComponent({
|
|||||||
ifSingle:!!item.ifSingle,
|
ifSingle:!!item.ifSingle,
|
||||||
globalCompositeOperation:'',
|
globalCompositeOperation:'',
|
||||||
}
|
}
|
||||||
if(item.object)value.object = item.object
|
if(item.object)value.object = item.object;
|
||||||
|
value.angle = value.ifSingle?item.pattern.transform.rotateZ:item.angle
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if(editPrintElementData.printStyleList[props.type].single.length>0){
|
if(editPrintElementData.printStyleList[props.type].single.length>0){
|
||||||
sort(editPrintElementData.printStyleList[props.type].single)
|
sort(editPrintElementData.printStyleList[props.type].single)
|
||||||
}
|
}
|
||||||
|
if(editPrintElementData.printStyleList[props.type].overall.length>0){
|
||||||
|
sort(editPrintElementData.printStyleList[props.type].overall)
|
||||||
|
}
|
||||||
editPrintElementData.printStyleList[props.type].overall.forEach((item:any)=>{
|
editPrintElementData.printStyleList[props.type].overall.forEach((item:any)=>{
|
||||||
data.push(setData(item,index))
|
data.push(setData(item,index))
|
||||||
index++
|
index++
|
||||||
})
|
})
|
||||||
|
console.log(editPrintElementData.printStyleList[props.type].single)
|
||||||
editPrintElementData.printStyleList[props.type].single.forEach((item:any)=>{
|
editPrintElementData.printStyleList[props.type].single.forEach((item:any)=>{
|
||||||
data.push(setData(item,index))
|
data.push(setData(item,index))
|
||||||
index++
|
index++
|
||||||
@@ -336,10 +359,9 @@ export default defineComponent({
|
|||||||
top = item.location[1] / editPrintElementData.sketchWH.scale[1]
|
top = item.location[1] / editPrintElementData.sketchWH.scale[1]
|
||||||
}else{
|
}else{
|
||||||
//overall
|
//overall
|
||||||
editPrintElementData.systemDesignerPercentage = item.scale[0]*1000
|
|
||||||
left = item.location[0] / editPrintElementData.sketchWH.scale[0]
|
left = item.location[0] / editPrintElementData.sketchWH.scale[0]
|
||||||
top = item.location[1] / editPrintElementData.sketchWH.scale[1]
|
top = item.location[1] / editPrintElementData.sketchWH.scale[1]
|
||||||
editPrintElementData.systemDesignerPercentage = item.scale?.[0]?item.scale[0]*100:30
|
item.scale = item.scale || [1,1]
|
||||||
}
|
}
|
||||||
let pattern = {
|
let pattern = {
|
||||||
centers:{left:0,top:0},
|
centers:{left:0,top:0},
|
||||||
@@ -357,7 +379,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
designOpenrtionBtn:false
|
designOpenrtionBtn:false
|
||||||
}
|
}
|
||||||
editPrintElementData.printZIndex++
|
|
||||||
item.pattern = pattern
|
item.pattern = pattern
|
||||||
|
|
||||||
if(item.object){
|
if(item.object){
|
||||||
@@ -373,6 +394,7 @@ export default defineComponent({
|
|||||||
flipX: false,
|
flipX: false,
|
||||||
flipY: false,
|
flipY: false,
|
||||||
blendMode: "multiply",
|
blendMode: "multiply",
|
||||||
|
// blendMode: "source-over",
|
||||||
gapX: 0,
|
gapX: 0,
|
||||||
gapY: 0,
|
gapY: 0,
|
||||||
}
|
}
|
||||||
@@ -399,7 +421,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const setPosition = ()=>{
|
const setPosition = async ()=>{
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
let img = new Image
|
let img = new Image
|
||||||
img.onload = ()=>{
|
img.onload = ()=>{
|
||||||
@@ -435,15 +458,12 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
setItemPosition()
|
setItemPosition()
|
||||||
}
|
}
|
||||||
// if(props.type == 'print'){
|
resolve('')
|
||||||
// editPrintElementData.overallSingle = state
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
// undividedLayer
|
img.src = editPrintElementData.selectDetail.path
|
||||||
//计算宽高使用editPrintElementData.selectDetail.path
|
|
||||||
// img.src = editPrintElementData.selectDetail.path
|
|
||||||
img.src = editPrintElementData.selectDetail.undividedLayer?editPrintElementData.selectDetail.undividedLayer:editPrintElementData.selectDetail.path
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
// watch(()=>editPrintElementData.selectDetail?.id,(newVal)=>{
|
// watch(()=>editPrintElementData.selectDetail?.id,(newVal)=>{
|
||||||
// if(!newVal)return
|
// if(!newVal)return
|
||||||
@@ -517,7 +537,6 @@ export default defineComponent({
|
|||||||
let scale = Number(editPrintElementDom.imgDom.children[0].style.transform?.split('scale(')[1]?.split(')')[0])
|
let scale = Number(editPrintElementDom.imgDom.children[0].style.transform?.split('scale(')[1]?.split(')')[0])
|
||||||
let rotateZ = Number(editPrintElementDom.imgDom.children[0].style.transform?.split('rotateZ(')[1]?.split('deg')[0])
|
let rotateZ = Number(editPrintElementDom.imgDom.children[0].style.transform?.split('rotateZ(')[1]?.split('deg')[0])
|
||||||
editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle][index].pattern.designOpenrtionBtn = true
|
editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle][index].pattern.designOpenrtionBtn = true
|
||||||
// editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle][index].pattern.style.zIndex = editPrintElementData.printZIndex++
|
|
||||||
editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle][index].pattern.transform = {
|
editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle][index].pattern.transform = {
|
||||||
scale:scale,
|
scale:scale,
|
||||||
rotateZ:rotateZ?rotateZ:0,
|
rotateZ:rotateZ?rotateZ:0,
|
||||||
@@ -651,7 +670,6 @@ export default defineComponent({
|
|||||||
top:editPrintElementDom.imgDom.offsetTop+'px',
|
top:editPrintElementDom.imgDom.offsetTop+'px',
|
||||||
height:editPrintElementDom.imgDom.offsetHeight+'px',
|
height:editPrintElementDom.imgDom.offsetHeight+'px',
|
||||||
width:editPrintElementDom.imgDom.offsetWidth+'px',
|
width:editPrintElementDom.imgDom.offsetWidth+'px',
|
||||||
// zIndex:editPrintElementData.printZIndex
|
|
||||||
}
|
}
|
||||||
document.removeEventListener('mousemove',sizeMouseMove)
|
document.removeEventListener('mousemove',sizeMouseMove)
|
||||||
document.removeEventListener('touchmove',sizeTouchmove)
|
document.removeEventListener('touchmove',sizeTouchmove)
|
||||||
@@ -803,7 +821,8 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
elList[item.index].sort = moveIndex;
|
let index = elList.findIndex((elListItem:any)=>item.id == elListItem.id)
|
||||||
|
elList[index].sort = moveIndex;
|
||||||
moveItem();
|
moveItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -834,6 +853,7 @@ export default defineComponent({
|
|||||||
collItemSize.elList.forEach((elItem:any)=>{
|
collItemSize.elList.forEach((elItem:any)=>{
|
||||||
let clothesIndex = arr.findIndex((item:any)=>item.uniqueId == elItem.uniqueId)
|
let clothesIndex = arr.findIndex((item:any)=>item.uniqueId == elItem.uniqueId)
|
||||||
arr[clothesIndex].pattern.style.zIndex = elItem.sort
|
arr[clothesIndex].pattern.style.zIndex = elItem.sort
|
||||||
|
arr[clothesIndex].priority = elItem.id.split('_')[0]
|
||||||
// let clothesId = editPrintElementData.designDetail.clothes[clothesIndex].id
|
// let clothesId = editPrintElementData.designDetail.clothes[clothesIndex].id
|
||||||
// editPrintElementData.designDetail.clothes[clothesIndex].priority = elItem.sort
|
// editPrintElementData.designDetail.clothes[clothesIndex].priority = elItem.sort
|
||||||
// let frontIndex = editPrintElementData.frontBack_.front.findIndex((item:any)=>item.id == clothesId)
|
// let frontIndex = editPrintElementData.frontBack_.front.findIndex((item:any)=>item.id == clothesId)
|
||||||
@@ -854,7 +874,6 @@ export default defineComponent({
|
|||||||
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
|
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
|
||||||
|
|
||||||
arr.forEach((item,index) => {item.uniqueId = `${Date.now()}_${index}`});
|
arr.forEach((item,index) => {item.uniqueId = `${Date.now()}_${index}`});
|
||||||
|
|
||||||
const sortedArray = [...arr].sort((a, b) => a.priority - b.priority);
|
const sortedArray = [...arr].sort((a, b) => a.priority - b.priority);
|
||||||
const sortMap = {} as any;
|
const sortMap = {} as any;
|
||||||
sortedArray.forEach((item, index) => {
|
sortedArray.forEach((item, index) => {
|
||||||
@@ -865,7 +884,8 @@ export default defineComponent({
|
|||||||
el: elArr[i],
|
el: elArr[i],
|
||||||
// sort: elArr.length - i -1,
|
// sort: elArr.length - i -1,
|
||||||
sort: sortMap[arr[i].priority],
|
sort: sortMap[arr[i].priority],
|
||||||
index: i,
|
id: `${arr[i].priority}_${Date.now() + i}`,
|
||||||
|
// index: i,
|
||||||
uniqueId:arr[i]?.uniqueId || 99999,
|
uniqueId:arr[i]?.uniqueId || 99999,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -897,6 +917,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const inputFillAngle = (angle:any)=>{
|
const inputFillAngle = (angle:any)=>{
|
||||||
let arr = editPrintElementData.printStyleList[props.type].overall
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
console.log(angle)
|
||||||
arr[editPrintElementData.imgDomIndex].angle = angle
|
arr[editPrintElementData.imgDomIndex].angle = angle
|
||||||
editPrintElementDom.pingpuRef.updataList([
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
:max="1000"
|
:max="1000"
|
||||||
:step="1"
|
:step="1"
|
||||||
is-input
|
is-input
|
||||||
:tipFormatter="(v) => `${scale.toFixed(0)}%`"
|
:tipFormatter="(v) => `${Number(scale)?.toFixed(0)}%`"
|
||||||
:value="scale"
|
:value="scale"
|
||||||
@input="inputFillScale"
|
@input="inputFillScale"
|
||||||
/>
|
/>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">Gap X</span>
|
<span class="label">Gap X</span>
|
||||||
<slider
|
<slider
|
||||||
:min="0"
|
:min="1"
|
||||||
:max="1000"
|
:max="1000"
|
||||||
:step="1"
|
:step="1"
|
||||||
is-input
|
is-input
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">Gap Y</span>
|
<span class="label">Gap Y</span>
|
||||||
<slider
|
<slider
|
||||||
:min="0"
|
:min="1"
|
||||||
:max="1000"
|
:max="1000"
|
||||||
:step="1"
|
:step="1"
|
||||||
is-input
|
is-input
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
const scale = computed(() => {
|
const scale = computed(() => {
|
||||||
// let scaleValue = props.object?.scale/10;
|
// let scaleValue = props.object?.scale/10;
|
||||||
// return props.object?.scale/10;
|
// return props.object?.scale/10;
|
||||||
return props.object?.scale[0] * 100;
|
return (props.object?.scale[0] * 100).toFixed(0);
|
||||||
});
|
});
|
||||||
const scalePrint = computed(() => {
|
const scalePrint = computed(() => {
|
||||||
let index = sketchWH.value[0] > sketchWH.value[1]?0:1;
|
let index = sketchWH.value[0] > sketchWH.value[1]?0:1;
|
||||||
|
|||||||
@@ -124,7 +124,11 @@ export default defineComponent({
|
|||||||
const handleResize = ()=>{
|
const handleResize = ()=>{
|
||||||
clearTimeout(time)
|
clearTimeout(time)
|
||||||
time = setTimeout(()=>{
|
time = setTimeout(()=>{
|
||||||
store.commit('DesignDetail/setDesignDetail',getDetailListData.designDetail)
|
let data = {
|
||||||
|
...getDetailListData.designDetail,
|
||||||
|
fromType:'resize',
|
||||||
|
}
|
||||||
|
store.commit('DesignDetail/setDesignDetail',data)
|
||||||
getDetailListDom.position?.updataPosition?.()
|
getDetailListDom.position?.updataPosition?.()
|
||||||
getDetailListDom.modelNav?.setItemPosition?.()
|
getDetailListDom.modelNav?.setItemPosition?.()
|
||||||
getDetailListDom.position?.updateRect?.()
|
getDetailListDom.position?.updateRect?.()
|
||||||
|
|||||||
@@ -3,76 +3,109 @@
|
|||||||
<div class="eventsDetail_title">
|
<div class="eventsDetail_title">
|
||||||
<div class="modal_title_text" @click="setBack">
|
<div class="modal_title_text" @click="setBack">
|
||||||
<i class="fi fi-sr-left"></i>
|
<i class="fi fi-sr-left"></i>
|
||||||
<div class="eventsDetail_title_text">{{ $t('event.back') }}</div>
|
<div class="eventsDetail_title_text">{{ $t("event.back") }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eventsDetail_content">
|
<div class="eventsDetail_content">
|
||||||
<div class="eventsDetail_content_left">
|
<div class="eventsDetail_content_left">
|
||||||
<fullScreenImg :src="eventsDetail.imgUrl" width="100%" :center="true"></fullScreenImg>
|
<fullScreenImg
|
||||||
|
:src="eventsDetail.imgUrl"
|
||||||
|
width="100%"
|
||||||
|
:center="true"
|
||||||
|
></fullScreenImg>
|
||||||
</div>
|
</div>
|
||||||
<div class="eventsDetail_content_right">
|
<div class="eventsDetail_content_right">
|
||||||
<div class="modal_title_text">
|
<div class="modal_title_text modal_title_text-header flex space-between">
|
||||||
<div>{{ eventsDetail.title }}</div>
|
<div>{{ eventsDetail.title }}</div>
|
||||||
|
<div class="detail-btn" v-if="eventsDetail.id === 3" @click="openDetail">
|
||||||
|
{{ $t("event.detail") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal_title_text" v-for="item in eventsDetail.textList">
|
</div>
|
||||||
|
<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_box">
|
||||||
<div class="eventsDetail_content_right_btn" v-for="buttonItem,buttonIndex in item?.button" @click="openButton(buttonItem,buttonIndex)">
|
<div
|
||||||
<div v-show="!loadingShow[buttonIndex]" class="started_btn">{{ buttonItem.text }}</div>
|
class="eventsDetail_content_right_btn"
|
||||||
<div v-show="loadingShow[buttonIndex]" class="started_btn"><i class="fi fi-br-loading"></i></div>
|
v-for="(buttonItem, buttonIndex) in item?.button"
|
||||||
|
@click="openButton(buttonItem, buttonIndex)"
|
||||||
|
>
|
||||||
|
<div v-show="!loadingShow[buttonIndex]" class="started_btn">
|
||||||
|
{{ buttonItem.text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-show="loadingShow[buttonIndex]" class="started_btn">
|
||||||
<div class="modal_title_text_intro" v-for="introItem in item?.paragraph" :class="{active:introItem.display == 'flex'}" v-detailText="introItem.text">
|
<i class="fi fi-br-loading"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="modal_title_text_intro"
|
||||||
|
v-for="introItem in item?.paragraph"
|
||||||
|
:class="{ active: introItem.display == 'flex' }"
|
||||||
|
v-detailText="introItem.text"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div class="tips" v-if="eventsDetail.tips">{{ eventsDetail.tips }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { LoadingOutlined } from "@ant-design/icons-vue";
|
import { LoadingOutlined } from "@ant-design/icons-vue"
|
||||||
import { defineComponent,h ,toRefs,ref,reactive,onMounted,nextTick,provide,computed} from 'vue'
|
import {
|
||||||
|
defineComponent,
|
||||||
|
h,
|
||||||
|
toRefs,
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
onMounted,
|
||||||
|
nextTick,
|
||||||
|
provide,
|
||||||
|
computed
|
||||||
|
} from "vue"
|
||||||
// import RobotAssist from "@/component/HomePage/RobotAssist.vue";
|
// import RobotAssist from "@/component/HomePage/RobotAssist.vue";
|
||||||
import { Https } from "@/tool/https";
|
import { Https } from "@/tool/https"
|
||||||
import { message, Upload, Modal } from "ant-design-vue";
|
import { message, Upload, Modal } from "ant-design-vue"
|
||||||
import fullScreenImg from '@/component/HomePage/fullScreenImg.vue'
|
import fullScreenImg from "@/component/HomePage/fullScreenImg.vue"
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router"
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n"
|
||||||
import generalMenu from "@/component/HomePage/generalMenu.vue";
|
import generalMenu from "@/component/HomePage/generalMenu.vue"
|
||||||
import eventData from "@/assets/json/events.json";
|
import eventData from "@/assets/json/events.json"
|
||||||
import eventDataCn from "@/assets/json/events_cn.json";
|
import eventDataCn from "@/assets/json/events_cn.json"
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex"
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
generalMenu,
|
generalMenu,
|
||||||
fullScreenImg,
|
fullScreenImg
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
isScroll: {
|
isScroll: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default:true,
|
default: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const router = useRouter();
|
const { t, locale } = useI18n()
|
||||||
const store = useStore();
|
const router = useRouter()
|
||||||
|
const store = useStore()
|
||||||
let filter: any = reactive({
|
let filter: any = reactive({
|
||||||
eventsDetail: {
|
eventsDetail: {},
|
||||||
},
|
|
||||||
getListDate: {
|
getListDate: {
|
||||||
"getLikePortfolio": 0,
|
getLikePortfolio: 0,
|
||||||
"getMyPortfolio": 0,
|
getMyPortfolio: 0,
|
||||||
page: 1,
|
page: 1,
|
||||||
size:10,
|
size: 10
|
||||||
},
|
},
|
||||||
isShowMark: false,
|
isShowMark: false,
|
||||||
isNoData: false, //如果数据为空就不加载
|
isNoData: false, //如果数据为空就不加载
|
||||||
loadingShow:{},
|
loadingShow: {}
|
||||||
})
|
})
|
||||||
let likeFile = (item:any,type:string) => {
|
let likeFile = (item: any, type: string) => {}
|
||||||
}
|
|
||||||
let setBack = () => {
|
let setBack = () => {
|
||||||
router.go(-1);
|
router.go(-1)
|
||||||
// router.push('/home/events')
|
// router.push('/home/events')
|
||||||
}
|
}
|
||||||
let openButton = (data: any, index: number) => {
|
let openButton = (data: any, index: number) => {
|
||||||
@@ -80,29 +113,40 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
filter.loadingShow[index] = true
|
filter.loadingShow[index] = true
|
||||||
Https.axiosGet(data.https).then(
|
Https.axiosGet(data.https)
|
||||||
(rv: any) => {
|
.then((rv: any) => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
message.success(data.success)
|
message.success(data.success)
|
||||||
filter.loadingShow[index] = false
|
filter.loadingShow[index] = false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
).catch(res=>{
|
.catch((res) => {
|
||||||
filter.loadingShow[index] = false
|
filter.loadingShow[index] = false
|
||||||
});
|
})
|
||||||
|
}
|
||||||
|
const openDetail = () => {
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const { t, locale } = useI18n();
|
const currentLocale = locale.value
|
||||||
const currentLocale = locale.value;
|
|
||||||
let eventLangData: any
|
let eventLangData: any
|
||||||
if(currentLocale == 'ENGLISH'){
|
if (currentLocale == "ENGLISH") {
|
||||||
eventLangData = eventData
|
eventLangData = eventData
|
||||||
} else {
|
} else {
|
||||||
eventLangData = eventDataCn
|
eventLangData = eventDataCn
|
||||||
}
|
}
|
||||||
eventLangData.eventsItem.forEach((item: any) => {
|
eventLangData.eventsItem.forEach((item: any) => {
|
||||||
if (item.id == router.currentRoute.value.query.eventId) {
|
if (item.id == router.currentRoute.value.query.eventId) {
|
||||||
filter.eventsDetail = item;
|
filter.eventsDetail = item
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -111,6 +155,7 @@ export default defineComponent({
|
|||||||
likeFile,
|
likeFile,
|
||||||
setBack,
|
setBack,
|
||||||
openButton,
|
openButton,
|
||||||
|
openDetail
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
@@ -120,9 +165,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted(){
|
async mounted() {}
|
||||||
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@@ -176,7 +219,8 @@ export default defineComponent({
|
|||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.eventsDetail_content_left,.eventsDetail_content_right{
|
.eventsDetail_content_left,
|
||||||
|
.eventsDetail_content_right {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -199,8 +243,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
.eventsDetail_content_right {
|
.eventsDetail_content_right {
|
||||||
.modal_title_text {
|
.modal_title_text {
|
||||||
letter-spacing: .4rem;
|
letter-spacing: 0.3rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
&-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
> div:first-child {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
.modal_title_text_intro {
|
.modal_title_text_intro {
|
||||||
display: block;
|
display: block;
|
||||||
&.active {
|
&.active {
|
||||||
@@ -209,7 +264,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
li {
|
li {
|
||||||
width: 48%;
|
width: 48%;
|
||||||
|
|
||||||
}
|
}
|
||||||
em {
|
em {
|
||||||
// font-family: auto;
|
// font-family: auto;
|
||||||
@@ -221,20 +275,44 @@ export default defineComponent({
|
|||||||
.eventsDetail_content_right_btn_box {
|
.eventsDetail_content_right_btn_box {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
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 {
|
.modal_title_text:last-child::after {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
border-top: 3px solid;
|
border-top: 3px solid;
|
||||||
height: 6rem;
|
height: 6rem;
|
||||||
}
|
}
|
||||||
|
.modal_title_text.award:last-child:after {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.detail-btn {
|
||||||
|
// width: 11rem;
|
||||||
|
padding: 0 1.4rem;
|
||||||
|
height: 4rem;
|
||||||
|
line-height: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 2rem;
|
||||||
|
background-color: #000;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
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>
|
</style>
|
||||||
@@ -531,7 +531,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const setSpeed = (item: any) => {
|
const setSpeed = (item: any) => {
|
||||||
speed.speedData = item
|
speed.speedData = {...item}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.msg == 'Sketchboard') {
|
if (props.msg == 'Sketchboard') {
|
||||||
@@ -734,6 +734,8 @@ export default defineComponent({
|
|||||||
let maxImg = 8
|
let maxImg = 8
|
||||||
if (this.type_.type2 == 'Sketchboard') {
|
if (this.type_.type2 == 'Sketchboard') {
|
||||||
maxImg = 20
|
maxImg = 20
|
||||||
|
}else if(this.type_.type2 == 'Printboard'){
|
||||||
|
maxImg = 16
|
||||||
}
|
}
|
||||||
let parent: any = this.$parent
|
let parent: any = this.$parent
|
||||||
if (parent.isUseGenerate) {
|
if (parent.isUseGenerate) {
|
||||||
@@ -853,9 +855,7 @@ export default defineComponent({
|
|||||||
level2Type = this.sketchboardList?.[0]?.categoryValue
|
level2Type = this.sketchboardList?.[0]?.categoryValue
|
||||||
? this.sketchboardList[0].categoryValue
|
? this.sketchboardList[0].categoryValue
|
||||||
: ''
|
: ''
|
||||||
if (this.workspace.styleName) {
|
sloganText = `${this.workspace.styleName || 'all'},${sloganText}`
|
||||||
sloganText = `${this.workspace.styleName},${sloganText}`
|
|
||||||
}
|
|
||||||
} else if (this.upload.level1Type == 'Printboard') {
|
} else if (this.upload.level1Type == 'Printboard') {
|
||||||
level2Type = this.scene?.value
|
level2Type = this.scene?.value
|
||||||
if (level2Type == 'Slogan' && this.searchPictureName == '') {
|
if (level2Type == 'Slogan' && this.searchPictureName == '') {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
:get-container="() => $refs.upgradePlan"
|
:get-container="() => $refs.upgradePlan"
|
||||||
width="35%"
|
width="35%"
|
||||||
height="auto"
|
height="auto"
|
||||||
|
zIndex="9999999"
|
||||||
:maskClosable="false"
|
:maskClosable="false"
|
||||||
:centered="true"
|
:centered="true"
|
||||||
:closable="false"
|
:closable="false"
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="payment">
|
<div class="payment">
|
||||||
<div class="allocation">
|
<div class="allocation">
|
||||||
<div class="selectType">
|
<!-- <div class="selectType">
|
||||||
<div class="text">{{ $t('Renew.Payment') }}:</div>
|
<div class="text">{{ $t('Renew.Payment') }}:</div>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t('Renew.Alipay') }}
|
{{ $t('Renew.Alipay') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="gallery_btn gallery_btn_radius" @click="payment">
|
<div class="gallery_btn gallery_btn_radius" @click="payment">
|
||||||
{{ $t('upgradePlan.Continue') }}
|
{{ $t('upgradePlan.Continue') }}
|
||||||
|
|||||||
@@ -77,17 +77,10 @@ export default defineComponent({
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%,-50%);
|
transform: translate(-50%,-50%);
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
max-height: 80vh;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: max-content;
|
|
||||||
video{
|
video{
|
||||||
width: 100%;
|
|
||||||
max-height:80vh;
|
max-height:80vh;
|
||||||
height: 100%;
|
max-width:80vw;
|
||||||
object-fit: contain;
|
|
||||||
width: max-content;
|
|
||||||
}
|
}
|
||||||
.general_video_btn{
|
.general_video_btn{
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|||||||
@@ -790,7 +790,6 @@ export default defineComponent({
|
|||||||
.login_form_content {
|
.login_form_content {
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&[state="2"] {
|
&[state="2"] {
|
||||||
> * {
|
> * {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -826,7 +826,6 @@ export default defineComponent({
|
|||||||
.login_form_content {
|
.login_form_content {
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&[state="2"] {
|
&[state="2"] {
|
||||||
> * {
|
> * {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ defineExpose({
|
|||||||
/* 图片网格 */
|
/* 图片网格 */
|
||||||
.image-grid {
|
.image-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
align-content: start;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ export default defineComponent({
|
|||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t,locale} = useI18n()
|
const {t,locale} = useI18n()
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
const route = useRoute()
|
||||||
const editDesignType = reactive({
|
const editDesignType = reactive({
|
||||||
selectProbject:computed(()=>{
|
selectProbject:computed(()=>{
|
||||||
return store.state.Workspace.probjects
|
return store.state.Workspace.probjects
|
||||||
@@ -624,6 +625,7 @@ export default defineComponent({
|
|||||||
collItemSize.collTime = setTimeout(()=>{
|
collItemSize.collTime = setTimeout(()=>{
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
let parentWidth = likeItemDom.value.parentElement.offsetWidth
|
let parentWidth = likeItemDom.value.parentElement.offsetWidth
|
||||||
|
if(parentWidth == 0)return
|
||||||
collItemSize.widthValue.value = collItemSize.widthValue.value == -1?100:collItemSize.widthValue.value
|
collItemSize.widthValue.value = collItemSize.widthValue.value == -1?100:collItemSize.widthValue.value
|
||||||
collItemSize.widthValue.value = collItemSize.widthValue.value > parentWidth?parentWidth:collItemSize.widthValue.value
|
collItemSize.widthValue.value = collItemSize.widthValue.value > parentWidth?parentWidth:collItemSize.widthValue.value
|
||||||
collItemSize.collValue = Math.floor(parentWidth / collItemSize.widthValue.value)
|
collItemSize.collValue = Math.floor(parentWidth / collItemSize.widthValue.value)
|
||||||
@@ -634,7 +636,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
collItemSize.collStyle.width = (collItemDom.value.offsetWidth - 30) / 3 * collItemSize.scale[0] + 'px'
|
collItemSize.collStyle.width = (collItemDom.value.offsetWidth - 30) / 3 * collItemSize.scale[0] + 'px'
|
||||||
collItemSize.collStyle.height = (collItemDom.value.offsetWidth - 30) / 3 * collItemSize.scale[1] + 'px'
|
collItemSize.collStyle.height = (collItemDom.value.offsetWidth - 30) / 3 * collItemSize.scale[1] + 'px'
|
||||||
|
|
||||||
collItemSize.likeStyle.width = collItemSize.itemStyle.width + 'px'
|
collItemSize.likeStyle.width = collItemSize.itemStyle.width + 'px'
|
||||||
collItemSize.likeStyle.height = collItemSize.itemStyle.height + 'px'
|
collItemSize.likeStyle.height = collItemSize.itemStyle.height + 'px'
|
||||||
let elArr = likeItemDom.value.children
|
let elArr = likeItemDom.value.children
|
||||||
@@ -744,6 +745,12 @@ export default defineComponent({
|
|||||||
"userLikeId": likeItem.id
|
"userLikeId": likeItem.id
|
||||||
}
|
}
|
||||||
arrData.push(obj)
|
arrData.push(obj)
|
||||||
|
designData.selectLikeDesign.forEach((v:any)=>{
|
||||||
|
if(v.id === likeItem.id){
|
||||||
|
v.oldSort = v.sort
|
||||||
|
v.sort = likeItem.sort
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
let data = {
|
let data = {
|
||||||
"userLikeGroupId": userGroupId.value,
|
"userLikeGroupId": userGroupId.value,
|
||||||
@@ -1303,9 +1310,9 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
return
|
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) => {
|
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
|
delete parent.oldSort
|
||||||
return {
|
return {
|
||||||
...parent,
|
...parent,
|
||||||
@@ -1532,7 +1539,7 @@ export default defineComponent({
|
|||||||
this.observerData.time = setTimeout(()=>{
|
this.observerData.time = setTimeout(()=>{
|
||||||
|
|
||||||
this.setSystemDesigner(0)
|
this.setSystemDesigner(0)
|
||||||
this.setDesignItemStyle()
|
// this.setDesignItemStyle()
|
||||||
},100)
|
},100)
|
||||||
// const { width } = entry.contentRect;
|
// const { width } = entry.contentRect;
|
||||||
}
|
}
|
||||||
@@ -1930,6 +1937,7 @@ export default defineComponent({
|
|||||||
this.disLikeLoading = true;
|
this.disLikeLoading = true;
|
||||||
Https.axiosPost(Https.httpUrls.designDislike, data)
|
Https.axiosPost(Https.httpUrls.designDislike, data)
|
||||||
.then((rv: any) => {
|
.then((rv: any) => {
|
||||||
|
console.log(rv)
|
||||||
if (rv) {
|
if (rv) {
|
||||||
this.recycleDomHidden = true
|
this.recycleDomHidden = true
|
||||||
this.store.commit("addDesignCollectionList", [design]);
|
this.store.commit("addDesignCollectionList", [design]);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
@changeCanvas="changeCanvas"
|
@changeCanvas="changeCanvas"
|
||||||
@trigger-library="triggerLibrary"
|
@trigger-library="triggerLibrary"
|
||||||
:canvasJSON="canvasJSON"
|
:canvasJSON="canvasJSON"
|
||||||
:hideCanvas="hideCanvas"
|
:hideCanvas="hideCanvas || !key"
|
||||||
ref="editCanvas">
|
ref="editCanvas">
|
||||||
<template #existsImageList>
|
<template #existsImageList>
|
||||||
<ExistsImageList :list="canvasSelectList" @select="handleImageSelect" />
|
<ExistsImageList :list="canvasSelectList" @select="handleImageSelect" />
|
||||||
@@ -135,7 +135,7 @@ export default defineComponent({
|
|||||||
unLikeList:[],
|
unLikeList:[],
|
||||||
locale:null as any,
|
locale:null as any,
|
||||||
t:null as any,
|
t:null as any,
|
||||||
|
key:true as any
|
||||||
})
|
})
|
||||||
const dataDom = reactive({
|
const dataDom = reactive({
|
||||||
toProduct:null as any,
|
toProduct:null as any,
|
||||||
@@ -271,7 +271,7 @@ export default defineComponent({
|
|||||||
allCollectionStr.forEach((itemStr:any)=>{
|
allCollectionStr.forEach((itemStr:any)=>{
|
||||||
let list = [] as any
|
let list = [] as any
|
||||||
allCollection[itemStr.value].forEach((imgItem)=>{
|
allCollection[itemStr.value].forEach((imgItem)=>{
|
||||||
list.push({url:imgItem.url || imgItem.imgUrl})
|
list.push({url:imgItem?.url || imgItem?.imgUrl})
|
||||||
})
|
})
|
||||||
let obj = {
|
let obj = {
|
||||||
value:itemStr.value,
|
value:itemStr.value,
|
||||||
@@ -462,9 +462,11 @@ export default defineComponent({
|
|||||||
imgUrl:imageDataURL,
|
imgUrl:imageDataURL,
|
||||||
userlikeGroupId:'',
|
userlikeGroupId:'',
|
||||||
}
|
}
|
||||||
|
data.key = false
|
||||||
dataDom.publish.init(value)
|
dataDom.publish.init(value)
|
||||||
}
|
}
|
||||||
const setPublish = ()=>{
|
const setPublish = ()=>{
|
||||||
|
data.key = true
|
||||||
saveCanvas()
|
saveCanvas()
|
||||||
}
|
}
|
||||||
return{
|
return{
|
||||||
|
|||||||
@@ -196,9 +196,9 @@ export default defineComponent({
|
|||||||
type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
||||||
httpType:rv.process,//项目类型
|
httpType:rv.process,//项目类型
|
||||||
ageGroup:rv.workspaceVO?.ageGroup,
|
ageGroup:rv.workspaceVO?.ageGroup,
|
||||||
style:rv.workspaceVO?.style,
|
style:rv.workspaceVO?.style || '',
|
||||||
styleId:rv.workspaceVO?.styleId,
|
styleId:rv.workspaceVO?.styleId || null,
|
||||||
styleName:rv.workspaceVO?.styleName,
|
styleName:rv.workspaceVO?.styleName || '',
|
||||||
sex:rv.workspaceVO?.sex,
|
sex:rv.workspaceVO?.sex,
|
||||||
userBrandDnaImg:rv.workspaceVO?.userBrandDnaImg,
|
userBrandDnaImg:rv.workspaceVO?.userBrandDnaImg,
|
||||||
userBrandDnaName:rv.workspaceVO?.userBrandDnaName,
|
userBrandDnaName:rv.workspaceVO?.userBrandDnaName,
|
||||||
|
|||||||
@@ -94,9 +94,9 @@ export default defineComponent({
|
|||||||
type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
||||||
httpType:rv.process,//项目类型
|
httpType:rv.process,//项目类型
|
||||||
ageGroup:rv.workspaceVO.ageGroup,
|
ageGroup:rv.workspaceVO.ageGroup,
|
||||||
style:rv.workspaceVO.style,
|
style:rv.workspaceVO.style || '',
|
||||||
styleId:rv.workspaceVO.styleId,
|
styleId:rv.workspaceVO.styleId || null,
|
||||||
styleName:rv.workspaceVO.styleName,
|
styleName:rv.workspaceVO.styleName || '',
|
||||||
sex:rv.workspaceVO.sex,
|
sex:rv.workspaceVO.sex,
|
||||||
userBrandDnaImg:rv.workspaceVO.userBrandDnaImg,
|
userBrandDnaImg:rv.workspaceVO.userBrandDnaImg,
|
||||||
userBrandDnaName:rv.workspaceVO.userBrandDnaName,
|
userBrandDnaName:rv.workspaceVO.userBrandDnaName,
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
<div class="center">{{ selectObject?.styleName?selectObject?.styleName:$t('Header.All') }}</div>
|
<div class="center">{{ selectObject?.styleName?selectObject?.styleName:$t('Header.All') }}</div>
|
||||||
<div class="gallery_btn" @click="setStyle">{{ $t('Habit.Select') }}</div>
|
<div class="gallery_btn" @click="setStyle">{{ $t('Habit.Select') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="style brand marginBottom">
|
<!-- <div class="style brand marginBottom">
|
||||||
<div class="text">{{$t('Habit.Brand')}}:</div>
|
<div class="text">{{$t('Habit.Brand')}}:</div>
|
||||||
<div class="gallery_btn" @click="setBrandDNA">{{ $t('Habit.Select') }}</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="brandImg" v-if="selectObject.userBrandDna"><img :src="selectObject.userBrandDnaImg"></div>
|
||||||
<div class="brandDNAStrenght marginBottom" v-if="selectObject.userBrandDna">
|
<div class="brandDNAStrenght marginBottom" v-if="selectObject.userBrandDna">
|
||||||
<div class="text" style="font-size: 1.6rem;">
|
<div class="text" style="font-size: 1.6rem;">
|
||||||
@@ -179,9 +179,9 @@ export default defineComponent({
|
|||||||
dataDom.brandDNA.init(data.selectObject);
|
dataDom.brandDNA.init(data.selectObject);
|
||||||
}
|
}
|
||||||
const setWorkspaceStyle = (value:any)=>{
|
const setWorkspaceStyle = (value:any)=>{
|
||||||
data.selectObject.styleName = value.name
|
data.selectObject.styleName = value.name || ''
|
||||||
data.selectObject.style = value.value
|
data.selectObject.style = value.value || ''
|
||||||
data.selectObject.styleId = value.id
|
data.selectObject.styleId = value.id || null
|
||||||
// store.commit('setProbject',data)
|
// store.commit('setProbject',data)
|
||||||
}
|
}
|
||||||
const setWorkspaceBrandDNA = (value:any)=>{
|
const setWorkspaceBrandDNA = (value:any)=>{
|
||||||
@@ -238,9 +238,9 @@ export default defineComponent({
|
|||||||
// type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
// type:rv.process == 'SERIES_DESIGN'?'seriesDesign':'singleProductDesign',
|
||||||
// httpType:rv.process,//项目类型
|
// httpType:rv.process,//项目类型
|
||||||
ageGroup:rv.workspaceVO?.ageGroup,
|
ageGroup:rv.workspaceVO?.ageGroup,
|
||||||
style:rv.workspaceVO?.style,
|
style:rv.workspaceVO?.style || '',
|
||||||
styleId:rv.workspaceVO?.styleId,
|
styleId:rv.workspaceVO?.styleId || null,
|
||||||
styleName:rv.workspaceVO?.styleName,
|
styleName:rv.workspaceVO?.styleName || '',
|
||||||
sex:rv.workspaceVO?.sex,
|
sex:rv.workspaceVO?.sex,
|
||||||
userBrandDnaImg:rv.workspaceVO?.userBrandDnaImg,
|
userBrandDnaImg:rv.workspaceVO?.userBrandDnaImg,
|
||||||
userBrandDnaName:rv.workspaceVO?.userBrandDnaName,
|
userBrandDnaName:rv.workspaceVO?.userBrandDnaName,
|
||||||
|
|||||||
@@ -352,7 +352,8 @@ export default defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
isDesignPage: {
|
isDesignPage: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
|
required:false
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -773,7 +774,7 @@ export default defineComponent({
|
|||||||
data.lastSelectImg = res.data
|
data.lastSelectImg = res.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 同步尾帧文件列表到全局 store
|
// 同步尾帧文件列表到全局 store(使用专门的 lastFrameList)
|
||||||
store.commit('setPoseTransferLastFrameList', {
|
store.commit('setPoseTransferLastFrameList', {
|
||||||
str: 'set',
|
str: 'set',
|
||||||
list: [file]
|
list: [file]
|
||||||
@@ -989,6 +990,7 @@ export default defineComponent({
|
|||||||
if (data.lastSelectImg?.id === item.id) {
|
if (data.lastSelectImg?.id === item.id) {
|
||||||
data.lastSelectImg = {}
|
data.lastSelectImg = {}
|
||||||
}
|
}
|
||||||
|
// 使用专门的 lastFrameList mutation 清空列表
|
||||||
store.commit('setPoseTransferLastFrameList')
|
store.commit('setPoseTransferLastFrameList')
|
||||||
} else {
|
} else {
|
||||||
// 如果删除的是当前选中的首帧,清空选中状态
|
// 如果删除的是当前选中的首帧,清空选中状态
|
||||||
@@ -1176,10 +1178,10 @@ export default defineComponent({
|
|||||||
firstFrameList.value = store.state.HomeStoreModule.uploadElement.filter(
|
firstFrameList.value = store.state.HomeStoreModule.uploadElement.filter(
|
||||||
item => item.frameType === 'first'
|
item => item.frameType === 'first'
|
||||||
)
|
)
|
||||||
|
// 注意:尾帧通过专门的 watch (lastFrameList) 监听,不需要从这里过滤
|
||||||
lastFrameList.value = store.state.HomeStoreModule.uploadElement.filter(
|
// lastFrameList.value = store.state.HomeStoreModule.uploadElement.filter(
|
||||||
item => item.frameType === 'last'
|
// item => item.frameType === 'last'
|
||||||
)
|
// )
|
||||||
// 更新 showFirstFrameList 中项的选中状态
|
// 更新 showFirstFrameList 中项的选中状态
|
||||||
showFirstFrameList.value.forEach((listItem: any) => {
|
showFirstFrameList.value.forEach((listItem: any) => {
|
||||||
if (listItem.id == data.selectImg.id) {
|
if (listItem.id == data.selectImg.id) {
|
||||||
|
|||||||
@@ -916,10 +916,14 @@ export default defineComponent({
|
|||||||
.login_form_content {
|
.login_form_content {
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
min-height: 34rem;
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
margin-top: 2.4rem;
|
margin-top: 2.4rem;
|
||||||
|
min-height: auto;
|
||||||
|
&[state="2"] {
|
||||||
height: 20rem;
|
height: 20rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&[state="2"] {
|
&[state="2"] {
|
||||||
> * {
|
> * {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ setup(props,{emit}) {
|
|||||||
// if(habitSetStyleData.styleList.length == 0){
|
// if(habitSetStyleData.styleList.length == 0){
|
||||||
// getStyleList()
|
// getStyleList()
|
||||||
// }
|
// }
|
||||||
oldDataId = data.styleId
|
oldDataId = data.styleId || null
|
||||||
habitSetStyleData.selectStyle.id = data.styleId
|
habitSetStyleData.selectStyle.id = data.styleId || null
|
||||||
habitSetStyleData.selectStyle.name = data.styleName
|
habitSetStyleData.selectStyle.name = data.styleName || ''
|
||||||
// habitSetStyleData.selectStyleId = 'feng2'
|
// habitSetStyleData.selectStyleId = 'feng2'
|
||||||
}
|
}
|
||||||
let setCover = (item:any)=>{
|
let setCover = (item:any)=>{
|
||||||
@@ -258,6 +258,7 @@ methods: {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.content_bottom_item:nth-child(4n){
|
.content_bottom_item:nth-child(4n){
|
||||||
|
|||||||
@@ -1532,7 +1532,8 @@ export default {
|
|||||||
LiquefactionTool: '液化工具'
|
LiquefactionTool: '液化工具'
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
back: '返回'
|
back: '返回',
|
||||||
|
detail:'查看详情'
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
allUser: '所有用户',
|
allUser: '所有用户',
|
||||||
|
|||||||
@@ -1184,7 +1184,7 @@ export default {
|
|||||||
CanvasTitle: {
|
CanvasTitle: {
|
||||||
ModifySketch: 'Modify Sketch',
|
ModifySketch: 'Modify Sketch',
|
||||||
ModifyItem: 'Modify Item',
|
ModifyItem: 'Modify Item',
|
||||||
RedGreen: 'Edit Front and Back Section',
|
RedGreen: 'Edit Front and Back Section'
|
||||||
},
|
},
|
||||||
Canvas: {
|
Canvas: {
|
||||||
Canvas: 'Canvas',
|
Canvas: 'Canvas',
|
||||||
@@ -1559,7 +1559,7 @@ export default {
|
|||||||
PointSelection: 'Point Selection',
|
PointSelection: 'Point Selection',
|
||||||
MarqueeSelection: 'Marquee Selection',
|
MarqueeSelection: 'Marquee Selection',
|
||||||
BrushSelection: 'Brush Selection',
|
BrushSelection: 'Brush Selection',
|
||||||
Erase: 'Erase',
|
Erase: 'Erase'
|
||||||
},
|
},
|
||||||
speedList: {
|
speedList: {
|
||||||
High: 'High',
|
High: 'High',
|
||||||
@@ -1583,7 +1583,8 @@ export default {
|
|||||||
LiquefactionTool: 'Liquefaction Tool'
|
LiquefactionTool: 'Liquefaction Tool'
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
back: 'Back'
|
back: 'Back',
|
||||||
|
detail: 'View Details'
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
allUser: 'All User',
|
allUser: 'All User',
|
||||||
@@ -1657,7 +1658,7 @@ export default {
|
|||||||
Cancel: 'Cancel',
|
Cancel: 'Cancel',
|
||||||
SelectPlan: 'Select Plan',
|
SelectPlan: 'Select Plan',
|
||||||
AllPlan: 'All',
|
AllPlan: 'All',
|
||||||
PlanStart:'This plan will be actived from',
|
PlanStart: 'This plan will be actived from'
|
||||||
},
|
},
|
||||||
Login: {
|
Login: {
|
||||||
Login: 'Login',
|
Login: 'Login',
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: { enter: "all" },
|
meta: { enter: "all" },
|
||||||
component: () => import("@/views/Register.vue"),
|
component: () => import("@/views/Register.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/register/:lang",
|
||||||
|
name: "registerLang",
|
||||||
|
meta: { enter: "all" },
|
||||||
|
component: () => import("@/views/Register.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/upgrade",
|
path: "/upgrade",
|
||||||
name: "upgrade",
|
name: "upgrade",
|
||||||
@@ -172,6 +178,12 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: { enter: "all" },
|
meta: { enter: "all" },
|
||||||
component: () => import("@/views/HomeRecommend.vue"),
|
component: () => import("@/views/HomeRecommend.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/Square/:lang",
|
||||||
|
name: "HomeRecommendLang",
|
||||||
|
meta: { enter: "all" },
|
||||||
|
component: () => import("@/views/HomeRecommend.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/administrator",
|
path: "/administrator",
|
||||||
name: "administrator",
|
name: "administrator",
|
||||||
@@ -325,6 +337,13 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: { enter: 3 },
|
meta: { enter: 3 },
|
||||||
component: () =>
|
component: () =>
|
||||||
import("@/component/Administrator/SE/getGenerateFrequency/index.vue"),
|
import("@/component/Administrator/SE/getGenerateFrequency/index.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "globalAwardPopularity",
|
||||||
|
name: "globalAwardPopularity",
|
||||||
|
meta: { enter: 3 },
|
||||||
|
component: () =>
|
||||||
|
import("@/component/Administrator/globalAwardPopularity.vue"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -81,14 +81,16 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
left:v.layersObject[i].position?.[1],
|
left:v.layersObject[i].position?.[1],
|
||||||
width:v.layersObject[i].imageSize?.[0],
|
width:v.layersObject[i].imageSize?.[0],
|
||||||
height:v.layersObject[i].imageSize?.[1],
|
height:v.layersObject[i].imageSize?.[1],
|
||||||
transform:`scaleX(${v.layersObject[i].transpose?.[0] || 1}) scaleY(${v.layersObject[i].transpose?.[1] || 1}) rotate(${v.layersObject?.[i]?.rotate || 0}deg)`,
|
transform:`rotate(${v.layersObject?.[i]?.rotate || 0}deg) scaleX(${v.layersObject[i].transpose?.[0] || 1}) scaleY(${v.layersObject[i].transpose?.[1] || 1})`,
|
||||||
}
|
}
|
||||||
v.layersObject[i].centers={
|
v.layersObject[i].centers={
|
||||||
left:0,
|
left:0,
|
||||||
top:0,
|
top:0,
|
||||||
}
|
}
|
||||||
|
if(data?.fromType !== 'resize'){
|
||||||
v.maskMinioUrl = v.layersObject?.[0]?.maskMinioUrl
|
v.maskMinioUrl = v.layersObject?.[0]?.maskMinioUrl
|
||||||
v.maskUrl = v.layersObject?.[0]?.maskUrl
|
v.maskUrl = v.layersObject?.[0]?.maskUrl
|
||||||
|
}
|
||||||
v.layersObject[i].designOpenrtionBtn = false
|
v.layersObject[i].designOpenrtionBtn = false
|
||||||
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
|
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
|
||||||
front[index] = v.layersObject[i]
|
front[index] = v.layersObject[i]
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const HomeStoreModule : Module<DesignDetail,RootState> = {
|
|||||||
},
|
},
|
||||||
setPoseTransferLastFrameList(state,data){
|
setPoseTransferLastFrameList(state,data){
|
||||||
// 支持两种方式:set 替换整个列表;add/删除与 uploadElement 一致
|
// 支持两种方式:set 替换整个列表;add/删除与 uploadElement 一致
|
||||||
if(data.str === 'set'){
|
if(data?.str === 'set'){
|
||||||
state.lastFrameList = data.list || []
|
state.lastFrameList = data.list || []
|
||||||
return
|
return
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const userHabit : Module<UserHabit,RootState> = {
|
|||||||
followeeCount: '-',
|
followeeCount: '-',
|
||||||
followerCount: '-',
|
followerCount: '-',
|
||||||
accountExtendList:null,
|
accountExtendList:null,
|
||||||
systemList:[],
|
systemList:[1],
|
||||||
expireTime:null,
|
expireTime:null,
|
||||||
language:'',
|
language:'',
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
@@ -194,7 +194,7 @@ const userHabit : Module<UserHabit,RootState> = {
|
|||||||
followeeCount: '-',
|
followeeCount: '-',
|
||||||
followerCount: '-',
|
followerCount: '-',
|
||||||
accountExtendList:null,
|
accountExtendList:null,
|
||||||
systemList:[],
|
systemList:[1],
|
||||||
expireTime:null,
|
expireTime:null,
|
||||||
language:'',
|
language:'',
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
@@ -407,7 +407,7 @@ const userHabit : Module<UserHabit,RootState> = {
|
|||||||
item.name = name
|
item.name = name
|
||||||
});
|
});
|
||||||
// const {t} = useI18n()
|
// const {t} = useI18n()
|
||||||
rv.unshift({name:t('Model.all'),value:'',id:''})
|
rv.unshift({name:t('Model.all'),value:'',id:null})
|
||||||
store.commit('setMannequinStyle',rv)
|
store.commit('setMannequinStyle',rv)
|
||||||
resolve('')
|
resolve('')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ const Workspace: Module<DesignDetail, RootState> = {
|
|||||||
},
|
},
|
||||||
setProbject(state, data) {
|
setProbject(state, data) {
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
if (data[key] == undefined) continue
|
let list = ['styleName','styleId','style']
|
||||||
|
if (data[key] == undefined && !list.includes(key)) continue
|
||||||
state.probjects[key] = data[key]
|
state.probjects[key] = data[key]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -198,6 +198,13 @@ const all = (t)=>{
|
|||||||
route: '/administrator/subscriptionPlan',
|
route: '/administrator/subscriptionPlan',
|
||||||
key: 'sub14',
|
key: 'sub14',
|
||||||
isShow: true
|
isShow: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Global Award Popularity',
|
||||||
|
icon: 'usetime',
|
||||||
|
route: '/administrator/globalAwardPopularity',
|
||||||
|
key: 'sub15',
|
||||||
|
isShow: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ export const Https = {
|
|||||||
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
|
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
|
||||||
switchSubAccountSubscribePlan:
|
switchSubAccountSubscribePlan:
|
||||||
'/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
|
'/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
|
||||||
|
getGlobalAwardPopularity: '/api/global-award/page/visit/count', // 获取global award流量
|
||||||
|
|
||||||
//云生成
|
//云生成
|
||||||
designCloud: `/api/design/designCloud`, //创建云生成
|
designCloud: `/api/design/designCloud`, //创建云生成
|
||||||
|
|||||||
@@ -340,12 +340,12 @@ const navTypeList = (t)=>{
|
|||||||
value:'Models',
|
value:'Models',
|
||||||
router:'library=Models'
|
router:'library=Models'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
icon:'fi-ss-gem',
|
// icon:'fi-ss-gem',
|
||||||
label:t('LibraryPage.brandDNA'),
|
// label:t('LibraryPage.brandDNA'),
|
||||||
value:'MyBrand',
|
// value:'MyBrand',
|
||||||
router:'library=MyBrand'
|
// router:'library=MyBrand'
|
||||||
},
|
// },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// history:{
|
// history:{
|
||||||
|
|||||||
@@ -672,6 +672,17 @@ function sketchToMask(sketchImage) {
|
|||||||
img.src = 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 {
|
export {
|
||||||
isEmail,
|
isEmail,
|
||||||
getUploadUrl,
|
getUploadUrl,
|
||||||
@@ -695,5 +706,6 @@ export {
|
|||||||
calculateGradientCoordinate,
|
calculateGradientCoordinate,
|
||||||
segmentImage,
|
segmentImage,
|
||||||
UrlToFile,
|
UrlToFile,
|
||||||
sketchToMask
|
sketchToMask,
|
||||||
|
isValidUrl
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,152 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="apply-container container flex flex-col" ref="applyRef">
|
<div
|
||||||
<div class="title" ref="applyTitleRef">How to Apply</div>
|
class="apply-container flex flex-col"
|
||||||
<div class="sub-title" ref="applySubTitleRef">Requirments</div>
|
id="apply"
|
||||||
<div class="requirments-list flex" ref="reqListRef">
|
ref="applyRef"
|
||||||
<div class="left flex flex-col space-between">
|
>
|
||||||
<div class="item-box" v-for="item in leftRequirment" :key="item.type">
|
<div
|
||||||
|
class="title animation-element"
|
||||||
|
ref="applyTitleRef"
|
||||||
|
>
|
||||||
|
{{ $t('AwardsPage.howToApply') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="sub-title animation-element"
|
||||||
|
ref="applySubTitleRef"
|
||||||
|
>
|
||||||
|
{{ $t('AwardsPage.stepByStep') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="requirments-list flex flex-col"
|
||||||
|
ref="reqListRef"
|
||||||
|
>
|
||||||
|
<div class="top flex">
|
||||||
|
<div
|
||||||
|
class="item-box animation-element"
|
||||||
|
v-for="(item, index) in leftRequirment"
|
||||||
|
:key="item.type"
|
||||||
|
:ref="el => { if(el) itemRefs[index] = el }"
|
||||||
|
:style="{ background: item.background || '#fff' }"
|
||||||
|
>
|
||||||
|
<div class="item-header flex flex-center">
|
||||||
|
<div class="item-title">{{ $t(item.type) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="context-container flex flex-center">
|
||||||
|
<div
|
||||||
|
class="context"
|
||||||
|
v-for="el in item.desc"
|
||||||
|
>
|
||||||
|
{{ $t(el) }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="list"
|
||||||
|
v-if="item.listTitle"
|
||||||
|
>
|
||||||
|
<div class="list-title">{{ $t(item.listTitle) }}</div>
|
||||||
|
<ul class="list-items">
|
||||||
|
<li
|
||||||
|
class="list-item"
|
||||||
|
v-for="el in item.list"
|
||||||
|
>
|
||||||
|
{{ $t(el) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom flex">
|
||||||
|
<div class="step-3 flex flex-col animation-element" ref="step3Ref">
|
||||||
|
<div class="header">{{ $t('AwardsPage.step3Title') }}</div>
|
||||||
|
<div class="content flex">
|
||||||
|
<div class="content-left flex flex-col space-between">
|
||||||
|
<div class="content-item">
|
||||||
<div class="item-header flex align-center">
|
<div class="item-header flex align-center">
|
||||||
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
|
<div class="point"></div>
|
||||||
<div class="item-title">{{ item.type }}</div>
|
<div>{{ $t('AwardsPage.processVideo') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="context" v-for="el in item.desc">
|
<div class="desc-wrapper flex flex-col space-between">
|
||||||
{{ el }}
|
<div class="item-desc">
|
||||||
|
{{ $t('AwardsPage.processVideoDesc') }}
|
||||||
|
</div>
|
||||||
|
<ul class="desc-lists">
|
||||||
|
<div class="desc-lists-title">
|
||||||
|
{{ $t('AwardsPage.videoRequirements') }}
|
||||||
|
</div>
|
||||||
|
<li>{{ $t('AwardsPage.videoFormat') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.videoResolution') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.videoDuration') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.videoSize') }}</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="content-item">
|
||||||
<div class="right">
|
|
||||||
<div class="item-box">
|
|
||||||
<div class="item-box">
|
|
||||||
<div class="item-header flex align-center">
|
<div class="item-header flex align-center">
|
||||||
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
|
<div class="point"></div>
|
||||||
<div class="item-title">{{ rightRequirment.type }}</div>
|
<div>{{ $t('AwardsPage.fileName') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-desc indent">
|
||||||
|
{{ $t('AwardsPage.fileNameDesc') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content-right">
|
||||||
|
<div class="content-item flex flex-col">
|
||||||
|
<div class="item-header flex align-center">
|
||||||
|
<div class="point"></div>
|
||||||
|
<div>{{ $t('AwardsPage.designPortfolio') }}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="desc-wrapper flex-1 flex flex-col space-between"
|
||||||
|
>
|
||||||
|
<ul class="desc-lists">
|
||||||
|
<div class="desc-lists-title">
|
||||||
|
<p>
|
||||||
|
{{ $t('AwardsPage.submitPdf') }}
|
||||||
|
</p>
|
||||||
|
<p>{{ $t('AwardsPage.requiredStructure') }}</p>
|
||||||
|
</div>
|
||||||
|
<li>{{ $t('AwardsPage.pdfDesignTitle') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.pdfMoodboard') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.pdfConcept') }}</li>
|
||||||
|
<div>{{ $t('AwardsPage.pdfConceptDesc') }}</div>
|
||||||
|
</ul>
|
||||||
|
<ul class="desc-lists">
|
||||||
|
<div class="desc-lists-title">
|
||||||
|
<p>{{ $t('AwardsPage.pdfRequirements') }}</p>
|
||||||
|
</div>
|
||||||
|
<li>{{ $t('AwardsPage.pdfMaxPages') }}</li>
|
||||||
|
<li>{{ $t('AwardsPage.pdfMaxSize') }}</li>
|
||||||
|
<li>
|
||||||
|
{{ $t('AwardsPage.pdfLanguage') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="step-4 animation-element" ref="step4Ref">
|
||||||
|
<div class="header flex flex-col flex-center">
|
||||||
|
<p>{{ $t('AwardsPage.step4Title') }}</p>
|
||||||
|
<p class="sub-title">{{ $t('AwardsPage.step4Subtitle') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="content-item">
|
||||||
|
<div class="desc-wrapper flex-1 flex flex-col space-between">
|
||||||
|
<ul class="desc-lists">
|
||||||
|
<div class="desc-lists-title">
|
||||||
|
{{ $t('AwardsPage.step4Desc') }}
|
||||||
|
</div>
|
||||||
|
<li>{{ $t('AwardsPage.finalistPieces') }}</li>
|
||||||
|
<li>
|
||||||
|
{{ $t('AwardsPage.finalistBasedOn') }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ $t('AwardsPage.finalistShipping') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="context" v-for="el in rightRequirment.desc">
|
|
||||||
{{ el }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,40 +157,44 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const leftRequirment = ref([
|
const leftRequirment = ref([
|
||||||
{
|
{
|
||||||
type: 'Video',
|
type: 'AwardsPage.step1Title',
|
||||||
desc: ['The process of doing design']
|
desc: ['AwardsPage.step1Desc']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Design',
|
type: 'AwardsPage.step2Title',
|
||||||
desc: [
|
desc: ['AwardsPage.step2Desc'],
|
||||||
'Structure: design title, moodboard and elaboration (how will you use AiDA to design)',
|
listTitle: 'AwardsPage.step2ListTitle',
|
||||||
'Design sketch: Maximum 4 outfit design with proposed materials'
|
list: [
|
||||||
]
|
'AwardsPage.step2List[0]',
|
||||||
|
'AwardsPage.step2List[1]',
|
||||||
|
'AwardsPage.step2List[2]'
|
||||||
|
],
|
||||||
|
background: '#F9F9F9'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const rightRequirment = ref({
|
const applyRef = ref()
|
||||||
type: 'Submission Format',
|
const applyTitleRef = ref()
|
||||||
desc: [
|
const applySubTitleRef = ref()
|
||||||
'Naming as “AiDA global award 2026_applicantname”',
|
const reqListRef = ref()
|
||||||
'Mp4\n(1080x1920pixels/20mb within 1min)',
|
const itemRefs = ref<HTMLElement[]>([])
|
||||||
'Single PDF file\n(within 15 pages, maximum 20mb)',
|
const step3Ref = ref()
|
||||||
'English or native language\nwith English translation'
|
const step4Ref = ref()
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const applyRef = ref<HTMLElement | null>(null)
|
const hasPlayedAnim = ref(false)
|
||||||
const applyTitleRef = ref<HTMLElement | null>(null)
|
let timeline: gsap.core.Timeline | null = null
|
||||||
const applySubTitleRef = ref<HTMLElement | null>(null)
|
|
||||||
const reqListRef = ref<HTMLElement | null>(null)
|
let observer: IntersectionObserver | null = null
|
||||||
const hasPlayedApplyAnim = ref(false)
|
|
||||||
let applyObserver: IntersectionObserver | null = null
|
|
||||||
|
|
||||||
const setupApplyInitialState = () => {
|
const setupApplyInitialState = () => {
|
||||||
|
// 设置标题和副标题的初始状态
|
||||||
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
|
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
|
||||||
Boolean
|
Boolean
|
||||||
) as HTMLElement[]
|
) as HTMLElement[]
|
||||||
@@ -77,87 +205,121 @@ const setupApplyInitialState = () => {
|
|||||||
transformOrigin: '50% 50%'
|
transformOrigin: '50% 50%'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const headers = reqListRef.value?.querySelectorAll<HTMLElement>('.item-header')
|
|
||||||
const contexts = reqListRef.value?.querySelectorAll<HTMLElement>('.context')
|
// 设置步骤元素的初始状态
|
||||||
gsap.set([headers, contexts], { opacity: 0 })
|
const allStepElements: HTMLElement[] = []
|
||||||
|
if (itemRefs.value && itemRefs.value.length > 0) {
|
||||||
|
allStepElements.push(...itemRefs.value)
|
||||||
|
}
|
||||||
|
if (step3Ref.value) {
|
||||||
|
allStepElements.push(step3Ref.value as HTMLElement)
|
||||||
|
}
|
||||||
|
if (step4Ref.value) {
|
||||||
|
allStepElements.push(step4Ref.value as HTMLElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
const playApplyAnimation = () => {
|
if (allStepElements.length > 0) {
|
||||||
if (hasPlayedApplyAnim.value) return
|
gsap.set(allStepElements, {
|
||||||
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
|
opacity: 0,
|
||||||
Boolean
|
y: 50
|
||||||
) as HTMLElement[]
|
})
|
||||||
const headers = reqListRef.value?.querySelectorAll<HTMLElement>('.item-header')
|
}
|
||||||
const contexts = reqListRef.value?.querySelectorAll<HTMLElement>('.context')
|
}
|
||||||
if (!titleEls.length) return
|
|
||||||
|
|
||||||
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
|
const initAnimations = () => {
|
||||||
tl.to(titleEls, {
|
if (hasPlayedAnim.value) return
|
||||||
opacity: 1,
|
|
||||||
|
timeline = gsap.timeline({
|
||||||
|
defaults: { ease: 'back.out(1.7)' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (applyTitleRef.value && applySubTitleRef.value) {
|
||||||
|
timeline.to([applyTitleRef.value, applySubTitleRef.value], {
|
||||||
scale: 1,
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
duration: 0.6,
|
duration: 0.6,
|
||||||
ease: 'back.out(1.6)',
|
|
||||||
stagger: 0.1
|
stagger: 0.1
|
||||||
})
|
})
|
||||||
if (headers?.length) {
|
|
||||||
tl.to(
|
|
||||||
headers,
|
|
||||||
{
|
|
||||||
opacity: 1,
|
|
||||||
duration: 0.4,
|
|
||||||
stagger: 0.1
|
|
||||||
},
|
|
||||||
'-=0.1'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (contexts?.length) {
|
|
||||||
tl.to(
|
|
||||||
contexts,
|
|
||||||
{
|
|
||||||
opacity: 1,
|
|
||||||
duration: 0.4,
|
|
||||||
stagger: 0.05
|
|
||||||
},
|
|
||||||
'-=0.05'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPlayedApplyAnim.value = true
|
const allStepElements: HTMLElement[] = []
|
||||||
applyObserver?.disconnect()
|
if (itemRefs.value && itemRefs.value.length > 0) {
|
||||||
|
allStepElements.push(...itemRefs.value)
|
||||||
|
}
|
||||||
|
if (step3Ref.value) {
|
||||||
|
allStepElements.push(step3Ref.value as HTMLElement)
|
||||||
|
}
|
||||||
|
if (step4Ref.value) {
|
||||||
|
allStepElements.push(step4Ref.value as HTMLElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allStepElements.length > 0) {
|
||||||
|
timeline.to(allStepElements, {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
duration: 0.6,
|
||||||
|
stagger: 0.2
|
||||||
|
}, '>')
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPlayedAnim.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setupApplyInitialState()
|
setupApplyInitialState()
|
||||||
if ('IntersectionObserver' in window) {
|
observer = new IntersectionObserver(
|
||||||
applyObserver = new IntersectionObserver(
|
|
||||||
(entries) => {
|
(entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
playApplyAnimation()
|
initAnimations()
|
||||||
|
observer?.disconnect()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ threshold: 0.25 }
|
{
|
||||||
|
threshold: 0.3,
|
||||||
|
rootMargin: '0px 0px -100px 0px'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
if (applyRef.value) applyObserver.observe(applyRef.value)
|
|
||||||
} else {
|
// Start observing the component root element
|
||||||
playApplyAnimation()
|
if (applyRef.value) {
|
||||||
|
observer.observe(applyRef.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
applyObserver?.disconnect()
|
// Cleanup animation timeline
|
||||||
|
if (timeline) {
|
||||||
|
timeline.kill()
|
||||||
|
}
|
||||||
|
// Cleanup IntersectionObserver
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.animation-element{
|
||||||
|
will-change: opacity transform;
|
||||||
|
}
|
||||||
.apply-container {
|
.apply-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
height: 143.3rem;
|
||||||
background: url('@/assets/images/award/apply_bg.png') no-repeat;
|
background: url('@/assets/images/award/apply_bg.png') no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
padding: 12.7rem 0 16.9rem;
|
padding: 12.7rem 21.4rem 12rem;
|
||||||
.title {
|
.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #232323;
|
color: #232323;
|
||||||
@@ -172,38 +334,196 @@ onBeforeUnmount(() => {
|
|||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
margin-bottom: 8.2rem;
|
||||||
}
|
}
|
||||||
.requirments-list {
|
.requirments-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-left: 41.4rem;
|
row-gap: 8.2rem;
|
||||||
column-gap: 17.7rem;
|
.top {
|
||||||
margin-top: 12rem;
|
height: 27.4rem;
|
||||||
.left {
|
color: #585858;
|
||||||
color: #232323;
|
column-gap: 4.6rem;
|
||||||
height: 100%;
|
.item-box {
|
||||||
|
height: 27.4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.item-box {
|
.item-box {
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
&:nth-of-type(1) {
|
||||||
|
width: 47rem;
|
||||||
|
flex-grow: initial;
|
||||||
|
}
|
||||||
|
&:nth-of-type(2) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
.item-header {
|
.item-header {
|
||||||
column-gap: 3.2rem;
|
background-color: #424242;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
height: 7.8rem;
|
||||||
.item-title {
|
.item-title {
|
||||||
color: #232323;
|
color: #fff;
|
||||||
font-family: 'PoppinsBold';
|
font-family: 'PoppinsBold';
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 2.8rem;
|
font-size: 2.4rem;
|
||||||
|
text-align: center;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.context-container {
|
||||||
|
margin-top: 4rem;
|
||||||
|
column-gap: 7rem;
|
||||||
|
.list {
|
||||||
|
font-family: 'Instrument';
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
line-height: 3rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.context {
|
.context {
|
||||||
margin-top: 4rem;
|
// margin-top: 4rem;
|
||||||
width: 46.8rem;
|
// width: 46.8rem;
|
||||||
|
text-align: center;
|
||||||
color: #585858;
|
color: #585858;
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
font-size: 2.4rem;
|
font-size: 2.4rem;
|
||||||
padding-left: 5.6rem;
|
// padding-left: 5.6rem;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bottom {
|
||||||
|
column-gap: 4.6rem;
|
||||||
|
height: 63.4rem;
|
||||||
|
.step-3 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.step-3,
|
||||||
|
.step-4 {
|
||||||
|
.header {
|
||||||
|
font-family: 'PoppinsBold';
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
text-align: center;
|
||||||
|
height: 7.4rem;
|
||||||
|
line-height: 7.4rem;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #b10000;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 4rem;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
column-gap: 6.4rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
#ffe8e8 0%,
|
||||||
|
#feefef 25%,
|
||||||
|
#f9f9f9 100%
|
||||||
|
);
|
||||||
|
flex: 1;
|
||||||
|
.content-left {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-item {
|
||||||
|
.item-header {
|
||||||
|
column-gap: 2rem;
|
||||||
|
color: #585858;
|
||||||
|
font-family: 'InstrumentBold';
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
line-height: 3rem;
|
||||||
|
.point {
|
||||||
|
width: 1.2rem;
|
||||||
|
height: 1.2rem;
|
||||||
|
background-color: #b10000;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.item-desc {
|
||||||
|
font-family: 'Instrument';
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
color: #585858;
|
||||||
|
&.indent {
|
||||||
|
padding-left: 3.8rem;
|
||||||
|
line-height: 3rem;
|
||||||
|
padding-top: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.desc-wrapper {
|
||||||
|
margin-top: 3rem;
|
||||||
|
/* 基线行高变量,供子元素计算方块垂直偏移以对齐首行 */
|
||||||
|
--desc-line-height: 3rem;
|
||||||
|
font-family: 'Instrument';
|
||||||
|
font-weight: 400;
|
||||||
|
color: #585858;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
line-height: 3rem;
|
||||||
|
row-gap: 3rem;
|
||||||
|
.desc-lists {
|
||||||
|
/* 使用自定义方块代替浏览器 marker,保证大小为 1rem 并与文字垂直居中 */
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
/* 使内容对齐到首行顶部,方块通过 margin-top 调整到首行中间 */
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0.4rem 0;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
/* 固定为 1rem 方块 */
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
background-color: #585858;
|
||||||
|
flex: 0 0 0.5rem;
|
||||||
|
border-radius: 0;
|
||||||
|
/* 让方块垂直居中于第一行文字:(line-height - square)/2 */
|
||||||
|
margin-top: calc(
|
||||||
|
(var(--desc-line-height, 3rem) - 1rem) / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content-right {
|
||||||
|
.content-item {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.step-4 {
|
||||||
|
width: 45.1rem;
|
||||||
|
.header {
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #424242;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
height: 7.8rem;
|
||||||
|
white-space: pre-line;
|
||||||
|
font-family: 'PoppinsBold';
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
.sub-title {
|
||||||
|
font-family: 'Poppins';
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,34 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bloom container flex flex-col align-center">
|
<div class="bloom flex flex-col align-center">
|
||||||
<div
|
<div
|
||||||
class="title"
|
class="title"
|
||||||
ref="titleRef"
|
ref="titleRef"
|
||||||
>
|
>
|
||||||
Bloom Your Creativity
|
{{ $t('AwardsPage.bloomYourCreativity') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="season"
|
class="season"
|
||||||
ref="subtitleRef"
|
ref="subtitleRef"
|
||||||
>
|
>
|
||||||
Theme of 2026
|
{{ $t('AwardsPage.themeOf2026') }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="desc"
|
class="desc"
|
||||||
ref="textRef"
|
ref="textRef"
|
||||||
>
|
>
|
||||||
Where imagination meets innovation, creativity blooms. This theme celebrates
|
<p class="section-1">
|
||||||
AI as a catalyst for fashion design, allowing your vision to flourish beyond
|
{{ $t('AwardsPage.bloomText.desc1.regular1') }}
|
||||||
traditional boundaries. Let your ideas blossom into extraordinary designs that
|
<span class="arial-bold">
|
||||||
merge human artistry with artificial intelligence.
|
{{ $t('AwardsPage.bloomText.desc1.bold1') }}
|
||||||
|
</span>
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.regular2') }}
|
||||||
|
<span class="arial-bold">
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.bold2') }}
|
||||||
|
</span>
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.regular3') }}
|
||||||
|
<span class="arial-bold">
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.bold3') }}
|
||||||
|
</span>
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.regular4') }}
|
||||||
|
<span class="arial-bold">
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.bold4') }}
|
||||||
|
</span>
|
||||||
|
{{ $t('AwardsPage.bloomText.desc1.regular5') }}
|
||||||
|
</p>
|
||||||
|
<p class="section-2">
|
||||||
|
{{ $t('AwardsPage.bloomText.desc2.regular1') }}
|
||||||
|
<span class="arial-bold">
|
||||||
|
{{ $t('AwardsPage.bloomText.desc2.bold1') }}
|
||||||
|
</span>
|
||||||
|
{{ $t('AwardsPage.bloomText.desc2.regular2') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const titleRef = ref<HTMLElement | null>(null)
|
const titleRef = ref<HTMLElement | null>(null)
|
||||||
const subtitleRef = ref<HTMLElement | null>(null)
|
const subtitleRef = ref<HTMLElement | null>(null)
|
||||||
const textRef = ref<HTMLElement | null>(null)
|
const textRef = ref<HTMLElement | null>(null)
|
||||||
@@ -37,7 +62,9 @@
|
|||||||
let bloomObserver: IntersectionObserver | null = null
|
let bloomObserver: IntersectionObserver | null = null
|
||||||
|
|
||||||
const setupBloomInitialState = () => {
|
const setupBloomInitialState = () => {
|
||||||
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
|
const titleEls = [titleRef.value, subtitleRef.value].filter(
|
||||||
|
Boolean
|
||||||
|
) as HTMLElement[]
|
||||||
if (titleEls.length) {
|
if (titleEls.length) {
|
||||||
gsap.set(titleEls, {
|
gsap.set(titleEls, {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
@@ -58,7 +85,9 @@
|
|||||||
|
|
||||||
const playBloomAnimation = () => {
|
const playBloomAnimation = () => {
|
||||||
if (hasPlayedBloomAnim.value) return
|
if (hasPlayedBloomAnim.value) return
|
||||||
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
|
const titleEls = [titleRef.value, subtitleRef.value].filter(
|
||||||
|
Boolean
|
||||||
|
) as HTMLElement[]
|
||||||
const textEl = textRef.value
|
const textEl = textRef.value
|
||||||
if (!titleEls.length || !textEl) return
|
if (!titleEls.length || !textEl) return
|
||||||
|
|
||||||
@@ -81,7 +110,7 @@
|
|||||||
duration: 0.3,
|
duration: 0.3,
|
||||||
ease: 'power2.out'
|
ease: 'power2.out'
|
||||||
},
|
},
|
||||||
'+=0.12'
|
'-=0.3'
|
||||||
)
|
)
|
||||||
tl.to(
|
tl.to(
|
||||||
textEl,
|
textEl,
|
||||||
@@ -103,8 +132,8 @@
|
|||||||
setupBloomInitialState()
|
setupBloomInitialState()
|
||||||
if ('IntersectionObserver' in window) {
|
if ('IntersectionObserver' in window) {
|
||||||
bloomObserver = new IntersectionObserver(
|
bloomObserver = new IntersectionObserver(
|
||||||
(entries) => {
|
entries => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
playBloomAnimation()
|
playBloomAnimation()
|
||||||
}
|
}
|
||||||
@@ -125,11 +154,19 @@
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
bloomObserver?.disconnect()
|
bloomObserver?.disconnect()
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.arial-bold {
|
||||||
|
font-family: 'ArialBold';
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
.bloom {
|
.bloom {
|
||||||
|
height: 108rem;
|
||||||
padding-top: 12.8rem;
|
padding-top: 12.8rem;
|
||||||
font-family: 'Poppins';
|
font-family: 'Poppins';
|
||||||
background: url('@/assets/images/award/bloom_bg.png') no-repeat;
|
background: url('@/assets/images/award/bloom_bg.png') no-repeat;
|
||||||
@@ -149,13 +186,17 @@
|
|||||||
}
|
}
|
||||||
.desc {
|
.desc {
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
font-size: 2.8rem;
|
font-weight: 400;
|
||||||
|
font-size: 2.4rem;
|
||||||
color: #585858;
|
color: #585858;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 21.5rem;
|
padding: 0 21.5rem;
|
||||||
line-height: 4.5rem;
|
line-height: 4.5rem;
|
||||||
margin-bottom: 12.3rem;
|
margin-bottom: 12.3rem;
|
||||||
|
white-space: pre-line;
|
||||||
|
.section-2 {
|
||||||
|
margin-top: 4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="judges-container flex flex-col align-center">
|
<div class="judges-container flex flex-col align-center">
|
||||||
<div class="title" ref="judgesTitleRef">Panel of Judges</div>
|
<div class="title" ref="judgesTitleRef">{{ $t('AwardsPage.panelOfJudges') }}</div>
|
||||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||||
<div class="sub-title" ref="judgesSubTitleRef">Expertise</div>
|
<div class="sub-title" ref="judgesSubTitleRef">{{ $t('AwardsPage.expertise') }}</div>
|
||||||
<div class="judgement-list" ref="judgementListRef">
|
<div class="judgement-list" ref="judgementListRef">
|
||||||
<div
|
<div
|
||||||
class="judgement-item flex flex-col align-center"
|
class="judgement-item flex flex-col align-center"
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
:key="item.name"
|
:key="item.name"
|
||||||
>
|
>
|
||||||
<img :src="item.picture" class="picture" />
|
<img :src="item.picture" class="picture" />
|
||||||
<div class="name">{{ item.name }}</div>
|
<div class="name">{{ $t(item.name) }}</div>
|
||||||
<div class="desc">{{ item.desc }}</div>
|
<div class="desc">{{ $t(item.desc) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onBeforeUnmount, onMounted, nextTick, ref } from 'vue'
|
import { onBeforeUnmount, onMounted, nextTick, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
import jae from '@/assets/images/award/jae.png'
|
import jae from '@/assets/images/award/jae.png'
|
||||||
import diego from '@/assets/images/award/diego.png'
|
import diego from '@/assets/images/award/diego.png'
|
||||||
@@ -27,36 +28,38 @@ import vincenzo from '@/assets/images/award/vincenzo.png'
|
|||||||
import tim from '@/assets/images/award/tim.png'
|
import tim from '@/assets/images/award/tim.png'
|
||||||
import desmond from '@/assets/images/award/desmond.png'
|
import desmond from '@/assets/images/award/desmond.png'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const judgements = [
|
const judgements = [
|
||||||
{
|
{
|
||||||
picture: jae,
|
picture: jae,
|
||||||
name: 'Jae Hyuk Lim',
|
name: 'Jae Hyuk Lim',
|
||||||
desc: 'Code-create\nKorea Branch Director\nBesfxxk creative director'
|
desc: 'AwardsPage.judgesHat.jae'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
picture: diego,
|
picture: diego,
|
||||||
name: 'Diego Dultzin Lacoste',
|
name: 'Diego Dultzin Lacoste',
|
||||||
desc: 'Co-founder & Chief Father\nOfficer of OnTheList\n(Hong Kong)'
|
desc: 'AwardsPage.judgesHat.diego'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
picture: gregory,
|
picture: gregory,
|
||||||
name: 'Gregory de la Hogue Moran',
|
name: 'Gregory de la Hogue Moran',
|
||||||
desc: 'Senior Designer at\nGabriela Heasrst (Italy)'
|
desc: 'AwardsPage.judgesHat.gregory'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
picture: vincenzo,
|
picture: vincenzo,
|
||||||
name: 'Vincenzo La Torre',
|
name: 'Vincenzo La Torre',
|
||||||
desc: 'Cheif Editor of SCMP Style\n(Hong Kong)'
|
desc: 'AwardsPage.judgesHat.vincenzo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
picture: tim,
|
picture: tim,
|
||||||
name: 'Tim Lim',
|
name: 'Tim Lim',
|
||||||
desc: 'Group Fashion Direction of\n Modern Media Group\n(Shanghai)'
|
desc: 'AwardsPage.judgesHat.tim'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
picture: desmond,
|
picture: desmond,
|
||||||
name: 'Desmond Lim',
|
name: 'Desmond Lim',
|
||||||
desc: 'Cheif Editor of Vogue\n(Singapore)'
|
desc: 'AwardsPage.judgesHat.desmond'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -199,6 +202,9 @@ onBeforeUnmount(() => {
|
|||||||
column-gap: 23.22rem;
|
column-gap: 23.22rem;
|
||||||
row-gap: 8rem;
|
row-gap: 8rem;
|
||||||
padding: 0 25rem 0 26.6rem;
|
padding: 0 25rem 0 26.6rem;
|
||||||
|
div{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
.judgement-item {
|
.judgement-item {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.picture {
|
.picture {
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
class="title"
|
class="title"
|
||||||
ref="prizesTitleRef"
|
ref="prizesTitleRef"
|
||||||
>
|
>
|
||||||
Award & Prizes
|
{{ $t('AwardsPage.awardPrizes') }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||||
<div
|
<div
|
||||||
class="desc"
|
class="desc"
|
||||||
ref="prizesSubTitleRef"
|
ref="prizesSubTitleRef"
|
||||||
>
|
>
|
||||||
Recongnition
|
{{ $t('AwardsPage.recognition') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -24,17 +24,20 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="prize-item flex flex-col flex-center"
|
class="prize-item flex flex-col flex-center"
|
||||||
|
:class="{ smaller: item.smaller }"
|
||||||
v-for="item in prizes"
|
v-for="item in prizes"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
>
|
>
|
||||||
<div class="prize-money">{{ item.money }}</div>
|
<div class="prize-money">
|
||||||
<div class="prize-name">{{ item.name }}</div>
|
{{ $t(item.money) }}
|
||||||
|
</div>
|
||||||
|
<div class="prize-name">{{ $t(item.name) }}</div>
|
||||||
<div class="prize-desc flex flex-col flex-center">
|
<div class="prize-desc flex flex-col flex-center">
|
||||||
<div
|
<div
|
||||||
class="desc-item"
|
class="desc-item"
|
||||||
v-for="el in item.desc"
|
v-for="el in item.desc"
|
||||||
>
|
>
|
||||||
{{ el }}
|
{{ $t(el) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,28 +47,51 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isZh: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const prizes = [
|
const prizes = [
|
||||||
{
|
{
|
||||||
money: 'US$5000',
|
money: 'AwardsPage.grandMoney',
|
||||||
name: 'Grand Prize',
|
name: 'AwardsPage.grandAwards',
|
||||||
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
|
desc: [
|
||||||
|
'AwardsPage.cashAward',
|
||||||
|
'AwardsPage.awardCertificate',
|
||||||
|
'AwardsPage.globalMediaExposure'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
money: 'US$3000',
|
money: 'AwardsPage.goldMoney',
|
||||||
name: 'First Runner-Up',
|
name: 'AwardsPage.goldAwards',
|
||||||
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
|
desc: [
|
||||||
|
'AwardsPage.cashAward',
|
||||||
|
'AwardsPage.awardCertificate',
|
||||||
|
'AwardsPage.globalMediaExposure'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
money: 'US$2000',
|
money: 'AwardsPage.silverMoney',
|
||||||
name: 'Second Runner-Up',
|
name: 'AwardsPage.silverAwards',
|
||||||
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
|
desc: [
|
||||||
|
'AwardsPage.cashAward',
|
||||||
|
'AwardsPage.awardCertificate',
|
||||||
|
'AwardsPage.globalMediaExposure'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
money: 'Certification',
|
money: 'AwardsPage.awardCertification',
|
||||||
name: 'Finalists',
|
name: 'AwardsPage.finalists',
|
||||||
desc: ['Award Ceritificate', 'Global Media Exposure']
|
desc: ['AwardsPage.TravelAllowance', 'AwardsPage.globalMediaExposure'],
|
||||||
|
smaller: !props.isZh
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -214,10 +240,22 @@
|
|||||||
no-repeat;
|
no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
}
|
}
|
||||||
|
&.smaller {
|
||||||
|
.prize-money {
|
||||||
|
font-size: 3.6rem;
|
||||||
|
line-height: 3.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
.prize-money {
|
.prize-money {
|
||||||
font-family: 'PoppinsBold';
|
font-family: 'PoppinsBold';
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
|
white-space: pre-line;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 7.6rem;
|
||||||
|
&.smaller {
|
||||||
|
font-size: 3.6rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.prize-name {
|
.prize-name {
|
||||||
font-family: 'PoppinsMedium';
|
font-family: 'PoppinsMedium';
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
class="selection-container container flex flex-col align-center"
|
class="selection-container container flex flex-col align-center"
|
||||||
ref="selectionRef"
|
ref="selectionRef"
|
||||||
>
|
>
|
||||||
<div class="title">Selection Criteria</div>
|
<div class="title">{{ $t('AwardsPage.selectionCriteria') }}</div>
|
||||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||||
<div class="sub-title">Evaluation</div>
|
<div class="sub-title">{{ $t('AwardsPage.evaluation') }}</div>
|
||||||
<div class="criteria-list flex" ref="criteriaListRef">
|
<div class="criteria-list flex" ref="criteriaListRef">
|
||||||
<div
|
<div
|
||||||
class="item flex flex-col align-center"
|
class="item flex flex-col align-center"
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
:key="item.name"
|
:key="item.name"
|
||||||
>
|
>
|
||||||
<img :src="item.icon" class="icon" :style="item.style" />
|
<img :src="item.icon" class="icon" :style="item.style" />
|
||||||
<div class="name">{{ item.name }}</div>
|
<div class="name">{{ $t(item.name) }}</div>
|
||||||
<div class="desc">{{ item.desc }}</div>
|
<div class="desc">{{ $t(item.desc) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,35 +22,38 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
import criteria1 from '@/assets/images/award/criteria_1.png'
|
import criteria1 from '@/assets/images/award/criteria_1.png'
|
||||||
import criteria2 from '@/assets/images/award/criteria_2.png'
|
import criteria2 from '@/assets/images/award/criteria_2.png'
|
||||||
import criteria3 from '@/assets/images/award/criteria_3.png'
|
import criteria3 from '@/assets/images/award/criteria_3.png'
|
||||||
import criteria4 from '@/assets/images/award/criteria_4.png'
|
import criteria4 from '@/assets/images/award/criteria_4.png'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const criteriaList = ref([
|
const criteriaList = ref([
|
||||||
{
|
{
|
||||||
icon: criteria1,
|
icon: criteria1,
|
||||||
name: 'Originality',
|
name: 'AwardsPage.originality',
|
||||||
desc: 'Unique perspective and innovative approach to fashion design',
|
desc: 'AwardsPage.originalityDesc',
|
||||||
style: { width: '13rem', height: '17rem' }
|
style: { width: '13rem', height: '17rem' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: criteria2,
|
icon: criteria2,
|
||||||
name: 'Creativity',
|
name: 'AwardsPage.creativity',
|
||||||
desc: 'Artistic vision and exceptional design excellence',
|
desc: 'AwardsPage.creativityDesc',
|
||||||
style: { width: '16rem', height: '18rem' }
|
style: { width: '16rem', height: '18rem' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: criteria3,
|
icon: criteria3,
|
||||||
name: 'AiDA Integration',
|
name: 'AwardsPage.aidaIntegration',
|
||||||
desc: 'Effective application of AI design tools and functions',
|
desc: 'AwardsPage.aidaIntegrationDesc',
|
||||||
style: { width: '16rem', height: '18rem' }
|
style: { width: '16rem', height: '18rem' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: criteria4,
|
icon: criteria4,
|
||||||
name: 'Execution',
|
name: 'AwardsPage.execution',
|
||||||
desc: 'Quality of presentation and technical craftsmanship',
|
desc: 'AwardsPage.executionDesc',
|
||||||
style: { width: '18.8rem', height: '18rem' }
|
style: { width: '18.8rem', height: '18rem' }
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
@@ -166,6 +169,7 @@ onBeforeUnmount(() => {
|
|||||||
font-size: 2.4rem;
|
font-size: 2.4rem;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="blocks-list flex" ref="root" :class="{ 'in-view': inView }">
|
<div
|
||||||
|
class="blocks-list flex"
|
||||||
|
ref="root"
|
||||||
|
:class="{ 'in-view': inView }"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="block-item flex flex-col flex-center"
|
class="block-item flex flex-col flex-center"
|
||||||
v-for="(item, idx) in blocksList"
|
v-for="(item, idx) in blocksList"
|
||||||
:key="item.number"
|
:key="item.number"
|
||||||
:style="{ '--delay': `${idx * 0.18}s` }"
|
:style="{ '--delay': `${idx * 0.18}s` }"
|
||||||
>
|
>
|
||||||
<div class="number">{{ item.number }}</div>
|
<div class="number">{{ $t(item.number) }}</div>
|
||||||
<div class="label">{{ item.label }}</div>
|
<div class="label">{{ $t(item.label) }}</div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const blocksList = ref([
|
const blocksList = ref([
|
||||||
{
|
{
|
||||||
number: 'NETWORKING\n OPPORTUNITIES',
|
number: 'AwardsPage.totalCashPrizes',
|
||||||
label: 'with international\nmedia and designers'
|
label: 'AwardsPage.totalCashPrizesLabel'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 'INTERNATIONAL\nMEDIA EXPOSE',
|
number: 'AwardsPage.globalMediaExpose',
|
||||||
label: 'through\nleading outlets'
|
label: 'AwardsPage.globalMediaExposeLabel'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 'UP TO\nUS$9000',
|
number: 'AwardsPage.networkingOpportunities',
|
||||||
label: 'in total prize\npool awards'
|
label: 'AwardsPage.networkingOpportunitiesLabel'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 'TRAVEL\NALLOWANCE',
|
number: 'AwardsPage.awardCeremonyHongKong',
|
||||||
label: 'for finalists to attend\naward ceremony'
|
label: 'AwardsPage.awardCeremonyLabel'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const root = ref<HTMLElement | null>(null)
|
const root = ref<HTMLElement | null>(null)
|
||||||
@@ -40,7 +47,7 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
io = new IntersectionObserver(
|
io = new IntersectionObserver(
|
||||||
(entries) => {
|
entries => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
// 延迟 0.5s 后触发动画并断开观察
|
// 延迟 0.5s 后触发动画并断开观察
|
||||||
@@ -112,17 +119,17 @@
|
|||||||
|
|
||||||
/* 当组件进入视口并且等待 0.5s 后,.in-view 会加入根节点,下面规则触发动画 */
|
/* 当组件进入视口并且等待 0.5s 后,.in-view 会加入根节点,下面规则触发动画 */
|
||||||
.in-view .block-item .number {
|
.in-view .block-item .number {
|
||||||
animation: scaleIn 0.48s cubic-bezier(.2,.9,.2,1) forwards;
|
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
|
||||||
animation-delay: var(--delay);
|
animation-delay: var(--delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
.in-view .block-item .label {
|
.in-view .block-item .label {
|
||||||
animation: scaleIn 0.48s cubic-bezier(.2,.9,.2,1) forwards;
|
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
|
||||||
animation-delay: calc(var(--delay) + 0.12s);
|
animation-delay: calc(var(--delay) + 0.12s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.in-view .block-item .line {
|
.in-view .block-item .line {
|
||||||
animation: growLine 0.7s cubic-bezier(.2,.9,.2,1) forwards;
|
animation: growLine 0.7s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
|
||||||
animation-delay: calc(var(--delay) + 0.18s);
|
animation-delay: calc(var(--delay) + 0.18s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
alt=""
|
alt=""
|
||||||
class="icon-img"
|
class="icon-img"
|
||||||
/>
|
/>
|
||||||
<div class="title">{{ info.title }}</div>
|
<div class="title">{{ $t(info.title) }}</div>
|
||||||
<div class="desc">
|
<div class="desc">
|
||||||
{{ info.desc }}
|
{{ $t(info.desc) }}
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
Please review your submitted information in the AiDA in-platform message.
|
Please review your submitted information in the AiDA in-platform message.
|
||||||
</div>
|
</div>
|
||||||
@@ -21,8 +21,11 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import successIcon from '@/assets/images/award/successful.png'
|
import successIcon from '@/assets/images/award/successful.png'
|
||||||
import expiredIcon from '@/assets/images/award/expired.png'
|
import expiredIcon from '@/assets/images/award/expired.png'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isExpired: {
|
isExpired: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -34,14 +37,14 @@
|
|||||||
if (props.isExpired) {
|
if (props.isExpired) {
|
||||||
return {
|
return {
|
||||||
icon: expiredIcon,
|
icon: expiredIcon,
|
||||||
title: 'Application Deadline Passed',
|
title: 'AwardsPage.deadlinePassed',
|
||||||
desc: 'The submission deadline for AIDA Global Fashion Award 2026 has ended.\nWe are no longer accepting new applications. '
|
desc: 'AwardsPage.deadlinePassedDesc'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
icon: successIcon,
|
icon: successIcon,
|
||||||
title: 'Submission Successful',
|
title: 'AwardsPage.submissionSuccessful',
|
||||||
desc: 'Please review your submitted information in the AiDA in-platform message.\nYou may edit it if needed. Competition updates and results will be sent via email.'
|
desc: 'AwardsPage.submissionSuccessfulDesc'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,54 +3,62 @@
|
|||||||
ref="containerRef"
|
ref="containerRef"
|
||||||
class="timeline-container container flex flex-col align-center"
|
class="timeline-container container flex flex-col align-center"
|
||||||
>
|
>
|
||||||
<div class="timeline-title">Competition Timeline</div>
|
<div class="timeline-title">{{ $t('AwardsPage.competitionTimeline') }}</div>
|
||||||
<div class="desc">Shaping the Future</div>
|
<div class="desc">{{ $t('AwardsPage.shapingTheFuture') }}</div>
|
||||||
<div class="timeline-point">
|
|
||||||
<div class="labels-row flex align-center">
|
|
||||||
<div
|
<div
|
||||||
class="item-label flex flex-col"
|
class="timeline-point"
|
||||||
|
ref="timelineRef"
|
||||||
|
>
|
||||||
|
<!-- 顶部标签行 -->
|
||||||
|
<div class="grid-row labels-row">
|
||||||
|
<div
|
||||||
|
class="grid-cell label-cell"
|
||||||
v-for="item in points"
|
v-for="item in points"
|
||||||
:key="'label-' + item.time"
|
:key="'label-' + item.time"
|
||||||
>
|
>
|
||||||
<div class="main-label">{{ item.label }}</div>
|
<div class="main-label">{{ $t(item.label) }}</div>
|
||||||
<div
|
<div
|
||||||
class="sub-label"
|
class="sub-label"
|
||||||
v-if="item.subLabel"
|
v-if="item.subLabel"
|
||||||
>
|
>
|
||||||
{{ item.subLabel }}
|
{{ $t(item.subLabel) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Icons row -->
|
<!-- 图标行 -->
|
||||||
<div class="icons-row flex align-center">
|
<div class="grid-row icons-row">
|
||||||
<div class="timeline-line"></div>
|
<div class="timeline-line"></div>
|
||||||
|
<div
|
||||||
|
class="grid-cell icon-cell"
|
||||||
|
v-for="item in points"
|
||||||
|
:key="'icon-' + item.time"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
src="@/assets/images/award/point.png"
|
src="@/assets/images/award/point.png"
|
||||||
class="point-icon"
|
class="point-icon"
|
||||||
v-for="item in points"
|
|
||||||
:key="'icon-' + item.time"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Times row -->
|
<!-- 时间行 -->
|
||||||
<div class="times-row flex align-center">
|
<div class="grid-row times-row">
|
||||||
<div
|
<div
|
||||||
class="item-time"
|
class="grid-cell time-cell"
|
||||||
v-for="item in points"
|
v-for="item in points"
|
||||||
:key="'time-' + item.time"
|
:key="'time-' + item.time"
|
||||||
>
|
>
|
||||||
{{ item.time }}
|
{{ $t(item.time) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Descriptions row -->
|
|
||||||
<div class="descs-row flex align-center">
|
<!-- 描述行 -->
|
||||||
|
<div class="grid-row descs-row">
|
||||||
<div
|
<div
|
||||||
class="item-desc flex justify-center"
|
class="grid-cell desc-cell"
|
||||||
v-for="item in points"
|
v-for="item in points"
|
||||||
:key="'desc-' + item.time"
|
:key="'desc-' + item.time"
|
||||||
>
|
>
|
||||||
<div class="txt">
|
<div class="txt">
|
||||||
{{ item.desc }}
|
{{ $t(item.desc) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,34 +67,46 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { nextTick, onBeforeUnmount, onMounted, ref, computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { gsap } from 'gsap'
|
import { gsap } from 'gsap'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const containerRef = ref<HTMLElement | null>(null)
|
const containerRef = ref<HTMLElement | null>(null)
|
||||||
|
const timelineRef = ref<HTMLElement | null>(null)
|
||||||
const hasAnimated = ref(false)
|
const hasAnimated = ref(false)
|
||||||
|
|
||||||
const points = ref([
|
const points = ref([
|
||||||
{
|
{
|
||||||
label: 'Select Top 20',
|
label: 'AwardsPage.timelineApplicationLabel',
|
||||||
time: 'May',
|
subLabel: 'AwardsPage.timelineDeadlineLabel',
|
||||||
desc: 'Submit your design concept, mood board, and initial sketch.'
|
time: 'AwardsPage.timeJul15',
|
||||||
|
desc: 'AwardsPage.applicationDeadlineDesc'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: `Top 20`,
|
label: 'AwardsPage.twentyFinalistsAnnounced',
|
||||||
subLabel: 'Collections Finalize',
|
subLabel: 'AwardsPage.announcedLabel',
|
||||||
time: 'June',
|
time: 'AwardsPage.timeAug30',
|
||||||
desc: 'Complete collections, physical garments, and AiDA process videos due.'
|
desc: 'AwardsPage.twentyFinalistsDesc'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: `Top 3`,
|
label: 'AwardsPage.finalistSubmission',
|
||||||
subLabel: 'Finalists Select',
|
subLabel: 'AwardsPage.submissionLabel',
|
||||||
time: 'August',
|
time: 'AwardsPage.timeSept30',
|
||||||
desc: 'Complete collections, physical garments, and AiDA process videos due.'
|
desc: 'AwardsPage.finalistSubmissionDesc'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Award Ceremony',
|
label: 'AwardsPage.receivingOutfits',
|
||||||
time: 'November',
|
subLabel: 'AwardsPage.fromFinalistsLabel',
|
||||||
desc: 'Winners revealed with media coverage and live showcase.'
|
time: 'AwardsPage.timeOctober',
|
||||||
|
desc: 'AwardsPage.receivingOutfitsDesc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'AwardsPage.awardCeremony',
|
||||||
|
subLabel: 'AwardsPage.ceremonyLabel',
|
||||||
|
time: 'AwardsPage.timeNov12',
|
||||||
|
desc: 'AwardsPage.awardCeremonyDesc'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -98,17 +118,12 @@
|
|||||||
const timeline = containerRef.value.querySelector('.timeline-point')
|
const timeline = containerRef.value.querySelector('.timeline-point')
|
||||||
|
|
||||||
const tl = gsap.timeline()
|
const tl = gsap.timeline()
|
||||||
if (title && subtitle) {
|
|
||||||
tl.from([title, subtitle], {
|
|
||||||
scaleX: 0,
|
|
||||||
autoAlpha: 0,
|
|
||||||
transformOrigin: '50% 50%',
|
|
||||||
duration: 0.6,
|
|
||||||
stagger: 0.1,
|
|
||||||
ease: 'power2.out'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 我们使用一个统一的开始 label,使横线、timeline 裁剪与所有文字同时启动,
|
||||||
|
// 点图标在它们完成后立即开始。
|
||||||
|
tl.addLabel('start')
|
||||||
|
|
||||||
|
// 整体 timeline 的裁剪展开(与 start 同步)
|
||||||
if (timeline) {
|
if (timeline) {
|
||||||
tl.fromTo(
|
tl.fromTo(
|
||||||
timeline,
|
timeline,
|
||||||
@@ -117,12 +132,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
clipPath: 'inset(0 0% 0 0)',
|
clipPath: 'inset(0 0% 0 0)',
|
||||||
duration: 1.6,
|
duration: 1.3,
|
||||||
ease: 'power1.out'
|
ease: 'power1.out'
|
||||||
}
|
},
|
||||||
|
'start'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 线条动画(与 start 同步)
|
||||||
if (line) {
|
if (line) {
|
||||||
tl.from(
|
tl.from(
|
||||||
line,
|
line,
|
||||||
@@ -132,7 +149,38 @@
|
|||||||
duration: 1.3,
|
duration: 1.3,
|
||||||
ease: 'power1.out'
|
ease: 'power1.out'
|
||||||
},
|
},
|
||||||
'-=1.1'
|
'start'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题与副标题(与 start 同步)
|
||||||
|
if (title && subtitle) {
|
||||||
|
tl.from(
|
||||||
|
[title, subtitle],
|
||||||
|
{
|
||||||
|
scaleX: 0,
|
||||||
|
autoAlpha: 0.5,
|
||||||
|
transformOrigin: '50% 50%',
|
||||||
|
duration: 0.6,
|
||||||
|
stagger: 0.1,
|
||||||
|
ease: 'power2.out'
|
||||||
|
},
|
||||||
|
'start'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行内文字(标签、时间、描述、图标)与 start 同步开始
|
||||||
|
const textItems = containerRef.value.querySelectorAll('.grid-cell')
|
||||||
|
if (textItems && textItems.length) {
|
||||||
|
tl.from(
|
||||||
|
textItems,
|
||||||
|
{
|
||||||
|
// autoAlpha: 0.5,
|
||||||
|
duration: 0.7,
|
||||||
|
stagger: 0.08,
|
||||||
|
ease: 'power2.out'
|
||||||
|
},
|
||||||
|
'start'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,8 +193,8 @@
|
|||||||
await nextTick()
|
await nextTick()
|
||||||
if (!containerRef.value) return
|
if (!containerRef.value) return
|
||||||
observer = new IntersectionObserver(
|
observer = new IntersectionObserver(
|
||||||
(entries) => {
|
entries => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
playAnimation()
|
playAnimation()
|
||||||
}
|
}
|
||||||
@@ -170,7 +218,7 @@
|
|||||||
background: url('@/assets/images/award/timeline_bg.png') no-repeat;
|
background: url('@/assets/images/award/timeline_bg.png') no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-top: 12.8rem;
|
padding: 12.8rem 0 15.9rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
.timeline-title {
|
.timeline-title {
|
||||||
@@ -194,42 +242,45 @@
|
|||||||
will-change: clip-path;
|
will-change: clip-path;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 12rem;
|
margin-top: 11rem;
|
||||||
padding: 0 21.2rem 0 22rem;
|
padding: 0 13.8rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
.labels-row {
|
// 主网格布局:5列
|
||||||
position: relative;
|
display: grid;
|
||||||
z-index: 2;
|
grid-template-columns: repeat(5, 1fr);
|
||||||
margin-bottom: 8rem;
|
grid-template-rows: auto auto auto auto;
|
||||||
.item-label {
|
grid-column-gap: 0;
|
||||||
flex: 1;
|
grid-row-gap: 0;
|
||||||
color: #fff;
|
|
||||||
font-family: 'PoppinsBold';
|
// 所有 grid 子行的通用样式
|
||||||
font-weight: 600;
|
.grid-row {
|
||||||
font-size: 2.8rem;
|
display: grid;
|
||||||
text-align: center;
|
grid-template-columns: repeat(5, 1fr);
|
||||||
white-space: pre-line;
|
grid-column: 1 / -1;
|
||||||
height: 6rem;
|
}
|
||||||
|
|
||||||
|
.grid-cell {
|
||||||
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 图标行
|
||||||
.icons-row {
|
.icons-row {
|
||||||
margin-bottom: 1.6rem;
|
align-items: center;
|
||||||
|
height: 6.4rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
.point-icon {
|
margin-bottom: 1.6rem;
|
||||||
width: 6.4rem;
|
|
||||||
height: 6.4rem;
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.timeline-line {
|
.timeline-line {
|
||||||
width: calc(100% + 22rem + 21.2rem);
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
left: -22rem;
|
left: -22rem;
|
||||||
|
right: -21.2rem;
|
||||||
height: 0.15rem;
|
height: 0.15rem;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
@@ -239,39 +290,78 @@
|
|||||||
rgba(199, 52, 44, 0.762376) 75.96%,
|
rgba(199, 52, 44, 0.762376) 75.96%,
|
||||||
rgba(199, 52, 44, 0) 100%
|
rgba(199, 52, 44, 0) 100%
|
||||||
);
|
);
|
||||||
position: absolute;
|
|
||||||
bottom: 50%;
|
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-cell {
|
||||||
|
position: relative;
|
||||||
|
.point-icon {
|
||||||
|
width: 6.4rem;
|
||||||
|
height: 6.4rem;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 标签行
|
||||||
|
.labels-row {
|
||||||
|
margin-bottom: 8rem;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
.label-cell {
|
||||||
|
flex-direction: column;
|
||||||
|
color: #fff;
|
||||||
|
font-family: 'PoppinsBold';
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 2.8rem;
|
||||||
|
white-space: pre-line;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 6rem;
|
||||||
|
|
||||||
|
// .sub-label {
|
||||||
|
// font-family: 'Arial';
|
||||||
|
// font-weight: 400;
|
||||||
|
// font-size: 1.4rem;
|
||||||
|
// color: rgba(255, 255, 255, 0.8);
|
||||||
|
// margin-top: 0.4rem;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间行
|
||||||
.times-row {
|
.times-row {
|
||||||
margin-bottom: 6rem;
|
margin-bottom: 6rem;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
.item-time {
|
.time-cell {
|
||||||
flex: 1;
|
|
||||||
color: #f95750;
|
color: #f95750;
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 2.8rem;
|
font-size: 2.8rem;
|
||||||
line-height: 4.5rem;
|
line-height: 4.5rem;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 描述行
|
||||||
.descs-row {
|
.descs-row {
|
||||||
.item-desc {
|
.desc-cell {
|
||||||
flex: 1;
|
|
||||||
.txt {
|
.txt {
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
width: 31.2rem;
|
width: 100%;
|
||||||
height: 10.2rem;
|
max-width: 31.2rem;
|
||||||
|
min-height: 10.2rem;
|
||||||
|
white-space: pre-line;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,16 @@
|
|||||||
class="progress-icon successful-icon"
|
class="progress-icon successful-icon"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="text">{{ text }}</div>
|
<div class="text">{{ $t(text) }}</div>
|
||||||
<div class="tips">{{ tips }}</div>
|
<div class="tips">{{ $t(tips) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch } from 'vue'
|
import { computed, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
status: string
|
status: string
|
||||||
type: 'pdf' | 'video'
|
type: 'pdf' | 'video'
|
||||||
@@ -29,16 +32,16 @@
|
|||||||
|
|
||||||
const textMap: Record<string, string> = {
|
const textMap: Record<string, string> = {
|
||||||
idle: '',
|
idle: '',
|
||||||
uploading: 'Upload in progress…',
|
uploading: 'AwardsPage.uploadInProgress',
|
||||||
success: 'Uploaded Successfully',
|
success:'AwardsPage.uploadSuccess',
|
||||||
error: 'Upload failed'
|
error: 'AwardsPage.fileUploadFailed'
|
||||||
}
|
}
|
||||||
|
|
||||||
const tips = computed(() => {
|
const tips = computed(() => {
|
||||||
if (props.type === 'pdf') {
|
if (props.type === 'pdf') {
|
||||||
return 'PDF file, max 20MB'
|
return 'AwardsPage.pdfFileTip'
|
||||||
} else if (props.type === 'video') {
|
} else if (props.type === 'video') {
|
||||||
return 'Video file (MP4, MOV), 1080p, max 100MB'
|
return 'AwardsPage.videoFileTip'
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="award-container">
|
<div class="award-container">
|
||||||
|
<div class="header-wrapper">
|
||||||
<div class="header flex align-center space-between">
|
<div class="header flex align-center space-between">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<img
|
<img
|
||||||
@@ -19,6 +20,8 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="header-placeholder"></div>
|
||||||
|
</div>
|
||||||
<router-view />
|
<router-view />
|
||||||
<div class="footer flex space-between align-center">
|
<div class="footer flex space-between align-center">
|
||||||
<div class="social-list flex">
|
<div class="social-list flex">
|
||||||
@@ -80,23 +83,39 @@
|
|||||||
class="close-icon"
|
class="close-icon"
|
||||||
@click="handleCloseQRcode"
|
@click="handleCloseQRcode"
|
||||||
/>
|
/>
|
||||||
<div class="code-title">WeChat Official Account</div>
|
<div class="code-title">{{ $t('AwardsPage.wechatTitle') }}</div>
|
||||||
<img
|
<img
|
||||||
src="@/assets/images/award/qrcode.jpg"
|
src="@/assets/images/award/qrcode.jpg"
|
||||||
class="qrcode"
|
class="qrcode"
|
||||||
/>
|
/>
|
||||||
<div class="tips">Scan the QR code in WeChat</div>
|
<div class="tips">{{ $t('AwardsPage.wechatDesc') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue'
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { getCookie } from '@/tool/cookie'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { locale } = useI18n()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化语言设置
|
||||||
|
const loginLanguage = localStorage.getItem('loginLanguage')
|
||||||
|
if (loginLanguage) {
|
||||||
|
locale.value = loginLanguage
|
||||||
|
} else {
|
||||||
|
const userLanguage = getCookie('language')
|
||||||
|
if (userLanguage) {
|
||||||
|
locale.value = userLanguage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const showQRcode = ref(false)
|
const showQRcode = ref(false)
|
||||||
const handleCloseQRcode = () => {
|
const handleCloseQRcode = () => {
|
||||||
@@ -107,10 +126,10 @@
|
|||||||
const btnType = ref<BtnType>('index')
|
const btnType = ref<BtnType>('index')
|
||||||
const btnText = computed(() => {
|
const btnText = computed(() => {
|
||||||
if (btnType.value === 'index') {
|
if (btnType.value === 'index') {
|
||||||
return 'Submit your Application'
|
return locale.value === 'CHINESE_SIMPLIFIED' ? '提交申请' : 'Submit your Application'
|
||||||
}
|
}
|
||||||
if (btnType.value === 'form') {
|
if (btnType.value === 'form') {
|
||||||
return 'Back to Introduction'
|
return locale.value === 'CHINESE_SIMPLIFIED' ? '赛事介绍' : 'Back to Introduction'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -142,6 +161,7 @@
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
// 隐藏滚动条箭头,只显示滚动条本体
|
// 隐藏滚动条箭头,只显示滚动条本体
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
width: 0;
|
width: 0;
|
||||||
@@ -150,12 +170,20 @@
|
|||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
}
|
}
|
||||||
|
.header-wrapper {
|
||||||
|
.header-placeholder {
|
||||||
|
height: 8rem;
|
||||||
|
}
|
||||||
.header {
|
.header {
|
||||||
height: 8rem;
|
height: 8rem;
|
||||||
background-color: #232323;
|
background-color: #232323;
|
||||||
padding-left: 21.5rem;
|
padding-left: 21.5rem;
|
||||||
padding-right: 8.6rem;
|
padding-right: 8.6rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 9;
|
||||||
.header-left {
|
.header-left {
|
||||||
.logo {
|
.logo {
|
||||||
width: 13rem;
|
width: 13rem;
|
||||||
@@ -175,6 +203,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.footer {
|
.footer {
|
||||||
height: 10rem;
|
height: 10rem;
|
||||||
padding-left: 21.5rem;
|
padding-left: 21.5rem;
|
||||||
|
|||||||
@@ -1,17 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="award-page">
|
<div
|
||||||
|
class="award-page"
|
||||||
|
:class="{ 'is-zh': isZh }"
|
||||||
|
>
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
|
<video
|
||||||
|
:src="bannerUrl"
|
||||||
|
autoplay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
class="banner-video"
|
||||||
|
playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
x5-playsinline
|
||||||
|
></video>
|
||||||
<div
|
<div
|
||||||
class="submit-btn flex flex-center"
|
class="submit-btn flex flex-center"
|
||||||
@click="handleSubmitApplication"
|
@click="handleSubmitApplication"
|
||||||
>
|
>
|
||||||
<div>Submit your Application</div>
|
<div>{{ $t('AwardsPage.submitApplication') }}</div>
|
||||||
<img
|
<img
|
||||||
src="@/assets/images/award/arrow_right.png"
|
src="@/assets/images/award/arrow_right.png"
|
||||||
alt=""
|
alt=""
|
||||||
class="arrow"
|
class="arrow"
|
||||||
/>
|
/>
|
||||||
<div class="ddl">Application Deadline:15th March 2026</div>
|
<div class="ddl">{{ $t('AwardsPage.applicationDeadline') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -19,14 +32,15 @@
|
|||||||
<Bloom />
|
<Bloom />
|
||||||
<TimeLine />
|
<TimeLine />
|
||||||
<JudgesSection />
|
<JudgesSection />
|
||||||
<PrizesSection />
|
<PrizesSection :is-zh="isZh" />
|
||||||
<ApplySection />
|
<ApplySection />
|
||||||
<SelectionSection />
|
<SelectionSection />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import JudgesSection from './components/JudgesSection.vue'
|
import JudgesSection from './components/JudgesSection.vue'
|
||||||
import SelectionSection from './components/SelectionSection.vue'
|
import SelectionSection from './components/SelectionSection.vue'
|
||||||
@@ -36,7 +50,19 @@
|
|||||||
import Bloom from './components/Bloom.vue'
|
import Bloom from './components/Bloom.vue'
|
||||||
import Slogan from './components/Slogan.vue'
|
import Slogan from './components/Slogan.vue'
|
||||||
|
|
||||||
|
import banner from '@/assets/images/award/banner.mp4'
|
||||||
|
import bannerZh from '@/assets/images/award/banner_chinese.mp4'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { locale } = useI18n()
|
||||||
|
|
||||||
|
const isZh = computed(() => {
|
||||||
|
return locale.value === 'CHINESE_SIMPLIFIED'
|
||||||
|
})
|
||||||
|
|
||||||
|
const bannerUrl = computed(() => {
|
||||||
|
return isZh.value ? bannerZh : banner
|
||||||
|
})
|
||||||
|
|
||||||
const handleSubmitApplication = () => {
|
const handleSubmitApplication = () => {
|
||||||
router.push('/award/contestants')
|
router.push('/award/contestants')
|
||||||
@@ -53,10 +79,15 @@
|
|||||||
height: 2.4rem;
|
height: 2.4rem;
|
||||||
}
|
}
|
||||||
.banner {
|
.banner {
|
||||||
height: 108rem;
|
height: 100rem;
|
||||||
background: url('@/assets/images/award/banner.png') no-repeat;
|
// background: url('@/assets/images/award/banner.png') no-repeat;
|
||||||
background-size: cover;
|
// background-size: cover;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
.banner-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
.submit-btn {
|
.submit-btn {
|
||||||
width: 41rem;
|
width: 41rem;
|
||||||
height: 6.394rem;
|
height: 6.394rem;
|
||||||
@@ -87,11 +118,25 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 41rem;
|
width: 41rem;
|
||||||
font-family: 'Arial';
|
font-family: 'ArialBold';
|
||||||
font-weight: 400;
|
font-weight: 700;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
line-height: 2.2rem;
|
line-height: 2.2rem;
|
||||||
color: #232323E5;
|
color: #232323e5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-zh {
|
||||||
|
.submit-btn {
|
||||||
|
padding: 0 7.5rem;
|
||||||
|
height: 7.8rem;
|
||||||
|
border-radius: 7.74rem;
|
||||||
|
column-gap: 3.8rem;
|
||||||
|
// justify-content: space-between;
|
||||||
|
&,
|
||||||
|
.ddl {
|
||||||
|
width: 35.4rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,7 +400,7 @@
|
|||||||
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
|
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
|
||||||
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
|
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
|
||||||
</a>
|
</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="">
|
<img src="@/assets/images/socialMediaLogo/socialIcons.svg" alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
|
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
|
||||||
|
|||||||