162 Commits

Author SHA1 Message Date
李志鹏
3ed5a37e5b 1 2026-05-15 16:25:08 +08:00
李志鹏
5546c71ec0 线稿图手动排序后更新bug 2026-05-15 15:01:17 +08:00
李志鹏
8a7776a4b6 去掉管理员界面的allUser编辑userName 2026-05-15 10:15:18 +08:00
X1627315083@163.com
a1281c8e3f fix 2026-05-14 18:06:01 +08:00
X1627315083@163.com
9a40e69081 fix 2026-05-14 09:27:06 +08:00
X1627315083@163.com
e27b43dc67 管理员页面增加globalAward流量页面 2026-05-13 17:29:05 +08:00
X1627315083@163.com
b6a55a8124 调整选择风格布局 2026-05-12 17:18:16 +08:00
6cace08a51 style: 去除底边距 2026-04-28 17:11:19 +08:00
6207095221 feat: 管理员页面 2026-04-28 17:11:10 +08:00
李志鹏
7bb38bf2e5 处理Safari 不支持requestIdleCallback方法 2026-04-24 17:11:48 +08:00
X1627315083@163.com
743fc762d6 fix 2026-04-23 16:57:03 +08:00
7297e4e7a4 bugfix 2026-04-23 14:08:59 +08:00
3bff1ebb66 feat: 工具函数 2026-04-23 14:05:00 +08:00
0d1656ee0a style: 字体间距 2026-04-23 13:56:54 +08:00
7d0873d874 style: 调整活动页样式 2026-04-23 13:56:47 +08:00
82941bca7c feat: 活动页 2026-04-23 11:22:21 +08:00
949ff9292d feat: 活动页面文案 2026-04-23 11:10:02 +08:00
X1627315083@163.com
11c9de8ced fix 2026-04-22 16:12:23 +08:00
X1627315083@163.com
fd518ad9b3 更新youtube地址 2026-04-22 13:24:23 +08:00
X1627315083@163.com
a2b45e2041 Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-04-17 16:35:14 +08:00
X1627315083@163.com
da64b57c1c 登录页路由加语言设置 2026-04-17 16:35:12 +08:00
李志鹏
7c14b1d831 Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-04-15 11:37:13 +08:00
李志鹏
8966b52430 红绿图b 2026-04-15 11:37:11 +08:00
X1627315083@163.com
5fa049f73d 隐藏brandDNA功能 2026-04-14 15:30:19 +08:00
X1627315083@163.com
575445f767 fix 2026-04-14 15:27:57 +08:00
李志鹏
f43c56236b 液化苹果浏览器闪屏问题 2026-04-14 10:02:06 +08:00
李志鹏
4352f7c2f4 111 2026-04-13 11:52:24 +08:00
李志鹏
c6b1bdbdf1 红绿图导出问题 2026-04-13 11:20:26 +08:00
X1627315083@163.com
f16aa6ea14 fix 2026-04-10 18:14:20 +08:00
X1627315083@163.com
a25abeb527 fix 2026-04-10 16:54:22 +08:00
X1627315083@163.com
d359cd7763 注释选择信用卡支付和支付宝支付的选项,改为默认信用卡自动续费支付 2026-03-30 10:43:27 +08:00
23085d9a9b Merge branch 'dev_vite' into StableVersion 2026-03-25 10:18:13 +08:00
bb021ae9ac style: 文案修改 2026-03-25 10:12:45 +08:00
bfb4e128f5 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-03-25 09:48:39 +08:00
2f9b33e4ca feat: transaction分页器显示总数据数量 2026-03-25 09:48:36 +08:00
X1627315083@163.com
35c6dfe29c 印花默认为正片叠底 2026-03-24 14:43:12 +08:00
X1627315083@163.com
48c37e0810 风格字段全部处理空情况 2026-03-23 17:22:57 +08:00
b869a82fae Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-03-23 14:08:42 +08:00
e61a8e372d feat: Transaction Record页面totalamount改为所有数据总数 2026-03-23 13:59:17 +08:00
X1627315083@163.com
f5a74991c9 fix 2026-03-23 11:57:10 +08:00
X1627315083@163.com
e58e8540c9 fix 2026-03-23 10:41:16 +08:00
e75ed7684e Merge branch 'StableVersion' into dev_vite 2026-03-13 14:05:39 +08:00
918d71072b bugfix: 首尾帧模式上传图片转视频 2026-03-13 14:01:44 +08:00
X1627315083@163.com
242bc7a01d fix 2026-03-06 18:44:48 +08:00
X1627315083@163.com
02ad8a340a 用户身份默认值改为1 2026-03-05 17:33:50 +08:00
X1627315083@163.com
0c250a21b4 Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-03-05 10:58:10 +08:00
X1627315083@163.com
f781060e7b fix 2026-03-05 10:55:54 +08:00
李志鹏
832c9101ab Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-03-02 11:28:42 +08:00
李志鹏
c48e836f8e fix 2026-03-02 11:28:39 +08:00
李志鹏
6f0780ac2e Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-03-02 11:24:06 +08:00
李志鹏
5acb91e584 fix 2026-03-02 11:24:05 +08:00
X1627315083@163.com
f66ba9e6fa 修复design过程中切换其他页面在切换回来后like异常 2026-03-02 09:50:32 +08:00
7a90cb8db9 feat: 隐藏竞赛活动入口 2026-02-25 15:02:47 +08:00
dafe87fad8 feat: 竞赛页面活动页 2026-02-25 15:01:40 +08:00
c44747e2c2 feat: 竞赛页面地址 2026-02-25 14:48:47 +08:00
X1627315083@163.com
341c765c73 修复getMoudel后直接打开detail印花衣服没有类型我呢提 2026-02-25 13:36:49 +08:00
X1627315083@163.com
ed6cc294a5 注册页面可以根据输入的地址设置不同的语言 2026-02-24 17:27:13 +08:00
X1627315083@163.com
a77dc718f9 fix 2026-02-24 11:30:02 +08:00
X1627315083@163.com
86953a91a1 fix 2026-02-24 11:28:18 +08:00
cabbb653bd Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-09 14:35:33 +08:00
99533c12b6 bugfix: 竞赛表单验证码输入 2026-02-09 11:52:31 +08:00
X1627315083@163.com
59da67e4b4 Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-02-06 16:46:37 +08:00
X1627315083@163.com
1428f191dd fix 2026-02-06 14:17:46 +08:00
李志鹏
13024cdd99 画布loading 2026-02-06 13:07:06 +08:00
李志鹏
fd85ea02c1 画布loading 2026-02-06 13:05:19 +08:00
李志鹏
c196ab6678 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-02-06 11:11:06 +08:00
李志鹏
c005b85c06 设置画布loading 2026-02-06 11:11:04 +08:00
李志鹏
b50dbbc246 去掉部件选取 2026-02-06 10:36:31 +08:00
X1627315083@163.com
01d09f4c34 修复overall印花和画布中印花scale不同 2026-02-05 17:38:27 +08:00
X1627315083@163.com
79c9a66296 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-05 16:49:50 +08:00
X1627315083@163.com
761b1b3512 Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-02-05 16:49:47 +08:00
X1627315083@163.com
b2cb7378d6 修复overall模式角度设置不上 2026-02-05 16:41:56 +08:00
4d9ea75146 chore: i18n内容 2026-02-05 16:30:24 +08:00
f7e6926ee9 bugfix: events i18n 2026-02-05 16:25:12 +08:00
7aba4e30c9 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-05 10:33:47 +08:00
dc1ab330cf AiDA跳转竞赛页面 2026-02-05 10:33:42 +08:00
李志鹏
18c70fe6a3 1 2026-02-05 10:32:56 +08:00
李志鹏
5c746aca4d fix 2026-02-05 10:27:53 +08:00
李志鹏
72c4898101 部件选取框选工具合并操作 2026-02-05 10:26:40 +08:00
X1627315083@163.com
a905971dae 测试 2026-02-05 10:16:52 +08:00
69643dbc83 chore: prettier配置 2026-02-05 10:07:39 +08:00
f3a707d6d8 feat: 上传过程中不允许删除文件 2026-02-05 10:07:30 +08:00
8f4a43db14 feat: size改为form内 2026-02-04 17:30:09 +08:00
186a158114 chore: 中文版竞赛海报 2026-02-04 17:27:20 +08:00
3da4a97400 bugfix: i18n问题 2026-02-04 16:10:10 +08:00
X1627315083@163.com
96b3636aea 取消3d 拼贴功能 2026-02-04 15:59:45 +08:00
228e3d56b5 bugfix: 参赛表单i18n 2026-02-04 13:50:55 +08:00
99ea7eedc7 bugfix: award参赛表单 2026-02-04 13:39:13 +08:00
d4fb435db9 feat: 参赛表单页面i18n 2026-02-04 13:33:05 +08:00
0c8b3ee8f1 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-04 10:57:30 +08:00
ca782d0aff feat: 竞赛主页中文 2026-02-04 10:57:25 +08:00
X1627315083
3dfb607b91 Merge remote-tracking branch 'origin/dev_vite' into StableVersion 2026-02-03 15:29:37 +08:00
X1627315083
981b4dad5c fix 2026-02-03 15:29:07 +08:00
X1627315083
181e6a87b8 Merge remote-tracking branch 'origin/dev_vite' into StableVersion 2026-02-03 10:46:09 +08:00
287825b4bf Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 17:18:17 +08:00
1ffc303721 feat: 竞赛页面AiDA入口 2026-02-02 17:00:32 +08:00
李志鹏
bdf1bb2669 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-02-02 16:52:11 +08:00
李志鹏
1fe79ffcf9 fix 2026-02-02 16:52:10 +08:00
758f63615a style: 字体大小 2026-02-02 16:13:01 +08:00
20145742c5 style: timeline布局修改 2026-02-02 15:48:50 +08:00
8ec9b1bcea Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 14:09:43 +08:00
a9cb6e16e9 style: select样式 2026-02-02 14:09:28 +08:00
X1627315083
5690fc6c5b fix 2026-02-02 13:55:12 +08:00
X1627315083
9db6a589f0 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 13:48:09 +08:00
X1627315083
896490e57b fix 2026-02-02 13:48:07 +08:00
fca04ba44b Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 13:41:56 +08:00
25e4fc06c6 style: 样式修改 2026-02-02 13:41:51 +08:00
X1627315083
4bd7740753 修复detail添加印花sort值设置不对 2026-02-02 13:30:43 +08:00
X1627315083
c428bfd93b Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 11:48:12 +08:00
X1627315083
2a29c6b2cc fix 2026-02-02 11:48:10 +08:00
李志鹏
e9d7203804 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-02-02 11:33:38 +08:00
李志鹏
5d7cec520b 平铺默认参数 2026-02-02 11:33:36 +08:00
X1627315083
fe72df0c07 fix 2026-02-02 11:30:26 +08:00
X1627315083
7c04332290 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-02-02 11:08:22 +08:00
X1627315083
73d912d3cd detail设置印花顺序相关问题 2026-02-02 11:08:20 +08:00
李志鹏
b320294764 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-02-02 10:37:14 +08:00
李志鹏
4913d02c93 fix 2026-02-02 10:37:13 +08:00
X1627315083
56916c8d10 fix 2026-02-02 10:31:37 +08:00
李志鹏
393a06eceb Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-02-02 09:47:13 +08:00
李志鹏
fdb6a87ab4 添加印花元素排序priority 2026-02-02 09:47:10 +08:00
6d868c7c7a Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-30 17:21:15 +08:00
89a89ea5ef style: 竞赛主页样式修改 2026-01-30 17:21:11 +08:00
李志鹏
811e179889 fix 2026-01-30 14:52:10 +08:00
李志鹏
0e0eed2566 fix 2026-01-30 14:12:17 +08:00
李志鹏
8588c74ffd 图层可以持续粘贴 2026-01-30 13:54:21 +08:00
李志鹏
62e7f34c98 画布问题更改 2026-01-30 13:47:38 +08:00
李志鹏
8f0a56965f Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-29 17:17:26 +08:00
李志鹏
59422e54d8 fix 2026-01-29 17:16:31 +08:00
X1627315083
012f0ef1b5 修复画布打开发布后仍然可以对画布里面复制内容 2026-01-29 16:55:38 +08:00
X1627315083
ec4ae4a259 画布打开发布界面复制不能再把图片元素复制到画布上 2026-01-29 15:43:27 +08:00
X1627315083
8da66d54c0 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-29 14:10:57 +08:00
X1627315083
2839953d8e 添加印花默认不正片叠底 2026-01-29 14:10:55 +08:00
X1627315083
2d5d1b7a5e 删除衣服时候imgDom要随着变化 2026-01-29 09:55:15 +08:00
李志鹏
33aaf0b600 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-29 09:38:36 +08:00
李志鹏
bf4d7bdba8 打开服装选取功能 2026-01-29 09:38:33 +08:00
X1627315083
944071201d 修复detail黑色颜色bug 2026-01-28 17:11:28 +08:00
X1627315083
f6556ec9a9 fix 2026-01-28 17:10:58 +08:00
X1627315083
8967439d4e Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-01-28 16:35:58 +08:00
X1627315083
85ae158952 fix 2026-01-28 16:35:40 +08:00
X1627315083
813d2e9645 Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-01-28 16:12:36 +08:00
X1627315083
d94ade6641 fix 2026-01-28 16:11:55 +08:00
X1627315083
eda893ce10 fix 2026-01-28 15:20:02 +08:00
X1627315083
c8cb2de9ab Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-01-28 14:24:23 +08:00
X1627315083
7cda2cce27 调整画布遮罩修改了及时更新 2026-01-28 14:23:31 +08:00
41893cab86 Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-01-28 10:14:31 +08:00
b23531f18b Merge branch 'dev_vite' into StableVersion 2026-01-28 10:11:07 +08:00
de78bfc051 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-28 10:09:48 +08:00
李志鹏
0a507fb158 部件选取icon大小 2026-01-28 10:08:36 +08:00
0930e8cc77 bugfix: 教育管理员搜索用户 2026-01-27 17:34:25 +08:00
李志鹏
1764e2a0bf fix 2026-01-27 13:30:11 +08:00
李志鹏
0729917a7e 打开部件选取 2026-01-27 11:20:56 +08:00
李志鹏
79293901b3 多选解决 2026-01-27 10:58:27 +08:00
李志鹏
8ff7a31e92 部件选取多语言 2026-01-26 17:07:06 +08:00
李志鹏
44674b5396 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-26 16:16:42 +08:00
李志鹏
9cecbdcf9b 部件选取 2026-01-26 16:16:40 +08:00
X1627315083
a6b0a60eb6 调整编辑按钮样式 2026-01-26 15:11:03 +08:00
X1627315083
68067aa777 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-26 15:07:19 +08:00
X1627315083
ca6fe65dd8 detail等比缩放 2026-01-26 15:07:16 +08:00
564e179082 feat: 表单过期 2026-01-26 13:26:46 +08:00
dc469add22 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-26 12:27:59 +08:00
d54e656192 style: award主页动画 2026-01-26 12:27:55 +08:00
李志鹏
ba49b02ebe 印花组不让多选 2026-01-26 09:40:38 +08:00
103 changed files with 12653 additions and 10482 deletions

View File

@@ -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
View 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',
};

Binary file not shown.

Binary file not shown.

View 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');
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 MiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,93 +1,130 @@
{ {
"eventsList": [ "eventsList": [
{
"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",
"imgUrl": "/image/events/workshop-En.jpg"
},
{ {
"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",
"imgUrl": "/image/events/workshop-En.jpg"
},{
"id": 2, "id": 2,
"title":"AiDA X SFT AI Fashion Award 2024", "title": "AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png" "imgUrl": "/image/events/Fashion-Award-2024.png"
},
{
"id": 3,
"title": "AiDA Global Design Awards 2026",
"imgUrl": "/image/events/award-poster.gif"
} }
], ],
"eventsItem":[ "eventsItem": [
{ {
"id":1, "id": 3,
"title":"Just post your design work, you could have the chance to come to Hong Kong and interact with industry leaders face-to-face", "title": "AiDA Global Design Awards 2026",
"imgUrl": "/image/events/workshop-En.jpg", "imgUrl": "/image/events/award-poster.gif",
"textList":[ "tips": "For inquiries: awards2026@code-create.com.hk",
{ "textList": [
"paragraph":[ {
{ "paragraph": [
"text":"🎨AiDA Workshop!" {
} "text": "Click the “View Details” button for more information and to join the competition! The AiDA Global Design Award 2026 is an international design competition hosted by CodeCreate, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers worldwide the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
] }
},{ ]
"paragraph":[ },
{ {
"text":"The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! " "paragraph": [
} {
] "text": "Participants have the opportunity to compete for cash prizes totaling up to US$9,000, gain global media exposure showcased by top international platforms, and connect with designers and industry leaders worldwide. Finalists will also attend an exclusive award ceremony in Hong Kong, with travel allowance, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
},{ }
"paragraph":[ ]
{ }
"text":"<b>⚠ATTENTION❗❗</b>" ]
} },
] {
},{ "id": 1,
"paragraph":[ "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",
"text":"1. Add the tag in the work description #AiDAworkshop_2024" "textList": [
},{ {
"text":"2. One winner only" "paragraph": [
} {
] "text": "🎨AiDA Workshop!"
},{ }
"paragraph":[ ]
{ },
"text":"<b>🤩Code-Create will provide (Terms and conditions apply):</b>" {
} "paragraph": [
] {
},{ "text": "The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
"paragraph":[ }
{ ]
"text":"✅Round-trip transportation fee (only within China)" },
} {
] "paragraph": [
},{ {
"paragraph":[ "text": "<b>⚠ATTENTION❗❗</b>"
{ }
"text":"✅One night accommodation fee" ]
} },
] {
},{ "paragraph": [
"paragraph":[ {
{ "text": "1. Add the tag in the work description #AiDAworkshop_2024"
"text":"⌛Deadline: October 31, 2024" },
} {
] "text": "2. One winner only"
} }
] ]
}, },
{ {
"id":2, "paragraph": [
"title":"AiDA X SFT AI Fashion Award 2024", {
"imgUrl": "/image/events/Fashion-Award-2024.png", "text": "<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
"textList":[ }
{ ]
"paragraph":[ },
{ {
"text":"With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion." "paragraph": [
} {
] "text": "✅Round-trip transportation fee (only within China)"
},{ }
"paragraph":[ ]
{ },
"text":"The competition is open to all SFT students, with the winners having the chance to win cash prizes (up to 20,000 HKD), internship opportunity at BESFXXK (will work with the renowned designer, Mr Jae Hyuk Lim, for the BESFXXK collection, that will be featured at NY Fashion Week and Paris Fashion Week) and more surprises! Scan the QR code to learn more." {
} "paragraph": [
] {
} "text": "✅One night accommodation fee"
] }
]
},
{
"paragraph": [
{
"text": "⌛Deadline: October 31, 2024"
}
]
}
]
},
{
"id": 2,
"title": "AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"textList": [
{
"paragraph": [
{
"text": "With the aim of inspiring students to innovate in fashion design using AI, Code-Create and The Hong Kong Polytechnic University School of Fashion and Textiles (SFT) have jointly launched the 'AiDA X SFT AI Fashion Award 2024'. This competition provides students with valuable practical AiDA experience, laying the foundation for the future fashion design industry and positioning them as pioneers in AI fashion."
}
]
},
{
"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."
}
]
}
]
} }
] ]
} }

View File

@@ -1,93 +1,130 @@
{ {
"eventsList": [ "eventsList": [
{ {
"id": 1, "id": 1,
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!", "title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
"imgUrl": "/image/events/workshop-Cn.jpg" "imgUrl": "/image/events/workshop-Cn.jpg"
},{ },
"id": 2, {
"title":"AiDA X SFT AI时尚设计比赛2024", "id": 2,
"imgUrl": "/image/events/Fashion-Award-2024.png" "title": "AiDA X SFT AI时尚设计比赛2024",
} "imgUrl": "/image/events/Fashion-Award-2024.png"
},
{
"id": 3,
"title": "AiDA全球设计奖 2026",
"imgUrl": "/image/events/award-poster-zh.gif"
}
], ],
"eventsItem":[ "eventsItem": [
{ {
"id":1, "id": 3,
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!", "title": "AiDA全球设计奖 2026",
"imgUrl": "/image/events/workshop-Cn.jpg", "imgUrl": "/image/events/award-poster-zh.gif",
"textList":[ "tips": "如有疑问请联系awards2026@code-create.com.hk",
{ "textList": [
"paragraph":[ {
{ "paragraph": [
"text":"🎨这是一趟艺术巅峰之旅AiDA Workshop" {
} "text": "秉承推动 AI 赋能创意设计的初衷CodeCreate 举办了「AiDA 全球设计大奖 2026」面向来全球的设计师鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
] }
},{ ]
"paragraph":[ },
{ {
"text":"参与过程很简单利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞将被邀请至11月14日 举办的AiDA Workshop香港线下活动与英国皇家艺术学院RCA、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流(名额仅限1名" "paragraph": [
} {
] "text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅津贴,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
},{ }
"paragraph":[ ]
{ }
"text":"<b>⚠️注意❗❗</b>" ]
} },
] {
},{ "id": 1,
"paragraph":[ "title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
{ "imgUrl": "/image/events/workshop-Cn.jpg",
"text":"1. 作品描述添加tag: #AiDAworkshop_2024" "textList": [
},{ {
"text":"2. 一个冠军名额" "paragraph": [
} {
] "text": "🎨这是一趟艺术巅峰之旅AiDA Workshop"
},{ }
"paragraph":[ ]
{ },
"text":"<b>🤩Code-Create将提供适用条款条规</b>" {
} "paragraph": [
] {
},{ "text": "参与过程很简单利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞将被邀请至11月14日 举办的AiDA Workshop香港线下活动与英国皇家艺术学院RCA、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流(名额仅限1名"
"paragraph":[ }
{ ]
"text":"✅往返机票/动车费用(仅限中国地区)" },
} {
] "paragraph": [
},{ {
"paragraph":[ "text": "<b>⚠️注意❗❗</b>"
{ }
"text":"✅一晚酒店住宿费用" ]
} },
] {
},{ "paragraph": [
"paragraph":[ {
{ "text": "1. 作品描述添加tag: #AiDAworkshop_2024"
"text":"⌛截止时间2024.10.31" },
} {
] "text": "2. 一个冠军名额"
} }
] ]
}, },
{ {
"id":2, "paragraph": [
"title":"AiDA X SFT AI时尚设计比赛2024", {
"imgUrl": "/image/events/Fashion-Award-2024.png", "text": "<b>🤩Code-Create将提供适用条款条规</b>"
"textList":[ }
{ ]
"paragraph":[ },
{ {
"text":"秉承着激发学生使用AI进行时尚设计的创新能力的初衷Code-Create和香港理工大学时装及纺织学院SFT共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验为未来的时尚设计行业打下了坚实的基础成为时尚界的AI先锋。" "paragraph": [
} {
] "text": "✅往返机票/动车费用(仅限中国地区)"
},{ }
"paragraph":[ ]
{ },
"text":" 此次比赛面向全体SFT 学生最终获奖者将赢取丰厚奖金最高可达2万港币获得在BESFXXK的实习机会将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。" {
} "paragraph": [
] {
} "text": "✅一晚酒店住宿费用"
] }
} ]
] },
} {
"paragraph": [
{
"text": "⌛截止时间2024.10.31"
}
]
}
]
},
{
"id": 2,
"title": "AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"textList": [
{
"paragraph": [
{
"text": "秉承着激发学生使用AI进行时尚设计的创新能力的初衷Code-Create和香港理工大学时装及纺织学院SFT共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验为未来的时尚设计行业打下了坚实的基础成为时尚界的AI先锋。"
}
]
},
{
"paragraph": [
{
"text": " 此次比赛面向全体SFT 学生最终获奖者将赢取丰厚奖金最高可达2万港币获得在BESFXXK的实习机会将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
}
]
}
]
}
]
}

View File

@@ -2506,4 +2506,7 @@ textarea:focus {
} }
.justify-center { .justify-center {
justify-content: center; justify-content: center;
}
.flex-1{
flex: 1;
} }

View File

@@ -2424,4 +2424,7 @@ textarea:focus{
} }
.justify-center { .justify-center {
justify-content: center; justify-content: center;
}
.flex-1{
flex: 1;
} }

View File

@@ -1,22 +1,37 @@
<template> <template>
<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>
<div class="account_generalMessage_item modal_title_text" v-for="item in dataList" :key="item.id" @click="setRead(item)"> <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>
@@ -24,120 +39,138 @@
<a-spin size="large" /> <a-spin size="large" />
</span> </span>
</div> </div>
</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)
accountMessage.isShowMark = false .then((rv: any) => {
accountMessage.isShowMark = false
if(rv.content.length == 0) {
if (rv.content.length == 0) {
accountMessage.isNoData = true
} else {
rv.content.forEach((item: any) => {
item.content = JSON.parse(item.content)
})
accountMessage.dataList.push(...rv.content)
}
})
.catch(() => {
accountMessage.isShowMark = false
accountMessage.isNoData = true accountMessage.isNoData = true
}else{ })
rv.content.forEach((item:any) => { }
item.content = JSON.parse(item.content) let setRead = (item: any) => {
}); let content = item.content.content
accountMessage.dataList.push(...rv.content) if (isValidUrl(content)) {
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
content += "&env=dev"
} }
}).catch(() => { window.open(content, "_blank")
accountMessage.isShowMark = false }
accountMessage.isNoData = true
}) prop.setReadStatus(item)
} .then((rv: any) => {
let setRead = (item:any)=>{
prop.setReadStatus(item).then((rv:any)=>{
item.isRead = 1
}).catch((err:any)=>{
})
}
let allRead = ()=>{
// emit('setAllmessage')
prop.setAllmessage().then(()=>{
accountMessage.dataList.forEach((item:any)=>{
item.isRead = 1 item.isRead = 1
}) })
}).catch((err:any)=>{ .catch((err: any) => {})
}) }
let allRead = () => {
// emit('setAllmessage')
prop.setAllmessage()
.then(() => {
accountMessage.dataList.forEach((item: any) => {
item.isRead = 1
})
})
.catch((err: any) => {})
} }
// provide('exhibitionList',exhibitionList) // provide('exhibitionList',exhibitionList)
onMounted (()=>{ onMounted(() => {
accountMessage.isNoData = false accountMessage.isNoData = false
accountMessage.page = 0 accountMessage.page = 0
let imgParent:any = document.querySelector('.account_systemMessage .page_loading') let imgParent: any = document.querySelector(".account_systemMessage .page_loading")
new IntersectionObserver( new IntersectionObserver(
(entries, observer) => { (entries, observer) => {
// 如果不是相交,则直接返回 // 如果不是相交,则直接返回
// console.log(entries[0]); // console.log(entries[0]);
if (!entries[0].intersectionRatio) return; if (!entries[0].intersectionRatio) return
accountMessage.page+=1 accountMessage.page += 1
setmessageList() setmessageList()
}, }
// { root:worksPage } // { root:worksPage }
).observe(loadingDom.value); ).observe(loadingDom.value)
}) })
return{ return {
...toRefs(accountMessage), ...toRefs(accountMessage),
setmessageList, setmessageList,
setRead, setRead,
allRead, allRead,
loadingDom, loadingDom
} }
}, },
data(){ data() {
return{ return {}
}
}
},
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.account_systemMessage{ .account_systemMessage {
width: 100%; width: 100%;
.account_generalMessage_item{ .account_generalMessage_item {
font-size: var(--aida-fsize1-6); font-size: var(--aida-fsize1-6);
.account_generalMessage_item_title{ .account_generalMessage_item_title {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 2rem; margin-bottom: 2rem;
.account_generalMessage_item_title_text{ .account_generalMessage_item_title_text {
max-width: 80%; max-width: 80%;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.modal_title_text_intro{ .modal_title_text_intro {
margin-left: 4rem; margin-left: 4rem;
} }
} }
} }
.modal_title_text_intro{ .modal_title_text_intro {
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;

View File

@@ -18,7 +18,7 @@
</div> </div>
<div class="admin_state_item"> <div class="admin_state_item">
<span>{{ $t('admin.UserName') }}:</span> <span>{{ $t('admin.UserName') }}:</span>
<a-select <!-- <a-select
v-model:value="ids" v-model:value="ids"
mode="multiple" mode="multiple"
style="width: 230px" style="width: 230px"
@@ -28,7 +28,8 @@
max-tag-count="responsive" max-tag-count="responsive"
:options="allUserList" :options="allUserList"
@keydown.enter="gettrialList" @keydown.enter="gettrialList"
></a-select> ></a-select> -->
<SelectUser v-model="ids" labelKey="label" valueKey="label" multiple />
</div> </div>
</div> </div>
<div class="admin_search"> <div class="admin_search">
@@ -180,9 +181,10 @@
import { Modal, message, Input } from 'ant-design-vue' import { Modal, message, Input } from 'ant-design-vue'
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue' import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
import allUserPoerationsVue from './addAllUser.vue' import allUserPoerationsVue from './addAllUser.vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import SelectUser from '@/component/common/SelectUser.vue'
export default defineComponent({ export default defineComponent({
components: { allUserPoerationsVue, MoreOutlined }, components: { allUserPoerationsVue, MoreOutlined, SelectUser },
setup() { setup() {
const store: any = useStore() const store: any = useStore()
const currentOrganizationId = computed( const currentOrganizationId = computed(

View File

@@ -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
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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()

View File

@@ -0,0 +1,99 @@
<template>
<div class="admin_page globalAwardPopularity" ref="adminPage">
<div class="admin_table_search">
<div class="admin_state">
<div class="admin_state_item">
<span>Current Time:</span>
<span>{{ currentTimeStr }}</span>
</div>
<div class="admin_state_item">
<span>Raw Visi Count:</span>
<span>{{ rawVisitCount }}</span>
</div>
<div class="admin_state_item">
<span>Unique Visit Count:</span>
<span>{{ uniqueVisitCount }}</span>
</div>
</div>
<div class="admin_search">
<div class="admin_search_item" @click="getGlobalAwardPopularity">
<i class="fi fi-br-refresh"></i>
</div>
</div>
</div>
<!-- <div class="admin_table_content" ref="questionnaireTable">
</div> -->
</div>
</template>
<script lang="ts">
import { defineComponent, ref, createVNode,toRefs, computed,reactive, onMounted, nextTick } from "vue";
import { Https } from "@/tool/https";
import type { TableColumnsType } from 'ant-design-vue';
export default defineComponent({
components: {},
setup() {
const currentTime = ref(new Date())
const currentTimeStr = computed(()=>{
return currentTime.value.toLocaleString()
})
const rawVisitCount = ref(0)
const uniqueVisitCount = ref(0)
const getGlobalAwardPopularity = () => {
Https.axiosGet(Https.httpUrls.getGlobalAwardPopularity,).then((rv)=>{
currentTime.value = new Date()
rawVisitCount.value = rv.rawVisitCount
uniqueVisitCount.value = rv.uniqueVisitCount
})
}
onMounted(()=>{
getGlobalAwardPopularity()
})
return {
currentTimeStr,
getGlobalAwardPopularity,
rawVisitCount,
uniqueVisitCount,
};
},
data() {
return {
};
},
mounted() {
},
methods: {},
});
</script>
<style lang="less" scoped>
.admin_page.globalAwardPopularity{
.admin_table_search{
// flex: 1;
width: min-content;
justify-content: flex-start;
border-radius: 2rem;
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2);
margin-left: 2rem;
flex-wrap: nowrap;
gap: 3rem;
}
.admin_state{
flex-direction: column;
width: auto;
cursor: auto;
.admin_state_item{
> span{
font-size: 2rem;
}
}
}
.admin_search{
i{
display: flex;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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();
} }

View File

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

View File

@@ -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_) {
@@ -764,7 +770,7 @@
} }
.tool-content { .tool-content {
overflow-y: auto; // overflow-y: auto;
max-height: 20rem; max-height: 20rem;
margin-top: 1rem; margin-top: 1rem;
padding: 0 1.5rem; padding: 0 1.5rem;

View File

@@ -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,
}); });
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -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);
// }); // });

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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(); // else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) {
this.resetPartObject(); // this.clearPointData();
} // this.resetPartObject();
if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) { // }
if (this.pointList.length > 0) { // if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) {
this.clearPointData(); // if (this.pointList.length > 0) {
this.resetPartObject(); // this.clearPointData();
} // this.resetPartObject();
} // }
// }
// 如果从非选区工具切换到选区工具,初始化事件 // 如果从非选区工具切换到选区工具,初始化事件
if (!wasActive && this.isActive) { if (!wasActive && this.isActive) {
@@ -307,7 +308,12 @@ export class PartManager {
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
const item = list[i]; const item = list[i];
const icon = await this.loadImageToObject(item.label === 1 ? addIcon : removeIcon); const icon = await this.loadImageToObject(item.label === 1 ? addIcon : removeIcon);
let size = 20;
let scaleX = size / (icon.width * this.partGroup.scaleX);
let scaleY = size / (icon.height * this.partGroup.scaleY);
icon.set({ icon.set({
scaleX: scaleX,
scaleY: scaleY,
left: item.x - this.partGroup.width / 2, left: item.x - this.partGroup.width / 2,
top: item.y - this.partGroup.height / 2, top: item.y - this.partGroup.height / 2,
originX: fixedObject.originX, originX: fixedObject.originX,
@@ -315,6 +321,7 @@ export class PartManager {
}) })
this.partGroup.add(icon); this.partGroup.add(icon);
} }
console.log(this.partGroup);
this.canvas.renderAll(); this.canvas.renderAll();
return true; return true;
} }
@@ -374,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);
} }
/** 获取分隔后图片 */ /** 获取分隔后图片 */

View File

@@ -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, // 恢复红绿图模式下的透明度

View File

@@ -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) {

View File

@@ -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);
} }

View File

@@ -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,7 +692,9 @@ export class CanvasEventManager {
// 清除临时状态记录 // 清除临时状态记录
delete activeObj._initialTransformState; delete activeObj._initialTransformState;
} }
} }else{
this.canvasManager.changeCanvas();
}
if (this.thumbnailManager && e.target) { if (this.thumbnailManager && e.target) {
if (e.target.id) { if (e.target.id) {
@@ -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);
} }
/** /**

View File

@@ -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;
// }); // });

View File

@@ -30,27 +30,30 @@ export class LayerSort {
if (canvasObjects.length === 0) return; if (canvasObjects.length === 0) return;
// 使用画布渲染优化 // 使用画布渲染优化
await optimizeCanvasRendering(this.canvas, () => { await new Promise((resolve) => {
// 计算每个对象应该在的 z-index 位置 optimizeCanvasRendering(this.canvas, () => {
const objectZIndexMap = this.calculateObjectZIndexes(); // 计算每个对象应该在的 z-index 位置
const objectZIndexMap = this.calculateObjectZIndexes();
// 按照新的 z-index 排序对象 // 按照新的 z-index 排序对象
const sortedObjects = canvasObjects const sortedObjects = canvasObjects
.map((obj) => ({ .map((obj) => ({
object: obj, object: obj,
targetZIndex: objectZIndexMap.get(obj.id) ?? -1, targetZIndex: objectZIndexMap.get(obj.id) ?? -1,
})) }))
.filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象 .filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象
.sort((a, b) => a.targetZIndex - b.targetZIndex); .sort((a, b) => a.targetZIndex - b.targetZIndex);
// 使用 fabric.js 的 moveTo 方法重新排序 // 使用 fabric.js 的 moveTo 方法重新排序
sortedObjects.forEach((item, index) => { sortedObjects.forEach((item, index) => {
const currentIndex = this.canvas.getObjects().indexOf(item.object); const currentIndex = this.canvas.getObjects().indexOf(item.object);
if (currentIndex !== index && currentIndex !== -1) { if (currentIndex !== index && currentIndex !== -1) {
// 将对象移动到正确的位置 // 将对象移动到正确的位置
this.canvas.moveTo(item.object, index); this.canvas.moveTo(item.object, index);
} }
}); });
resolve();
});
}); });
} }

View File

@@ -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", // 部件选择器图层
} }

View File

@@ -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=合并revDatafalse=反转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 {
data.data[i + 0] = rgba.r; isHave = true;
data.data[i + 1] = rgba.g;
data.data[i + 2] = rgba.b;
data.data[i + 3] = rgba.a;
} }
}
if (isMerge && (revR || revG || revB || revA)) isHave = true;
if (isHave) {
data.data[i + 0] = rgba.r;
data.data[i + 1] = rgba.g;
data.data[i + 2] = rgba.b;
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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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">
* { * {

View File

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

View File

@@ -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'){
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}`:'' 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}`:''
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)
@@ -542,7 +548,7 @@ export default defineComponent({
detailData.loadingShow = false detailData.loadingShow = false
}); });
} }
const previwe = async ()=>{ const previwe = async ()=>{
detailData.loadingShow = true detailData.loadingShow = true
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')
@@ -557,11 +563,14 @@ export default defineComponent({
} }
}else{ }else{
//走画布合成图片并且直接分割 //走画布合成图片并且直接分割
if(detailData.isEditPattern.value !== 'canvasEditor'){ if(detailData.isEditPattern.value !== 'canvasEditor' && detailData.isEditPattern.value !== 'redGreenExample'){
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail() if(detailData.isEditPattern.value !== 'canvasEditor'){
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,6 +590,7 @@ export default defineComponent({
segmentImage(detailData.selectDetail.maskUrl,partialDesign,size).then(async (rv)=>{ segmentImage(detailData.selectDetail.maskUrl,partialDesign,size).then(async (rv)=>{
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]
if(front?.oldImageUrl)front.oldImageUrl = '' if(front?.oldImageUrl)front.oldImageUrl = ''
if(front?.oldMaskUrl)front.oldMaskUrl = '' if(front?.oldMaskUrl)front.oldMaskUrl = ''
if(back?.oldImageUrl)back.oldImageUrl = '' if(back?.oldImageUrl)back.oldImageUrl = ''
@@ -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){

View File

@@ -6,13 +6,12 @@
<div class="content-bottom" ref="canvasContent"> <div class="content-bottom" ref="canvasContent">
<div class="contet"> <div class="contet">
<div class="canvas" :class="{'active': currentView === 'canvasEditor'}"@click.stop> <div class="canvas" :class="{'active': currentView === 'canvasEditor'}"@click.stop>
<!-- :clothingMinIOPath="selectDetail.minIOPath" 部件选取 -->
<editCanvas v-if="canvasLoad" :config="canvasConfig" <editCanvas v-if="canvasLoad" :config="canvasConfig"
:title="t('CanvasTitle.ModifyItem')" :title="t('CanvasTitle.ModifyItem')"
@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"
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,
@@ -246,17 +244,27 @@ export default defineComponent({
const frontBackChange = async (value:any)=>{ const frontBackChange = async (value:any)=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
await nextTick()
if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){ if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){
await privewDetail() 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 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
@@ -268,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

View File

@@ -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 = {}

View File

@@ -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),
}, },

View File

@@ -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,

View File

@@ -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,51 +421,49 @@ export default defineComponent({
} }
} }
} }
const setPosition = ()=>{ const setPosition = async ()=>{
nextTick(()=>{ await new Promise<void>((resolve, reject) => {
let img = new Image nextTick(()=>{
img.onload = ()=>{ let img = new Image
// let sketchScale = editPrintElementData.selectDetail.layersObject[0].scale img.onload = ()=>{
let sketchScale = [1,1] // let sketchScale = editPrintElementData.selectDetail.layersObject[0].scale
let scaleX = img.width * sketchScale[0] / editPrintElementDom.sketchImg.offsetWidth let sketchScale = [1,1]
let scaleY = img.height * sketchScale[1] / editPrintElementDom.sketchImg.offsetHeight let scaleX = img.width * sketchScale[0] / editPrintElementDom.sketchImg.offsetWidth
let scaleY = img.height * sketchScale[1] / editPrintElementDom.sketchImg.offsetHeight
editPrintElementData.sketchWH = { editPrintElementData.sketchWH = {
width:editPrintElementDom.sketchImg.offsetWidth, width:editPrintElementDom.sketchImg.offsetWidth,
height:editPrintElementDom.sketchImg.offsetHeight, height:editPrintElementDom.sketchImg.offsetHeight,
scale:[scaleX,scaleY], scale:[scaleX,scaleY],
}
if(!editPrintElementData.selectDetail.printObject.prints)return
let state = true
// editPrintElementData.stateOverallSingle = 'single'
let arr:any = editPrintElementData.selectDetail.printObject.prints
if(props.type == 'element'){
arr = editPrintElementData.selectDetail.trims.prints
}
// if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
// arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
// }
if(arr && arr.length > 0){
editPrintElementData.printStyleList[props.type].single = []
editPrintElementData.printStyleList[props.type].overall = []
arr.forEach((item:any)=>{
// if(!item.ifSingle){
// editPrintElementData.stateOverallSingle = 'overall',
// state = false
// }
getItemPosition(item)
})
setItemPosition()
}
resolve('')
} }
if(!editPrintElementData.selectDetail.printObject.prints)return img.src = editPrintElementData.selectDetail.path
let state = true })
// editPrintElementData.stateOverallSingle = 'single'
let arr:any = editPrintElementData.selectDetail.printObject.prints
if(props.type == 'element'){
arr = editPrintElementData.selectDetail.trims.prints
}
// if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
// arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
// }
if(arr && arr.length > 0){
editPrintElementData.printStyleList[props.type].single = []
editPrintElementData.printStyleList[props.type].overall = []
arr.forEach((item:any)=>{
// if(!item.ifSingle){
// editPrintElementData.stateOverallSingle = 'overall',
// state = false
// }
getItemPosition(item)
})
setItemPosition()
}
// if(props.type == 'print'){
// editPrintElementData.overallSingle = state
// }
}
// undividedLayer
//计算宽高使用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([
{ {

View File

@@ -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;

View File

@@ -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?.()

View File

@@ -28,7 +28,7 @@
<div class="detail_modal_item_front"> <div class="detail_modal_item_front">
<img <img
style="object-fit: cover;" style="object-fit: cover;"
:style="observerWH.width == '0px'?{width:observerWH.width+'px',height:observerWH.height+'px'}:{'object-fit': 'contain'}" :style="observerWH.width > 0?{width:observerWH.width+'px',height:observerWH.height+'px'}:{width:'100%',height:'auto','object-fit': 'contain'}"
:src="designDetail.designItemUrl" alt=""> :src="designDetail.designItemUrl" alt="">
</div> </div>
</div> </div>

File diff suppressed because one or more lines are too long

View File

@@ -1,142 +1,185 @@
<template> <template>
<div class="eventsDetail_page" :class="{active:isScroll}"> <div class="eventsDetail_page" :class="{ active: isScroll }">
<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>
<div class="modal_title_text" v-for="item in eventsDetail.textList"> <div
class="modal_title_text content"
v-for="item in eventsDetail.textList"
:class="{ award: eventsDetail.id === 3 }"
>
<div class="eventsDetail_content_right_btn_box"> <div class="eventsDetail_content_right_btn_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 v-show="loadingShow[buttonIndex]" class="started_btn">
<i class="fi fi-br-loading"></i>
</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> class="modal_title_text_intro"
v-for="introItem in item?.paragraph"
:class="{ active: introItem.display == 'flex' }"
v-detailText="introItem.text"
></div>
</div> </div>
<div class="tips" v-if="eventsDetail.tips">{{ eventsDetail.tips }}</div>
</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:{
isScroll:{
type:Boolean,
default:true,
},
}, },
setup() { props: {
const router = useRouter(); isScroll: {
const store = useStore(); type: Boolean,
let filter:any = reactive({ default: true
eventsDetail: {
},
getListDate:{
"getLikePortfolio": 0,
"getMyPortfolio": 0,
page:1,
size:10,
},
isShowMark:false,
isNoData:false,//如果数据为空就不加载
loadingShow:{},
})
let likeFile = (item:any,type:string) => {
} }
let setBack = ()=>{ },
router.go(-1); setup() {
const { t, locale } = useI18n()
const router = useRouter()
const store = useStore()
let filter: any = reactive({
eventsDetail: {},
getListDate: {
getLikePortfolio: 0,
getMyPortfolio: 0,
page: 1,
size: 10
},
isShowMark: false,
isNoData: false, //如果数据为空就不加载
loadingShow: {}
})
let likeFile = (item: any, type: string) => {}
let setBack = () => {
router.go(-1)
// router.push('/home/events') // router.push('/home/events')
} }
let openButton = (data:any,index:number)=>{ let openButton = (data: any, index: number) => {
if(filter.loadingShow[index]){ if (filter.loadingShow[index]) {
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
}); })
} }
onMounted (()=>{ const openDetail = () => {
const { t, locale } = useI18n(); let language = locale.value === "ENGLISH" ? "en" : "cn"
const currentLocale = locale.value; let url = `https://aida-global-design-awards.com.hk/${language}`
let eventLangData:any // 如果是dev环境把域名换成http://192.168.31.198
if(currentLocale == 'ENGLISH'){
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(() => {
const currentLocale = locale.value
let eventLangData: any
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
} }
}) })
}) })
return { return {
...toRefs(filter), ...toRefs(filter),
likeFile, likeFile,
setBack, setBack,
openButton, openButton,
} openDetail
}, }
directives:{ },
detailText:{ directives: {
mounted (el,binding) { detailText: {
mounted(el, binding) {
el.innerHTML = binding.value el.innerHTML = binding.value
} }
} }
}, },
async mounted(){ async mounted() {}
},
}) })
</script> </script>
<style lang="less"> <style lang="less">
.eventsDetail_page { .eventsDetail_page {
min-height: 100%; min-height: 100%;
width: 100%; width: 100%;
padding: 0 6rem; padding: 0 6rem;
padding-top: 5rem; padding-top: 5rem;
&.active{ &.active {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
.eventsDetail_content{ .eventsDetail_content {
overflow-y: auto; overflow-y: auto;
width: 100%; width: 100%;
} }
@@ -146,7 +189,7 @@ export default defineComponent({
min-height: auto; min-height: auto;
padding-bottom: 10rem; padding-bottom: 10rem;
} }
.eventsDetail_title{ .eventsDetail_title {
display: flex; display: flex;
padding: 2rem 0rem; padding: 2rem 0rem;
align-items: center; align-items: center;
@@ -154,21 +197,21 @@ export default defineComponent({
top: 0; top: 0;
z-index: 222; z-index: 222;
background: #fff; background: #fff;
.modal_title_text{ .modal_title_text {
cursor: pointer; cursor: pointer;
display: flex; display: flex;
margin-bottom: 0; margin-bottom: 0;
} }
.modal_title_text:hover .eventsDetail_title_text{ .modal_title_text:hover .eventsDetail_title_text {
text-decoration: underline; text-decoration: underline;
} }
i{ i {
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 1rem; margin-right: 1rem;
} }
} }
.eventsDetail_content{ .eventsDetail_content {
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -176,65 +219,100 @@ 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%;
} }
} }
.eventsDetail_content_left{ .eventsDetail_content_left {
width: 40%; width: 40%;
max-height: 60rem; max-height: 60rem;
@media (max-width: 768px) { @media (max-width: 768px) {
width: 100%; width: 100%;
} }
.ant-image{ .ant-image {
// height: auto; // height: auto;
height: 100%; height: 100%;
} }
.eventsDetail_content_left_img{ .eventsDetail_content_left_img {
width: 100%; width: 100%;
cursor: zoom-in; cursor: zoom-in;
} }
} }
.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;
.modal_title_text_intro{ &-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 {
display: block; display: block;
&.active{ &.active {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
li{ li {
width: 48%; width: 48%;
} }
em{ em {
// font-family: auto; // font-family: auto;
} }
a{ a {
display: inline; display: inline;
} }
} }
.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;
}
} }
} }
} }
</style> .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>

View File

@@ -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,7 +734,9 @@ 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) {
// parent.useGenerate.designType = 'collection' // parent.useGenerate.designType = 'collection'
@@ -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 == '') {

View File

@@ -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"

View File

@@ -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') }}

View File

@@ -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; max-width:80vw;
height: 100%;
object-fit: contain;
width: max-content;
} }
.general_video_btn{ .general_video_btn{
color: #fff; color: #fff;

View File

@@ -20,7 +20,7 @@
</div> </div>
<!-- 图片网格 --> <!-- 图片网格 -->
<div class="image-grid" @scroll="handleScroll"> <div class="image-grid" v-show="list.length > 0" @scroll="handleScroll">
<div <div
v-for="(item, index) in list" v-for="(item, index) in list"
:key="index" :key="index"
@@ -460,6 +460,7 @@ defineExpose({
padding: 20px; padding: 20px;
// overflow-y: auto; // overflow-y: auto;
flex: 1; flex: 1;
overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;
@@ -516,11 +517,13 @@ 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;
min-height: 22rem; flex: 1;
max-height: 50rem; // min-height: 22rem;
// max-height: 50rem;
padding-bottom: 2rem; padding-bottom: 2rem;
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
@@ -615,9 +618,9 @@ defineExpose({
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 60px 20px;
color: #666; color: #666;
min-height: 300px; min-height: 300px;
margin: auto 0;
.empty-icon { .empty-icon {
font-size: 48px; font-size: 48px;

View File

@@ -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]);

View File

@@ -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{

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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){

View File

@@ -1503,6 +1503,12 @@ export default {
CompositeLuminosity: '亮度', CompositeLuminosity: '亮度',
CompositeLuminosityTip: '亮度:保留原图像颜色,改变新图像亮度', CompositeLuminosityTip: '亮度:保留原图像颜色,改变新图像亮度',
GarmentPartSelector: '服装部件选取', GarmentPartSelector: '服装部件选取',
LeftClickAdd: '左键添加',
RightClickRemove: '右键移除',
PointSelection: '点选',
MarqueeSelection: '框选',
BrushSelection: '画笔',
Erase: '擦除',
}, },
speedList: { speedList: {
High: '高级', High: '高级',
@@ -1526,7 +1532,8 @@ export default {
LiquefactionTool: '液化工具' LiquefactionTool: '液化工具'
}, },
event: { event: {
back: '返回' back: '返回',
detail:'查看详情'
}, },
admin: { admin: {
allUser: '所有用户', allUser: '所有用户',

File diff suppressed because it is too large Load Diff

View File

@@ -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"),
}, },
], ],
}, },

View File

@@ -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,
} }
v.maskMinioUrl = v.layersObject?.[0]?.maskMinioUrl if(data?.fromType !== 'resize'){
v.maskUrl = v.layersObject?.[0]?.maskUrl v.maskMinioUrl = v.layersObject?.[0]?.maskMinioUrl
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]

View File

@@ -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{

View File

@@ -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('')
} }

View File

@@ -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]
} }
}, },

View File

@@ -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
} }
] ]
} }

View File

@@ -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`, //创建云生成

View File

@@ -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:{

View File

@@ -672,28 +672,40 @@ 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,
getUniversalZoomLevel, getUniversalZoomLevel,
rgbaToHex, rgbaToHex,
getMinioUrl, getMinioUrl,
base64ToFile, base64ToFile,
dataURLtoFile, dataURLtoFile,
blobToFile, blobToFile,
base64toFile, base64toFile,
rgbToHsv, rgbToHsv,
formatTime, formatTime,
dataURLtoBlob, dataURLtoBlob,
isMoible, isMoible,
downloadIamge, downloadIamge,
downloadVideoWithFetch, downloadVideoWithFetch,
getBrowserInfo, getBrowserInfo,
setPubDate, setPubDate,
murmur, murmur,
setGradual, setGradual,
calculateGradientCoordinate, calculateGradientCoordinate,
segmentImage, segmentImage,
UrlToFile, UrlToFile,
sketchToMask sketchToMask,
isValidUrl
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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
<div class="item-header flex align-center"> class="title animation-element"
<img src="@/assets/images/award/bloom_logo.png" class="logo" /> ref="applyTitleRef"
<div class="item-title">{{ item.type }}</div> >
{{ $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>
<div class="context" v-for="el in item.desc"> <div class="context-container flex flex-center">
{{ el }} <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>
</div> </div>
<div class="right"> <div class="bottom flex">
<div class="item-box"> <div class="step-3 flex flex-col animation-element" ref="step3Ref">
<div class="item-box"> <div class="header">{{ $t('AwardsPage.step3Title') }}</div>
<div class="item-header flex align-center"> <div class="content flex">
<img src="@/assets/images/award/bloom_logo.png" class="logo" /> <div class="content-left flex flex-col space-between">
<div class="item-title">{{ rightRequirment.type }}</div> <div class="content-item">
<div class="item-header flex align-center">
<div class="point"></div>
<div>{{ $t('AwardsPage.processVideo') }}</div>
</div>
<div class="desc-wrapper flex flex-col space-between">
<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 class="content-item">
<div class="item-header flex align-center">
<div class="point"></div>
<div>{{ $t('AwardsPage.fileName') }}</div>
</div>
<div class="item-desc indent">
{{ $t('AwardsPage.fileNameDesc') }}
</div>
</div>
</div> </div>
<div class="context" v-for="el in rightRequirment.desc"> <div class="content-right">
{{ el }} <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>
</div> </div>
</div> </div>
@@ -32,178 +156,374 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue' import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
import { gsap } from 'gsap' import { useI18n } from 'vue-i18n'
import { gsap } from 'gsap'
const leftRequirment = ref([ const { t } = useI18n()
{
type: 'Video', const leftRequirment = ref([
desc: ['The process of doing design'] {
}, type: 'AwardsPage.step1Title',
{ desc: ['AwardsPage.step1Desc']
type: 'Design', },
desc: [ {
'Structure: design title, moodboard and elaboration (how will you use AiDA to design)', type: 'AwardsPage.step2Title',
'Design sketch: Maximum 4 outfit design with proposed materials' desc: ['AwardsPage.step2Desc'],
] listTitle: 'AwardsPage.step2ListTitle',
list: [
'AwardsPage.step2List[0]',
'AwardsPage.step2List[1]',
'AwardsPage.step2List[2]'
],
background: '#F9F9F9'
}
])
const applyRef = ref()
const applyTitleRef = ref()
const applySubTitleRef = ref()
const reqListRef = ref()
const itemRefs = ref<HTMLElement[]>([])
const step3Ref = ref()
const step4Ref = ref()
const hasPlayedAnim = ref(false)
let timeline: gsap.core.Timeline | null = null
let observer: IntersectionObserver | null = null
const setupApplyInitialState = () => {
// 设置标题和副标题的初始状态
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
scale: 0,
transformOrigin: '50% 50%'
})
}
// 设置步骤元素的初始状态
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)
}
if (allStepElements.length > 0) {
gsap.set(allStepElements, {
opacity: 0,
y: 50
})
}
} }
])
const rightRequirment = ref({ const initAnimations = () => {
type: 'Submission Format', if (hasPlayedAnim.value) return
desc: [
'Naming as “AiDA global award 2026_applicantname”',
'Mp4\n(1080x1920pixels/20mb within 1min)',
'Single PDF file\n(within 15 pages, maximum 20mb)',
'English or native language\nwith English translation'
]
})
const applyRef = ref<HTMLElement | null>(null) timeline = gsap.timeline({
const applyTitleRef = ref<HTMLElement | null>(null) defaults: { ease: 'back.out(1.7)' }
const applySubTitleRef = ref<HTMLElement | null>(null)
const reqListRef = ref<HTMLElement | null>(null)
const hasPlayedApplyAnim = ref(false)
let applyObserver: IntersectionObserver | null = null
const setupApplyInitialState = () => {
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
scale: 0,
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 playApplyAnimation = () => { if (applyTitleRef.value && applySubTitleRef.value) {
if (hasPlayedApplyAnim.value) return timeline.to([applyTitleRef.value, applySubTitleRef.value], {
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter( scale: 1,
Boolean
) 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' } })
tl.to(titleEls, {
opacity: 1,
scale: 1,
duration: 0.6,
ease: 'back.out(1.6)',
stagger: 0.1
})
if (headers?.length) {
tl.to(
headers,
{
opacity: 1, opacity: 1,
duration: 0.4, duration: 0.6,
stagger: 0.1 stagger: 0.1
}, })
'-=0.1' }
)
} const allStepElements: HTMLElement[] = []
if (contexts?.length) { if (itemRefs.value && itemRefs.value.length > 0) {
tl.to( allStepElements.push(...itemRefs.value)
contexts, }
{ 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, opacity: 1,
duration: 0.4, y: 0,
stagger: 0.05 duration: 0.6,
}, stagger: 0.2
'-=0.05' }, '>')
) }
hasPlayedAnim.value = true
} }
hasPlayedApplyAnim.value = true onMounted(() => {
applyObserver?.disconnect() nextTick(() => {
} setupApplyInitialState()
observer = new IntersectionObserver(
onMounted(() => {
nextTick(() => {
setupApplyInitialState()
if ('IntersectionObserver' in window) {
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(() => {
// Cleanup animation timeline
if (timeline) {
timeline.kill()
}
// Cleanup IntersectionObserver
if (observer) {
observer.disconnect()
} }
}) })
})
onBeforeUnmount(() => {
applyObserver?.disconnect()
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.apply-container { p {
flex: 1; margin: 0;
background: url('@/assets/images/award/apply_bg.png') no-repeat; padding: 0;
background-size: 100% 100%;
padding: 12.7rem 0 16.9rem;
.title {
text-align: center;
color: #232323;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 4rem;
margin-bottom: 3rem;
} }
.sub-title { ul {
text-align: center; margin: 0;
color: #b10000; padding: 0;
font-size: 3rem;
font-family: 'Arial';
font-weight: 400;
} }
.requirments-list { .animation-element{
will-change: opacity transform;
}
.apply-container {
flex: 1; flex: 1;
padding-left: 41.4rem; height: 143.3rem;
column-gap: 17.7rem; background: url('@/assets/images/award/apply_bg.png') no-repeat;
margin-top: 12rem; background-size: 100% 100%;
.left { padding: 12.7rem 21.4rem 12rem;
.title {
text-align: center;
color: #232323; color: #232323;
height: 100%; font-family: 'PoppinsBold';
font-weight: 600;
font-size: 4rem;
margin-bottom: 3rem;
} }
.item-box { .sub-title {
.item-header { text-align: center;
column-gap: 3.2rem; color: #b10000;
.item-title { font-size: 3rem;
color: #232323; font-family: 'Arial';
font-family: 'PoppinsBold'; font-weight: 400;
font-weight: 600; margin-bottom: 8.2rem;
font-size: 2.8rem; }
.requirments-list {
flex: 1;
row-gap: 8.2rem;
.top {
height: 27.4rem;
color: #585858;
column-gap: 4.6rem;
.item-box {
height: 27.4rem;
} }
} }
.context { .item-box {
margin-top: 4rem; border-radius: 0.8rem;
width: 46.8rem; &:nth-of-type(1) {
color: #585858; width: 47rem;
font-family: 'Arial'; flex-grow: initial;
font-weight: 400; }
line-height: 3rem; &:nth-of-type(2) {
font-size: 2.4rem; flex: 1;
padding-left: 5.6rem; }
white-space: pre-line; .item-header {
background-color: #424242;
border-radius: 0.8rem;
height: 7.8rem;
.item-title {
color: #fff;
font-family: 'PoppinsBold';
font-weight: 600;
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 {
// margin-top: 4rem;
// width: 46.8rem;
text-align: center;
color: #585858;
font-family: 'Arial';
font-weight: 400;
line-height: 3rem;
font-size: 2.4rem;
// padding-left: 5.6rem;
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>

View File

@@ -1,43 +1,172 @@
<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 } from 'vue' import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import gsap from 'gsap' import { useI18n } from 'vue-i18n'
import { gsap } from 'gsap'
const titleRef = ref<HTMLElement | null>(null) const { t } = useI18n()
const subtitleRef = ref<HTMLElement | null>(null)
const textRef = ref<HTMLElement | null>(null)
const titleRef = ref<HTMLElement | null>(null)
const subtitleRef = ref<HTMLElement | null>(null)
const textRef = ref<HTMLElement | null>(null)
const hasPlayedBloomAnim = ref(false)
let bloomObserver: IntersectionObserver | null = null
const setupBloomInitialState = () => {
const titleEls = [titleRef.value, subtitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
// start larger than final size, then animate down to scale:1
scale: 1.6,
transformOrigin: '50% 50%'
})
}
if (textRef.value) {
// start below and hidden
gsap.set(textRef.value, {
opacity: 0,
y: 60
})
}
}
const playBloomAnimation = () => {
if (hasPlayedBloomAnim.value) return
const titleEls = [titleRef.value, subtitleRef.value].filter(
Boolean
) as HTMLElement[]
const textEl = textRef.value
if (!titleEls.length || !textEl) return
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
tl.to(titleEls, {
opacity: 1,
scale: 1,
duration: 0.9,
ease: 'back.out(1.6)',
stagger: 0.12
})
tl.to(
textEl,
{
opacity: 1,
y: -12,
scale: 1.05,
duration: 0.3,
ease: 'power2.out'
},
'-=0.3'
)
tl.to(
textEl,
{
y: 0,
scale: 1,
duration: 0.18,
ease: 'bounce.out'
},
'+=0.08'
)
hasPlayedBloomAnim.value = true
bloomObserver?.disconnect()
}
onMounted(() => {
nextTick(() => {
setupBloomInitialState()
if ('IntersectionObserver' in window) {
bloomObserver = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
playBloomAnimation()
}
})
},
{ threshold: 0.3 }
)
if (titleRef.value) {
bloomObserver.observe(titleRef.value)
}
} else {
// fallback
playBloomAnimation()
}
})
})
onBeforeUnmount(() => {
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;
@@ -57,12 +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>

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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;
} }
} }
} }

View File

@@ -0,0 +1,156 @@
<template>
<div
class="blocks-list flex"
ref="root"
:class="{ 'in-view': inView }"
>
<div
class="block-item flex flex-col flex-center"
v-for="(item, idx) in blocksList"
:key="item.number"
:style="{ '--delay': `${idx * 0.18}s` }"
>
<div class="number">{{ $t(item.number) }}</div>
<div class="label">{{ $t(item.label) }}</div>
<div class="line"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const blocksList = ref([
{
number: 'AwardsPage.totalCashPrizes',
label: 'AwardsPage.totalCashPrizesLabel'
},
{
number: 'AwardsPage.globalMediaExpose',
label: 'AwardsPage.globalMediaExposeLabel'
},
{
number: 'AwardsPage.networkingOpportunities',
label: 'AwardsPage.networkingOpportunitiesLabel'
},
{
number: 'AwardsPage.awardCeremonyHongKong',
label: 'AwardsPage.awardCeremonyLabel'
}
])
const root = ref<HTMLElement | null>(null)
const inView = ref(false)
let io: IntersectionObserver | null = null
onMounted(() => {
io = new IntersectionObserver(
entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
// 延迟 0.5s 后触发动画并断开观察
setTimeout(() => {
inView.value = true
}, 500)
if (io) {
io.disconnect()
}
}
}
},
{ threshold: 0.05 }
)
if (root.value) {
io.observe(root.value)
}
})
onUnmounted(() => {
io?.disconnect()
})
</script>
<style lang="less" scoped>
.blocks-list {
height: 31.4rem;
background: linear-gradient(98.55deg, #232323 18.22%, #898989 101.1%);
.block-item {
flex: 1;
height: 100%;
color: #fff;
position: relative;
text-align: center;
white-space: pre-line;
row-gap: 3rem;
/* text scale-in animations */
.number {
font-size: 3.6rem;
font-family: 'PoppinsBold';
font-weight: 600;
transform: scale(0);
opacity: 0;
will-change: transform, opacity;
}
.label {
font-size: 2.4rem;
font-family: 'Arial';
font-weight: 400;
letter-spacing: 0.05em;
transform: scale(0);
opacity: 0;
will-change: transform, opacity;
}
/* vertical line grows top -> bottom */
.line {
position: absolute;
right: 0;
/* 固定 top 为最终高度的一半位置,这样 height 从 0 -> 27.4rem 时会从上向下增长 */
top: calc(50% - 13.7rem);
width: 0.1rem;
height: 0;
background-color: #8d8d8d;
will-change: height;
}
}
}
/* 当组件进入视口并且等待 0.5s 后,.in-view 会加入根节点,下面规则触发动画 */
.in-view .block-item .number {
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: var(--delay);
}
.in-view .block-item .label {
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: calc(var(--delay) + 0.12s);
}
.in-view .block-item .line {
animation: growLine 0.7s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: calc(var(--delay) + 0.18s);
}
/* keyframes */
@keyframes scaleIn {
from {
transform: scale(0);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
@keyframes growLine {
from {
height: 0;
}
to {
height: 27.4rem;
}
}
</style>

View File

@@ -1,24 +1,54 @@
<template> <template>
<div class="success-container flex flex-col align-center"> <div class="success-container flex flex-col align-center">
<img <img
src="@/assets/images/award/successful.png" :src="info.icon"
alt="" alt=""
class="icon-img" class="icon-img"
/> />
<div class="title">Submission Successful</div> <div class="title">{{ $t(info.title) }}</div>
<div class="desc"> <div class="desc">
<div> {{ $t(info.desc) }}
<!-- <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>
<div> <div>
You may edit it if needed. Competition updates and results will be sent You may edit it if needed. Competition updates and results will be sent
via email. via email.
</div> </div> -->
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"></script> <script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import successIcon from '@/assets/images/award/successful.png'
import expiredIcon from '@/assets/images/award/expired.png'
const { t } = useI18n()
const props = defineProps({
isExpired: {
type: Boolean,
default: false
}
})
const info = computed(() => {
if (props.isExpired) {
return {
icon: expiredIcon,
title: 'AwardsPage.deadlinePassed',
desc: 'AwardsPage.deadlinePassedDesc'
}
} else {
return {
icon: successIcon,
title: 'AwardsPage.submissionSuccessful',
desc: 'AwardsPage.submissionSuccessfulDesc'
}
}
})
</script>
<style lang="less" scoped> <style lang="less" scoped>
.success-container { .success-container {
margin: 0 21.5rem; margin: 0 21.5rem;

View File

@@ -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
<div class="labels-row flex align-center"> class="timeline-point"
ref="timelineRef"
>
<!-- 顶部标签行 -->
<div class="grid-row labels-row">
<div <div
class="item-label flex flex-col" 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>
<img <div
src="@/assets/images/award/point.png" class="grid-cell icon-cell"
class="point-icon"
v-for="item in points" v-for="item in points"
:key="'icon-' + item.time" :key="'icon-' + item.time"
/> >
<img
src="@/assets/images/award/point.png"
class="point-icon"
/>
</div>
</div> </div>
<!-- 时间行 -->
<!-- Times row --> <div class="grid-row times-row">
<div class="times-row flex align-center">
<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;
justify-content: center;
}
} }
.grid-cell {
display: flex;
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;
} }
} }
} }

View File

@@ -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 ''
}) })

View File

@@ -1,23 +1,26 @@
<template> <template>
<div class="award-container"> <div class="award-container">
<div class="header flex align-center space-between"> <div class="header-wrapper">
<div class="header-left"> <div class="header flex align-center space-between">
<img <div class="header-left">
src="@/assets/images/award/code_create_logo.png" <img
class="logo" src="@/assets/images/award/code_create_logo.png"
/> class="logo"
</div> />
<div </div>
class="header-right flex align-center" <div
@click="handleBtnClick" class="header-right flex align-center"
> @click="handleBtnClick"
<div class="text">{{ btnText }}</div> >
<img <div class="text">{{ btnText }}</div>
src="@/assets/images/award/arrow.png" <img
alt="" src="@/assets/images/award/arrow.png"
class="arrow" alt=""
/> class="arrow"
/>
</div>
</div> </div>
<div class="header-placeholder"></div>
</div> </div>
<router-view /> <router-view />
<div class="footer flex space-between align-center"> <div class="footer flex space-between align-center">
@@ -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'
} }
}) })
@@ -141,6 +160,8 @@
overflow: auto; overflow: auto;
height: 100vh; height: 100vh;
// 隐藏滚动条箭头,只显示滚动条本体 // 隐藏滚动条箭头,只显示滚动条本体
box-sizing: border-box;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
@@ -149,33 +170,44 @@
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: none; -ms-overflow-style: none;
} }
.header { .header-wrapper {
height: 8rem; .header-placeholder {
background-color: #232323; height: 8rem;
padding-left: 21.5rem;
padding-right: 8.6rem;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
} }
.header-right { .header {
column-gap: 1rem; height: 8rem;
cursor: pointer; background-color: #232323;
.text { padding-left: 21.5rem;
font-size: 1.6rem; padding-right: 8.6rem;
color: #fff; box-sizing: border-box;
position: fixed;
top: 0;
width: 100%;
z-index: 9;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
} }
.arrow { .header-right {
width: 2.4rem; column-gap: 1rem;
height: 2.4rem; cursor: pointer;
.text {
font-size: 1.6rem;
color: #fff;
}
.arrow {
width: 2.4rem;
height: 2.4rem;
}
} }
} }
} }
.footer { .footer {
height: 10rem; height: 10rem;
padding-left: 21.5rem; padding-left: 21.5rem;
box-sizing: border-box;
padding-right: 22rem; padding-right: 22rem;
background-color: #232323; background-color: #232323;
.social-list { .social-list {

View File

@@ -1,42 +1,46 @@
<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 class="blocks-list flex">
<div
class="block-item flex flex-col flex-center"
v-for="item in blocksList"
:key="item.number"
>
<div class="number">{{ item.number }}</div>
<div class="label">{{ item.label }}</div>
<div class="line"></div>
</div> </div>
</div> </div>
<Slogan />
<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'
@@ -44,31 +48,25 @@
import PrizesSection from './components/PrizesSection.vue' import PrizesSection from './components/PrizesSection.vue'
import TimeLine from './components/TimeLine.vue' import TimeLine from './components/TimeLine.vue'
import Bloom from './components/Bloom.vue' import Bloom from './components/Bloom.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')
} }
const blocksList = ref([
{
number: 'NETWORKING\n OPPORTUNITIES',
label: 'with international\nmedia and designers'
},
{
number: 'INTERNATIONAL\nMEDIA EXPOSE',
label: 'through\nleading outlets'
},
{
number: 'UP TO\nUS$9000',
label: 'in total prize\npool awards'
},
{
number: 'TRAVEL\NALLOWANCE',
label: 'for finalists to attend\naward ceremony'
}
])
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@@ -81,16 +79,22 @@
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: 100% 100%; // 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;
line-height: 6.394rem; line-height: 6.394rem;
text-align: center; text-align: center;
border-radius: 3.2rem; border-radius: 3.2rem;
background-color: rgba(35, 35, 35, 0.7);
box-shadow: inset 0 0 1119px 0 rgba(255, 255, 255, 0.3), box-shadow: inset 0 0 1119px 0 rgba(255, 255, 255, 0.3),
inset -0.8px -2.4px 1.6px 0.4px rgba(255, 255, 255, 0.1), inset -0.8px -2.4px 1.6px 0.4px rgba(255, 255, 255, 0.1),
inset 0.8px 2.4px 1.6px 0 rgba(255, 255, 255, 0.3); inset 0.8px 2.4px 1.6px 0 rgba(255, 255, 255, 0.3);
@@ -100,8 +104,8 @@
font-size: 2.4rem; font-size: 2.4rem;
column-gap: 3.2rem; column-gap: 3.2rem;
position: absolute; position: absolute;
top: 23.88rem; left: 42.1rem;
left: 51rem; bottom: 15.7rem;
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
cursor: pointer; cursor: pointer;
.arrow { .arrow {
@@ -114,44 +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;
} }
} }
} }
.blocks-list {
height: 31.4rem;
background: linear-gradient(98.55deg, #232323 18.22%, #898989 101.1%);
.block-item { .is-zh {
flex: 1; .submit-btn {
height: 100%; padding: 0 7.5rem;
color: #fff; height: 7.8rem;
position: relative; border-radius: 7.74rem;
text-align: center; column-gap: 3.8rem;
white-space: pre-line; // justify-content: space-between;
row-gap: 3rem; &,
.number { .ddl {
font-size: 3.6rem; width: 35.4rem;
font-family: 'PoppinsBold';
font-weight: 600;
}
.label {
font-size: 2.4rem;
font-family: 'Arial';
font-weight: 400;
letter-spacing: 0.05em;
}
.line {
position: absolute;
bottom: 50%;
right: 0;
transform: translate(0, 50%);
width: 0.1rem;
height: 27.4rem;
background-color: #8d8d8d;
} }
} }
} }

View File

@@ -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" >

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