265 Commits

Author SHA1 Message Date
X1627315083@163.com
ae1d7245f4 Merge remote-tracking branch 'origin/dev_vite' into research 2026-04-08 09:25:56 +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
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
X1627315083@163.com
b8f38db351 overall印花scale为字符串时候使用toFixed会报错 2026-02-24 11:27:43 +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
7fb7ffaced fix 2026-02-06 16:47:45 +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
X1627315083
a18dead4ff fix 2026-01-28 10:05:08 +08:00
X1627315083
76047b763d 修复detail新增衣服报错 2026-01-28 09:32:52 +08:00
0930e8cc77 bugfix: 教育管理员搜索用户 2026-01-27 17:34:25 +08:00
X1627315083
9f09a2f31b fix 2026-01-27 14:18:14 +08:00
X1627315083
1e0bf83d12 fix 2026-01-27 14:18:00 +08:00
李志鹏
1764e2a0bf fix 2026-01-27 13:30:11 +08:00
李志鹏
0729917a7e 打开部件选取 2026-01-27 11:20:56 +08:00
李志鹏
b7f7aea0b7 Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-01-27 11:01:35 +08:00
李志鹏
4dfa9433fd 画布 部件选取、印花禁用多选 2026-01-27 11:01:33 +08:00
李志鹏
79293901b3 多选解决 2026-01-27 10:58:27 +08:00
X1627315083
03a9e2f52c fix 2026-01-27 10:15:20 +08:00
X1627315083
fb1d09d98e 修改注册输入验证码最小高度 2026-01-27 10:12:13 +08:00
李志鹏
8ff7a31e92 部件选取多语言 2026-01-26 17:07:06 +08:00
李志鹏
65323febee Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-01-26 16:47:09 +08:00
李志鹏
b158341d6e 印花组禁止多选 2026-01-26 16:47:03 +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
X1627315083
06fa763f26 Merge remote-tracking branch 'origin/dev_vite' into StableVersion 2026-01-24 13:26:06 +08:00
X1627315083
6ad81a1896 修复detail角度和镜像问题 2026-01-24 13:25:40 +08:00
X1627315083
9b0ec12738 Merge remote-tracking branch 'origin/dev_vite' into StableVersion 2026-01-24 11:56:10 +08:00
X1627315083
26abb2aa88 修复颜色bug 2026-01-24 11:55:51 +08:00
X1627315083
07b7a6f1d7 FIX 2026-01-23 22:31:51 +08:00
bff3ea8459 Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-01-23 21:44:21 +08:00
29e68757a6 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-23 21:43:51 +08:00
12ea0f7c35 feat: 试用期5天改为7天 2026-01-23 21:43:48 +08:00
X1627315083
920d01a972 调整维护时间 2026-01-23 21:42:43 +08:00
X1627315083
13b4767992 fix 2026-01-23 19:46:34 +08:00
X1627315083
086481bfb9 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-23 18:33:06 +08:00
X1627315083
89bdba45be fix 2026-01-23 18:33:04 +08:00
李志鹏
8d0b792fd4 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-23 17:54:32 +08:00
李志鹏
a6bfca3b2f 111 2026-01-23 17:54:24 +08:00
X1627315083
a1b51d5807 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-23 17:52:58 +08:00
X1627315083
2f32cee502 fix 2026-01-23 17:52:55 +08:00
李志鹏
a05655da1c 111 2026-01-23 17:50:33 +08:00
李志鹏
6cdc8c5486 111 2026-01-23 17:43:15 +08:00
X1627315083
972743d3b8 fix 2026-01-23 16:58:03 +08:00
X1627315083
df5cb918a2 调整detail前后对比大小 2026-01-23 16:06:47 +08:00
X1627315083
bc8ce0bd47 fix 2026-01-23 15:57:40 +08:00
李志鹏
4afe1b637e Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-23 15:41:45 +08:00
李志鹏
55ede508cb 111 2026-01-23 15:41:43 +08:00
X1627315083
fbb66fd192 fix 2026-01-23 15:31:24 +08:00
X1627315083
c87b41ae11 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-23 15:25:36 +08:00
X1627315083
142c24a947 fix 2026-01-23 15:25:34 +08:00
李志鹏
2ee200e1ba Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-23 15:24:42 +08:00
李志鹏
86db2f22a1 同步印花的缩放偏移显示 2026-01-23 15:24:39 +08:00
X1627315083
9cc012b851 修复detail相关bug 2026-01-23 14:43:19 +08:00
X1627315083
c5b7365977 调整部署日期修复detail印花累加问题 2026-01-23 13:34:28 +08:00
X1627315083
43464ae85e fix 2026-01-22 16:00:45 +08:00
X1627315083
39c85cd1d1 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-22 15:40:31 +08:00
X1627315083
3c77c97532 fix 2026-01-22 15:40:28 +08:00
李志鹏
2ab23d0f30 印花元素分类 2026-01-22 15:23:15 +08:00
X1627315083
85d4569a25 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-22 14:30:42 +08:00
X1627315083
cd7d572e43 更新首次打开detail 应该使用接口数据而不是new数据 2026-01-22 14:30:40 +08:00
37157ca94d bugfix: 文件路径 2026-01-22 14:19:50 +08:00
a30897a4b2 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-22 14:08:03 +08:00
9a62d277f2 feat: 上传文件Url 2026-01-22 14:07:56 +08:00
李志鹏
0de5fe276a Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-22 13:46:57 +08:00
李志鹏
ca17956135 111 2026-01-22 13:46:55 +08:00
028c6a6540 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-22 13:34:44 +08:00
9d8c3155e6 feat: 表单回显时禁止操作 2026-01-22 13:34:38 +08:00
李志鹏
6c921730ef 背景报错 2026-01-22 13:17:11 +08:00
李志鹏
eaa94edfac Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-22 11:19:14 +08:00
李志鹏
1b30a7a873 更改画布标题 2026-01-22 11:19:12 +08:00
X1627315083
59399d672f fix 2026-01-22 10:48:42 +08:00
X1627315083
bb5c319a7f 修复detail打开画布直接提交数据没有正确更新 2026-01-22 10:29:58 +08:00
X1627315083
b114d352f6 修复detail印花界面打开花不修改元素preview后没有同步元素数据 2026-01-22 09:51:57 +08:00
李志鹏
ea4b27776a 11 2026-01-21 17:15:56 +08:00
李志鹏
faa6db9c73 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-21 16:55:18 +08:00
李志鹏
6b5c2c0b2e fix 2026-01-21 16:55:16 +08:00
X1627315083
de3cb37bc1 fix 2026-01-21 16:54:40 +08:00
X1627315083
9a69450fb6 Merge remote-tracking branch 'origin/StableVersion' into dev_vite 2026-01-21 16:54:22 +08:00
X1627315083
513eac9e49 fix 2026-01-21 16:46:51 +08:00
李志鹏
8c4f4c206b 111 2026-01-21 16:38:10 +08:00
李志鹏
c731df2ae7 Merge branch 'StableVersion' of http://18.167.251.121:10003/aidlab/aida_front into StableVersion 2026-01-21 16:31:09 +08:00
李志鹏
40c9bb1190 json修复 2026-01-21 16:31:07 +08:00
X1627315083
ef1c1c349d 画布图片数据递归设置minio地址 2026-01-21 16:27:59 +08:00
1c49dc25b1 feat: 回显表单 2026-01-21 16:24:56 +08:00
542583efc6 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-21 15:29:38 +08:00
f8f5b98854 feat: 上传文件接口&表单成功提交页面 2026-01-21 15:29:34 +08:00
李志鹏
39a65add7c Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-21 15:05:14 +08:00
李志鹏
0feade1f5b 111 2026-01-21 15:05:12 +08:00
X1627315083
5d45eee7a3 修复直接在印花preview后印花overall丢失 2026-01-21 14:45:39 +08:00
李志鹏
d31a809fa8 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-21 13:37:52 +08:00
李志鹏
750d90ee0b 瞎改 2026-01-21 13:37:50 +08:00
X1627315083
70537847bc 修复detail撤回存储数据过大问题 2026-01-21 11:55:43 +08:00
X1627315083
4688f234d9 修复印花编辑界面重复对画布上添加 2026-01-21 10:38:03 +08:00
X1627315083
5599edfcd0 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-21 10:09:31 +08:00
X1627315083
73c2d1d41e fix 2026-01-21 10:09:29 +08:00
李志鹏
2fad680490 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-21 10:06:13 +08:00
李志鹏
85da122590 平铺按钮位置调整 2026-01-21 10:06:11 +08:00
X1627315083
62e977c703 修复印花overall偏移和画布对不上问题 2026-01-21 09:59:17 +08:00
X1627315083
a1e0e19412 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-21 09:43:57 +08:00
X1627315083
b10fd72008 fix 2026-01-21 09:43:26 +08:00
X1627315083
a78056c898 fix: 修复canvas快捷键隐藏问题、提交preview后切换sketch再切回来前后片变为最早版本 2026-01-21 09:41:38 +08:00
X1627315083
07c261d74c Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-01-20 16:48:37 +08:00
X1627315083
fc28d78357 处理generate生成失败逻辑 2026-01-20 16:48:34 +08:00
李志鹏
6bee02dfa5 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-20 16:44:57 +08:00
李志鹏
e19c850214 fix 2026-01-20 16:44:56 +08:00
9bdd0a23d3 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-20 16:41:41 +08:00
08b8a52d83 style:页面动画 2026-01-20 16:41:37 +08:00
李志鹏
11fb6f908c 平铺不可以添加相同的token 2026-01-20 16:39:02 +08:00
李志鹏
27198cc35b Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-20 16:11:42 +08:00
李志鹏
844694d638 平铺偏移 2026-01-20 16:11:40 +08:00
695a91ac1c bugfix: 教育版管理员页面分页器消失 2026-01-20 15:44:55 +08:00
4fd66fcc05 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-20 15:42:23 +08:00
aa193f08cb style: 页面动画效果 2026-01-20 15:42:17 +08:00
X1627315083
3692361551 fix 2026-01-20 15:40:36 +08:00
X1627315083
008e14ec57 ifx 2026-01-20 15:31:06 +08:00
X1627315083
248732b085 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-20 15:29:06 +08:00
X1627315083
033950babe 修复印花界面,切换线稿图印花储存有问题 2026-01-20 15:29:04 +08:00
李志鹏
dbd1651a37 gap 2026-01-20 14:10:10 +08:00
X1627315083
25ad9799f8 修改sketch或者切换sketch bug修复 2026-01-20 13:49:34 +08:00
李志鹏
747a3b0ebc Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-20 13:18:30 +08:00
李志鹏
27e43f3c97 老数据重置画布大小 2026-01-20 13:18:28 +08:00
516ad19db7 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-20 10:31:57 +08:00
d1af68d60a chore: award页面修改 2026-01-20 10:31:52 +08:00
李志鹏
eb1de5abb3 fix 2026-01-20 10:31:47 +08:00
X1627315083
cdcb18c02c fix 2026-01-19 17:16:20 +08:00
f11805c65a chore: 字体包 2026-01-19 17:08:41 +08:00
ce21acba93 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-19 17:07:09 +08:00
a48e517e76 feat: award表单页面 2026-01-19 17:07:05 +08:00
李志鹏
f837542797 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-19 16:57:12 +08:00
李志鹏
74b43e431b 去除画布打印信息 2026-01-19 16:57:11 +08:00
X1627315083
c20ef9d00c fix 2026-01-19 16:55:45 +08:00
X1627315083
a7b5cc1685 当前页面直接提交数据没有存储到衣服上 2026-01-19 16:53:20 +08:00
X1627315083
5971ab56c0 ifx 2026-01-19 16:40:10 +08:00
X1627315083
7ff2c2095a 添加元素图层合并模式由正片叠底改为默认 2026-01-19 16:08:08 +08:00
李志鹏
9613d2b5b2 fix 2026-01-19 15:26:04 +08:00
X1627315083
94b9977ef6 Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite 2026-01-19 14:44:47 +08:00
X1627315083
315254b6d5 fix 2026-01-19 14:44:45 +08:00
李志鹏
31c2ca4e8b 平铺画布更改 2026-01-19 14:44:18 +08:00
李志鹏
af5f178476 Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite 2026-01-19 14:26:07 +08:00
李志鹏
0aae85e94d 添加任务队列 2026-01-19 14:25:44 +08:00
X1627315083
4c25e4a5a3 fix 2026-01-19 13:58:31 +08:00
李志鹏
87fd5b9a93 fix 2026-01-19 13:37:24 +08:00
李志鹏
e81049c332 印花其他属性同步 2026-01-19 11:16:23 +08:00
fb1bfc353c Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion 2026-01-15 10:47:57 +08:00
cc0127f195 bugfix: 教育版管理员页面分页器消失 2026-01-15 10:38:53 +08:00
X1627315083
f4043d6f61 调整手机注册输入验证码样式 2026-01-14 16:56:39 +08:00
X1627315083
1df7b62fe6 调整系统维护页面文案 2025-12-19 21:36:42 +08:00
144 changed files with 12433 additions and 8179 deletions

View File

@@ -7,5 +7,7 @@ VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
# VITE_APP_BASE_URL = 'https://www.api.aida.com.hk'
# 徐佩
# VITE_APP_BASE_URL = 'http://192.168.31.118:5567'
# 李天祥
# VITE_APP_BASE_URL = 'http://192.168.31.82:5567'
# 海波
# VITE_APP_BASE_URL = 'http://192.168.31.34:5567'

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 = '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

@@ -0,0 +1,41 @@
/* 字体定义 */
@font-face {
font-family: 'Arial';
src: url('./fonts/ARIAL.ttf') format('truetype');
}
@font-face {
font-family: 'ArialBold';
src: url('./fonts/ARIALBD.ttf') format('truetype');
}
@font-face {
font-family: 'ArialMedium';
src: url('./fonts/ArialMdm.ttf') format('truetype');
}
@font-face {
font-family: 'Poppins';
src: url('./fonts/Poppins-Regular.ttf') format('truetype');
font-weight: normal;
}
@font-face {
font-family: 'PoppinsMedium';
src: url('./fonts/Poppins-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'PoppinsBold';
src: url('./fonts/Poppins-SemiBold.ttf') format('truetype');
}
@font-face {
font-family: 'Instrument';
src: url('./InstrumentSans-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'InstrumentBold';
src: url('./InstrumentSans-Bold.ttf') format('truetype');
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

View File

@@ -1,31 +0,0 @@
/* 字体定义 */
@font-face {
font-family: 'Arial';
src: url('./fonts/ARIAL.ttf') format('ttf');
}
@font-face {
font-family: 'ArialBold';
src: url('./fonts/ARIALBD.ttf') format('ttf');
}
@font-face {
font-family: 'ArialMedium';
src: url('./fonts/ArialMdm.ttf') format('ttf');
}
@font-face {
font-family: 'Poppins';
src: url('./fonts/Poppins-Regular.ttf') format('ttf');
font-weight: normal;
}
@font-face {
font-family: 'PoppinsMedium';
src: url('./fonts/Poppins-Medium.ttf') format('ttf');
}
@font-face {
font-family: 'PoppinsBold';
src: url('./fonts/Poppins-SemiBold.ttf') format('ttf');
}

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

View File

@@ -1,68 +1,29 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="103.000000pt" height="92.000000pt" viewBox="0 0 103.000000 92.000000"
preserveAspectRatio="xMidYMid meet">
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 184.06 163.52">
<defs>
<style>
.cls-1, .cls-2 {
fill: #333;
}
<g transform="translate(0.000000,92.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M365 895 c-5 -2 -36 -6 -67 -10 -45 -5 -58 -10 -59 -23 0 -11 -2 -12
-6 -4 -7 17 -32 15 -40 -4 -4 -11 -8 -12 -13 -4 -5 8 -13 9 -21 4 -7 -4 -22
-9 -34 -10 -11 -1 -41 -11 -66 -21 l-47 -18 20 -63 c11 -38 23 -60 30 -56 6 4
8 -1 3 -15 -3 -11 -3 -21 2 -21 4 0 9 -12 9 -26 1 -14 5 -28 8 -32 4 -3 33 3
66 15 33 11 61 19 62 18 2 -2 1 -139 -2 -304 l-5 -301 309 2 309 3 -2 108 c-2
77 2 113 11 125 10 12 10 14 1 8 -7 -4 -13 -2 -13 4 0 6 10 8 23 5 18 -5 26
-1 36 17 9 17 10 18 6 3 -5 -16 -4 -18 6 -7 18 17 -1 34 -40 37 l-32 2 -2 151
c-1 82 0 147 3 144 9 -12 44 -11 52 1 5 8 8 7 8 -4 0 -14 26 -28 52 -29 11 0
39 70 33 80 -3 5 1 11 7 13 10 4 9 8 -2 16 -13 10 -8 15 12 12 8 -1 38 91 32
98 -2 2 -10 -2 -18 -8 -9 -7 -17 -8 -20 -2 -3 5 0 11 6 14 7 2 -18 14 -56 26
-38 12 -71 19 -74 16 -3 -3 -11 0 -18 6 -8 6 -20 9 -28 6 -8 -3 -16 -2 -18 3
-5 15 -154 30 -286 29 -70 0 -131 -2 -137 -4z m21 -30 c-6 -18 3 -47 14 -40 4
2 18 -7 30 -20 27 -29 17 -34 -14 -7 -20 16 -20 16 -7 -1 23 -29 66 -47 112
-47 34 0 40 3 35 16 -5 14 -4 15 9 4 13 -11 19 -9 36 6 12 11 29 35 38 54 15
31 20 35 58 35 24 0 43 -2 43 -5 0 -11 115 -27 121 -18 3 5 9 2 13 -7 4 -13
14 -16 34 -12 15 2 36 1 47 -4 16 -7 14 -8 -10 -5 l-30 5 32 -14 c39 -18 39
-19 14 -83 -15 -38 -17 -52 -8 -61 9 -9 8 -11 -7 -5 -16 6 -18 4 -12 -19 3
-14 2 -29 -4 -32 -6 -3 -7 1 -4 9 6 16 -9 20 -73 19 -12 0 -20 4 -17 8 3 5 -4
9 -15 9 -20 0 -21 -5 -21 -151 l0 -151 -27 8 c-16 4 -38 7 -50 7 -19 -1 -21 2
-13 17 15 28 12 57 -6 57 -11 0 -15 -8 -12 -27 4 -24 1 -27 -23 -26 -15 1 -25
4 -22 9 2 4 -2 7 -10 7 -9 0 -14 -10 -14 -25 0 -13 3 -22 8 -19 5 3 6 -1 3 -9
-2 -7 0 -25 5 -40 8 -20 7 -25 -3 -21 -7 3 -13 -2 -13 -11 0 -12 7 -15 26 -11
14 3 21 3 14 0 -7 -3 -9 -12 -6 -20 3 -7 10 -11 16 -7 5 3 7 1 4 -4 -9 -14 3
-74 12 -68 4 2 7 -6 7 -18 -1 -32 32 -34 44 -3 5 14 7 34 5 46 -3 13 0 18 7
14 8 -5 9 -1 5 10 -4 9 -3 15 2 12 5 -3 12 1 15 10 3 8 2 12 -4 9 -6 -3 -10
-1 -10 4 0 13 3 13 24 5 13 -5 16 -24 16 -103 0 -63 4 -102 13 -111 10 -12 9
-12 -4 -2 -13 10 -88 12 -300 10 l-284 -3 3 303 3 302 -26 0 c-14 0 -25 -4
-25 -10 0 -5 -7 -6 -17 -3 -9 4 -14 2 -10 -3 4 -6 -6 -9 -24 -6 -28 4 -41 -11
-19 -21 6 -3 5 -4 -2 -3 -7 2 -13 11 -13 22 -1 32 -25 104 -35 104 -5 0 -6 7
-3 17 4 10 2 14 -5 9 -7 -4 -10 2 -8 17 3 29 14 47 29 47 7 0 3 -8 -8 -17
l-20 -16 20 8 c11 4 28 10 37 12 10 3 18 9 18 13 0 4 6 7 12 7 22 -2 158 26
158 32 0 3 20 6 45 5 25 0 45 3 45 8 0 4 3 8 6 8 3 0 4 -7 0 -15z m237 -5 c-3
-9 1 -8 11 4 9 11 16 15 16 9 0 -6 -7 -16 -15 -23 -8 -7 -15 -9 -15 -4 0 10
-29 -28 -30 -40 0 -4 8 -5 17 -2 15 6 15 4 -2 -14 -22 -24 -37 -26 -28 -4 5
14 3 15 -15 5 -26 -14 -77 -14 -103 -1 -10 6 -27 27 -38 48 l-19 37 113 0 c95
0 112 -2 108 -15z"/>
<path d="M346 641 c-3 -5 1 -12 10 -15 23 -9 36 -7 29 4 -3 6 1 7 9 4 9 -3 16
-1 16 5 0 13 -56 15 -64 2z"/>
<path d="M440 640 c0 -16 33 -26 38 -12 2 7 8 10 13 6 5 -3 9 0 9 5 0 6 -13
11 -30 11 -16 0 -30 -5 -30 -10z"/>
<path d="M530 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
-9z"/>
<path d="M620 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
-9z"/>
<path d="M310 593 c0 -20 5 -30 16 -30 10 0 14 8 12 25 -4 37 -28 40 -28 5z"/>
<path d="M697 613 c-13 -13 -7 -50 8 -50 10 0 15 10 15 29 0 27 -9 35 -23 21z"/>
<path d="M317 534 c-4 -4 -7 -20 -7 -36 0 -35 23 -34 28 1 4 25 -10 46 -21 35z"/>
<path d="M692 503 c4 -39 28 -42 28 -4 0 21 -5 31 -16 31 -11 0 -14 -8 -12
-27z"/>
<path d="M312 415 c4 -33 22 -33 26 0 2 18 -1 25 -13 25 -12 0 -15 -7 -13 -25z"/>
<path d="M312 329 c2 -19 8 -33 13 -31 15 3 12 55 -3 60 -10 3 -13 -5 -10 -29z"/>
<path d="M342 278 c3 -7 19 -14 37 -16 24 -3 32 0 29 10 -3 7 -19 14 -37 16
-24 3 -32 0 -29 -10z"/>
<path d="M443 275 c0 -10 10 -15 29 -15 18 0 28 5 28 15 0 10 -10 15 -28 15
-19 0 -29 -5 -29 -15z"/>
<path d="M530 275 c0 -10 10 -15 33 -15 22 0 28 3 18 9 -11 7 -11 9 0 14 8 3
-1 6 -18 6 -23 1 -33 -4 -33 -14z"/>
</g>
</svg>
.cls-2 {
stroke: #333;
stroke-miterlimit: 10;
}
</style>
</defs>
<path class="cls-2" d="M35.53,54.52c-.76-.96-.84-1.16-2.06-1.12-4.02.13-16.7,6.5-19.81,4.48C12.45,52.21-1.21,21.14.68,18.17c56.98-23.47,125.74-23.63,182.7,0,1.88,2.98-11.77,34.04-12.98,39.72-3.11,2.01-15.78-4.36-19.81-4.48-1.23-.04-1.3.16-2.06,1.12v48c2.87,3.81,14.6,2.98,14.05,8.95-1.06,5.75-12.53,3.84-13.85,8.24l.34,39.85c.08.98-1.55,3.46-2.04,3.46H37.03c-2.08,0-1.5-3.59-1.5-4.5V54.52ZM41.53,47.52v108.5h101v-36c-7.66,1.58-6.82,23.41-12.7,24.86-1.18.17-2.67-.14-3.63-.79-2.98-2.02-6.47-24.26-10.3-25.81-.94-.38-4.46.95-5.31-1.9-1.01-3.4,3.85-4,4.01-5.02-.12-4.15-6.85-15.14-3.84-18.1,4.45-3.04,8.95,1.93,13.76,1.74-1.35-3.15-2.75-11.61,2.46-11.03s3.05,9.89,1.55,13.02l14,4.01v-53.5c0-5.17,22.25,4.69,23.94,3.46,1.7-8.98,7.54-18.42,9.64-26.94.32-1.3.79-1.48-.58-2.5-2.81-2.08-21.4-6.93-25.98-8.02-10.05-2.4-20.36-3.72-30.52-5.53-2.44.17-3.98,7.98-6.05,10.97-13.1,18.91-41.58,12.05-45.92-9.95l-2-1.02c-19.44,3.3-39.69,6.08-57.48,14.6l10.03,28.4c4.22.52,22.41-8.34,23.94-3.46ZM110.53,8.02h-37c4,20.53,33,20.53,37,0Z"/>
<path class="cls-1" d="M89.27,117.8c-.94.96-10.2,1.42-11.25-.78-4.1-8.61,17.67-5.76,11.25.78Z"/>
<path class="cls-1" d="M94.79,117.8c-6.42-6.54,15.35-9.39,11.25-.78-1.05,2.19-10.31,1.74-11.25.78Z"/>
<path class="cls-1" d="M60.62,113.11c1.1-1.64,14.59-2.57,12.84,3.27-1.14,3.81-16.87,2.76-12.84-3.27Z"/>
<path class="cls-1" d="M62.18,46.17h9.69s1.53,3.19,1.53,3.19c-1.22,4.73-18.53,3.97-11.22-3.19Z"/>
<path class="cls-1" d="M112.19,46.18l10.91.77.34,3.47c-.87,2.65-12.93,2.92-12.96-1.9l1.7-2.34Z"/>
<path class="cls-1" d="M56.23,84.18c6.63-1.86,6.45,14.76-.7,11.35-2.24-1.07-2.61-10.42.7-11.35Z"/>
<path class="cls-1" d="M89.37,46.16l.96,3.22c-.81,4.5-16.92,3.98-12.37-2.43l11.42-.79Z"/>
<path class="cls-1" d="M94.68,46.16l11.42.79.34,3.47c-1.03,3.13-16.69,2.9-11.76-4.26Z"/>
<path class="cls-1" d="M54.75,63.76c-1.01-.99-2.01-12.94,3.11-11.63,5.4,1.38,2.78,17.42-3.11,11.63Z"/>
<path class="cls-1" d="M129.31,63.76c-5.88,5.78-8.51-10.25-3.11-11.63,5.12-1.31,4.12,10.64,3.11,11.63Z"/>
<path class="cls-1" d="M59.44,68.12c1.19.8,3.28,13.19-3.02,12.43l-2.23-1.77c-.57-2.83-.34-14.39,5.25-10.66Z"/>
<path class="cls-1" d="M59.44,111.92c-5.59,3.73-5.82-7.83-5.25-10.66l2.23-1.77c6.3-.76,4.22,11.63,3.02,12.43Z"/>
<path class="cls-1" d="M129.32,79.79c-5.12,5.18-7.81-7.81-4.7-11.67l3.28.02,1.48,1.52c-.35,2.45,1.51,8.54-.07,10.13Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -0,0 +1,3 @@
<svg width="22" height="12" viewBox="0 0 22 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 1L11 11L21 1" stroke="#585858" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

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: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 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: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,93 +1,124 @@
{
"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,
"title":"AiDA X SFT AI Fashion Award 2024",
"title": "AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png"
}
],
"eventsItem":[
{
"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",
"textList":[
{
"paragraph":[
{
"text":"🎨AiDA Workshop!"
}
]
},{
"paragraph":[
{
"text":"The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
}
]
},{
"paragraph":[
{
"text":"<b>⚠ATTENTION❗❗</b>"
}
]
},{
"paragraph":[
{
"text":"1. Add the tag in the work description #AiDAworkshop_2024"
},{
"text":"2. One winner only"
}
]
},{
"paragraph":[
{
"text":"<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
}
]
},{
"paragraph":[
{
"text":"✅Round-trip transportation fee (only within China)"
}
]
},{
"paragraph":[
{
"text":"✅One night accommodation fee"
}
]
},{
"paragraph":[
{
"text":"⌛Deadline: October 31, 2024"
}
]
}
]
},
{
"id":2,
"title":"AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"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."
}
]
}
]
],
"eventsItem": [
{
"id": 3,
"title": "AiDA Global Design Awards 2026",
"imgUrl": "/image/events/award-poster.gif",
"textList": [
{
"paragraph": [
{
"text": "Click the “View Details” button for more information and to join the competition! The AiDA Global Design Award 2026 is an international design competition hosted by CodeCreate, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers from Hong Kong, China, Singapore, South Korea, and beyond, the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
}
]
},
{
"paragraph": [
{
"text": "Participants have the opportunity to compete for cash prizes totaling up to US$9,000, gain global media exposure showcased by top international platforms, and connect with designers and industry leaders worldwide. Finalists will also attend an exclusive award ceremony in Hong Kong, with travel support provided, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
}
]
}
]
},
{
"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",
"textList": [
{
"paragraph": [
{
"text": "🎨AiDA Workshop!"
}
]
},
{
"paragraph": [
{
"text": "The process is simple: use AiDA to post your design work on the 'Gallery', and the one with the most likes(at least 20 likes) will be invited to the AiDA Workshop offline event in Hong Kong on November 14th, to exchange ideas with the Royal College of Art (RCA), Jae Lim, co-founder of the renowned fashion brand BESFXXK, and outstanding designers! "
}
]
},
{
"paragraph": [
{
"text": "<b>⚠ATTENTION❗❗</b>"
}
]
},
{
"paragraph": [
{
"text": "1. Add the tag in the work description #AiDAworkshop_2024"
},
{
"text": "2. One winner only"
}
]
},
{
"paragraph": [
{
"text": "<b>🤩Code-Create will provide (Terms and conditions apply):</b>"
}
]
},
{
"paragraph": [
{
"text": "✅Round-trip transportation fee (only within China)"
}
]
},
{
"paragraph": [
{
"text": "✅One night accommodation fee"
}
]
},
{
"paragraph": [
{
"text": "⌛Deadline: October 31, 2024"
}
]
}
]
},
{
"id": 2,
"title": "AiDA X SFT AI Fashion Award 2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"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,124 @@
{
"eventsList": [
{
"id": 1,
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
"imgUrl": "/image/events/workshop-Cn.jpg"
},{
"id": 2,
"title":"AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png"
}
"eventsList": [
{
"id": 1,
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
"imgUrl": "/image/events/workshop-Cn.jpg"
},
{
"id": 2,
"title": "AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png"
}
],
"eventsItem":[
{
"id":1,
"title":"什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
"imgUrl": "/image/events/workshop-Cn.jpg",
"textList":[
{
"paragraph":[
{
"text":"🎨这是一趟艺术巅峰之旅AiDA Workshop"
}
]
},{
"paragraph":[
{
"text":"参与过程很简单利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞将被邀请至11月14日 举办的AiDA Workshop香港线下活动与英国皇家艺术学院RCA、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流(名额仅限1名"
}
]
},{
"paragraph":[
{
"text":"<b>⚠️注意❗❗</b>"
}
]
},{
"paragraph":[
{
"text":"1. 作品描述添加tag: #AiDAworkshop_2024"
},{
"text":"2. 一个冠军名额"
}
]
},{
"paragraph":[
{
"text":"<b>🤩Code-Create将提供适用条款条规</b>"
}
]
},{
"paragraph":[
{
"text":"✅往返机票/动车费用(仅限中国地区)"
}
]
},{
"paragraph":[
{
"text":"✅一晚酒店住宿费用"
}
]
},{
"paragraph":[
{
"text":"⌛截止时间2024.10.31"
}
]
}
]
},
{
"id":2,
"title":"AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"textList":[
{
"paragraph":[
{
"text":"秉承着激发学生使用AI进行时尚设计的创新能力的初衷Code-Create和香港理工大学时装及纺织学院SFT共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验为未来的时尚设计行业打下了坚实的基础成为时尚界的AI先锋。"
}
]
},{
"paragraph":[
{
"text":" 此次比赛面向全体SFT 学生最终获奖者将赢取丰厚奖金最高可达2万港币获得在BESFXXK的实习机会将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
}
]
}
]
}
]
}
"eventsItem": [
{
"id": 3,
"title": "AiDA全球设计奖 2026",
"imgUrl": "/image/events/award-poster-zh.gif",
"textList": [
{
"paragraph": [
{
"text": "秉承推动 AI 赋能创意设计的初衷CodeCreate 举办了「AiDA 全球设计大奖 2026」面向来自香港、中国、新加坡、韩国及全球的设计师鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧"
}
]
},
{
"paragraph": [
{
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅支持,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
}
]
}
]
},
{
"id": 1,
"title": "什么?只要发布设计作品就有机会来香港与大佬面对面交流?!",
"imgUrl": "/image/events/workshop-Cn.jpg",
"textList": [
{
"paragraph": [
{
"text": "🎨这是一趟艺术巅峰之旅AiDA Workshop"
}
]
},
{
"paragraph": [
{
"text": "参与过程很简单利用AiDA 在 “Gallery广场 ”发布设计作品,最终获赞最高者(至少20个赞将被邀请至11月14日 举办的AiDA Workshop香港线下活动与英国皇家艺术学院RCA、韩国知名时尚品牌BESFXXK创始人JAE以及优秀设计师一同交流(名额仅限1名"
}
]
},
{
"paragraph": [
{
"text": "<b>⚠️注意❗❗</b>"
}
]
},
{
"paragraph": [
{
"text": "1. 作品描述添加tag: #AiDAworkshop_2024"
},
{
"text": "2. 一个冠军名额"
}
]
},
{
"paragraph": [
{
"text": "<b>🤩Code-Create将提供适用条款条规</b>"
}
]
},
{
"paragraph": [
{
"text": "✅往返机票/动车费用(仅限中国地区)"
}
]
},
{
"paragraph": [
{
"text": "✅一晚酒店住宿费用"
}
]
},
{
"paragraph": [
{
"text": "⌛截止时间2024.10.31"
}
]
}
]
},
{
"id": 2,
"title": "AiDA X SFT AI时尚设计比赛2024",
"imgUrl": "/image/events/Fashion-Award-2024.png",
"textList": [
{
"paragraph": [
{
"text": "秉承着激发学生使用AI进行时尚设计的创新能力的初衷Code-Create和香港理工大学时装及纺织学院SFT共同举办了“AiDA X SFT AI时尚设计比赛2024”让学生们在比赛中获得宝贵的AiDA实践经验为未来的时尚设计行业打下了坚实的基础成为时尚界的AI先锋。"
}
]
},
{
"paragraph": [
{
"text": " 此次比赛面向全体SFT 学生最终获奖者将赢取丰厚奖金最高可达2万港币获得在BESFXXK的实习机会将与著名设计师Lim Jae Hyuk先生合作设计BESFXXK 系列,该系列将在纽约时装周和巴黎时装周上展出)及更多惊喜哦!扫描二维码获取更多比赛信息。"
}
]
}
]
}
]
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -148,6 +148,7 @@
total: total,
showQuickJumper: true,
bordered: false,
showTotal: (total) => `Total Transaction: ${total}`
}"
>
<template #bodyCell="{ column, text, record, index }">
@@ -465,13 +466,16 @@ export default defineComponent({
(rv: any) => {
if (rv) {
// this.dataList = rv
// console.log('rv----',rv);
filter.dataList = rv.content;
filterData.total = rv.total;
filter.tableLoading = false;
filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
return total + (isNaN(value) ? 0 : value);
}, 0);
filterData.totalPayer = rv.totalAmount;
// filterData.totalPayer = rv.content.reduce((total: number, item: any) => {
// const value = item && item.status === 'Success' ? parseFloat(item.payerTotal) : 0;
// return total + (isNaN(value) ? 0 : value);
// }, 0);
// this.workspaceItem.position = this.singleTypeList[0].label
}

View File

@@ -207,7 +207,8 @@ export class BackgroundSizeCommand extends Command {
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
// 记录原尺寸
this.backgroundObject = findObjectById(this.canvas, this.bgLayer.fabricObject.id).object;
this.bgId = this.bgLayer.fabricObject?.id || this.bgLayer.fabricObjects?.[0]?.id;
this.backgroundObject = findObjectById(this.canvas, this.bgId).object;
this.oldWidth = this.backgroundObject.width;
this.oldHeight = this.backgroundObject.height;

View File

@@ -50,7 +50,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
);
this.layer = layer;
this.parent = parent;
console.log("==========",layer);
if (!layer) return false;
if(!isUndo){
@@ -107,7 +106,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
});
}
}
// 判断fabricObjects是否是组对象
const firstObj = layer.fabricObjects?.[0] || null;
// 如果没有找到第一个对象,则直接添加到当前画布
@@ -174,8 +172,8 @@ export class FillGroupLayerBackgroundCommand extends Command {
}
const canvasObj = findObjectById(this.canvas, firstObj?.id)?.object;
if (
(canvasObj && canvasObj.type === "group") ||
canvasObj._objects?.length > 0
canvasObj && (canvasObj.type === "group" ||
canvasObj._objects?.length > 0)
) {
this.newFill.set({
left: 0,
@@ -343,10 +341,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
minTop = Infinity,
maxRight = -Infinity,
maxBottom = -Infinity;
console.log(
"计算当前所有对象的边界信息:===>",
this.originalfabricObjects.length
);
this.originalfabricObjects?.forEach((obj) => {
const { object } = findObjectById(this.canvas, obj.id) || {};
if (object) {

View File

@@ -7,12 +7,11 @@ import {
insertObjectAtZIndex,
removeCanvasObjectByObject,
createPatternTransform,
getTransformScaleAngle,
imageAddGapToCanvas,
} from "../utils/helper";
import { restoreFabricObject } from "../utils/objectHelper";
const scale = 0.3;// 默认缩放比例
export const FillSourceToBase64 = (source) => {
if (source?.toDataURL) {
return source.toDataURL?.();
@@ -39,7 +38,6 @@ export class FillRepeatCommand extends Command {
this.fillRepeat = options.fillRepeat;
this.oldObjects = null;
this.oldLocked = null;
this.oldIsDisableUnlock = null;
}
async execute() {
@@ -64,17 +62,15 @@ export class FillRepeatCommand extends Command {
);
});
image.set({
id: object.id,
layerId: object.layerId,
layerName: object.layerName,
...this.copyObjectProperties(object),
...(fill_.originalInfo || {
top: object.top,
left: object.left,
})
});
layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
this.oldLocked = layer.locked;
layer.locked = false;
// this.oldLocked = layer.locked;
// layer.locked = false;
this.canvas.add(image);
this.canvas.remove(object);
@@ -110,24 +106,35 @@ export class FillRepeatCommand extends Command {
height: object.height,
}
};
const fdObject = this.canvasManager.getFixedLayerObject();
const bgObject = this.canvasManager.getBackgroundLayerObject();
const tObject = fdObject || bgObject;
const tWidth = tObject.width;
const tHeight = tObject.height;
// const offsetX = object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : tObject.width / 2;
// const offsetY = object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : tObject.height / 2;
const scaleX_ = tWidth / img.width / 5;
const scaleY_ = tHeight / img.height / 5;
const scale_ = tWidth > tHeight ? scaleX_ : scaleY_;
const patternTransform = object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale_, 0);
const scale = getTransformScaleAngle(patternTransform).scale;
const offsetX = tWidth / 2 - img.width * scale / 2;
const offsetY = tHeight / 2 - img.height * scale / 2;
const pattern = new fabric.Pattern({
source: img,
repeat: this.fillRepeat,
patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0),
offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : bgObject.width / 2, // 水平偏移
offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : bgObject.height / 2, // 垂直偏移
patternTransform,
offsetX, // 水平偏移
offsetY, // 垂直偏移
});
const rect = new fabric.Rect({
id: object.id,
layerId: object.layerId,
layerName: object.layerName,
...this.copyObjectProperties(object),
fill_,
});
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
this.oldLocked = layer.locked;
// this.oldIsDisableUnlock = layer.isDisableUnlock;
// layer.isDisableUnlock = true;
// this.oldLocked = layer.locked;
if (this.oldObjects.type === "rect") {
rect.set({
width: object.width,
@@ -143,17 +150,17 @@ export class FillRepeatCommand extends Command {
flipY: object.flipY,
});
} else {
let scaleX = bgObject.scaleX || 1;
let scaleY = bgObject.scaleY || 1;
let scaleX = tObject.scaleX || 1;
let scaleY = tObject.scaleY || 1;
rect.set({
width: bgObject.width,
height: bgObject.height,
top: bgObject.top - bgObject.height * scaleY / 2,
left: bgObject.left - bgObject.width * scaleX / 2,
width: tWidth,
height: tHeight,
top: tObject.top - tHeight * scaleY / 2,
left: tObject.left - tWidth * scaleX / 2,
scaleX,
scaleY,
});
layer.locked = true;
// layer.locked = true;
}
rect.set("fill", pattern);
this.canvas.add(rect);
@@ -182,14 +189,23 @@ export class FillRepeatCommand extends Command {
this.canvas.remove(object);
this.canvas.add(this.oldObjects);
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
layer.locked = this.oldLocked;
// layer.isDisableUnlock = this.oldIsDisableUnlock;
// layer.locked = this.oldLocked;
await this.layerManager?.updateLayersObjectsInteractivity();
await this.layerManager?.sortLayersWithTool?.();
this.canvas.renderAll();
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
return true;
}
// 复制原对象的属性
copyObjectProperties(object) {
return {
id: object.id,
layerId: object.layerId,
layerName: object.layerName,
isPrintTrims: object.isPrintTrims,
}
}
}
@@ -228,6 +244,10 @@ export class FillRepeatChangeCommand extends Command {
...this.newPattern,
});
object.set("fill", pattern);
if (object.globalCompositeOperation_) {
object.globalCompositeOperation = object.globalCompositeOperation_;
object.globalCompositeOperation_ = null;
}
this.canvas.renderAll();
return true;
}
@@ -274,7 +294,7 @@ export class FillRepeatGapChangeCommand extends Command {
this.oldGapY = null;
}
async execute(isUndo = false) {
async execute(isCommand = true, isUndo = false) {
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
console.warn("图层不存在或没有 fabric 对象");
@@ -305,6 +325,7 @@ export class FillRepeatGapChangeCommand extends Command {
object.fill_.gapY = this.newGapY;
}
const image = new Image();
image.crossOrigin = "anonymous";
image.src = object.fill_.source;
await image.decode();
object.fill_.width = image.width;
@@ -312,6 +333,10 @@ export class FillRepeatGapChangeCommand extends Command {
const fill = object.get("fill");
fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY);
object.set("fill", new fabric.Pattern(fill));
if (isCommand && object.globalCompositeOperation_) {
object.globalCompositeOperation = object.globalCompositeOperation_;
object.globalCompositeOperation_ = null;
}
this.canvas.renderAll();
return true;
}
@@ -321,7 +346,7 @@ export class FillRepeatGapChangeCommand extends Command {
console.warn("没有旧间隙可恢复");
return false;
}
await this.execute(true);
await this.execute(true, true);
return true;
}

View File

@@ -147,11 +147,11 @@ export class LassoCutoutCommand extends CompositeCommand {
}
// 确定源图层
const sourceLayer = this.layerManager.getActiveLayer();
if (!sourceLayer) {
console.error("无法执行套索抠图:源图层无效");
return false;
}
// const sourceLayer = this.layerManager.getActiveLayer();
// if (!sourceLayer) {
// console.error("无法执行套索抠图:源图层无效");
// return false;
// }
// 获取源图层的所有对象(包括子图层)
// const sourceObjects = this._getLayerObjects(sourceLayer);
@@ -225,7 +225,7 @@ export class LassoCutoutCommand extends CompositeCommand {
const layers = this.layerManager.layers.value;
var topLayerIndex = 0;
layers.forEach((layer, index) => {
if(this.originalLayer)layers.forEach((layer, index) => {
if (layer.id === this.originalLayer.id) {
topLayerIndex = index;
}else if (layer.children.length > 0) {

View File

@@ -280,8 +280,13 @@ export class PasteLayerCommand extends Command {
isCut: undefined,
serializedObjects: undefined,
};
if (this.insertIndex !== undefined && this.insertIndex !== null) {
if(this.newLayer.isPrintTrims){
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);
} else {
this.layers.value.push(this.newLayer);
@@ -3684,7 +3689,7 @@ export class ChangeFixedImageCommand extends Command {
opacity: currentObj.opacity,
};
console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
// console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
}
}
@@ -3794,7 +3799,7 @@ export class ChangeFixedImageCommand extends Command {
false
);
if (insertSuccess) {
console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
// console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
} else {
// 如果插入失败,回退到普通添加
this.canvas.add(newImage);

View File

@@ -600,7 +600,7 @@ export class ChangeFixedImageCommand extends Command {
opacity: currentObj.opacity,
};
console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
// console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
}
}
@@ -716,7 +716,7 @@ export class ChangeFixedImageCommand extends Command {
false
);
if (insertSuccess) {
console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
// console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
} else {
// 如果插入失败,回退到普通添加
this.canvas.add(newImage);

View File

@@ -0,0 +1,56 @@
import { Command } from "./Command.js";
/**
* 部件绘制命令
*/
export class PartDrawCommand extends Command {
constructor(options) {
super({
name: "部件绘制命令",
saveState: false,
});
this.canvas = options.canvas;
this.partManager = options.partManager;
this.partCanvas = options.partCanvas;
this.oldPartCanvas = this.partManager.partCanvas;
}
execute() {
this.partManager.drawPartCanvas(this.partCanvas);
return true;
}
undo() {
this.partManager.drawPartCanvas(this.oldPartCanvas);
return true;
}
}
/**
* 部件点选绘制命令
*/
export class PartPointDrawCommand extends Command {
constructor(options) {
super({
name: "部件点选绘制命令",
saveState: false,
});
this.canvas = options.canvas;
this.partManager = options.partManager;
this.partCanvas = options.partCanvas;
this.pointList = options.pointList;
this.oldPartCanvas = this.partManager.partCanvas;
this.oldPointList = [...this.partManager.pointList];
}
async execute() {
const list = [...this.pointList];
const canvas = this.partCanvas;
const res = await this.partManager.pointDrawPartCanvas(list, canvas);
return res;
}
async undo() {
const list = [...this.oldPointList];
const canvas = this.oldPartCanvas;
const res = await this.partManager.pointDrawPartCanvas(list, canvas);
return res;
}
}

View File

@@ -285,17 +285,15 @@ export class RasterizeLayerCommand extends Command {
// 提取排序后的对象
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
console.log(
`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
);
console.log(
"🔢 对象z-index顺序:",
objectsWithZIndex.map((item) => ({
id: item.object.id,
type: item.object.type,
zIndex: item.zIndex,
}))
);
// console.log(`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合` );
// console.log(
// "🔢 对象z-index顺序:",
// objectsWithZIndex.map((item) => ({
// id: item.object.id,
// type: item.object.type,
// zIndex: item.zIndex,
// }))
// );
}
/**
@@ -611,17 +609,17 @@ export class ExportLayerToImageCommand extends Command {
// 提取排序后的对象
this.objectsToRasterize = objectsWithZIndex.map((item) => item.object);
console.log(
`📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
);
console.log(
"🔢 对象z-index顺序:",
objectsWithZIndex.map((item) => ({
id: item.object.id,
type: item.object.type,
zIndex: item.zIndex,
}))
);
// console.log(
// `📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合`
// );
// console.log(
// "🔢 对象z-index顺序:",
// objectsWithZIndex.map((item) => ({
// id: item.object.id,
// type: item.object.type,
// zIndex: item.zIndex,
// }))
// );
}
/**

View File

@@ -159,6 +159,8 @@ export class BatchInitializeRedGreenModeCommand extends Command {
absolutePositioned: true,
opacity: 0.01, // 设置为几乎透明
id: generateId("redGreenImageMask_"),
rx: 15,
ry: 15,
});
// this.canvas.add(this.redGreenImageMask);
this.canvas.clipPath = this.redGreenImageMask;

View File

@@ -25,7 +25,7 @@ export class TransformCommand extends Command {
this.layerManager = options.layerManager;
this.layers = options.layers || null;
this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID
this.isCommand = options.isCommand == undefined ? true : options.isCommand
const targetObject =
findObjectById(this.canvas, this.objectId)?.object || null;
@@ -189,6 +189,11 @@ export class TransformCommand extends Command {
object.set(key, value);
});
if(this.isCommand && object.globalCompositeOperation_){
object.globalCompositeOperation = object.globalCompositeOperation_;
object.globalCompositeOperation_ = null;
}
// 确保对象更新
object.setCoords();
}

View File

@@ -154,6 +154,8 @@ const isVisible = computed(() => {
OperationType.ERASER,
OperationType.RED_BRUSH,
OperationType.GREEN_BRUSH,
OperationType.PART_BRUSH,
OperationType.PART_ERASER,
].includes(props.activeTool);
});

View File

@@ -11,6 +11,7 @@ const layerManager = inject("layerManager");
const isShowLayerPanel = inject("isShowLayerPanel", ref(false));
const props = defineProps({
title: String,
activeTool: String,
canvasWidth: Number,
canvasHeight: Number,
@@ -22,6 +23,7 @@ const props = defineProps({
default: true, // 是否显示图层面板
},
isBackgroundChangeable: Boolean,
isChangeCanvasSize: Boolean,
});
const emit = defineEmits([
@@ -273,7 +275,7 @@ onMounted(() => {
<template>
<div class="canvas-header">
<div class="canvas-header-wrapper">
<span class="canvas-title">{{ $t('Canvas.Canvas') }}</span>
<span class="canvas-title">{{ props.title || $t("Canvas.Canvas") }}</span>
<!-- 默认设置 -->
<!-- v-if="
!activeTool ||
@@ -284,6 +286,7 @@ onMounted(() => {
<div class="setting-group">
<span class="setting-label">{{ $t("Canvas.width") }}</span>
<a-input-number
:disabled="!isChangeCanvasSize"
:value="canvasWidth?.toFixed(2)"
class="setting-input"
:min="1"
@@ -300,6 +303,7 @@ onMounted(() => {
<div class="setting-group">
<span class="setting-label">{{ $t("Canvas.height") }}</span>
<a-input-number
:disabled="!isChangeCanvasSize"
:value="canvasHeight?.toFixed(2)"
class="setting-input"
:min="1"

View File

@@ -242,7 +242,7 @@ const canDeleteComputed = computed(() => {
return parentLayer?.children?.length > 1;
}
// 否则直接返回根图层的可删除状态
return props.layers.length > 3;
return true;
});
</script>

View File

@@ -414,14 +414,14 @@ function deleteSelectedLayers() {
}
// 检查删除后是否还有足够的普通图层
const remainingNormalLayers = layers.value.filter(
(layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
).length;
// const remainingNormalLayers = layers.value.filter(
// (layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)
// ).length;
if (remainingNormalLayers < 1) {
console.warn("不能删除所有普通图层");
return;
}
// if (remainingNormalLayers < 1) {
// console.warn("不能删除所有普通图层");
// return;
// }
// 确认删除
if (selectedLayers.length > 1) {
@@ -584,15 +584,16 @@ function handleLayerClick(layer, event) {
// 如果不是多选模式,才可激活图层
// 1.如果是组,则设置组下的第一个子图层为活动图层
// 2.否则直接设置活动图层
if (isGroupLayerType(layer) && layer.children && layer.children.length > 0) {
if (isGroupLayerType(layer) && layer.children && layer.children.length > 0 && !layer.isPrintTrimsGroup) {
// 如果是组图层,设置第一个子图层为活动图层
layerManager?.setAllActiveGroupLayerCanvasObject?.(layer);
setActiveLayer(layer.children[0].id, { parentId: layer.id });
} else {
let id = layer.isPrintTrimsGroup ? layer.children?.[0]?.id || layer.id : layer.id;
// 选中画布中的图层对象
layerManager?.selectLayerObjects(layer.id);
layerManager?.selectLayerObjects(id);
// 否则直接设置当前图层为活动图层
setActiveLayer(layer.id);
setActiveLayer(id);
layerManager?.updateLayersObjectsInteractivity();
}
}
@@ -876,13 +877,15 @@ function toggleSelectedLayersVisibility() {
function canDeleteLayers() {
const selectedLayers = getSelectedLayers();
console.log(selectedLayers);
if (selectedLayers.length === 0) return false;
// 检查是否包含不能删除的图层
const undeletableLayers = selectedLayers.filter((layer) => layer.isBackground || layer.isFixed);
if (undeletableLayers.length > 0) return false;
return true
// 检查删除后是否还有足够的普通图层
const remainingNormalLayers = layers.value.filter(
(layer) => !layer.isBackground && !layer.isFixed && !selectedLayerIds.value.includes(layer.id)

View File

@@ -119,7 +119,7 @@ export default defineComponent({
})
const palletRef = ref(null)
watch(()=>palletData.color_,(newVal:any)=>{
if(!newVal?.rgba?.r)return
if(newVal?.rgba?.r == null)return
if(palletData.color?.gradient?.gradientShow){
palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = {
r:newVal.rgba.r,
@@ -143,7 +143,7 @@ export default defineComponent({
},{deep: true })
const setOperate = ()=>{
if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7'))
palletData.color.rgba = palletData.color?.rgba?.r?palletData.color.rgba:{r:0,g:0,b:0,a:1}
palletData.color.rgba = palletData.color?.rgba?.r != null?palletData.color.rgba:{r:0,g:0,b:0,a:1}
palletData.gradient.selectIndex = 0
palletData.gradient.gradientShow = true
if(!palletData.color.gradient){
@@ -257,7 +257,7 @@ export default defineComponent({
}
const openPallet = ()=>{
if(palletData.palletShow && props.selectColor?.rgba?.r){
if(palletData.palletShow && props.selectColor?.rgba?.r != null){
if(props.selectColor.gradient){
palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba
}else{

View File

@@ -20,13 +20,13 @@
<img
src="/src/assets/images/canvas/shubiao-l.png"
/>
<span>Left Click: Add</span>
<span>{{ t("Canvas.LeftClickAdd") }}</span>
</div>
<div>
<img
src="/src/assets/images/canvas/shubiao-r.png"
/>
<span>Right Click: Remove</span>
<span>{{ t("Canvas.RightClickRemove") }}</span>
</div>
</div>
</div>
@@ -57,15 +57,15 @@
$t("Canvas.creation")
}}</span>
</div>
<div class="action-btn" @click="onCopyCreate">
<!-- <div class="action-btn" @click="onCopyCreate">
<svg-icon name="CCut" size="26" />
<span class="btn-text">{{
$t("Canvas.CreateAndCopy")
}}</span>
</div>
</div> -->
<div class="action-btn" @click="onReset">
<svg-icon name="CCut" size="26" />
<span class="btn-text">清空当前点位</span>
<span class="btn-text">{{ $t("Canvas.TheClearlySelectedContent") }}</span>
</div>
</div>
</div>
@@ -76,23 +76,9 @@
<script setup>
import { ref, onMounted, watch } from "vue";
import { useI18n } from "vue-i18n";
import {
CreateSelectionCommand,
InvertSelectionCommand,
FeatherSelectionCommand,
FillSelectionCommand,
} from "../commands/SelectionCommands";
import { ToolCommand } from "../commands/ToolCommands";
import {
LassoCutoutCommand,
ClearSelectionCommand,
// CutSelectionToNewLayerCommand,
} from "../commands/LassoCutoutCommand";
import { OperationType } from "../utils/layerHelper";
import { ClearSelectionContentCommand } from "../commands/ClearSelectionContentCommand";
import { CutSelectionToNewLayerCommand } from "../commands/CutSelectionToNewLayerCommand";
// 国际化
const { t } = useI18n();
const props = defineProps({
canvas: {
type: Object,
@@ -137,32 +123,30 @@
const toolList = [
{
type: OperationType.PART,
label: "Point Selection",
label: t("Canvas.PointSelection"),
icon: "CPoint",
size: "20",
},
{
type: OperationType.PART_RECTANGLE,
label: "Marquee Selection",
label: t("Canvas.MarqueeSelection"),
icon: "CMarquee",
size: "20",
},
{
type: OperationType.PART_BRUSH,
label: "Brush Selection",
label: t("Canvas.BrushSelection"),
icon: "CBrush2",
size: "16",
},
{
type: OperationType.PART_ERASER,
label: "Erase",
label: t("Canvas.Erase"),
icon: "CEraser2",
size: "22",
},
];
// 国际化
const { t } = useI18n();
onMounted(() => {});
@@ -182,12 +166,6 @@
show();
// 根据工具类型设置选区类型
toolType.value = newTool;
// 更新选区管理器的选区类型
// if (props.partManager) {
// props.partManager.setPartType(toolType.value);
// props.partManager.setupPartEvents();
// }
} else {
close();
}
@@ -220,12 +198,6 @@
if (props.toolManager) {
props.toolManager.setToolWithCommand(type);
}
// // 备用方案:如果没有 toolManager直接更新 partManager
// else if (props.partManager) {
// props.partManager.setPartType(type);
// props.partManager.setupPartEvents();
// }
}
// 创建
@@ -418,35 +390,11 @@
.tool-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(2, 1fr);
gap: 5px;
padding: 0 30px;
}
/* 平板适配 - 每行4个按钮 */
@media screen and (max-width: 768px) {
.tool-actions {
grid-template-columns: repeat(3, 1fr);
gap: 8px 6px;
padding: 0 8px;
}
}
/* 手机适配 - 每行3个按钮 */
@media screen and (max-width: 480px) {
.tool-actions {
grid-template-columns: repeat(3, 1fr);
gap: 6px 4px;
padding: 0 6px;
}
.header-btn {
font-size: 11px;
padding: 2px 4px;
min-width: 28px;
}
}
.action-btn {
display: flex;
// flex-direction: column;

View File

@@ -14,7 +14,7 @@
<span class="label">{{ t("Canvas.scale") }}</span>
<slider
:min="1"
:max="500"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${scale}%`"
@@ -32,8 +32,8 @@
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapX"
@input="(e) => emit('inputFill_Gap', e, gapY)"
@change="(e) => emit('changeFill_Gap', e, gapY)"
@input="(e) => emit('inputFillGap', e, gapY)"
@change="(e) => emit('changeFillGap', e, gapY)"
/>
</div>
<div class="repeat-setting-item">
@@ -45,26 +45,26 @@
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapY"
@input="(e) => emit('inputFill_Gap', gapX, e)"
@change="(e) => emit('changeFill_Gap', gapX, e)"
@input="(e) => emit('inputFillGap', gapX, e)"
@change="(e) => emit('changeFillGap', gapX, e)"
/>
</div>
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.offset") }}</span>
<offset-tool
:left="offsetX"
:top="offsetY"
@input="(e) => emit('inputFillOffset', e)"
@change="(e) => emit('changeFillOffset', e)"
:left="offset.x"
:top="offset.y"
@input="inputFillOffset"
@change="changeFillOffset"
:show-dish="false"
/>
</div>
<div class="repeat-setting-item offset">
<offset-tool
:left="offsetX"
:top="offsetY"
@input="(e) => emit('inputFillOffset', e)"
@change="(e) => emit('changeFillOffset', e)"
:left="offset.x"
:top="offset.y"
@input="inputFillOffset"
@change="changeFillOffset"
:show-input="false"
/>
</div>
@@ -79,6 +79,16 @@
import Slider from "../tools/Slider.vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const emit = defineEmits([
"inputFillAngle",
"changeFillAngle",
"inputFillOffset",
"changeFillOffset",
"inputFillScale",
"changeFillScale",
"inputFillGap",
"changeFillGap",
]);
const props = defineProps({
object: {
@@ -89,36 +99,53 @@
const angle = computed(
() => getTransformScaleAngle(props.object.fill?.patternTransform).angle
);
const scale = computed(() => {
const patternTransform = props.object.fill?.patternTransform;
const scaleValue = getTransformScaleAngle(patternTransform).scale * 100;
return Number(Number(scaleValue).toFixed(2));
});
const gapX = computed(() => props.object.fill_?.gapX || 0);
const gapY = computed(() => props.object.fill_?.gapY || 0);
const offsetX = computed(
() => (props.object.fill?.offsetX / props.object.width) * 100
);
const offsetY = computed(
() => (props.object.fill?.offsetY / props.object.height) * 100
);
const emit = defineEmits([
"inputFillAngle",
"changeFillAngle",
"inputFillOffset",
"changeFillOffset",
"inputFillScale",
"changeFillScale",
"inputFill_Gap",
"changeFill_Gap",
]);
const inputFillScale = (e) => {
// 缩放比例
const scale = computed(() => {
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scaleValue = getTransformScaleAngle(patternTransform).scale;
const scaleX = scaleValue / (object.width / object.fill_.width / 5);
const scaleY = scaleValue / (object.height / object.fill_.height / 5);
const scaleXY = object.width > object.height ? scaleX : scaleY;
return Number(Number(scaleXY * 100).toFixed(2));
});
const inputFillScale = (e) => setFillScale(e, true);
const changeFillScale = (e) => setFillScale(e, false);
const setFillScale = (e, isInput) => {
const object = props.object;
const scale = e / 100;
emit("inputFillScale", scale);
const scaleX = (object.width / object.fill_.width / 5) * scale;
const scaleY = (object.height / object.fill_.height / 5) * scale;
const scaleXY = object.width > object.height ? scaleX : scaleY;
emit(isInput ? "inputFillScale" : "changeFillScale", scaleXY);
};
const changeFillScale = (e) => {
const scale = e / 100;
emit("changeFillScale", scale);
// 偏移量
const offset = computed(() => {
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scale = getTransformScaleAngle(patternTransform).scale;
const offsetX = object.fill?.offsetX;
const offsetY = object.fill?.offsetY;
const twidth = object.fill_?.width;
const theight = object.fill_?.height;
const x = ((offsetX + (twidth * scale) / 2) * 100) / object.width;
const y = ((offsetY + (theight * scale) / 2) * 100) / object.height;
return { x, y };
});
const inputFillOffset = (e) => setFillOffset(e, true);
const changeFillOffset = (e) => setFillOffset(e, false);
const setFillOffset = (e, isInput) => {
const { left, top } = e;
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scale = getTransformScaleAngle(patternTransform).scale;
const x = (left / 100) * object.width - (object.fill_?.width * scale) / 2;
const y = (top / 100) * object.height - (object.fill_?.height * scale) / 2;
emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y });
};
</script>
@@ -126,6 +153,7 @@
.repeat-setting {
user-select: none;
width: 228px;
overflow: hidden;
> .title {
line-height: 35px;
font-size: 14px;

View File

@@ -22,7 +22,7 @@
v-for="v in activeObjects"
:key="v.id"
>
<div class="title">{{ v.layer?.name }}</div>
<!-- <div class="title">{{ v.layer?.name }}</div> -->
<div class="list">
<div
class="input"
@@ -125,6 +125,10 @@
"
:options="selectOptions"
@change="(e) => changeFillRepeat(e, v)"
:disabled="
v.layer?.metadata?.sourceData?.type ===
'trims'
"
/>
</div>
<!-- 平铺设置 -->
@@ -154,11 +158,11 @@
@changeFillScale="
(e) => changeFillScale(e, v)
"
@inputFill_Gap="
(x, y) => inputFill_Gap(x, y, v)
@inputFillGap="
(x, y) => inputFillGap(x, y, v)
"
@changeFill_Gap="
(x, y) => changeFill_Gap(x, y, v)
@changeFillGap="
(x, y) => changeFillGap(x, y, v)
"
/>
</template>
@@ -282,10 +286,10 @@
activeObjects.value.forEach((v) => {
v.layer = props.layerManager.getLayerById(v.layerId);
});
if (activeObjects.value.length === 0) {
close();
} else {
if (activeObjects.value.length === 1) {
show();
} else {
close();
}
};
//取消当前选中
@@ -311,6 +315,7 @@
layerManager: props.layerManager,
layers: layers,
lastSelectLayerId: lastSelectLayerId,
isCommand,
});
if (isCommand) {
props.commandManager.execute(cmd);
@@ -332,6 +337,7 @@
const finalState = computeAngleState(angle, obj, initialState);
transformObject(obj, initialState, finalState, false);
if (!obj.hasOwnProperty("oldState")) obj.oldState = initialState;
props.canvasManager.beforeChangeCanvas([obj]);
};
const changeAngle = (angle, obj) => {
var initialState;
@@ -424,6 +430,7 @@
});
obj.set("fill", pattern);
props.canvas.renderAll();
props.canvasManager.beforeChangeCanvas([obj]);
};
const changeFillAngle = (angle, obj) => {
const fill = obj.get("fill");
@@ -438,16 +445,17 @@
if (!obj.oldPattern) obj.oldPattern = obj.get("fill");
const pattern = new fabric.Pattern({
...obj.get("fill"),
offsetX: (value.left / 100) * obj.width,
offsetY: (value.top / 100) * obj.height,
offsetX: value.x,
offsetY: value.y,
});
obj.set("fill", pattern);
props.canvas.renderAll();
props.canvasManager.beforeChangeCanvas([obj]);
};
const changeFillOffset = (value, obj) => {
const pattern = new fabric.Pattern({
offsetX: (value.left / 100) * obj.width,
offsetY: (value.top / 100) * obj.height,
offsetX: value.x,
offsetY: value.y,
});
changeFill(obj, pattern);
};
@@ -462,6 +470,7 @@
});
obj.set("fill", pattern);
props.canvas.renderAll();
props.canvasManager.beforeChangeCanvas([obj]);
};
const changeFillScale = (scale, obj) => {
const fill = obj.get("fill");
@@ -483,7 +492,7 @@
props.commandManager.execute(cmd);
};
// 改变填充间隙
const inputFill_Gap = (gapX, gapY, obj) => {
const inputFillGap = (gapX, gapY, obj) => {
const cmd = new FillRepeatGapChangeCommand({
canvas: props.canvas,
layers: layers,
@@ -494,9 +503,10 @@
newGapY: gapY,
record: true,
});
cmd.execute();
cmd.execute(false);
props.canvasManager.beforeChangeCanvas([obj]);
};
const changeFill_Gap = (gapX, gapY, obj) => {
const changeFillGap = (gapX, gapY, obj) => {
if (obj.oldFill_) {
obj.fill_ = { ...obj.oldFill_ };
delete obj.oldFill_;
@@ -760,7 +770,7 @@
}
.tool-content {
overflow-y: auto;
// overflow-y: auto;
max-height: 20rem;
margin-top: 1rem;
padding: 0 1.5rem;

View File

@@ -34,7 +34,6 @@ const props = defineProps({
default: "", // 衣服底图URL-线稿
},
});
console.log(props.clothingMinIOPath)
const commandManager = inject("commandManager");
const layerManager = inject("layerManager"); // 图层管理器

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,6 @@ import {
isGroupLayer,
OperationType,
OperationTypes,
findLayer,
createLayer,
LayerType,
SpecialLayerId,
@@ -20,7 +19,6 @@ import { AnimationManager } from "./animation/AnimationManager";
import { createCanvas } from "../utils/canvasFactory";
import { CanvasEventManager } from "./events/CanvasEventManager";
import CanvasConfig from "../config/canvasConfig";
import { RedGreenModeManager } from "./RedGreenModeManager";
import { EraserStateManager } from "./EraserStateManager";
import {
deepClone,
@@ -70,8 +68,11 @@ export class CanvasManager {
this.isFixedErasable = options.isFixedErasable || false; // 是否允许擦除固定图层
this.eraserStateManager = null; // 橡皮擦状态管理器引用
this.handleCanvasInit = null; // 画布初始化回调函数
this.partManager = options.partManager || null;
this.props = options.props || {};
this.emit = options.emit || (() => {});
this.awaitCanvasRun = null;
this.canvasChangeing = false;
// 初始化画布
this.initializeCanvas();
}
@@ -174,7 +175,12 @@ export class CanvasManager {
_initCanvasEvents() {
// 添加笔刷图像转换处理回调
this.canvas.onBrushImageConverted = async (fabricImage) => {
await this.addImageToLayer({ fabricImage, targetLayerId: null });
const activeTool = this.toolManager?.activeTool?.value;
if(activeTool === OperationType.PART_BRUSH){
this.partManager?.addDrawPartImage(fabricImage);
}else{
await this.addImageToLayer({ fabricImage, targetLayerId: null });
}
// 返回false表示使用默认行为直接添加到画布
return false;
};
@@ -196,6 +202,10 @@ export class CanvasManager {
console.log("擦除完成", e.targets);
// 可以在这里保存状态到命令管理器
const affectedObjects = e.targets || [];
const activeTool = this.toolManager?.activeTool?.value;
if(activeTool === OperationType.PART_ERASER){
return this.partManager?.onErasingEnd(affectedObjects);
}
const command = this.eraserStateManager.endErasing(affectedObjects);
if (command && this.commandManager) {
await this.commandManager?.executeCommand?.(command);
@@ -327,6 +337,7 @@ export class CanvasManager {
setupCanvasEvents(activeElementId, layerManager) {
// 创建画布事件管理器
this.eventManager = new CanvasEventManager(this.canvas, {
canvasManager: this,
toolManager: this.toolManager,
animationManager: this.animationManager,
thumbnailManager: this.thumbnailManager,
@@ -444,12 +455,41 @@ export class CanvasManager {
}
// 居中所有画布元素,包括背景层和其他元素
this.centerAllObjects();
await this.centerAllObjects();
// // 重新渲染画布使变更生效
// this.canvas.renderAll();
}
// 重置画布大小参照固定图层
async resetCanvasSizeByFixedLayer(){
// 重置画布大小为固定图层的大小
const fixedLayerObj = this.getFixedLayerObject();
const backgroundObject = this.getBackgroundLayerObject();
if (!fixedLayerObj || !backgroundObject) return
const fwidth = fixedLayerObj.width * fixedLayerObj.scaleX
const fheight = fixedLayerObj.height * fixedLayerObj.scaleY
const bwidth = backgroundObject.width * backgroundObject.scaleX
const bheight = backgroundObject.height * backgroundObject.scaleY
console.log(fixedLayerObj.width,
fixedLayerObj.scaleX,
fixedLayerObj.height,
fixedLayerObj.scaleY,
backgroundObject.width,
backgroundObject.scaleX,
backgroundObject.height,
backgroundObject.scaleY,'CanvasManager resetCanvasSizeByFixedLayer')
if(Math.abs(fwidth/bwidth - fheight/bheight) < 0.1) return;
this.canvasWidth.value = fwidth
this.canvasHeight.value = fheight
backgroundObject.set({
width: this.canvasWidth.value,
height: this.canvasHeight.value,
})
this.canvas?.clipPath?.set?.({
width: this.canvasWidth.value,
height: this.canvasHeight.value,
})
}
/**
* 重置视图变换,使元素回到原始位置
* @private
@@ -469,7 +509,6 @@ export class CanvasManager {
*/
async centerAllObjects() {
if (!this.canvas) return;
// 获取所有可见对象(不是背景元素的对象)
const allObjects = this.canvas.getObjects();
if (allObjects.length === 0) return;
@@ -484,9 +523,6 @@ export class CanvasManager {
// 获取背景对象
const backgroundObject = visibleObjects.find((obj) => obj.isBackground);
// !this.canvas?.clipPath &&
// this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
this.canvas?.clipPath?.set?.({
left: this.width / 2,
top: this.height / 2,
@@ -578,6 +614,9 @@ export class CanvasManager {
});
});
}
!this.canvas?.clipPath &&
this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
// 如果有背景层,更新蒙层位置
if (backgroundObject && CanvasConfig.isCropBackground) {
@@ -829,9 +868,9 @@ export class CanvasManager {
return layerObjectByLayerId;
}
getObjectsByIds(ids){
getObjectsByIdOrLayerId(ids){
const objects = this.canvas.getObjects().filter((obj) => {
return ids.includes(obj.id);
return ids.includes(obj.id) || ids.includes(obj.layerId);
});
return objects;
}
@@ -843,7 +882,6 @@ export class CanvasManager {
updateMaskPosition(backgroundLayerObject) {
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
return;
console.log("backgroundLayerObject");
const left = backgroundLayerObject.left;
const top = backgroundLayerObject.top;
@@ -1109,7 +1147,7 @@ export class CanvasManager {
const glayer = this.layerManager.getLayerById(SpecialLayerId.SPECIAL_GROUP);
if(!glayer) return Promise.reject("印花和元素图层组不存在");
const ids = glayer.children.map((v) => v.id);
const objects = this.getObjectsByIds(ids);
const objects = this.getObjectsByIdOrLayerId(ids);
const fixedLayerObj = this.getFixedLayerObject();
if(!fixedLayerObj) return Promise.reject("固定图层不存在");
const flWidth = fixedLayerObj.width
@@ -1120,8 +1158,9 @@ export class CanvasManager {
const flScaleY = fixedLayerObj.scaleY
const prints = [];
const trims = [];
objects.forEach((v) => {
const sourceData = glayer.children.find((v_) => v_.id === v.id)?.metadata?.sourceData;
objects.forEach((v, i) => {
const label = glayer.children.find((v_) => (v_.id === v.layerId || v_.id === v.id));
const sourceData = label?.metadata?.sourceData;
if(!sourceData) return;
const obj = {
ifSingle: typeof v.fill === "string",
@@ -1133,7 +1172,7 @@ export class CanvasManager {
scale: [0, 0],
angle: v.angle,
name: sourceData.name,
priority: sourceData.priority,
priority: i + 1,
object:{
top: 0,
left: 0,
@@ -1146,6 +1185,7 @@ export class CanvasManager {
blendMode: v.globalCompositeOperation,
gapX: 0,// 平铺模式下的间距
gapY: 0,// 平铺模式下的间距
fill_repeat: "",
}
}
let left = (v.left - (flLeft - flWidth * flScaleX / 2));
@@ -1187,17 +1227,19 @@ export class CanvasManager {
obj.scale = [scaleXY, scaleXY];
obj.angle = angle;
obj.location = [left, top];
obj.gap = [fill_.gapX, fill_.gapY];
obj.object.gapX = fill_.gapX;
obj.object.gapY = fill_.gapY;
obj.object.fill_repeat = fill.repeat;
}
if(obj.level2Type === "Pattern"){
if(sourceData.type === "print"){
prints.push(obj);
}else if(obj.level2Type === "Embroidery"){
}else if(sourceData.type === "trims"){
trims.push(obj);
}
})
// prints.sort((a, b) => a.ifSingle ? 1 : -1);
prints.forEach((v, i) => v.priority = i + 1);
trims.forEach((v, i) => v.priority = i + 1);
// prints.forEach((v, i) => v.priority = i + 1);
// trims.forEach((v, i) => v.priority = i + 1);
return {prints, trims};
}
@@ -1284,6 +1326,7 @@ export class CanvasManager {
canvasColor: this.canvasColor.value,
activeLayerId: this.layerManager?.activeLayerId?.value,
};
this.FixJsonIdLoss(data);
console.log("获取画布JSON数据...", data);
return JSON.stringify(data);
} catch (error) {
@@ -1291,10 +1334,8 @@ export class CanvasManager {
throw new Error("获取画布JSON失败");
}
}
loadJSON(json, calllBack) {
console.log("加载画布JSON数据:", json);
this.canvas.loading.value = true;
// 确保传入的json是字符串格式
if (typeof json === "object") {
json = JSON.stringify(json);
@@ -1303,11 +1344,13 @@ export class CanvasManager {
}
// 解析JSON字符串
try {
const parsedJson = JSON.parse(json);
const parsedJson = window.testCanvasJson || JSON.parse(json);
console.log("加载画布JSON数据:", parsedJson);
this.FixJsonIdLoss(parsedJson);
this.canvasWidth.value = parsedJson.canvasWidth || this.width;
this.canvasHeight.value = parsedJson.canvasHeight || this.height;
this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
const tempLayers = parsedJson?.layers || [];
@@ -1329,7 +1372,7 @@ export class CanvasManager {
// this.canvasHeight.value = parsedJson.canvasHeight || this.height;
// this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor;
console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode);
// console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode);
// 重置视图变换以确保元素位置正确
this._resetViewportTransform(1);
@@ -1341,7 +1384,7 @@ export class CanvasManager {
// 清除当前画布内容
// this.canvas.clear(); // 清除画布内容 可以先去掉 这样加载闪动的情况就比较少 如果有问题 可以再打开
console.log("清除当前画布内容", canvasData);
// console.log("清除当前画布内容", canvasData);
delete canvasData.clipPath; // 删除当前裁剪路径
// 加载画布数据
this.canvas.loadFromJSON(canvasData, async () => {
@@ -1370,7 +1413,7 @@ export class CanvasManager {
// 重置画布数据
await this.setCanvasSize(this.canvas.width, this.canvas.height);
await this.centerBackgroundLayer(this.canvas.width, this.canvas.height);
await this.createOtherLayers(this.props.otherData);
await this.resetCanvasSizeByFixedLayer();
// 重新构建对象关系
// restoreObjectLayerAssociations(this.layers.value, this.canvas.getObjects());
// 验证图层关联关系 - 稳定后可以注释
@@ -1382,7 +1425,7 @@ export class CanvasManager {
// console.log("图层关联验证结果:", isValidate);
// 排序
// 使用LayerSort工具重新排列画布对象如果可用
await this?.layerManager?.layerSort?.rearrangeObjects();
await this?.layerManager?.layerSort?.rearrangeObjectsAsync();
this.layerManager.activeLayerId.value = this.layers.value[0]
.children?.length
@@ -1400,7 +1443,6 @@ export class CanvasManager {
await this.layerManager?.updateLayersObjectsInteractivity?.();
await calllBack?.();
this.emit("canvas-load-json-success");
// 更新所有缩略图
setTimeout(() => {
this.updateAllThumbnails();
@@ -1422,27 +1464,56 @@ export class CanvasManager {
throw new Error("解析JSON失败请检查输入格式: " + error.message);
}
}
/** 修复JSON数据中的ID丢失问题 */
FixJsonIdLoss(json){
const layerIds = [];
const layers = json?.layers || [];
const objects = json?.canvas?.objects || [];
layers.forEach((layer) => {
layerIds.push(layer.id);
layer.children?.forEach((child) => layerIds.push(child.id));
if(!layer.fabricObjects?.[0]?.id && !layer.fabricObject?.id){
const obj = objects?.find((o) => o.layerId === layer.id);
if(obj) {
layer.fabricObjects = [{
id: obj.id,
type: obj.type,
}]
}
}
})
// 排序
objects.sort((a, b) => {
if (a.isBackground) return -1;
if (b.isBackground) return 1;
})
// 排除的对象id
const excludedObjects = [SpecialLayerId.PART_SELECTOR];
json.canvas.objects = objects.filter((v) => {
// 指定ID排除
if(excludedObjects.includes(v.id)) return false;
if(v.isBackground || v.isFixed) return true;
// 当前图层不存在当前对象
if(!layerIds.includes(v.layerId)) return false;
return true
});
}
/**
* 创建其他图层:印花、颜色、元素...
* @param {Object} otherData - 其他图层数据
*/
async createOtherLayers(otherData, isUpdate = false) {
async createOtherLayers(otherData) {
if (!otherData) return console.warn("otherData 为空不需要添加");
let resolve = ()=>{};
this.awaitCanvasRun = ()=>(new Promise((v) => resolve = v))
const otherData_ = JSON.parse(JSON.stringify(otherData));
console.log("==========创建其他图层", otherData_);
const updateColor = !!otherData_.color;
const updateSpecialGroup = !!otherData_.printObject || !!otherData_.trims;
// 删除颜色图层和特殊组图层
const ids = [];
if(isUpdate){
updateColor && ids.push(SpecialLayerId.COLOR)
updateSpecialGroup && ids.push(SpecialLayerId.SPECIAL_GROUP)
}else{
ids.push(SpecialLayerId.COLOR)
ids.push(SpecialLayerId.SPECIAL_GROUP)
}
const ids = [SpecialLayerId.COLOR, SpecialLayerId.SPECIAL_GROUP];
this.layers.value = this.layers.value.filter((layer) => {
if(ids.includes(layer.id)){
ids.push(...layer.children?.map((child) => child.id));
@@ -1450,16 +1521,21 @@ export class CanvasManager {
}
return true;
})
this.canvas.getObjects().forEach((v) => ids.includes(v.id) && this.canvas.remove(v))
this.canvas.getObjects().forEach((v) => {
if(ids.includes(v.id) || ids.includes(v.layerId)){
this.canvas.remove(v)
}
})
// 创建颜色图层
otherData_.color && await this.createColorLayer(otherData_.color);
await this.createColorLayer(otherData_.color);
const printTrimsLayers = [];// 印花和元素图层
const singleLayers = [];// 平铺图层
otherData_.printObject?.prints?.forEach((print, index) => {// 印花
print.name = t("Canvas.Print") + (index + 1);
print.type = "print";
if(print.ifSingle){
printTrimsLayers.unshift({...print});
}else{
@@ -1468,12 +1544,16 @@ export class CanvasManager {
})
otherData_.trims?.prints?.forEach((trims, index) => {// 元素
trims.name = t("Canvas.Elements") + (index + 1);
trims.type = "trims";
printTrimsLayers.unshift({...trims});
})
if(isUpdate ? updateSpecialGroup : true){
if(printTrimsLayers.length || singleLayers.length){
await this.createPrintTrimsLayers(printTrimsLayers, singleLayers);
}
await this.changeCanvas();
console.log("==========创建其他图层成功");
resolve();
this.awaitCanvasRun = null;
}
// 设置画布对象的裁剪信息
@@ -1575,53 +1655,67 @@ export class CanvasManager {
let item = printTrimsLayers[index];
let id = generateId("layer_image_");
let name = item.name;
let blendMode = BlendMode.MULTIPLY;
if(item.level2Type === "Embroidery") blendMode = BlendMode.NORMAL;// 元素正常
let image = await new Promise(resolve => {
fabric.Image.fromURL(item.path, (fabricImage)=>{
const left = flLeft - flWidth * flScaleX / 2 + (item.location?.[0] || 0) * flScaleX
const top = flTop - flHeight * flScaleY / 2 + (item.location?.[1] || 0) * flScaleY
const scaleX = flWidth * (item.scale?.[0] || 1) / fabricImage.width * flScaleX
const scaleY = flHeight * (item.scale?.[1] || 1) / fabricImage.height * flScaleY
const {x, y} = calculateRotatedTopLeftDeg(
fabricImage.width * scaleX,
fabricImage.height * scaleY,
left,
top,
0,
item.angle || 0
)
const angle = item.angle || 0
fabricImage.set({
left: x,
top: y,
scaleX: scaleX,
scaleY: scaleY,
angle: angle,
id: id,
layerId: id,
layerName: name,
selectable: true,
hasControls: true,
hasBorders: true,
isPrintTrims: true,
globalCompositeOperation: blendMode,
});
resolve(fabricImage);
}, { crossOrigin: "anonymous" });
})
this.canvas.add(image);
let left = flLeft - flWidth * flScaleX / 2 + (item.location?.[0] || 0) * flScaleX
let top = flTop - flHeight * flScaleY / 2 + (item.location?.[1] || 0) * flScaleY
let scaleX = flWidth * (item.scale?.[0] || 1) / image.width * flScaleX
let scaleY = flHeight * (item.scale?.[1] || 1) / image.height * flScaleY
let {x, y} = calculateRotatedTopLeftDeg(
image.width * scaleX,
image.height * scaleY,
left,
top,
0,
item.angle || 0
)
let angle = item.angle || 0
let opacity = 1
let flipX = false;
let flipY = false;
let blendMode = BlendMode.NORMAL;
// if(item.type === "trims") blendMode = BlendMode.NORMAL;// 元素正常
if(item.object){
opacity = item.object.opacity
flipX = item.object.flipX
flipY = item.object.flipY
if(item.object.blendMode) blendMode = item.object.blendMode;
}
image.set({
left: x,
top: y,
scaleX: scaleX,
scaleY: scaleY,
angle: angle,
opacity: opacity,
flipX: flipX,
flipY: flipY,
globalCompositeOperation: blendMode,
id: id,
layerId: id,
layerName: name,
selectable: true,
hasControls: true,
hasBorders: true,
isPrintTrims: true,
});
// this.canvas.add(image);
let layer = createLayer({
id: id,
name: name,
type: LayerType.BITMAP,
visible: true,
locked: false,
opacity: 1.0,
opacity: opacity,
isPrintTrims: true,
blendMode: blendMode,
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
metadata: {sourceData: item},
object: image,
})
children.push(layer);
};
@@ -1642,15 +1736,15 @@ export class CanvasManager {
resolve(tcanvas);
}, { crossOrigin: "anonymous" });
})
let scaleX_ = fixedLayerObj.width / image.width * (item.scale?.[0] || 1) / 5;
let scaleY_ = fixedLayerObj.height / image.height * (item.scale?.[1] || 1) / 5;
let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX_ : scaleY_;
let scaleX_ = flWidth / image.width * (item.scale?.[0] || 1) / 5;
let scaleY_ = flHeight / image.height * (item.scale?.[1] || 1) / 5;
let scale = flWidth > flHeight ? scaleX_ : scaleY_;
let offsetX = (item.location?.[0] || 0) - image.width * scale / 2
let offsetY = (item.location?.[1] || 0) - image.height * scale / 2
let top = fixedLayerObj.top - fixedLayerObj.height * fixedLayerObj.scaleY / 2
let left = fixedLayerObj.left - fixedLayerObj.width * fixedLayerObj.scaleX / 2
let scaleX = fixedLayerObj.scaleX
let scaleY = fixedLayerObj.scaleY
let top = flTop - flHeight * flScaleY / 2
let left = flLeft - flWidth * flScaleX / 2
let scaleX = flScaleX
let scaleY = flScaleY
let opacity = 1
let angle = 0
let gapX = 0
@@ -1658,27 +1752,29 @@ export class CanvasManager {
let fillSource = image
let flipX = false;
let flipY = false;
let blendMode = BlendMode.MULTIPLY;
let blendMode = BlendMode.NORMAL;
let fill_repeat = "repeat"
if(item.object){
top += item.object.top * fixedLayerObj.scaleY
left += item.object.left * fixedLayerObj.scaleX
top += item.object.top * flScaleY
left += item.object.left * flScaleX
scaleX *= item.object.scaleX
scaleY *= item.object.scaleY
opacity = item.object.opacity
angle = item.object.angle
flipX = item.object.flipX
flipY = item.object.flipY
blendMode = item.object.blendMode || BlendMode.MULTIPLY;
if(item.object.blendMode) blendMode = item.object.blendMode;
gapX = item.object.gapX
gapY = item.object.gapY
fillSource = imageAddGapToCanvas(image, gapX, gapY);
if(item.object.fill_repeat) fill_repeat = item.object.fill_repeat;
}
let rect = new fabric.Rect({
id: id,
layerId: id,
layerName: name,
width: fixedLayerObj.width,
height: fixedLayerObj.height,
width: flWidth,
height: flHeight,
top: top,
left: left,
scaleX: scaleX,
@@ -1690,7 +1786,7 @@ export class CanvasManager {
globalCompositeOperation: blendMode,
fill: new fabric.Pattern({
source: fillSource,
repeat: "repeat",
repeat: fill_repeat,
patternTransform: createPatternTransform(scale, item.angle || 0),
offsetX: offsetX, // 水平偏移
offsetY: offsetY, // 垂直偏移
@@ -1704,18 +1800,19 @@ export class CanvasManager {
},
isPrintTrims: true,
});
this.canvas.add(rect);
// this.canvas.add(rect);
let layer = createLayer({
id: id,
name: name,
type: LayerType.BITMAP,
visible: true,
locked: true,
locked: false,
opacity: opacity,
isPrintTrims: true,
blendMode: BlendMode.MULTIPLY,
blendMode: blendMode,
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
metadata: {sourceData: item},
object: rect,
})
children.push(layer);
};
@@ -1732,6 +1829,13 @@ export class CanvasManager {
// children.push(layer);
// }
if(children.length === 0) return;
// 印花元素排序
if(new Set(children.map(v => v.metadata.sourceData.priority)).size === children.length){
children.sort((a, b) => b.metadata.sourceData.priority - a.metadata.sourceData.priority);
}
children.forEach(layer => {
this.canvas.add(layer.object);
});
const groupRect = new fabric.Rect({});
await this.setObjecCliptInfo(groupRect);
// 插入组图层
@@ -1754,12 +1858,13 @@ export class CanvasManager {
/**
* 画布事件变更后
*/
async changeCanvas(){
async changeCanvas(fids = [], isBeforeChange = false){
if(!isBeforeChange) this.canvasChangeing = false;
const fixedLayerObj = this.getFixedLayerObject();
if(!fixedLayerObj) return console.warn("固定图层对象不存在", fixedLayerObj)
const colorObject = this.getLayerObjectById(SpecialLayerId.COLOR);
if(colorObject){
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP);
const ids = this.layerManager.getBlendModeLayerIds(SpecialLayerId.SPECIAL_GROUP).filter(id => !fids.includes(id));
if(ids.length === 0){
ids.unshift(SpecialLayerId.SPECIAL_GROUP);
await this.setObjecCliptInfo(colorObject);
@@ -1779,6 +1884,24 @@ export class CanvasManager {
this.canvas.renderAll();
}
}
/** 画布变更之前 */
async beforeChangeCanvas(objects){
if(this.canvasChangeing) return;
const ids = objects.filter(v => {
return v.isPrintTrims && v.globalCompositeOperation && v.globalCompositeOperation !== BlendMode.NORMAL
}).map(v => v.layerId);
if(ids.length > 0){
this.canvasChangeing = true;
this.canvas.getObjects().forEach(v => {
if(ids.includes(v.layerId)){
v.globalCompositeOperation_ = v.globalCompositeOperation;
v.globalCompositeOperation = BlendMode.NORMAL;
}
})
this.canvas.renderAll();
await this.changeCanvas(ids, true);
}
}
/**
* 缩放红绿图模式内容以适应当前画布大小

View File

@@ -681,7 +681,7 @@ export class ExportManager {
isEnhanceImg, // 是否是增强图片
});
console.log("导出图片数据URL:", dataURL);
// console.log("导出图片数据URL:", dataURL);
return dataURL;
// // 创建与画布相同尺寸的临时画布

View File

@@ -149,7 +149,7 @@ export class LayerManager {
*/
initCommandManager() {
// 命令注册逻辑已移除,现在直接使用命令类实例化和执行
console.log("CommandManager 已初始化,使用直接命令调用模式");
// console.log("CommandManager 已初始化,使用直接命令调用模式");
}
/**
@@ -161,7 +161,7 @@ export class LayerManager {
this.layerSort = createLayerSort(this.canvas, this.layers, {
commandManager: this.commandManager,
});
console.log("图层排序工具已初始化");
// console.log("图层排序工具已初始化");
}
}
@@ -180,7 +180,7 @@ export class LayerManager {
// 更新所有对象的交互性
this.updateLayersObjectsInteractivity();
console.log(`已切换到${mode}模式`);
// console.log(`已切换到${mode}模式`);
}
setToolManager(toolManager) {
@@ -332,7 +332,7 @@ export class LayerManager {
// 私有方法:应用交互规则
async _applyInteractionRules({ isMoveing }) {
console.log("updateLayersObjectsInteractivity ===>", this.editorMode);
// console.log("updateLayersObjectsInteractivity ===>", this.editorMode);
const objects = this.canvas.getObjects();
const editorMode = this.editorMode || CanvasConfig.defaultTool;
const layers = this.layers?.value || [];
@@ -697,6 +697,7 @@ export class LayerManager {
* 初始化图层,确保有背景层、固定图层和一个空白图层
*/
async initializeLayers() {
console.log("初始化图层",this.layers.value.length)
// 如果没有任何图层,创建背景层、固定图层和一个空白图层
if (this.layers.value.length === 0) {
// 创建背景图层
@@ -975,7 +976,7 @@ export class LayerManager {
return !layer.isFixed && !layer.isFixedOther && !layer.isBackground
})
// const normalLayers = this.layers.value.filter((l) => !l.isBackground && !l.isFixed && !l.isFixedOther);
console.log("普通图层:", normalLayers)
// console.log("普通图层:", normalLayers)
if (isChild ? parentLength <= 1 : false) {//normalLayers.length <= 1
console.warn("不能删除唯一的普通图层");
message.warning(this.t("Canvas.cannotDeleteOnlyLayer"));
@@ -1096,14 +1097,14 @@ export class LayerManager {
if (this.commandManager) {
const result = this.commandManager.execute(command);
if (result) {
console.log(`✅ 图层移动成功: ${direction}`);
// console.log(`✅ 图层移动成功: ${direction}`);
}
return result;
} else {
const result = command.execute();
if (result) {
// 更新画布渲染顺序
console.log(`✅ 图层移动成功: ${direction}`);
// console.log(`✅ 图层移动成功: ${direction}`);
}
return result;
}
@@ -1147,7 +1148,6 @@ export class LayerManager {
return acc;
}, []);
console.log("==========", allObjects)
// if (layer.fill) {
// // 如果图层有填充颜色,设置所有对象的填充颜色
// const { object } = findObjectById(this.canvas, layer.fill.id);
@@ -1580,7 +1580,7 @@ export class LayerManager {
/**
* 排序图层,确保图层顺序: 普通图层 > 固定图层 > 背景图层
*/
sortLayers() {
async sortLayers() {
// 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间
this.layers.value.sort((a, b) => {
// 如果a是背景图层它应该排在后面最底层
@@ -1604,17 +1604,17 @@ export class LayerManager {
});
// 更新画布对象顺序
this._rearrangeObjects();
await this._rearrangeObjects();
}
/**
* 重新排列画布上的对象以匹配图层顺序
* @private
*/
_rearrangeObjects() {
async _rearrangeObjects() {
if (this.layerSort) {
// 使用LayerSort的高级排序
this.layerSort.rearrangeObjects();
await this.layerSort.rearrangeObjects();
return;
}
@@ -1750,7 +1750,7 @@ export class LayerManager {
layer.serializedObjects = layer.fabricObjects
.map((obj) => {
if (typeof obj.toObject === "function") {
return obj.toObject(["id", "layerId", "layerName"]);
return obj.toObject(["id", "layerId", "layerName", "fill_"]);
}
return null;
})
@@ -1763,7 +1763,7 @@ export class LayerManager {
if (layer.fabricObject) {
layer.serializedBackgroundObject =
typeof layer.fabricObject.toObject === "function"
? layer.fabricObject.toObject(["id", "layerId", "layerName"])
? layer.fabricObject.toObject(["id", "layerId", "layerName", "fill_"])
: null;
delete layer.fabricObject;
@@ -1793,7 +1793,7 @@ export class LayerManager {
return layer.fabricObjects
.map((obj) => {
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;
})
.filter(Boolean);
@@ -1839,13 +1839,14 @@ export class LayerManager {
// 存储到剪贴板
this.clipboardData = layerCopy;
console.log("复制图层:", layerCopy);
const input = document.createElement("input");
input.value = "aida_copy_canvas_layer: " + layer.name;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
document.body.removeChild(input);
console.log(`已复制图层:${layer.name}`);
// console.log(`已复制图层:${layer.name}`);
return this.clipboardData;
}
@@ -1870,7 +1871,7 @@ export class LayerManager {
// 检查是否是唯一的普通图层
const normalLayers = this.layers.value.filter((l) => !l.isBackground && !l.isFixed && !l.isFixedOther);
console.log("普通图层:", normalLayers)
// console.log("普通图层:", normalLayers)
if (normalLayers.length <= 1) {
console.warn("不能剪切唯一的普通图层");
return null;
@@ -1884,7 +1885,7 @@ export class LayerManager {
layerCopy.serializedObjects = layer.fabricObjects
.map((obj) =>
typeof obj.toObject === "function"
? obj.toObject(["id", "layerId", "layerName"])
? obj.toObject(["id", "layerId", "layerName", "fill_"])
: null
)
.filter(Boolean);
@@ -1930,21 +1931,17 @@ export class LayerManager {
// 更新对象交互性
this.updateLayersObjectsInteractivity();
console.log(`已剪切图层:${layer.name}`);
// console.log(`已剪切图层:${layer.name}`);
return this.clipboardData;
}
/**
* 粘贴图层
* @returns {string} 新创建的图层ID
*/
/**
* 粘贴图层
* @returns {string} 新创建的图层ID
*/
async pasteLayer(event) {
console.log("剪贴板数据:", this.clipboardData,event);
// console.log("剪贴板数据:", this.clipboardData,event);
if (!this.clipboardData) {
console.error("剪贴板中没有图层数据");
return null;
@@ -2099,7 +2096,7 @@ export class LayerManager {
// 重新初始化基本图层
this.initializeLayers();
console.log("已清空画布");
// console.log("已清空画布");
}
/**
@@ -2312,7 +2309,7 @@ export class LayerManager {
});
if (emptyLayerIds.length > 0) {
console.log(`已清理 ${emptyLayerIds.length} 个空图层`);
// console.log(`已清理 ${emptyLayerIds.length} 个空图层`);
}
return emptyLayerIds;
@@ -2344,7 +2341,7 @@ export class LayerManager {
this.canvasManager = null;
this.toolManager = null;
console.log("LayerManager 已销毁");
// console.log("LayerManager 已销毁");
}
/**
@@ -2652,13 +2649,13 @@ export class LayerManager {
// 启用红绿图模式
enableRedGreenMode() {
this.isRedGreenMode = true;
console.log("图层管理器:红绿图模式已启用");
// console.log("图层管理器:红绿图模式已启用");
}
// 禁用红绿图模式
disableRedGreenMode() {
this.isRedGreenMode = false;
console.log("图层管理器:红绿图模式已禁用");
// console.log("图层管理器:红绿图模式已禁用");
}
// 检查是否为红绿图模式
@@ -2708,14 +2705,14 @@ export class LayerManager {
: LayerSortUtils.shouldUseAsyncProcessing(objectsCount, layersCount);
if (shouldUseAsync) {
console.log(
`使用异步排序处理 ${objectsCount} 个对象, ${layersCount} 个图层`
);
// console.log(
// `使用异步排序处理 ${objectsCount} 个对象, ${layersCount} 个图层`
// );
return this.layerSort.rearrangeObjectsAsync();
} else {
console.log(
`使用同步排序处理 ${objectsCount} 个对象, ${layersCount} 个图层`
);
// console.log(
// `使用同步排序处理 ${objectsCount} 个对象, ${layersCount} 个图层`
// );
this.layerSort.rearrangeObjects();
}
}
@@ -2735,7 +2732,7 @@ export class LayerManager {
const result = this.layerSort.smartSort(targetLayerIds);
if (result) {
console.log("智能排序完成");
// console.log("智能排序完成");
// 更新对象交互性
this.updateLayersObjectsInteractivity();
}
@@ -2761,9 +2758,9 @@ export class LayerManager {
const stats = this.layerSort.optimizeLayerStructure();
if (stats.removedEmptyLayers > 0 || stats.reorderedLayers > 0) {
console.log(
`图层结构优化完成: 清理空图层 ${stats.removedEmptyLayers} 个, 重新排序 ${stats.reorderedLayers} 个图层`
);
// console.log(
// `图层结构优化完成: 清理空图层 ${stats.removedEmptyLayers} 个, 重新排序 ${stats.reorderedLayers} 个图层`
// );
// 更新对象交互性
this.updateLayersObjectsInteractivity();
}
@@ -2838,9 +2835,9 @@ export class LayerManager {
});
if (result) {
console.log(
`图层 ${layerId} - oldIndex: ${oldIndex} 已移动到位置 ${newIndex}`
);
// console.log(
// `图层 ${layerId} - oldIndex: ${oldIndex} 已移动到位置 ${newIndex}`
// );
// 更新对象交互性
// this.updateLayersObjectsInteractivity();
}
@@ -2917,9 +2914,9 @@ export class LayerManager {
const result = this.layerSort.reorderLayers(oldIndex, newIndex, layerId);
if (result) {
console.log(
`高级排序完成: 图层 ${layerId} 从位置 ${oldIndex} 移动到 ${newIndex}`
);
// console.log(
// `高级排序完成: 图层 ${layerId} 从位置 ${oldIndex} 移动到 ${newIndex}`
// );
// 更新对象交互性
this.updateLayersObjectsInteractivity();
}
@@ -2944,9 +2941,9 @@ export class LayerManager {
);
if (result) {
console.log(
`高级子图层排序完成: 图层 ${layerId} 在父图层 ${parentId} 中从位置 ${oldIndex} 移动到 ${newIndex}`
);
// console.log(
// `高级子图层排序完成: 图层 ${layerId} 在父图层 ${parentId} 中从位置 ${oldIndex} 移动到 ${newIndex}`
// );
// 重新排列画布对象
this.rearrangeCanvasObjects();
}
@@ -2971,7 +2968,7 @@ export class LayerManager {
// 重新排列画布对象
this.rearrangeCanvasObjects();
console.log("使用LayerSort工具完成图层排序");
// console.log("使用LayerSort工具完成图层排序");
}
/**
@@ -2979,7 +2976,7 @@ export class LayerManager {
* 当图层顺序发生变化后调用此方法确保画布对象顺序正确
*/
forceRebuildCanvasOrder() {
console.log("强制重建画布对象顺序");
// console.log("强制重建画布对象顺序");
if (this.layerSort) {
// 使用LayerSort的高级排序
@@ -3010,7 +3007,7 @@ export class LayerManager {
return false;
}
console.log(`开始批量重新排序 ${reorderOperations.length} 个图层`);
// console.log(`开始批量重新排序 ${reorderOperations.length} 个图层`);
let allSuccessful = true;
@@ -3042,7 +3039,7 @@ export class LayerManager {
}
if (allSuccessful) {
console.log("批量图层排序完成");
// console.log("批量图层排序完成");
} else {
console.warn("批量图层排序部分失败");
}
@@ -3079,11 +3076,11 @@ export class LayerManager {
// 执行命令
if (this.commandManager) {
const result = await this.commandManager.execute(command);
result && console.log(`✅ 成功合并组图层: ${groupLayer.name}`);
// result && console.log(`✅ 成功合并组图层: ${groupLayer.name}`);
return result;
} else {
const result = await command.execute();
result && console.log(`✅ 成功合并组图层: ${groupLayer.name}`);
// result && console.log(`✅ 成功合并组图层: ${groupLayer.name}`);
return result || [];
}
}
@@ -3132,13 +3129,13 @@ export class LayerManager {
if (this.commandManager) {
const result = await this.commandManager.execute(command);
if (result) {
console.log(`✅ 成功栅格化图层: ${targetLayer.name}`);
// console.log(`✅ 成功栅格化图层: ${targetLayer.name}`);
}
return result;
} else {
const result = await command.execute();
if (result) {
console.log(`✅ 成功栅格化图层: ${targetLayer.name}`);
// console.log(`✅ 成功栅格化图层: ${targetLayer.name}`);
}
return result;
}
@@ -3209,13 +3206,13 @@ export class LayerManager {
if (this.commandManager) {
const result = await this.commandManager.execute(command);
if (result) {
console.log(`✅ 成功导出图层: ${targetLayer.name}`);
// console.log(`✅ 成功导出图层: ${targetLayer.name}`);
}
return result;
} else {
const result = await command.execute();
if (result) {
console.log(`✅ 成功导出图层: ${targetLayer.name}`);
// console.log(`✅ 成功导出图层: ${targetLayer.name}`);
}
return result;
}
@@ -3259,7 +3256,7 @@ export class LayerManager {
// 执行命令
const result = await command.execute(false);
if (result) {
console.log(`✅ 成功导出图层: ${targetLayer.name}`);
// console.log(`✅ 成功导出图层: ${targetLayer.name}`);
}
return result;
}
@@ -3294,12 +3291,12 @@ export class LayerManager {
const isSginleObject = e.target === activeSelection?._objects?.[0];
if (e.target === activeSelection || isSginleObject) {
hasMoved = false; // 重置移动状态
console.log("🎯 开始移动组选择对象");
// console.log("🎯 开始移动组选择对象");
// 记录遮罩初始位置
console.log(
"🖼️ 记录遮罩初始位置",
`${layer.clippingMask.left || 0}, ${layer.clippingMask.top || 0}`
);
// console.log(
// "🖼️ 记录遮罩初始位置",
// `${layer.clippingMask.left || 0}, ${layer.clippingMask.top || 0}`
// );
// 记录初始位置
initialLeft = isSginleObject ? e.target.left : activeSelection.left;
initialTop = isSginleObject ? e.target.top : activeSelection.top;
@@ -3366,12 +3363,12 @@ export class LayerManager {
const isSginleObject = e.target === activeSelection?._objects?.[0];
if (isSginleObject) {
// 如果是单个对象,不处理
console.log("🚫 单个对象不处理移动完成");
// console.log("🚫 单个对象不处理移动完成");
hasMoved = false; // 重置移动状态
return;
}
if ((target === activeSelection || isSginleObject) && hasMoved) {
console.log("✅ 组选择对象移动完成");
// console.log("✅ 组选择对象移动完成");
// 计算最终移动距离
const deltaX = target.left - initialLeft;
@@ -3410,7 +3407,7 @@ export class LayerManager {
// 鼠标抬起事件处理 - 备用方案
const handleMouseUp = (e) => {
if (hasMoved && this.canvas.getActiveObject() === activeSelection) {
console.log("🖱️ 鼠标抬起 - 备用移动完成处理");
// console.log("🖱️ 鼠标抬起 - 备用移动完成处理");
handleModified(e);
}
};
@@ -3424,7 +3421,7 @@ export class LayerManager {
this.canvas.off("selection:cleared", cleanup);
this.canvas.off("selection:updated", cleanup);
console.log("🧹 清理组遮罩移动同步事件监听器");
// console.log("🧹 清理组遮罩移动同步事件监听器");
};
// 绑定事件监听器
@@ -3437,7 +3434,7 @@ export class LayerManager {
this.canvas.on("selection:cleared", cleanup);
this.canvas.on("selection:updated", cleanup);
console.log("🎨 已设置组遮罩移动同步 - 使用 object:modified 事件");
// console.log("🎨 已设置组遮罩移动同步 - 使用 object:modified 事件");
}
/**

View File

@@ -1,14 +1,12 @@
import { fabric } from "fabric-with-all";
import { traceImageContour, imageToCanvas } from "../utils/helper";
import { OperationType } from "../utils/layerHelper";
import { CreateSelectionCommand } from "../commands/SelectionCommands";
import { ClearSelectionCommand } from "../commands/LassoCutoutCommand";
import { OperationType, SpecialLayerId } from "../utils/layerHelper";
import { LassoCutoutCommand } from "../commands/LassoCutoutCommand";
import addIcon from "@/assets/images/canvas/add.png";
import removeIcon from "@/assets/images/canvas/remove.png";
import { Https } from "@/tool/https";
import store from "@/store";
import { createStaticCanvas } from "../utils/canvasFactory";
import { getObjectAlphaToCanvas } from "../utils/objectHelper";
import { Https } from "@/tool/https";
import { PartDrawCommand, PartPointDrawCommand } from "../commands/PartCommands";
/**
@@ -27,11 +25,31 @@ export class PartManager {
constructor(options = {}) {
this.canvas = options.canvas;
this.commandManager = options.commandManager;
this.selectionManager = options.selectionManager;
this.layerManager = options.layerManager;
this.canvasManager = options.canvasManager;
this.toolManager = options.toolManager;
this.props = options.props;
// 选区样式配置
this.selectionStyle = {
stroke: "#0096ff",
strokeWidth: 1,
strokeDashArray: [5, 5],
fill: "rgba(0, 150, 255, 0.1)",
strokeUniform: true, // 保持描边宽度不随缩放改变
// fill: "rgba(127, 255, 127, 0.3)",
// stroke: "#2AA81B",
// strokeWidth: 2,
// strokeDashArray: [8, 4],
// strokeLineCap: "round",// 折线端点样式
// strokeLineJoin: "bevel", // 折线连接样式
selectable: false,
evented: false,
excludeFromExport: true,
hoverCursor: "default",
moveCursor: "default",
};
// 状态
this.isActive = false;
@@ -53,11 +71,12 @@ export class PartManager {
// 当前工具
this.activeTool = this.toolManager.activeTool;
this.rgba = { r: 0, g: 255, b: 0, a: 200 };
this.partId = SpecialLayerId.PART_SELECTOR;
this.partGroup = null; // 当前选区对象
this.partId = "part_selector";
this.partCanvas = null;// 选区画布
// 点选工具相关
this.pointList = []; // 存储点选坐标
this.rectangleObject = null; // 矩形对象
this.pointList = []; // 点位列表 存储点选坐标
}
/**
@@ -69,6 +88,20 @@ export class PartManager {
const wasActive = this.isActive;
this.isActive = this.tools.includes(toolId);
if (toolId === OperationType.PART_ERASER) {
this.setEraserTool();
}
// else if (toolId === OperationType.PART || toolId === OperationType.PART_RECTANGLE) {
// this.clearPointData();
// this.resetPartObject();
// }
// if (toolId === OperationType.PART_ERASER || toolId === OperationType.PART_BRUSH) {
// if (this.pointList.length > 0) {
// this.clearPointData();
// this.resetPartObject();
// }
// }
// 如果从非选区工具切换到选区工具,初始化事件
if (!wasActive && this.isActive) {
this.initEvents();
@@ -80,6 +113,10 @@ export class PartManager {
this.clearPartObject();
this.clearPointData();
}
// 如果从选区工具切换到选区工具,重置选区
else if (wasActive && this.isActive) {
}
}
/** 初始化选区相关事件 */
@@ -205,12 +242,7 @@ export class PartManager {
}
/** 点选工具模式下点击事件处理 */
_pointDownkHandler(options) {
// const button = options.button;
// const isLeft = button === 1;// 左键1添加 右键3删除
// const icon = `url("${isLeft ? addIcon : removeIcon}") 16 16, default`
// this.canvas.upperCanvasEl.style.cursor = icon;
}
_pointDownkHandler(options) { }
/** 点选工具模式下移动事件处理 */
_pointMoveHandler(options) { }
/** 点选工具模式下抬起事件处理 */
@@ -219,57 +251,79 @@ export class PartManager {
const isLeft = button === 1;// 左键1添加 右键3删除
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) return console.warn("未找到固定图层");
const { x, y } = options.absolutePointer;
const width = fixedObject.width * fixedObject.scaleX;
const height = fixedObject.height * fixedObject.scaleY;
const X = (x - (fixedObject.left - width / 2)) / fixedObject.scaleX;
const Y = (y - (fixedObject.top - height / 2)) / fixedObject.scaleY;
const { x, y } = this.handleMousePosition(options, fixedObject);
const label = isLeft ? 1 : 0;
const points = [];
const labels = [];
this.pointList.forEach((item) => {
const pointList = [...this.pointList];
pointList.forEach((item) => {
points.push([item.x, item.y]);
labels.push(item.label);
});
points.push([X, Y]);
points.push([x, y]);
labels.push(label);
const url = await this.getSegAnythingImage({
image_path: this.props.clothingMinIOPath,
type: "point",
points,
labels,
// type: "box",
// box: [0,0,0,0],
});
this.pointList.push({
x: X,
y: Y,
pointList.push({
x: x,
y: y,
label: label,
})
const image1 = await this.loadImageToObject(url);
const canvas = getObjectAlphaToCanvas(image1, null, 0, this.rgba);
this.partPointDrawCommand(pointList, canvas);
}
partPointDrawCommand(list, canvas) {
const cmd = new PartPointDrawCommand({
canvas: this.canvas,
partManager: this,
partCanvas: canvas,
pointList: [...list],
})
if (this.commandManager?.execute) {
this.commandManager.execute(cmd);
} else {
cmd.execute();
}
}
async pointDrawPartCanvas(list, canvas) {
this.selectionManager.clearSelection();
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) {
console.warn("未找到固定图层")
return false;
}
this.resetPartObject();
const group = this.partGroup;
const rgba = { r: 0, g: 255, b: 0, a: 200 }
const canvas = getObjectAlphaToCanvas(image1, null, 0, rgba);
this.pointList = [...list];
this.partCanvas = canvas;
const image2 = new fabric.Image(canvas);
image2.set({
originX: fixedObject.originX,
originY: fixedObject.originY,
});
group.add(image2);
for (let i = 0; i < this.pointList.length; i++) {
const item = this.pointList[i];
this.partGroup.add(image2);
for (let i = 0; i < list.length; i++) {
const item = list[i];
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({
left: item.x - group.width / 2,
top: item.y - group.height / 2,
scaleX: scaleX,
scaleY: scaleY,
left: item.x - this.partGroup.width / 2,
top: item.y - this.partGroup.height / 2,
originX: fixedObject.originX,
originY: fixedObject.originY,
})
group.add(icon);
this.partGroup.add(icon);
}
console.log(this.partGroup);
this.canvas.renderAll();
return true;
}
/** 清空点选数据 */
clearPointData() {
@@ -280,43 +334,57 @@ export class PartManager {
/** 框选工具模式下点击事件处理 */
_rectangleDownHandler(options) {
console.log(options.absolutePointer);
this.pointList = [];
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) return console.warn("未找到固定图层");
const { x, y } = this.handleMousePosition(options, fixedObject);
this.pointList.push(x, y);
this.rectangleObject = new fabric.Rect({
left: x - fixedObject.width / 2,
top: y - fixedObject.height / 2,
width: 0,
height: 0,
...this.selectionStyle,
fill: "transparent", // 在绘制过程中不显示填充
strokeUniform: true,
});
this.partGroup.add(this.rectangleObject);
this.canvas.renderAll();
}
/** 框选工具模式下移动事件处理 */
_rectangleMoveHandler(options) {
if (!this.rectangleObject) return console.warn("未找到框选对象");
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) return console.warn("未找到固定图层");
const { x, y } = this.handleMousePosition(options, fixedObject);
this.rectangleObject.set({
width: x - this.rectangleObject.left - fixedObject.width / 2,
height: y - this.rectangleObject.top - fixedObject.height / 2,
});
this.canvas.renderAll();
}
/** 框选工具模式下抬起事件处理 */
_rectangleUpHandler(options) {
console.log(options.absolutePointer);
async _rectangleUpHandler(options) {
if (this.rectangleObject) {
this.partGroup.remove(this.rectangleObject);
this.canvas.renderAll();
}
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) return console.warn("未找到固定图层");
const { x, y } = this.handleMousePosition(options, fixedObject);
this.pointList.push(x, y);
if (this.pointList.length !== 4) return console.warn("框选工具选择区域必须是矩形");
const url = await this.getSegAnythingImage({
type: "box",
box: [...this.pointList],
});
const image = await this.loadImageToObject(url);
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);
}
/** 绘制工具模式下点击事件处理 */
_brushDownHandler(options) {
}
/** 绘制工具模式下移动事件处理 */
_brushMoveHandler(options) {
}
/** 绘制工具模式下抬起事件处理 */
_brushUpHandler(options) {
}
/** 擦除工具模式下抬起事件处理 */
_eraseUpHandler(options) {
}
/** 擦除工具模式下点击事件处理 */
_eraseDownHandler(options) {
}
/** 擦除工具模式下移动事件处理 */
_eraseMoveHandler(options) {
}
/** 获取分隔后图片 */
async getSegAnythingImage(obj) {
setTimeout(() => {
@@ -326,6 +394,7 @@ export class PartManager {
// const user_id = store.state.UserHabit.userDetail.userId;
const user_id = 24299;
const data = {
image_path: this.props.clothingMinIOPath,
user_id,
...obj,
}
@@ -344,6 +413,128 @@ export class PartManager {
});
});
}
/** 处理鼠标点位 */
handleMousePosition(options, fixedObject) {
const pos = options.absolutePointer;
const { x, y } = options.absolutePointer;
const width = fixedObject.width * fixedObject.scaleX;
const height = fixedObject.height * fixedObject.scaleY;
const X = (x - (fixedObject.left - width / 2)) / fixedObject.scaleX;
const Y = (y - (fixedObject.top - height / 2)) / fixedObject.scaleY;
return {
x: Math.round(X),
y: Math.round(Y),
}
}
/** 绘制工具模式下点击事件处理 */
_brushDownHandler(options) { }
/** 绘制工具模式下移动事件处理 */
_brushMoveHandler(options) { }
/** 绘制工具模式下抬起事件处理 */
_brushUpHandler(options) { }
/** 绘制模式添加画笔 */
async addDrawPartImage(fabricImage) {
const scaleX = fabricImage.scaleX / this.partGroup.scaleX;
const scaleY = fabricImage.scaleY / this.partGroup.scaleY;
const top = (fabricImage.top - this.partGroup.top) / this.partGroup.scaleY;
const left = (fabricImage.left - this.partGroup.left) / this.partGroup.scaleX;
fabricImage.set({
scaleX,
scaleY,
top: top + this.partGroup.height / 2,
left: left + this.partGroup.width / 2,
})
const tcanvas = new fabric.StaticCanvas(document.createElement("canvas"), {
width: this.partGroup.width,
height: this.partGroup.height,
enableRetinaScaling: false,
});
if (this.partCanvas) {
let image = new fabric.Image(this.partCanvas);
tcanvas.add(image)
}
tcanvas.add(fabricImage)
tcanvas.renderAll();
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, this.rgba);
this.partDrawCommand(canvas);
}
/** 切换到擦除工具 */
setEraserTool() {
if (!this.canvas) return console.warn("未找到画布");
const objects = this.canvas.getObjects();
objects.forEach(obj => {
if (obj.id === this.partId) {
obj.set({
erasable: true
})
}
})
}
/** 擦除工具模式下擦除完成事件处理 */
async onErasingEnd(affectedObjects) {
console.log("擦除完成", affectedObjects);
const tcanvas = new fabric.StaticCanvas(document.createElement("canvas"), {
width: this.partGroup.width,
height: this.partGroup.height,
enableRetinaScaling: false,
});
await new Promise((resolve, reject) => {
this.partGroup.clone((clone) => {
clone.set({
scaleX: 1,
scaleY: 1,
top: this.partGroup.height / 2,
left: this.partGroup.width / 2,
})
tcanvas.add(clone);
resolve(clone);
})
});
tcanvas.renderAll();
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, this.rgba);
this.partDrawCommand(canvas);
}
/** 擦除工具模式下点击事件处理 */
_eraseDownHandler(options) {
}
/** 擦除工具模式下移动事件处理 */
_eraseMoveHandler(options) {
}
/** 擦除工具模式下抬起事件处理 */
_eraseUpHandler(options) {
}
partDrawCommand(canvas) {
const cmd = new PartDrawCommand({
canvas: this.canvas,
partManager: this,
partCanvas: canvas,
})
if (this.commandManager?.execute) {
this.commandManager.execute(cmd);
} else {
cmd.execute();
}
}
/** 绘制部件画布 */
drawPartCanvas(canvas) {
this.selectionManager.clearSelection();
this.partCanvas = canvas;
const image = new fabric.Image(canvas);
image.set({
originX: this.partGroup.originX,
originY: this.partGroup.originY,
erasable: true,
});
this.resetPartObject();
this.partGroup.add(image);
this.canvas.renderAll();
}
/** 删除指定ID的对象 */
removeObjectsById(id) {
@@ -381,6 +572,7 @@ export class PartManager {
originY: fixedObject.originY,
selectable: false,
evented: false,
erasable: true,
})
this.canvas.add(group);
this.partGroup = group;
@@ -392,10 +584,33 @@ export class PartManager {
}
/** 创建当前选区 */
createPart() {
async createPart() {
if (!this.partCanvas) return console.warn("没有点位画布");
const fixedObject = this.canvasManager.getFixedLayerObject();
if (!fixedObject) return console.warn("未找到固定图层");
// const tcanvas = new fabric.StaticCanvas(document.createElement("canvas"), {
// width: fixedObject.width,
// height: fixedObject.height,
// enableRetinaScaling: false,
// });
// await new Promise((resolve, reject) => {
// fixedObject.clone((clone) => {
// const clipPath = new fabric.Image(this.partCanvas);
// clipPath.set({
// originX: fixedObject.originX,
// originY: fixedObject.originY,
// })
// clone.set({
// scaleX: 1,
// scaleY: 1,
// clipPath: clipPath,
// })
// tcanvas.add(clone);
// resolve(clone);
// })
// });
// tcanvas.renderAll();
const scaleY = fixedObject.scaleY
const scaleX = fixedObject.scaleX
const top = fixedObject.top - fixedObject.height * scaleY / 2;
@@ -414,22 +629,26 @@ export class PartManager {
top: top + minY * scaleY,
scaleX: scaleX,
scaleY: scaleY,
fill: "rgba(127, 255, 127, 0.3)",
stroke: "#2AA81B",
strokeWidth: 2,
strokeDashArray: [8, 4],
strokeLineCap: "round",// 折线端点样式
strokeLineJoin: "bevel", // 折线连接样式
strokeUniform: true, // 保持描边宽度不随缩放改变
...this.selectionStyle,
});
// this.partGroup.add(path);
this.canvas.add(path);
this.canvas.renderAll();
this.clearPart();
this.selectionManager.setSelectionObject(path);
const cmd = new LassoCutoutCommand({
canvas: this.canvas,
layerManager: this.layerManager,
selectionManager: this.selectionManager,
toolManager: this.toolManager,
})
this.commandManager.execute(cmd)
}
/** 清空点位 */
clearPart() {
this.pointList = [];
this.resetPartObject(true);
if (this.activeTool.value === OperationType.PART) {
this.partPointDrawCommand([], null);
} else {
this.pointList = [];
this.partDrawCommand(null);
}
}
/**

View File

@@ -27,7 +27,7 @@ export class ThumbnailManager {
const { layer } = findLayerRecursively(this.layers.value, layerId);
if (!fabricObjects || fabricObjects.length === 0) {
console.warn("⚠️ 无法生成缩略图:没有可栅格化的对象 返回空缩略图");
// console.warn("⚠️ 无法生成缩略图:没有可栅格化的对象 返回空缩略图");
// 如果没有对象,返回默认缩略图
if (layer) {
layer.thumbnailUrl = this.defaultThumbnail; // 更新图层对象的缩略图
@@ -123,7 +123,7 @@ export class ThumbnailManager {
*/
_collectLayersAndObjects(layerId) {
if (!layerId) {
console.warn("⚠️ 无效的图层ID无法收集对象");
// console.warn("⚠️ 无效的图层ID无法收集对象");
return [];
}
@@ -199,17 +199,17 @@ export class ThumbnailManager {
// 提取排序后的对象
const objectsToRasterize = objectsWithZIndex.map((item) => item.object);
console.log(
`📊 收集到 ${layersToRasterize.length} 个图层,${objectsToRasterize.length} 个对象进行栅格化`
);
console.log(
"🔢 对象z-index顺序:",
objectsWithZIndex.map((item) => ({
id: item.object.id,
type: item.object.type,
zIndex: item.zIndex,
}))
);
// console.log(
// `📊 收集到 ${layersToRasterize.length} 个图层,${objectsToRasterize.length} 个对象进行栅格化`
// );
// console.log(
// "🔢 对象z-index顺序:",
// objectsWithZIndex.map((item) => ({
// id: item.object.id,
// type: item.object.type,
// zIndex: item.zIndex,
// }))
// );
return objectsToRasterize;
}

View File

@@ -197,7 +197,7 @@ export class ToolManager {
[OperationType.PART_RECTANGLE]: {
name: "部件选取工具-矩形",
icon: "part",
cursor: "default",
cursor: "crosshair",
setup: this.setupPartRectangleTool.bind(this),
},
[OperationType.PART_BRUSH]: {
@@ -420,9 +420,9 @@ export class ToolManager {
// 设置工具特定的状态
if (tool && typeof tool.setup === "function") {
console.log(`画布切换工具:${tool.name}(${toolId})`)
// console.log(`画布切换工具:${tool.name}(${toolId})`)
this.canvas.toolId = toolId;
tool.setup();
tool.setup(true);
}
// 通知选区管理器工具已改变
@@ -482,7 +482,7 @@ export class ToolManager {
// 如有必要可以调用当前工具的setup方法来全面恢复状态
if (tool && typeof tool.setup === "function") {
tool.setup();
tool.setup(true);
}
}
@@ -695,7 +695,7 @@ export class ToolManager {
// // 设置矩形选区模式
// // 这里需要具体的矩形选区工具实现
console.log("矩形选区工具已激活");
// console.log("矩形选区工具已激活");
if (this.canvasManager && this.canvasManager.selectionManager) {
this.canvasManager.selectionManager.setCurrentTool(
@@ -707,45 +707,69 @@ export class ToolManager {
/**
* 设置部件选取工具
*/
setupPartTool() {
setupPartTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.selection = false;
if (this.canvasManager && this.canvasManager.partManager) {
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART);
}
}
/**
* 设置部件选取工具--矩形
*/
setupPartRectangleTool() {
setupPartRectangleTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.selection = true;
if (this.canvasManager && this.canvasManager.partManager) {
this.canvas.selection = false;
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_RECTANGLE);
}
}
/**
* 设置部件选取工具--画笔
*/
setupPartBrushTool() {
setupPartBrushTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
if (this.canvasManager && this.canvasManager.partManager) {
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_BRUSH);
}
const greenColor = "#0f0";
// 确保有笔刷管理器
if (this.brushManager) {
// 设置绿色笔刷
this.brushManager.setBrushColor(greenColor); // 纯绿色
this.brushManager.setBrushOpacity(200/255); // 完全不透明
this.brushManager.setBrushType("pencil"); // 铅笔类型
// 更新笔刷大小(使用当前大小)
if (BrushStore && BrushStore.state.size) {
this.brushManager.setBrushSize(BrushStore.state.size);
}
// 更新应用到画布
this.brushManager.updateBrush();
}
// 启用笔刷指示器并设置绿色
this._enableBrushIndicator(greenColor);
}
/**
* 设置部件选取工具--橡皮擦
*/
setupPartEraserTool() {
setupPartEraserTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
if (this.canvasManager && this.canvasManager.partManager) {
if (this.brushManager) {
this.brushManager.createEraser();
}
// 启用笔刷指示器
this._enableBrushIndicator();
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_ERASER);
}
}
@@ -894,7 +918,7 @@ export class ToolManager {
this._rasterizeLayerForLiquify(layerId);
},
onCancel: () => {
console.log("用户取消了栅格化操作");
// console.log("用户取消了栅格化操作");
// 用户取消,触发液化面板显示事件但不能液化
document.dispatchEvent(
new CustomEvent("showLiquifyPanel", {
@@ -1286,7 +1310,7 @@ export class ToolManager {
*/
showTextEditor(textObject, layer) {
// 这个方法将在TextEditorPanel组件实现后调用
console.log("显示文本编辑面板", textObject, layer);
// console.log("显示文本编辑面板", textObject, layer);
// 将发出一个事件让Vue组件捕获并显示编辑面板
document.dispatchEvent(
new CustomEvent("showTextEditor", {
@@ -1302,7 +1326,7 @@ export class ToolManager {
*/
hideTextEditor() {
// 这个方法将在TextEditorPanel组件实现后调用
console.log("隐藏文本编辑面板");
// console.log("隐藏文本编辑面板");
// 将发出一个事件让Vue组件捕获并隐藏编辑面板
document.dispatchEvent(
new CustomEvent("hideTextEditor", {
@@ -1323,7 +1347,7 @@ export class ToolManager {
if (this.brushIndicator) {
this.brushIndicator.dispose();
this.brushIndicator = null;
console.log("笔刷指示器已清理");
// console.log("笔刷指示器已清理");
}
// 移除文本编辑相关事件监听器
@@ -1348,7 +1372,7 @@ export class ToolManager {
this.canvas.isDrawingMode = false;
this.canvas.selection = false;
console.log("文本工具已激活");
// console.log("文本工具已激活");
}
/**
@@ -1424,7 +1448,7 @@ export class ToolManager {
// 切换到红色笔刷工具作为默认工具
this.setTool(OperationType.RED_BRUSH);
console.log("工具管理器已进入红绿图模式");
// console.log("工具管理器已进入红绿图模式");
}
/**
@@ -1437,7 +1461,7 @@ export class ToolManager {
// 切换回选择工具
this.setTool(OperationType.SELECT);
console.log("工具管理器已退出红绿图模式");
// console.log("工具管理器已退出红绿图模式");
}
/**
@@ -1495,7 +1519,7 @@ export class ToolManager {
// 更新指示器颜色
this.brushIndicator.updateColor(brushColor);
console.log(`笔刷指示器已启用,大小: ${brushSize}, 颜色: ${brushColor}`);
// console.log(`笔刷指示器已启用,大小: ${brushSize}, 颜色: ${brushColor}`);
}
/**
@@ -1506,7 +1530,7 @@ export class ToolManager {
if (!this.brushIndicator) return;
this.brushIndicator.disable();
console.log("笔刷指示器已禁用");
// console.log("笔刷指示器已禁用");
}
/**
@@ -1517,7 +1541,7 @@ export class ToolManager {
if (!this.brushIndicator) return;
this.brushIndicator.updateSize(size);
console.log(`笔刷指示器大小已更新为: ${size}`);
// console.log(`笔刷指示器大小已更新为: ${size}`);
}
/**
@@ -1528,7 +1552,7 @@ export class ToolManager {
if (!this.brushIndicator) return;
this.brushIndicator.updateColor(color);
console.log(`笔刷指示器颜色已更新为: ${color}`);
// console.log(`笔刷指示器颜色已更新为: ${color}`);
}
/**
@@ -1603,7 +1627,9 @@ export class ToolManager {
OperationType.ERASER,
OperationType.RED_BRUSH,
OperationType.GREEN_BRUSH,
OperationType.LIQUIFY,
OperationType.LIQUIFY,
OperationType.PART_BRUSH,
OperationType.PART_ERASER,
];
return brushTools.includes(currentTool);

View File

@@ -299,7 +299,7 @@ export class CommandManager {
this.undoStack = [];
this.redoStack = [];
this._notifyStateChange();
console.log("📝 命令历史已清空");
// console.log("📝 命令历史已清空");
}
/**

View File

@@ -6,6 +6,7 @@ import { OperationType, OperationTypes } from "../../utils/layerHelper";
export class CanvasEventManager {
constructor(canvas, options = {}) {
this.canvas = canvas;
this.canvasManager = options.canvasManager;
this.toolManager = options.toolManager || null;
this.animationManager = options.animationManager;
this.thumbnailManager = options.thumbnailManager;
@@ -485,7 +486,7 @@ export class CanvasEventManager {
// 调试信息
if (process.env.NODE_ENV === "development") {
console.log("iPad touchstart:", e.touches.length, "fingers");
// console.log("iPad touchstart:", e.touches.length, "fingers");
}
if (e.touches.length === 2) {
@@ -500,11 +501,11 @@ export class CanvasEventManager {
this.touchState.zoomCenter = { x: centerX, y: centerY };
if (process.env.NODE_ENV === "development") {
console.log("iPad双指缩放开始:", {
distance: lastTouchDistance,
zoom: lastZoom,
center: this.touchState.zoomCenter,
});
// console.log("iPad双指缩放开始:", {
// distance: lastTouchDistance,
// zoom: lastZoom,
// center: this.touchState.zoomCenter,
// });
}
e.preventDefault();
@@ -554,14 +555,14 @@ export class CanvasEventManager {
const clampedZoom = Math.max(0.1, Math.min(5, newZoom));
if (process.env.NODE_ENV === "development") {
console.log("iPad双指缩放中:", {
currentDistance,
lastTouchDistance,
scale,
currentZoom,
newZoom,
clampedZoom,
});
// console.log("iPad双指缩放中:", {
// currentDistance,
// lastTouchDistance,
// scale,
// currentZoom,
// newZoom,
// clampedZoom,
// });
}
// 使用缩放中心点进行缩放
@@ -691,7 +692,9 @@ export class CanvasEventManager {
// 清除临时状态记录
delete activeObj._initialTransformState;
}
}
}else{
this.canvasManager.changeCanvas();
}
if (this.thumbnailManager && e.target) {
if (e.target.id) {
@@ -839,7 +842,7 @@ export class CanvasEventManager {
const hasNewImage = !!fabricImage;
if (!hasExistingObjects && !hasNewImage) {
console.log("没有对象需要合并");
// console.log("没有对象需要合并");
return;
}
@@ -851,7 +854,7 @@ export class CanvasEventManager {
// 执行高保真合并操作
try {
console.log(`开始合并图层 ${activeLayer.name} 中的对象为组...`);
// console.log(`开始合并图层 ${activeLayer.name} 中的对象为组...`);
const command = await this.layerManager.LayerObjectsToGroup(
activeLayer,
@@ -869,7 +872,7 @@ export class CanvasEventManager {
// 降级处理:如果合并失败,至少保证新图像能添加到图层
if (fabricImage && this.layerManager) {
console.log("执行降级处理:直接添加图像到图层");
// console.log("执行降级处理:直接添加图像到图层");
this.layerManager.addObjectToLayer(fabricImage, activeLayer.id);
}
}
@@ -975,6 +978,13 @@ export class CanvasEventManager {
// 添加调试日志(可选)
// 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);
}
/**
@@ -1011,15 +1021,15 @@ export class CanvasEventManager {
// 调试日志 - 仅在开发环境输出
if (process.env.NODE_ENV === "development") {
console.log("设备检测结果:", {
userAgent,
platform,
isMobile,
isTablet,
isDesktop,
hasTouchSupport,
maxTouchPoints: navigator.maxTouchPoints,
});
// console.log("设备检测结果:", {
// userAgent,
// platform,
// isMobile,
// isTablet,
// isDesktop,
// hasTouchSupport,
// maxTouchPoints: navigator.maxTouchPoints,
// });
}
return {

View File

@@ -219,7 +219,7 @@ export class KeyboardManager {
const text = event.clipboardData?.getData("text/plain") || "";
if(/^aida_copy_canvas_layer/.test(text)) return;
const items = event.clipboardData?.items || [];
console.log(this);
// console.log(this);
for (const item of items) {
if (item.type.indexOf("text/plain") !== -1) {
item.getAsString((text) => {
@@ -249,7 +249,7 @@ export class KeyboardManager {
this.container.addEventListener("touchcancel", this._handleTouchEnd);
}
console.log(`键盘管理器已初始化,平台: ${this.platform}, 触摸设备: ${this.isTouchDevice}`);
// console.log(`键盘管理器已初始化,平台: ${this.platform}, 触摸设备: ${this.isTouchDevice}`);
}
/**
@@ -437,35 +437,35 @@ export class KeyboardManager {
case "copy":
// 复制逻辑
console.log("复制当前选中图层");
// console.log("复制当前选中图层");
if(this.isRedGreenMode.value) return;
this.layerManager.copyLayer(this.layerManager.activeLayerId.value);
break;
case "paste":
// 粘贴逻辑
console.log("粘贴");
// console.log("粘贴");
if(this.isRedGreenMode.value) return;
this.layerManager.pasteLayer();
break;
case "cut":
// 剪切逻辑
console.log("剪切");
// console.log("剪切");
if(this.isRedGreenMode.value) return;
this.layerManager.cutLayer(this.layerManager.activeLayerId.value);
break;
case "delete":
// 删除逻辑
console.log("删除");
// console.log("删除");
if(this.isRedGreenMode.value) return;
this.layerManager.removeLayer(this.layerManager.activeLayerId.value);
break;
case "selectAll":
// 全选逻辑
console.log("全选");
// console.log("全选");
if(this.isRedGreenMode.value) return;
// 这里需要实现全选逻辑 TODO: 是否在选择模式下才可以全选?
if (this.layerManager) {
@@ -475,7 +475,7 @@ export class KeyboardManager {
case "clearSelection":
// 清除选择逻辑
console.log("清除选择");
// console.log("清除选择");
// 这里需要实现清除选择逻辑
if (this.layerManager) {
this.layerManager.clearSelection();
@@ -484,7 +484,7 @@ export class KeyboardManager {
case "save":
// 保存逻辑
console.log("保存");
// console.log("保存");
break;
case "selectTool":
@@ -591,7 +591,7 @@ export class KeyboardManager {
case "contextMenu":
// 上下文菜单(通常由右击或触控设备上的特定手势触发)
console.log("显示上下文菜单");
// console.log("显示上下文菜单");
// 这里需要实现显示上下文菜单的逻辑
break;

View File

@@ -30,7 +30,7 @@ export class LiquifyStateManager {
// 设备性能检测
this.devicePerformance = this._detectDevicePerformance();
console.log("🎯 液化状态管理器已初始化,设备性能等级:", this.devicePerformance);
// console.log("🎯 液化状态管理器已初始化,设备性能等级:", this.devicePerformance);
}
/**
@@ -48,7 +48,7 @@ export class LiquifyStateManager {
// 显示操作反馈
this._showOperationFeedback();
console.log("🚀 开始液化操作");
// console.log("🚀 开始液化操作");
}
/**
@@ -68,7 +68,7 @@ export class LiquifyStateManager {
// 禁用不必要的画布功能
this._disableCanvasFeatures();
console.log("🖱️ 开始拖拽操作");
// console.log("🖱️ 开始拖拽操作");
}
/**
@@ -98,7 +98,7 @@ export class LiquifyStateManager {
}
}
console.log("✅ 结束拖拽操作");
// console.log("✅ 结束拖拽操作");
}
/**
@@ -116,7 +116,7 @@ export class LiquifyStateManager {
// 隐藏操作反馈
this._hideOperationFeedback();
console.log(`⏱️ 液化操作完成,耗时: ${operationTime.toFixed(2)}ms`);
// console.log(`⏱️ 液化操作完成,耗时: ${operationTime.toFixed(2)}ms`);
}
/**
@@ -158,11 +158,11 @@ export class LiquifyStateManager {
// 根据性能数据动态调整设置
this._adaptivePerformanceOptimization(operationTime);
console.log(
`📊 记录性能指标: ${operationType}/${mode}, 耗时: ${operationTime.toFixed(
2
)}ms, 渲染模式: ${renderMode}`
);
// console.log(
// `📊 记录性能指标: ${operationType}/${mode}, 耗时: ${operationTime.toFixed(
// 2
// )}ms, 渲染模式: ${renderMode}`
// );
}
/**
@@ -179,7 +179,7 @@ export class LiquifyStateManager {
const currentQuality = this.realtimeUpdater.config.imageQuality || 1.0;
if (currentQuality > 0.7) {
this.realtimeUpdater.setImageQuality(Math.max(0.7, currentQuality - 0.1));
console.log("⚡ 自动降低图像质量以提升性能");
// console.log("⚡ 自动降低图像质量以提升性能");
}
// 增加节流时间
@@ -188,7 +188,7 @@ export class LiquifyStateManager {
33,
this.realtimeUpdater.config.throttleTime + 8
);
console.log("⏱️ 自动增加节流时间以提升性能");
// console.log("⏱️ 自动增加节流时间以提升性能");
}
}
@@ -228,7 +228,7 @@ export class LiquifyStateManager {
this._updateCursor("default");
this.cursorCache.clear();
console.log("🧹 液化状态管理器已清理");
// console.log("🧹 液化状态管理器已清理");
}
// === 私有方法 ===

View File

@@ -30,27 +30,30 @@ export class LayerSort {
if (canvasObjects.length === 0) return;
// 使用画布渲染优化
await optimizeCanvasRendering(this.canvas, () => {
// 计算每个对象应该在的 z-index 位置
const objectZIndexMap = this.calculateObjectZIndexes();
await new Promise((resolve) => {
optimizeCanvasRendering(this.canvas, () => {
// 计算每个对象应该在的 z-index 位置
const objectZIndexMap = this.calculateObjectZIndexes();
// 按照新的 z-index 排序对象
const sortedObjects = canvasObjects
.map((obj) => ({
object: obj,
targetZIndex: objectZIndexMap.get(obj.id) ?? -1,
}))
.filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象
.sort((a, b) => a.targetZIndex - b.targetZIndex);
// 按照新的 z-index 排序对象
const sortedObjects = canvasObjects
.map((obj) => ({
object: obj,
targetZIndex: objectZIndexMap.get(obj.id) ?? -1,
}))
.filter((item) => item.targetZIndex >= 0) // 过滤掉无效对象
.sort((a, b) => a.targetZIndex - b.targetZIndex);
// 使用 fabric.js 的 moveTo 方法重新排序
sortedObjects.forEach((item, index) => {
const currentIndex = this.canvas.getObjects().indexOf(item.object);
if (currentIndex !== index && currentIndex !== -1) {
// 将对象移动到正确的位置
this.canvas.moveTo(item.object, index);
}
});
// 使用 fabric.js 的 moveTo 方法重新排序
sortedObjects.forEach((item, index) => {
const currentIndex = this.canvas.getObjects().indexOf(item.object);
if (currentIndex !== index && currentIndex !== -1) {
// 将对象移动到正确的位置
this.canvas.moveTo(item.object, index);
}
});
resolve();
});
});
}
@@ -71,17 +74,17 @@ export class LayerSort {
// if (!layer.visible) {
// continue;
// }
let id = layer.fabricObject?.id || layer.fabricObjects?.[0]?.id || null;
// 处理不同类型的图层
if (layer.isBackground && layer.fabricObject) {
if (layer.isBackground && id) {
// 背景图层对象放在最底层
zIndexMap.set(layer.fabricObject.id, currentZIndex++);
} else if (layer.isFixed && layer.fabricObject) {
zIndexMap.set(id, currentZIndex++);
} else if (layer.isFixed && id) {
// 固定图层对象
zIndexMap.set(layer.fabricObject.id, currentZIndex++);
} else if (layer.isFixedOther && layer.fabricObject) {
zIndexMap.set(id, currentZIndex++);
} else if (layer.isFixedOther && id) {
// 其他固定图层对象
zIndexMap.set(layer.fabricObject.id, currentZIndex++);
zIndexMap.set(id, currentZIndex++);
} else if (!layer.isBackground && !layer.isFixed) {
// 普通图层
currentZIndex = this.processLayerObjects(
@@ -91,7 +94,6 @@ export class LayerSort {
);
}
}
return zIndexMap;
}

View File

@@ -1045,6 +1045,7 @@ export async function imageToCanvas(image, scale = 1, sr = false) {
/**
* 图片边界跟踪算法(透明底)
* @param {HTMLCanvasElement} canvas - canvas元素
* @param {Number} scale - 缩放比例
* @returns {Array} 边界点数组 [{x, y}, ...]
*/
export function traceImageContour(canvas) {

View File

@@ -2208,8 +2208,13 @@ export const resizeImage = async (base64, width, height) => {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const scale = height / img.height;
const w = img.width * scale;
const h = img.height * scale;
const x = (width - w) / 2;
const y = 0;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
ctx.drawImage(img, x, y, w, h);
resolve(canvas.toDataURL());
};
img.onerror = reject;

View File

@@ -24,6 +24,7 @@ export const LayerType = {
export const SpecialLayerId = {
SPECIAL_GROUP: "group_special", // 特殊组
COLOR: "special_color", // 颜色图层
PART_SELECTOR: "part_selector", // 部件选择器图层
}

View File

@@ -65,10 +65,15 @@ export async function restoreFabricObject(serializedObject, canvas) {
* @param {ImageData} revData - 相反的ImageData白通道的相同位置是否为透明revData为白色为透明黑色为不透明
* @param {number} diff - 差值,默认 25
* @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 }
* @param {boolean} isMerge - 是否合并true=合并revDatafalse=反转revData
* @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();
if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") {
console.warn("对象不是图片");
return null;
}
const { width, height } = image;
if (!width || !height) {
console.warn("对象没有元素");
@@ -89,18 +94,20 @@ export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 2
const revG = revData?.data[i + 1] || 0;
const revB = revData?.data[i + 2] || 0;
const revA = revData?.data[i + 3] || 0;
let isHave = false;
if (r || g || b || a) {
if (revR > diff || revG > diff || revB > diff || revA > diff) {
data.data[i + 0] = 0;
data.data[i + 1] = 0;
data.data[i + 2] = 0;
data.data[i + 3] = 0;
isHave = false;
} else {
data.data[i + 0] = rgba.r;
data.data[i + 1] = rgba.g;
data.data[i + 2] = rgba.b;
data.data[i + 3] = rgba.a;
isHave = true;
}
}
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 {
data.data[i + 0] = 0;
data.data[i + 1] = 0;

View File

@@ -22,7 +22,7 @@ export const createRasterizedImage = async ({
isGroupWithMask = false, // 是否为带遮罩的组图层
} = {}) => {
try {
console.log(`📊 开始栅格化 ${fabricObjects.length} 个对象${maskObject ? "(带遮罩)" : ""}`);
// console.log(`📊 开始栅格化 ${fabricObjects.length} 个对象${maskObject ? "(带遮罩)" : ""}`);
// 确保有对象需要栅格化
if (fabricObjects.length === 0) {
@@ -36,7 +36,7 @@ export const createRasterizedImage = async ({
if (isThumbnail) scaleFactor = 0.2; // 缩略图使用较小的高清倍数
console.log(`高清倍数: ${scaleFactor}, 当前缩放: ${currentZoom}`);
// console.log(`高清倍数: ${scaleFactor}, 当前缩放: ${currentZoom}`);
// 如果有遮罩且保持原始质量,使用高质量的遮罩处理方法
if (maskObject && preserveOriginalQuality) {
@@ -58,7 +58,7 @@ export const createRasterizedImage = async ({
}
if (isReturenDataURL) {
console.log("✅ 带遮罩的栅格化图像创建成功返回DataURL");
// console.log("✅ 带遮罩的栅格化图像创建成功返回DataURL");
return rasterizedImage;
}
@@ -77,7 +77,7 @@ export const createRasterizedImage = async ({
},
});
console.log(`✅ 带遮罩的栅格化图像创建完成`);
// console.log(`✅ 带遮罩的栅格化图像创建完成`);
return rasterizedImage;
}
@@ -101,7 +101,7 @@ export const createRasterizedImage = async ({
}
if (isReturenDataURL) {
console.log("✅ 栅格化图像创建成功返回DataURL");
// console.log("✅ 栅格化图像创建成功返回DataURL");
return rasterizedImage;
}
@@ -120,7 +120,7 @@ export const createRasterizedImage = async ({
},
});
console.log(`✅ 栅格化图像创建完成`);
// console.log(`✅ 栅格化图像创建完成`);
}
return rasterizedImage;
@@ -172,7 +172,7 @@ const createRasterizedImageWithGroup = async ({
// 获取组的绝对边界框
const groupBounds = group.getBoundingRect(true, true);
console.log("📏 组边界框:", groupBounds);
// console.log("📏 组边界框:", groupBounds);
// 设置离屏画布尺寸,使用组的边界大小
const canvasWidth = Math.ceil(groupBounds.width * scaleFactor);
@@ -184,7 +184,7 @@ const createRasterizedImageWithGroup = async ({
hasControls: false,
});
console.log(`🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`);
// console.log(`🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`);
// 调整组的位置,让它位于画布的左上角
group.set({
@@ -266,11 +266,11 @@ const createRasterizedImageWithMask = async ({
isGroupWithMask,
}) => {
try {
console.log("🎭 使用遮罩创建栅格化图像");
// console.log("🎭 使用遮罩创建栅格化图像");
// 获取遮罩的边界框,这将作为最终图像的边界
const maskBounds = maskObject.getBoundingRect(true, true);
console.log("📏 遮罩边界框:", maskBounds);
// console.log("📏 遮罩边界框:", maskBounds);
// 克隆所有对象,并清除它们的遮罩,避免重复应用
const clonedObjects = [];
@@ -308,7 +308,7 @@ const createRasterizedImageWithMask = async ({
height: canvasHeight,
});
console.log(`🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`);
// console.log(`🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`);
// 调整对象位置,相对于遮罩边界重新定位
clonedObjects.forEach((obj) => {
@@ -376,7 +376,7 @@ const createRasterizedImageWithMask = async ({
// 确保图像位置正确
fabricImage.setCoords();
console.log("✅ 带遮罩的栅格化图像创建完成");
// console.log("✅ 带遮罩的栅格化图像创建完成");
return fabricImage;
} catch (error) {
console.error("带遮罩的栅格化失败:", error);
@@ -430,12 +430,12 @@ const createFabricImageFromDataURL = (dataURL) => {
*/
const applyMaskToCanvas = async (canvas, maskObject, bounds) => {
if (!maskObject) {
console.log("没有遮罩对象,跳过遮罩应用");
// console.log("没有遮罩对象,跳过遮罩应用");
return;
}
try {
console.log("🎭 应用遮罩到画布");
// console.log("🎭 应用遮罩到画布");
// 克隆遮罩对象,避免影响原对象
const clonedMask = await cloneObjectAsync(maskObject);
@@ -459,7 +459,7 @@ const applyMaskToCanvas = async (canvas, maskObject, bounds) => {
// 将遮罩设置为画布的clipPath
canvas.clipPath = clonedMask;
console.log("✅ 遮罩应用完成");
// console.log("✅ 遮罩应用完成");
} catch (error) {
console.error("应用遮罩失败:", error);
}

View File

@@ -24,7 +24,7 @@ export const createRasterizedImage = async ({
isEnhanceImg, // 是否是增强图片
} = {}) => {
try {
console.log(`📊 开始栅格化 ${fabricObjects.length} 个对象`);
// console.log(`📊 开始栅格化 ${fabricObjects.length} 个对象`);
// 确保有对象需要栅格化
if (fabricObjects.length === 0) {
@@ -86,14 +86,14 @@ const createClippedObjects = async ({
isEnhanceImg, // 是否是增强图片
}) => {
try {
console.log("🎯 使用新的图像遮罩裁剪方法创建对象");
// console.log("🎯 使用新的图像遮罩裁剪方法创建对象");
// 使用优化后的边界计算,确保包含描边区域
const optimizedBounds = calculateOptimizedBounds(
clippingObject,
fabricObjects
);
console.log("📐 优化后的选区边界框:", optimizedBounds);
// console.log("📐 优化后的选区边界框:", optimizedBounds);
// 获取羽化值
let featherAmount = 0;
@@ -102,7 +102,7 @@ const createClippedObjects = async ({
typeof selectionManager.getFeatherAmount === "function"
) {
featherAmount = selectionManager.getFeatherAmount();
console.log(`🌟 应用羽化效果: ${featherAmount}px`);
// console.log(`🌟 应用羽化效果: ${featherAmount}px`);
}
// 方法1如果只需要返回DataURL使用画布裁剪方法
@@ -160,7 +160,7 @@ const createClippedObjects = async ({
// 更新坐标
fabricImage.setCoords();
console.log("✅ 返回裁剪后的fabric对象已恢复到优化后的原始大小和位置");
// console.log("✅ 返回裁剪后的fabric对象已恢复到优化后的原始大小和位置");
return fabricImage;
} catch (error) {
console.warn("创建裁剪对象失败:", error);
@@ -181,36 +181,37 @@ const createClippedDataURLByCanvas = async ({
isEnhanceImg = false, // 是否是增强图片
}) => {
try {
console.log("🖼️ 使用图像遮罩裁剪方法生成DataURL");
// console.log("🖼️ 使用图像遮罩裁剪方法生成DataURL");
// 使用优化后的边界计算,确保包含描边区域
// const optimizedBounds = calculateOptimizedBounds(
// clippingObject,
// fabricObjects
// );
const optimizedBounds = {
left: clippingObject.left - clippingObject.width / 2,
top: clippingObject.top - clippingObject.height / 2,
width: clippingObject.width,
height: clippingObject.height,
}
const optimizedBounds = calculateOptimizedBounds(
clippingObject,
fabricObjects
);
console.log("📐 优化后的选区边界框:", optimizedBounds);
// const optimizedBounds = {
// left: clippingObject.left - clippingObject.width / 2,
// top: clippingObject.top - clippingObject.height / 2,
// width: clippingObject.width,
// height: clippingObject.height,
// }
// 使用高分辨率以保证质量
const pixelRatio = window.devicePixelRatio || 1;
const qualityMultiplier = !!isEnhanceImg ? Math.max(2, pixelRatio) : 1;
console.log("使用高分辨率以保证质量:" + isEnhanceImg, optimizedBounds);
// console.log("使用高分辨率以保证质量:" + isEnhanceImg, optimizedBounds);
const canvasWidth = Math.ceil(optimizedBounds.width * qualityMultiplier);
const canvasHeight = Math.ceil(optimizedBounds.height * qualityMultiplier);
console.log(
`📏 优化后画布尺寸: ${canvasWidth}x${canvasHeight} (质量倍数: ${qualityMultiplier})`
);
console.log("🎯 边界框对比:", {
original: selectionBounds,
optimized: optimizedBounds,
});
// console.log(
// `📏 优化后画布尺寸: ${canvasWidth}x${canvasHeight} (质量倍数: ${qualityMultiplier})`
// );
// console.log("🎯 边界框对比:", {
// original: selectionBounds,
// optimized: optimizedBounds,
// });
// 步骤1: 先将路径转换为遮罩图像(支持羽化)
const maskImageDataURL =
@@ -242,7 +243,7 @@ const createClippedDataURLByCanvas = async ({
canvasHeight,
});
console.log("✅ 图像遮罩裁剪完成生成DataURL");
// console.log("✅ 图像遮罩裁剪完成生成DataURL");
return clippedDataURL;
} catch (error) {
console.error("图像遮罩裁剪失败:", error);
@@ -262,7 +263,7 @@ const createSimpleClone = async ({
format,
}) => {
try {
console.log("📋 创建简单克隆对象");
// console.log("📋 创建简单克隆对象");
const clonedObjects = [];
@@ -370,7 +371,7 @@ const renderObjectsToDataURL = async (objects, quality, format) => {
*/
const renderClippedObjectsToDataURL = async (clippedObjects) => {
try {
console.log("🖼️ 渲染裁剪对象为DataURL");
// console.log("🖼️ 渲染裁剪对象为DataURL");
// 计算所有裁剪对象的总边界框
let totalBounds = null;
@@ -450,7 +451,7 @@ const renderClippedObjectsToDataURL = async (clippedObjects) => {
// 清理临时画布
tempCanvas.dispose();
console.log("✅ 裁剪对象渲染完成");
// console.log("✅ 裁剪对象渲染完成");
return dataURL;
} catch (error) {
console.error("渲染裁剪对象失败:", error);
@@ -472,7 +473,7 @@ const createLegacyRasterization = async ({
isCropByBg, // 是否根据背景裁剪
isEnhanceImg, // 是否是增强图片
}) => {
console.log("⚠️ 使用兼容的离屏渲染方法");
// console.log("⚠️ 使用兼容的离屏渲染方法");
// 这里保留原有的离屏渲染逻辑作为备选方案
const currentZoom = canvas.getZoom?.() || 1;
@@ -522,12 +523,12 @@ const calculateBounds = (fabricObjects) => {
// 获取绝对边界框(原始大小和位置)
const absoluteBound = obj.getBoundingRect(true, true);
console.log(`对象 ${obj.id || index} 边界框比较:`, {
relative: relativeBound,
absolute: absoluteBound,
scaleX: obj.scaleX,
scaleY: obj.scaleY,
});
// console.log(`对象 ${obj.id || index} 边界框比较:`, {
// relative: relativeBound,
// absolute: absoluteBound,
// scaleX: obj.scaleX,
// scaleY: obj.scaleY,
// });
// 计算绝对边界框的累积范围
if (!absoluteBounds) {
@@ -600,7 +601,7 @@ const createOffscreenRasterization = async ({
let renderBounds = absoluteBounds;
if (clippingObject) {
const clippingBounds = clippingObject.getBoundingRect(true, true);
console.log("🎯 使用裁剪对象边界框:", clippingBounds);
// console.log("🎯 使用裁剪对象边界框:", clippingBounds);
renderBounds = clippingBounds;
}
@@ -613,9 +614,9 @@ const createOffscreenRasterization = async ({
height: canvasHeight,
});
console.log(
`🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`
);
// console.log(
// `🎨 离屏画布尺寸: ${canvasWidth}x${canvasHeight}, 缩放: ${scaleFactor}`
// );
// 克隆对象到离屏画布
const clonedObjects = [];
@@ -786,7 +787,7 @@ const createMaskImageFromPath = async ({
qualityMultiplier,
}) => {
try {
console.log("🎭 创建路径遮罩图像");
// console.log("🎭 创建路径遮罩图像");
// 创建专门用于渲染遮罩的画布
const maskCanvas = new fabric.StaticCanvas();
@@ -820,7 +821,7 @@ const createMaskImageFromPath = async ({
// 清理遮罩画布
maskCanvas.dispose();
console.log("✅ 遮罩图像创建完成");
// console.log("✅ 遮罩图像创建完成");
return maskDataURL;
} catch (error) {
console.error("创建遮罩图像失败:", error);
@@ -841,7 +842,7 @@ const renderContentToImage = async ({
qualityMultiplier,
}) => {
try {
console.log("🖼️ 渲染内容图像");
// console.log("🖼️ 渲染内容图像");
// 创建内容渲染画布
const contentCanvas = new fabric.StaticCanvas();
@@ -880,7 +881,6 @@ const renderContentToImage = async ({
// if(obj.globalCompositeOperation === "multiply"){
// clonedObj.clipPath = null;
// }
console.log("==========", obj.id, obj.layerName);
contentCanvas.add(clonedObj);
}
@@ -897,7 +897,7 @@ const renderContentToImage = async ({
// 清理内容画布
contentCanvas.dispose();
console.log("✅ 内容图像渲染完成");
// console.log("✅ 内容图像渲染完成");
return contentDataURL;
} catch (error) {
console.error("渲染内容图像失败:", error);
@@ -920,7 +920,7 @@ const applyImageMask = async ({
canvasHeight,
}) => {
try {
console.log("🎯 应用图像遮罩");
// console.log("🎯 应用图像遮罩");
return new Promise((resolve, reject) => {
// 创建用于合成的Canvas元素
@@ -952,7 +952,7 @@ const applyImageMask = async ({
// 获取最终结果
const resultDataURL = compositeCanvas.toDataURL("image/png", 1.0);
console.log("✅ 图像遮罩应用完成");
// console.log("✅ 图像遮罩应用完成");
resolve(resultDataURL);
} catch (error) {
console.error("合成图像失败:", error);
@@ -994,7 +994,7 @@ const createAdvancedMaskImage = async ({
featherAmount = 0,
}) => {
try {
console.log(`🎭 创建高级遮罩图像 (羽化: ${featherAmount})`);
// console.log(`🎭 创建高级遮罩图像 (羽化: ${featherAmount})`);
// 创建专门用于渲染遮罩的画布
const maskCanvas = new fabric.StaticCanvas();
@@ -1047,7 +1047,7 @@ const createAdvancedMaskImage = async ({
// 清理遮罩画布
maskCanvas.dispose();
console.log("✅ 高级遮罩图像创建完成");
// console.log("✅ 高级遮罩图像创建完成");
return maskDataURL;
} catch (error) {
console.error("创建高级遮罩图像失败:", error);
@@ -1116,7 +1116,7 @@ const createSolidMaskPath = async (
qualityMultiplier
) => {
try {
console.log("🔧 创建实体遮罩路径,处理描边转填充");
// console.log("🔧 创建实体遮罩路径,处理描边转填充");
// 克隆原始对象
const maskPath = await cloneObjectAsync(clippingObject);
@@ -1125,9 +1125,9 @@ const createSolidMaskPath = async (
const hasStroke = maskPath.stroke && maskPath.strokeWidth > 0;
if (hasStroke) {
console.log(
`📏 检测到描边: ${maskPath.stroke}, 宽度: ${maskPath.strokeWidth}`
);
// console.log(
// `📏 检测到描边: ${maskPath.stroke}, 宽度: ${maskPath.strokeWidth}`
// );
// 对于有描边的路径,我们需要更精确的处理
const strokeWidth = maskPath.strokeWidth;
@@ -1182,7 +1182,7 @@ const createSolidMaskPath = async (
});
}
console.log(`✅ 描边已转换为填充,类型: ${maskPath.type}`);
// console.log(`✅ 描边已转换为填充,类型: ${maskPath.type}`);
} else {
// 没有描边,直接处理位置和缩放
maskPath.set({
@@ -1216,7 +1216,7 @@ const createSolidMaskPath = async (
*/
const calculateOptimizedBounds = (clippingObject, fabricObjects) => {
try {
console.log("📐 计算优化后的边界框");
// console.log("📐 计算优化后的边界框");
// 获取裁剪对象的边界框(包含描边)
const clippingBounds = clippingObject.getBoundingRect(true, true);
@@ -1232,7 +1232,7 @@ const calculateOptimizedBounds = (clippingObject, fabricObjects) => {
clippingBounds.width += strokeWidth;
clippingBounds.height += strokeWidth;
console.log(`🖊️ 调整描边边界框,描边宽度: ${strokeWidth}`);
// console.log(`🖊️ 调整描边边界框,描边宽度: ${strokeWidth}`);
}
// 计算内容对象的边界框
@@ -1246,11 +1246,11 @@ const calculateOptimizedBounds = (clippingObject, fabricObjects) => {
height: Math.max(1, clippingBounds.height),
};
console.log("✅ 边界框优化完成", {
original: clippingObject.getBoundingRect(true, true),
optimized: optimizedBounds,
hasStroke: !!(clippingObject.stroke && clippingObject.strokeWidth > 0),
});
// console.log("✅ 边界框优化完成", {
// original: clippingObject.getBoundingRect(true, true),
// optimized: optimizedBounds,
// hasStroke: !!(clippingObject.stroke && clippingObject.strokeWidth > 0),
// });
return optimizedBounds;
} catch (error) {

View File

@@ -375,6 +375,7 @@ const confirm = ()=>{
/* 图片网格 */
.image-grid {
display: grid;
align-content: start;
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
gap: 16px;
min-height: 20rem;

View File

@@ -137,7 +137,6 @@
<button @click="onAdd">添加</button>
<div class="box">
<pingpu
:list="list"
ref="pingpuRef"
:width="600"
:height="900"
@@ -161,58 +160,7 @@
const convertDotNotationToBracket = (str) =>
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
const activeToken = ref("1");
const list = ref([
{
token: "1",
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [0, 0],
scale: [1, 1],
angle: 0,
name: "Print1",
priority: 1,
object: {
top: 0,
left: 0,
scaleX: 1,
scaleY: 1,
opacity: 1,
angle: 0,
flipX: false,
flipY: false,
blendMode: "multiply",
gapX: 10,
gapY: 20,
},
},
{
token: "2",
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [0, 0],
scale: [2, 2],
angle: -45,
name: "Print2",
priority: 1,
object: {
top: 450,
left: 300,
scaleX: 0.5,
scaleY: 0.5,
opacity: 1,
angle: 0,
flipX: false,
flipY: false,
blendMode: "multiply",
gapX: 0,
gapY: 0,
},
},
]);
const list = ref([]);
// 深拷贝
const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));
const oldList = ref(deepCopy(list.value));

View File

@@ -3,8 +3,11 @@
</template>
<script setup>
import TaskQueue from "../utils/TaskQueue.js";
import { fabric } from "fabric-with-all";
import { ref, watch, onMounted } from "vue";
import { ref, watch, onMounted, nextTick } from "vue";
// 任务队列
const taskQueue = new TaskQueue();
const KEYS = {
FILL_X: "location[0]",
FILL_Y: "location[1]",
@@ -22,6 +25,7 @@
O_FLIPX: "object.flipX",
O_FLIPY: "object.flipY",
O_BLENDMODE: "object.blendMode",
O_FILL_REPEAT: "object.fill_repeat",
};
const ACTIONS = {
ADD: "add",
@@ -32,45 +36,36 @@
};
const emit = defineEmits(["change-canvas", "init-canvas"]);
const props = defineProps({
list: { type: Array, default: () => [] },
// list: { type: Array, default: () => [] },
width: { type: Number, required: true },
height: { type: Number, required: true },
});
const list = ref([]);
const el = ref(null);
const canvasRef = ref(null);
const observer = ref(null);
var canvas = null;
onMounted(async () => {
initCanvas();
await setCanvasData();
let throttleTimeout = null;
let lastRunTime = 0;
// taskQueue.addTask(async () => await setCanvasData());
emit("init-canvas", list.value);
let throttleDelay = 100;
let trailingTimeout = null;
observer.value = new ResizeObserver((entries) => {
const now = Date.now();
const throttleDelay = 100;
if (!throttleTimeout) {
updateCanvasSize();
lastRunTime = now;
throttleTimeout = setTimeout(() => {
throttleTimeout = null;
}, throttleDelay);
} else {
clearTimeout(trailingTimeout);
trailingTimeout = setTimeout(() => {
updateCanvasSize();
lastRunTime = Date.now();
}, throttleDelay);
}
clearTimeout(trailingTimeout);
trailingTimeout = setTimeout(() => {
console.log("OverallCanvas: resize");
taskQueue.addTask(async () => await updateCanvasSize());
}, throttleDelay);
});
observer.value.observe(el.value);
emit("init-canvas", props.list);
});
onBeforeUnmount(() => {
observer.value.disconnect();
unbindEvent();
});
const initCanvas = () => {
console.log("OverallCanvas: initCanvas");
canvas = new fabric.Canvas(canvasRef.value, {
selection: false,
preserveObjectStacking: true,
@@ -80,6 +75,7 @@
bindEvent();
};
const updateCanvasSize = async () => {
console.log("OverallCanvas: updateCanvasSize");
canvas.setWidth(el.value.offsetWidth);
canvas.setHeight(el.value.offsetHeight);
await setCanvasData();
@@ -98,7 +94,7 @@
};
// 处理对象修改事件
const onObjectModified = (e) => {
console.log(e);
console.log("OverallCanvas: onObjectModified", e);
const object = e.target;
const action = e.action;
const list = [];
@@ -150,7 +146,7 @@
const onDeleteItem = (object) => {
const list = [{ token: object.token, action: ACTIONS.DELETE }];
emit("change-canvas", list);
canvas.remove(object);
DeleteItemByToken(object.token);
canvas.renderAll();
};
const urlToCanvas = (url) => {
@@ -174,18 +170,20 @@
};
const setCanvasData = async () => {
canvas.clear();
for (let i = 0; i < props.list.length; i++) {
let item = props.list[i];
console.log("OverallCanvas: setCanvasData", list.value);
for (let i = 0; i < list.value.length; i++) {
let item = list.value[i];
await addObject(item);
}
canvas.renderAll();
};
const addObject = async (item) => {
const token = item.token;
const cwidth = canvas.width;
const cheight = canvas.height;
let pattern = await setFill(item);
let rect = new fabric.Rect({
token: item.token,
token: token,
width: cwidth,
height: cheight,
fill: pattern,
@@ -194,7 +192,6 @@
left: item.object.left / (props.width / canvas.width),
onDelete: (v) => onDeleteItem(v),
});
console.log("==========", props)
canvas.add(rect);
};
const setFill = async (item) => {
@@ -202,11 +199,14 @@
const cwidth = canvas.width;
const cheight = canvas.height;
let image = await urlToCanvas(item.path);
let offsetX = item.location[0];
let offsetY = item.location[1];
let scaleX = ((cwidth / image.width) * item.scale[0]) / 5;
let scaleY = ((cheight / image.height) * item.scale[1]) / 5;
let scale = cwidth > cheight ? scaleX : scaleY;
let offsetX =
(item.location[0] * cwidth) / props.width - (image.width * scale) / 2;
let offsetY =
(item.location[1] * cheight) / props.height -
(image.height * scale) / 2;
let angle = item.angle;
let gapX = item.object.gapX;
let gapY = item.object.gapY;
@@ -224,80 +224,102 @@
ctx.drawImage(image, 0, 0);
let pattern = new fabric.Pattern({
source: tcanvas,
repeat: "repeat",
repeat: item.object?.fill_repeat || "repeat",
patternTransform,
offsetX, // 水平偏移
offsetY, // 垂直偏移
});
return pattern;
};
const updataList = async (list) => {
console.log(list);
const objects = canvas.getObjects();
for (let i = 0; i < list.length; i++) {
let item = list[i];
let object = objects.find((o) => o.token === item.token);
if (item.action === ACTIONS.UPDATE) {
if (!object) continue;
let value = item.value;
switch (item.key) {
case KEYS.O_TOP:
object.set("top", value / (props.height / canvas.height));
break;
case KEYS.O_LEFT:
object.set("left", value / (props.width / canvas.width));
break;
case KEYS.O_OPACITY:
object.set("opacity", value);
break;
case KEYS.O_SCALE_X:
object.set("scaleX", value);
break;
case KEYS.O_SCALE_Y:
object.set("scaleY", value);
break;
case KEYS.O_ANGLE:
object.set("angle", value);
break;
case KEYS.O_FLIPX:
object.set("flipX", value);
break;
case KEYS.O_FLIPY:
object.set("flipY", value);
break;
case KEYS.O_BLENDMODE:
object.set("blendMode", value);
break;
case KEYS.FILL_X:
case KEYS.FILL_Y:
case KEYS.FILL_ANGLE:
case KEYS.FILL_SCALEX:
case KEYS.FILL_SCALEY:
case KEYS.FILL_GAPX:
case KEYS.FILL_GAPY:
let pattern = await setFill(
props.list.find((v) => v.token === item.token)
);
object.set("fill", pattern);
break;
const updataList = async (list_) => {
const cd = async (list_) => {
console.log("OverallCanvas: updataList", list_);
const objects = canvas.getObjects();
for (let i = 0; i < list_.length; i++) {
let item = list_[i];
let object = objects.find((o) => o.token === item.token);
if (item.action === ACTIONS.UPDATE) {
if (!object) continue;
let value = item.value;
switch (item.key) {
case KEYS.O_TOP:
object.set(
"top",
value / (props.height / canvas.height)
);
break;
case KEYS.O_LEFT:
object.set(
"left",
value / (props.width / canvas.width)
);
break;
case KEYS.O_OPACITY:
object.set("opacity", value);
break;
case KEYS.O_SCALE_X:
object.set("scaleX", value);
break;
case KEYS.O_SCALE_Y:
object.set("scaleY", value);
break;
case KEYS.O_ANGLE:
object.set("angle", value);
break;
case KEYS.O_FLIPX:
object.set("flipX", value);
break;
case KEYS.O_FLIPY:
object.set("flipY", value);
break;
case KEYS.O_BLENDMODE:
object.set("blendMode", value);
break;
case KEYS.FILL_X:
case KEYS.FILL_Y:
case KEYS.FILL_ANGLE:
case KEYS.FILL_SCALEX:
case KEYS.FILL_SCALEY:
case KEYS.FILL_GAPX:
case KEYS.FILL_GAPY:
case KEYS.O_FILL_REPEAT:
let pattern = await setFill(
list.value.find((v) => v.token === item.token)
);
object.set("fill", pattern);
break;
}
} else if (item.action === ACTIONS.SELECT) {
if (object) canvas.setActiveObject(object);
} else if (item.action === ACTIONS.SORT) {
let tokens = item.tokens;
canvas.clear();
const list_ = [];
for (let j = 0; j < tokens.length; j++) {
let item_ = list.value.find((v) => v.token === tokens[j]);
if (item_) list_.push(item_);
let object = objects.find((o) => o.token === tokens[j]);
if (object) canvas.add(object);
}
list.value = list_;
canvas.renderAll();
} else if (item.action === ACTIONS.DELETE) {
DeleteItemByToken(item.token);
} else if (item.action === ACTIONS.ADD) {
DeleteItemByToken(item.data.token);
list.value.push(item.data);
await addObject(item.data);
}
} else if (item.action === ACTIONS.SELECT) {
if (object) canvas.setActiveObject(object);
} else if (item.action === ACTIONS.SORT) {
let tokens = item.tokens;
canvas.clear();
for (let j = 0; j < tokens.length; j++) {
let object = objects.find((o) => o.token === tokens[j]);
if (object) canvas.add(object);
}
canvas.renderAll();
} else if (item.action === ACTIONS.DELETE) {
if (object) canvas.remove(object);
} else if (item.action === ACTIONS.ADD) {
await addObject(item.data);
}
}
canvas.renderAll();
canvas.renderAll();
};
taskQueue.addTask(async () => await cd(list_));
};
/** 删除 */
const DeleteItemByToken = (token) => {
list.value = list.value.filter((v) => v.token !== token);
const objects = canvas.getObjects().filter((o) => o.token === token);
objects.forEach((o) => canvas.remove(o));
};
defineExpose({
updataList,

View File

@@ -331,52 +331,59 @@
class: "export-btn",
},
]);
const otherData = {
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
printObject: {
prints: [
{
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [250, 780],
scale: [1.2, 1.6],
angle: 0,
object: {
top: 600,
left: 800,
scaleX: 0.5,
scaleY: 0.5,
opacity: 1,
angle: 45,
flipX: false,
flipY: false,
blendMode: "multiply",
gapX: 0,
gapY: 0,
const canvasLoadJsonSuccess = () => {
console.log("画布加载JSON成功");
return;
canvasEditor.value?.updateOtherLayers({
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
printObject: {
prints: [
{
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [800, 600],
scale: [1, 1],
angle: 0,
priority: 1,
object: {
top: 300,
left: 400,
scaleX: 0.5,
scaleY: 0.5,
opacity: 1,
angle: 0,
flipX: false,
flipY: false,
// blendMode: "multiply",
gapX: 0,
gapY: 0,
},
},
},
// {
// ifSingle: true,
// level2Type: "Pattern",
// designType: "Library",
// path: "/src/assets/images/canvas/yinhua1.jpg",
// location: [550, 650],
// scale: [0.15, 0.2],
// angle: 0,
// },
// {
// ifSingle: true,
// level2Type: "Pattern",
// designType: "Library",
// path: "/src/assets/images/canvas/yinhua1.jpg",
// location: [700, 400],
// scale: [0.1, 0.133],
// angle: 0,
// },
],
},
{
ifSingle: true,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [550, 650],
scale: [0.15, 0.2],
angle: 0,
priority: 2,
},
// {
// ifSingle: true,
// level2Type: "Pattern",
// designType: "Library",
// path: "/src/assets/images/canvas/yinhua1.jpg",
// location: [700, 400],
// scale: [0.1, 0.133],
// angle: 0,
// priority: 3,
// },
],
},
});
};
</script>
@@ -408,14 +415,13 @@
:clothingMinIOPath="clothingMinIOPath"
:clothingImageUrl="clothingImageUrl"
:clothingImageUrl2="clothingImageUrlInit"
:otherData="otherData"
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
:config="editorConfig"
:clothing-image-opts="{
imageMode: 'contains', // 设置底图包含在画布内
}"
@change-canvas="changeCanvas"
@canvas-init="canvasInit"
isFixedErasable
showFixedLayer
>
<template #existsImageList>
@@ -443,7 +449,16 @@
</div>
</div>
</template>
<style>
body > .lower-canvas {
position: fixed;
top: 0;
left: 0;
width: 800px !important;
height: 600px !important;
z-index: 99999999;
}
</style>
<style scoped lang="less">
* {
margin: 0;

View File

@@ -7,7 +7,7 @@
:enabledRedGreenMode="false"
/>
</div>
<div class="btn">123
<div class="btn">
<div class="gallery_btn" @click="exportElement">Export</div>
</div>
</div>

View File

@@ -53,7 +53,7 @@
};
});
// 边界追踪
function traceImageContour(canvas) {
function traceImageContour(canvas, scale = 1) {
const ctx = canvas.getContext("2d");
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;

View File

@@ -0,0 +1,28 @@
export default class TaskQueue {
constructor() {
this.tasks = [];
this.running = false;
}
// 添加任务
addTask(task) {
this.tasks.push(task);
// 执行任务
this.executeTasks();
}
// 执行任务
async executeTasks() {
if (this.running) {
return;
}
this.running = true;
for (const task of this.tasks) {
await task();
}
this.running = false;
this.clearTasks();
}
// 清空任务队列
clearTasks() {
this.tasks = [];
}
}

View File

@@ -101,7 +101,7 @@
</div>
</div>
<div class="contentRight canvas" v-if="selectDetail && selectDetail.id && currentDetailType" :class="{'active': isEditPattern.value}">
<canvasBox ref="canvasBox" :key="canvasKey" :sketchSize="sketchSize" @setSloganData="setSloganData" :isEditPattern="isEditPattern.value" :updateOtherLayers="updateOtherLayers"></canvasBox>
<canvasBox ref="canvasBox" v-model:loadingShow="loadingShow" :key="canvasKey" :sketchSize="sketchSize" @setSloganData="setSloganData" :isEditPattern="isEditPattern.value" :updateOtherLayers="updateOtherLayers"></canvasBox>
</div>
<!-- 画布 -->
<!-- <div class="content" v-else-if="selectDetail && selectDetail.id">
@@ -129,7 +129,9 @@ import { Modal,message } from 'ant-design-vue';
import {getUploadUrl,segmentImage,setGradual,rgbToHsv,rgbaToHex} from '@/tool/util'
import { useStore } from "vuex";
import { openGuide,driverObj__ } from "@/tool/guide";
import { KeyValueDB } from "@/tool/indexedDB";
import { useI18n } from 'vue-i18n'
import { convertToEC4StyleForCustomSerise } from 'echarts/types/src/util/styleCompat.js'
export default defineComponent({
components:{
detailLeft,model,detailRight,canvasBox
@@ -161,7 +163,7 @@ export default defineComponent({
isEditPattern:{
value:'' as any,
},// 是否编辑图案
canvasKey:0,
canvasKey:computed(()=>store.state.DesignDetail.canvasKey),
singleOveral:{
value:'overall'
},
@@ -190,15 +192,17 @@ export default defineComponent({
watch(()=>detailData.selectDetail,async (newValue,oldValue)=>{
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
if(newValue?.path)await getSketchSize()
detailData.canvasKey += 1
if(newValue?.id && (newValue?.id != oldValue?.id)){
store.commit('DesignDetail/changeCanvasKey')
}
// privewDetail(oldValue)
},{immediate: true})
provide('getCanvasIfEdit',detailData.getCanvasIfEdit)
provide('singleOveral',detailData.singleOveral)
provide('isEditPattern',detailData.isEditPattern)
const closeModal = ()=>{
sessionStorage.removeItem('oppositeRevocation')
sessionStorage.removeItem('revocation')
const closeModal = async ()=>{
await KeyValueDB.remove('oppositeRevocation')
await KeyValueDB.remove('revocation')
detailData.designDetailShow = false
emit('destroy')
}
@@ -212,10 +216,9 @@ export default defineComponent({
Https.axiosGet(url).then(
async (rv: any) => {
//清除画布JSON数据
sessionStorage.removeItem('canvasList');
sessionStorage.removeItem('revocation');
sessionStorage.removeItem('oppositeRevocation');
sessionStorage.setItem('key', 'value');
await KeyValueDB.remove('canvasList');
await KeyValueDB.remove('revocation');
await KeyValueDB.remove('oppositeRevocation');
store.commit('DesignDetail/setDesignDetail',rv)
rv.clothes.forEach((item:any)=>{
let a
@@ -259,7 +262,7 @@ export default defineComponent({
}
detailData.loadingShow = false
// detailData.loadingShow = false
resolve(rv)
}
).catch(rv=>{
@@ -270,24 +273,24 @@ export default defineComponent({
}
//撤回
const setRevocation = ()=>{//设置撤销
const setRevocation = async ()=>{//设置撤销
let itemDetail = JSON.parse(JSON.stringify(detailData.designDetail))
let revocation:any = JSON.parse((sessionStorage.getItem("revocation") as any))
let revocation:any = JSON.parse((await KeyValueDB.get("revocation") as any) || 'null')
if(!revocation)revocation = []
// let oppositeRevocation = JSON.parse((sessionStorage.getItem("oppositeRevocation") as any))
// let oppositeRevocation = JSON.parse((await KeyValueDB.get("oppositeRevocation") as any))
// if(revocation?.[0]?.designItemId != itemDetail.designItemId || revocation?.[0]?.designItemId == undefined){
// revocation = []
// }
revocation.push({designData:itemDetail,position:null})
detailData.revocationShow = revocation?.length
sessionStorage.setItem('revocation', JSON.stringify(revocation));
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
await KeyValueDB.set('revocation', JSON.stringify(revocation));
await KeyValueDB.set('oppositeRevocation',JSON.stringify([]));
}
provide('setRevocation',setRevocation)
const revocation = ()=>{//撤回
let oppositeRevocation = JSON.parse((sessionStorage.getItem("oppositeRevocation") as any))
let revocation = JSON.parse((sessionStorage.getItem("revocation") as any))
const revocation = async ()=>{//撤回
let oppositeRevocation = JSON.parse((await KeyValueDB.get("oppositeRevocation") as any) || 'null')
let revocation = JSON.parse((await KeyValueDB.get("revocation") as any) || 'null')
if(revocation.length <= 1)return
oppositeRevocation.push(revocation[revocation.length-1])
revocation.splice(revocation.length-1,1)
@@ -299,14 +302,14 @@ export default defineComponent({
store.commit('DesignDetail/setFrontBack',revocation[revocation.length-1].position)
}
store.commit('DesignDetail/setDesignColthes',detailData.selectDetail.id)
sessionStorage.setItem('oppositeRevocation', JSON.stringify(oppositeRevocation));
sessionStorage.setItem('revocation', JSON.stringify(revocation));
await KeyValueDB.set('oppositeRevocation', JSON.stringify(oppositeRevocation));
await KeyValueDB.set('revocation', JSON.stringify(revocation));
// clearSelect()
detailData.positionKey++
}
const oppositeRevocation = ()=>{//反撤回
let oppositeRevocation = JSON.parse((sessionStorage.getItem("oppositeRevocation") as any))
let revocation = JSON.parse((sessionStorage.getItem("revocation") as any))
const oppositeRevocation = async ()=>{//反撤回
let oppositeRevocation = JSON.parse((await KeyValueDB.get("oppositeRevocation") as any) || 'null')
let revocation = JSON.parse((await KeyValueDB.get("revocation") as any) || 'null')
// if(!oppositeRevocation[oppositeRevocation.length-1].designData)return
if(oppositeRevocation.length < 1)return
if(oppositeRevocation[oppositeRevocation.length-1]?.designData){
@@ -319,8 +322,8 @@ export default defineComponent({
detailData.revocationShow = revocation.length
oppositeRevocation.splice(oppositeRevocation.length-1,1)
detailData.oppositeRevocationShow = oppositeRevocation.length
sessionStorage.setItem('oppositeRevocation', JSON.stringify(oppositeRevocation));
sessionStorage.setItem('revocation', JSON.stringify(revocation));
await KeyValueDB.set('oppositeRevocation', JSON.stringify(oppositeRevocation));
await KeyValueDB.set('revocation', JSON.stringify(revocation));
// this.clearSelect()
detailData.positionKey++
}
@@ -328,17 +331,25 @@ export default defineComponent({
store.commit('DesignDetail/setCurrentDetailType',str)
}
const setClothes = async (list:any,str:string)=>{
console.log(JSON.parse(JSON.stringify(list)))
let clothesList:any = []
await nextTick()
if(detailData.isEditPattern.value == 'editSketch')await detailDom.canvasBox.submitBase64Data().then((rv)=>{
detailData.selectDetail.sketchString = rv
})
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
if(detailDom.canvasBox && (detailData.currentDetailType != 'sketch' || detailData.isEditPattern.value == 'canvasEditor')){
// if(detailData.isEditPattern.value !== 'editSketch'){
// let otherDataupDateFrontBackSketch = await updateOtherLayers(detailData.isEditPattern.value == 'canvasEditor'?'all':'single')
// await detailDom.canvasBox.updateOtherLayers(otherData)
// }
await detailDom.canvasBox.privewDetail()
await uploadSelectDetail()
// await uploadElement()
}
for(let i = 0;i<list.length;i++){
detailData.selectDetail
let {scale,offset,priority,transpose,rotate,maskUrl,maskMinioUrl} = await (detailDom.model as any).getSubmitData(list[i])
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
let gradient = null
let newData = list[i]?.newDetail?.[detailData.currentDetailType]
let newData = list[i]?.newDetail
// newData[0].location=[
// -233.13985,
// 406.90964
@@ -348,13 +359,27 @@ export default defineComponent({
// 0.35822305
// ]
let isCurrent = list[i].id == detailData?.selectDetail?.id
let color = (detailData.currentDetailType == 'color' && isCurrent && !detailData.isEditPattern.value)?
(newData?.rgba?.r?`${newData.rgba.r} ${newData.rgba.g} ${newData.rgba.b}`:''):
(list[i].color?.rgba?.r?
`${list[i].color.rgba.r} ${list[i].color.rgba.g} ${list[i].color.rgba.b}`:
'')
if(detailData.currentDetailType == 'sketch' && newData){
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}`:''
let color = ''
let gradient = null
// if((detailData.currentDetailType == 'color' && detailData.isEditPattern.value == 'canvasEditor') && isCurrent){
// color = newData?.color?.rgba?.r != null?`${newData?.color.rgba.r} ${newData?.color.rgba.g} ${newData?.color.rgba.b}`:''
// if(newData?.color?.gradient){
// gradient = newData?.color.gradient
// }
// }else if(isCurrent){
// }
console.log(JSON.parse(JSON.stringify(detailData.selectDetail.color)),'=====')
color = list[i].color?.rgba?.r != null?`${list[i].color.rgba.r} ${list[i].color.rgba.g} ${list[i].color.rgba.b}`:''
gradient = list[i].gradient
if((detailData.currentDetailType == 'sketch' && newData?.sketch) || detailData.isEditPattern.value == 'editSketch'){
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.maskMinioUrl = ''
}
@@ -368,9 +393,10 @@ export default defineComponent({
let data:any = {
changed:false,
color,
designType:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.designType:list[i].designType,
id:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.id:list[i].id,
maskMinioUrl:((newData && detailData.currentDetailType == 'sketch') || list[i].sketchString)?'':list[i]?.maskMinioUrl,
gradient,
designType:(newData?.sketch && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData?.sketch.designType:list[i].designType,
id:(newData?.sketch && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData?.sketch.id:list[i].id,
maskMinioUrl:((newData?.sketch && detailData.currentDetailType == 'sketch') || list[i].sketchString)?'':list[i]?.maskMinioUrl,
// maskUrl:'',
maskUrl:list[i]?.maskUrl || '',
// offset:[
@@ -382,28 +408,29 @@ export default defineComponent({
rotate,
partialDesign:list[i].partialDesign,
// partialDesign:detailData.isEditPattern.value?list[i].partialDesign:{},
path:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.minIOPath:list[i].minIOPath,
printObject:(newData && detailData.currentDetailType == 'print' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].printObject?list[i].printObject:{prints:[]},
path:(newData?.sketch && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData?.sketch.minIOPath:list[i].minIOPath,
printObject:((newData?.print?.length>0 && (detailData.currentDetailType == 'print' || detailData.isEditPattern.value == 'canvasEditor')) && isCurrent)?{prints:newData.print}:list[i].printObject?list[i].printObject:{prints:[]},
priority,
// scale:[
// 0.5,
// 0.35822305
// ],
scale:[scale[0]?scale[0]:1,scale[1]?scale[1]:1],
type:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.level2Type || newData.categoryValue:list[i].type,
type:(newData?.sketch && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData?.sketch.level2Type || newData?.sketch.categoryValue:list[i].type,
sketchString:list[i].sketchString?list[i].sketchString:'',
trims:(newData && detailData.currentDetailType == 'element' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
accessory:(newData && detailData.currentDetailType == 'accessory' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
trims:((newData?.element?.length>0 && (detailData.currentDetailType == 'element' || detailData.isEditPattern.value == 'canvasEditor')) && isCurrent)?{prints:newData.element}:list[i].trims?.prints?list[i].trims:{prints:[]},
}
// if(!data.partialDesign.partialDesignMinioPath){
// data.partialDesign.partialDesignMinioPath = data.path
// }
printObjectToJSON(data.printObject.prints)
printObjectToJSON(data.trims.prints)
if((detailData.isEditPattern.value && list[i].color?.gradient) || (!detailData.isEditPattern.value && (list[i].newDetail?.color?.gradient || list[i].color?.gradient))){
gradient = list[i].newDetail?.color?.gradient || list[i].color.gradient
console.log(list[i],'=======',isCurrent)
if((list[i]?.color?.gradient)){
// if(list[i].color?.gradient || (!detailData.isEditPattern.value && (list[i].newDetail?.color?.gradient || list[i].color?.gradient))){
gradient = list[i]?.color?.gradient
console.log(gradient,list[i],gradient)
gradient.colorImg = await setGradual(gradient,320,700)
data.gradient = gradient
}else{
data.gradient = null
}
clothesList.push(data)
}
@@ -411,47 +438,73 @@ export default defineComponent({
}
const getSubmitData = async (str:string)=>{
// return
let workspace = store.state.Workspace.probjects
if(!detailData?.selectDetail?.path && !detailData?.selectDetail?.newDetail?.sketch?.minIOPath)return
let clothes:any
if(detailData.currentDetailType == 'models'){
clothes = await setClothes(detailData.designDetail.clothes,str)
}else{
clothes = await setClothes([detailData.selectDetail],str)
}
let data = {
designItemId:detailData.designDetail.designItemId,
designSingleItemDTOList:clothes,
isPreview:str == 'sub'?false:true,
// ifSubmit:designItemDetail.isPreview,
gender:workspace?.sex,
sketchString:'',
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
designType:detailData.selectDetail.id?'merge':'default',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
processId:userDetail.value.userId,
probjectId:store.state.Workspace.probjects.id,
}
detailData.loadingShow = true
Https.axiosPost(Https.httpUrls.designSingle, data).then((rv)=>{
let value = {
currentType : JSON.parse(JSON.stringify(detailData.currentDetailType)),
rv:rv,
fun:setRevocation
await new Promise<void>(async (resolve, reject) => {
let workspace = store.state.Workspace.probjects
if(!detailData?.selectDetail?.path && !detailData?.selectDetail?.newDetail?.sketch?.minIOPath)return
let clothes:any
if(detailData.currentDetailType == 'models'){
clothes = await setClothes(detailData.designDetail.clothes,str)
}else{
clothes = await setClothes([detailData.selectDetail],str)
}
if(detailData?.designDetail?.newModel)detailData.designDetail.oldModel = JSON.parse(JSON.stringify(detailData.designDetail.newModel))
// delete detailData.designDetail.newModel
detailData.selectDetail.sketchString = null
store.commit('DesignDetail/setPraeview',value)
detailData.loadingShow = false
canvasReload()
// setRevocation()
}).catch(res=>{
detailData.loadingShow = false
});
let isDefault = detailData.selectDetail.sketchString || (!detailData.selectDetail.id || (detailData.selectDetail?.newDetail?.sketch && detailData.currentDetailType == 'sketch'))
let data = {
designItemId:detailData.designDetail.designItemId,
designSingleItemDTOList:clothes,
isPreview:str == 'sub'?false:true,
// ifSubmit:designItemDetail.isPreview,
gender:workspace?.sex,
sketchString:'',
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
designType:isDefault?'default':'merge',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
processId:userDetail.value.userId,
probjectId:store.state.Workspace.probjects.id,
}
await Https.axiosPost(Https.httpUrls.designSingle, data).then(async (rv)=>{
let value = {
currentType : JSON.parse(JSON.stringify(detailData.currentDetailType)),
rv:rv,
}
if(detailData?.designDetail?.newModel)detailData.designDetail.oldModel = JSON.parse(JSON.stringify(detailData.designDetail.newModel))
// delete detailData.designDetail.newModel
let el:any = document.querySelector('.molepositon .perview_img')
let scale = 0
await new Promise<void>(async (resolve, reject) => {
if(!detailData.frontBack.body.path)resolve(true)
const img = new Image();
img.src = detailData.frontBack.body.path;
img.onload = () => {
scale = el.parentNode.offsetWidth / img.width;
resolve(true)
};
})
value.scale = scale
store.commit('DesignDetail/setPraeview',value)
store.commit('DesignDetail/changeCanvasKey')
// console.log(detailData.selectDetail)
// if(detailData.selectDetail.sketchString || (detailData.selectDetail?.newDetail?.sketch && detailData.currentDetailType == 'sketch')){
// detailData.canvasKey += 1
// }
detailData.selectDetail.sketchString = null
resolve(true)
canvasReload()
// setRevocation()
}).catch(res=>{
resolve(true)
});
})
}
const submit = async ()=>{
detailData.loadingShow = true
if(detailData.isEditPattern.value !== 'canvasEditor' && detailDom.canvasBox){
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
}
let workspace = store.state.Workspace.probjects
let clothes:any = await setClothes(detailData.designDetail.clothes,'sub')
let data = {
@@ -468,11 +521,10 @@ export default defineComponent({
processId:userDetail.value.userId,
probjectId:store.state.Workspace.probjects.id,
}
detailData.loadingShow = true
Https.axiosPost(Https.httpUrls.designSingle, data).then(async (rv)=>{
saveCanvasJSONToSession()
// store.commit('DesignDetail/setPraeview',rv)
const sessionCanvasList = sessionStorage.getItem('canvasList');
const sessionCanvasList = await KeyValueDB.get('canvasList');
const canvasList = sessionCanvasList ? JSON.parse(sessionCanvasList) : []
for (let i = 0; i < canvasList.length; i++) {
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasList[i].id);
@@ -498,10 +550,19 @@ export default defineComponent({
detailData.loadingShow = false
});
}
const previwe = async ()=>{
if((detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
let data = getSubmitData('preview')
store.dispatch('DesignDetail/setSubmit',data)
const previwe = async ()=>{
detailData.loadingShow = true
if((detailData.currentDetailType == 'models' && !detailData.isEditPattern.value) || (detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
await getSubmitData('preview')
if(detailData.currentDetailType == 'models')return detailData.loadingShow = false
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == detailData.selectDetail.id)
await getSketchSize()
detailDom.canvasBox.changeSketchUpdateFrontBack = async ()=>{
await detailDom.canvasBox.privewDetail()
detailDom?.model?.updateRect()
await upDateFrontBackSketch()
detailData.loadingShow = false
}
}else{
//走画布合成图片并且直接分割
if(detailData.isEditPattern.value !== 'canvasEditor'){
@@ -510,6 +571,14 @@ export default defineComponent({
await detailDom.canvasBox.updateOtherLayers(otherData)
}
await detailDom.canvasBox.privewDetail()
await upDateFrontBackSketch()
await uploadSelectDetail()
saveCanvasJSONToSession()
detailData.loadingShow = false
}
}
const upDateFrontBackSketch = async ()=>{//更新模特身上的分割图
await new Promise<void>(async(resolve, reject) => {
let img = new Image()
img.onload = ()=>{
let partialDesign = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath
@@ -520,23 +589,22 @@ export default defineComponent({
segmentImage(detailData.selectDetail.maskUrl,partialDesign,size).then(async (rv)=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
if(!front?.oldMaskUrl)store.commit('DesignDetail/updataDetailItem',{maskUrl:front.oldMaskUrl})
if(front?.oldImageUrl)front.oldImageUrl = ''
if(front?.oldMaskUrl)front.oldMaskUrl = ''
if(back?.oldImageUrl)back.oldImageUrl = ''
front.imageUrl = rv.targetFrontUrl
back.imageUrl = rv.targetBackUrl
store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation})
resolve()
})
}
img.src = detailData.selectDetail.path
saveCanvasJSONToSession()
}
})
}
const saveCanvasJSONToSession = ()=>{
const saveCanvasJSONToSession = async ()=>{
let canvasJSON = detailDom.canvasBox.getCanvasJSON()
const sessionCanvasList = sessionStorage.getItem('canvasList');
const sessionCanvasList = await KeyValueDB.get('canvasList');
const list = sessionCanvasList ? JSON.parse(sessionCanvasList) : []
let index = -1
list.forEach((item:any,i:number)=>{
@@ -549,27 +617,36 @@ export default defineComponent({
}else{
list[index].canvasJSON = canvasJSON
}
sessionStorage.setItem('canvasList', JSON.stringify(list));
await KeyValueDB.set('canvasList', JSON.stringify(list));
}
const detailEdit = async (str:any)=>{
detailData.loadingShow = true
if(str){
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
// await detailDom.canvasBox.saveCanvas()
await (detailDom.canvasBox as any).privewDetail()
if(detailData.isEditPattern.value == 'canvasEditor')await uploadElement()
if(detailData.isEditPattern.value == 'canvasEditor')await uploadSelectDetail()
detailData.isEditPattern.value = ''
}else{
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
// detailDom.canvasBox.editFront(str)
// }
detailDom.canvasBox.editFront(str)
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
if(str == 'canvasEditor'){
if((detailData.currentDetailType == 'print' || detailData.currentDetailType == 'element') && !detailDom.detailRight?.privewDetail){
store.commit('DesignDetail/changeCanvasKey')
}else{
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
}
}
detailData.isEditPattern.value = str
}
}else{
detailData.isEditPattern.value = ''
}
detailData.loadingShow = false
}
const getColorName = (color:any)=>{
let rgb:any = [color.r, color.g, color.b];
@@ -591,14 +668,14 @@ export default defineComponent({
});
})
}
const updateOtherLayers = async (str:any='all')=>{//更新到画布图层
const updateOtherLayers = async (str:any='all',type:any='noFirst')=>{//更新到画布图层
let otherData:any = {}
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
if(str == 'all'){
// await uploadSelectDetail()
otherData = {
color: detailData.selectDetail.newDetail?.color?.r?detailData.selectDetail.newDetail?.color:detailData.selectDetail.color,
printObject: detailData.selectDetail.newDetail?.print?.length>0?{prints:detailData.selectDetail.newDetail?.print}:detailData.selectDetail.printObject || null,
trims: detailData.selectDetail.newDetail?.element?.length>0?detailData.selectDetail.newDetail?.element:detailData.selectDetail.trims || null,
color: detailData.selectDetail.color,
printObject: detailData.selectDetail.printObject || null,
trims: detailData.selectDetail.trims || null,
}
}else if(str == 'single'){
otherData = {
@@ -610,7 +687,7 @@ export default defineComponent({
let color = detailData.selectDetail.newDetail?.color
// let colorData:any = await getColorName(color?.rgba)
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}
}else{
color.rgba = {}
@@ -619,40 +696,38 @@ export default defineComponent({
}
}
if(detailData.currentDetailType == 'print'){
otherData.printObject = detailData.selectDetail.newDetail?.print?.length>0?{prints:detailData.selectDetail.newDetail?.print}:detailData.selectDetail.printObject || null
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
otherData.printObject = {prints:detailData.selectDetail.newDetail?.print || []}
}
if(detailData.currentDetailType == 'element'){
otherData.trims = detailData.selectDetail.newDetail?.element?.length>0?{prints:detailData.selectDetail.newDetail?.element}:detailData.selectDetail.trims || null
otherData.trims = {prints:detailData.selectDetail.newDetail?.element || []}
}
}
console.log(JSON.parse(JSON.stringify(otherData)),'=======',JSON.parse(JSON.stringify(detailData.selectDetail)))
return otherData
}
const uploadElement = async ()=>{//取出画布数据更新到detail
if(detailData.isEditPattern.value == 'canvasEditor'){
// await detailDom.canvasBox.saveCanvas()
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
if(allInfo.trims?.length > 0){
// detailData.selectDetail.trims.prints = allInfo.trims
let value = {
data:allInfo.trims,
str:'element'
}
store.commit('DesignDetail/setNewDetail',value)
let trimsValue = {
data:allInfo.trims || [],
str:'element'
}
if(allInfo.prints?.length > 0){
// detailData.selectDetail.printObject.prints = allInfo.prints
let value = {
data:allInfo.prints,
str:'print'
}
store.commit('DesignDetail/setNewDetail',value)
store.commit('DesignDetail/setNewDetail',trimsValue)
let printValue = {
data:allInfo.prints || [],
str:'print'
}
if(allInfo.color?.color?.rgba){
let canvasColor = allInfo.color.color;
let colorData:any = await getColorName(allInfo.color.color?.rgba)
store.commit('DesignDetail/setNewDetail',printValue)
if(allInfo.color?.color?.rgba || allInfo.color?.color?.gradient){
let value:any = {
data:{
str:'color',
data:{},
}
let canvasColor = allInfo.color.color;
if(allInfo.color?.color?.rgba){
let colorData:any = await getColorName(allInfo.color.color?.rgba)
value.data = {
hsv:{
h:colorData.h,
s:colorData.s,
@@ -662,37 +737,90 @@ export default defineComponent({
tcx:colorData.tcx,
rgba:canvasColor.rgba,
hex:rgbaToHex([canvasColor.rgba.r,canvasColor.rgba.g,canvasColor.rgba.b]),
},
str:'color'
}
}
if(canvasColor.gradient){
value.data.gradient = canvasColor.gradient
}
console.log(value,'=======')
store.commit('DesignDetail/setNewDetail',value)
if(allInfo.color.color.gradient)detailData.selectDetail.color.gradient = allInfo.color.color.gradient
if(detailData.currentDetailType == 'color'){
detailData.detailLeftColorKey++
}
}else{
let value = {
data:{},
str:'color'
}
store.commit('DesignDetail/setNewDetail',value)
}
}
}
const uploadSelectDetail = async ()=>{//更新选中的detail
// await detailDom.canvasBox.saveCanvas()
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
let color:any = {}
if(allInfo.color?.color?.rgba || allInfo.color?.color?.gradient){
let canvasColor = allInfo.color.color;
if(canvasColor?.rgba?.r != null){
let colorData:any = await getColorName(allInfo.color.color?.rgba)
color = {
hsv:{
h:colorData.h,
s:colorData.s,
v:colorData.v,
},
name:colorData.name,
tcx:colorData.tcx,
rgba:canvasColor.rgba,
hex:rgbaToHex([canvasColor.rgba.r,canvasColor.rgba.g,canvasColor.rgba.b]),
}
}
if(canvasColor?.gradient){
color.gradient = canvasColor.gradient
}
}
if(detailData.isEditPattern.value == 'canvasEditor'){
delete detailData.selectDetail.newDetail
detailData.selectDetail.trims.prints = allInfo.trims || []
detailData.selectDetail.printObject.prints = allInfo.prints || []
detailData.selectDetail.color = color
}else{
if(detailData.currentDetailType == 'color'){
if(detailData.selectDetail.newDetail?.color)delete detailData.selectDetail.newDetail.color
detailData.selectDetail.color = color
detailData.selectDetail.gradient = color.gradient
}
if(detailData.currentDetailType == 'print'){
if(detailData.selectDetail.newDetail?.print)delete detailData.selectDetail.newDetail.print
detailData.selectDetail.printObject.prints = allInfo.prints || []
}
if(detailData.currentDetailType == 'element'){
if(detailData.selectDetail.newDetail?.element)delete detailData.selectDetail.newDetail.element
detailData.selectDetail.trims.prints = allInfo.trims || []
}
}
if(detailData.currentDetailType == 'color'){
detailData.detailLeftColorKey++
}
}
const canvasReload = async ()=>{
if(detailData.isEditPattern.value){
await detailDom.canvasBox.saveCanvas()
}
detailData.canvasKey += 1
}
const sketchSysToLibrary = ()=>{//系统sketch添加到library更新library
coverRevocation()
detailDom.detailLeft.sketchSysToLibrary()
}
const coverRevocation = ()=>{
const coverRevocation = async ()=>{
let itemDetail = JSON.parse(JSON.stringify(detailData.designDetail))
let revocation = JSON.parse((sessionStorage.getItem("revocation") as any))
let revocation = JSON.parse((await KeyValueDB.get("revocation") as any) || 'null')
revocation.splice(revocation.length-1,1,{designData:itemDetail,position:null})
sessionStorage.setItem('revocation', JSON.stringify(revocation));
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
await KeyValueDB.set('revocation', JSON.stringify(revocation));
await KeyValueDB.set('oppositeRevocation',JSON.stringify([]));
}
const setSloganData = (data:any)=>{
detailData.selectDetail.sketchString = data
@@ -702,10 +830,10 @@ export default defineComponent({
}
onMounted(()=>{
})
onBeforeUnmount(()=>{
sessionStorage.removeItem('oppositeRevocation')
sessionStorage.removeItem('revocation')
store.commit('DesignDetail/clearDesignDetail')
onBeforeUnmount(async ()=>{
await KeyValueDB.remove('oppositeRevocation')
await KeyValueDB.remove('revocation')
store.commit('DesignDetail/clearDetailData')
})
@@ -737,36 +865,7 @@ export default defineComponent({
window.removeEventListener('beforeunload',beforeunload)
}
window.addEventListener('beforeunload',beforeunload)
// let url = Https.httpUrls.getDesignDetail + `?designItemId=34242&designPythonOutfitId=34004`
// this.loadingShow = true
// Https.axiosGet(url).then(
// async (rv: any) => {
// rv.clothes.forEach((item:any)=>{
// let a
// if(item.layersObject[0].imageCategory.indexOf("back") == -1){
// a = item.layersObject[0]
// item.layersObject[0] = item.layersObject[1]
// item.layersObject[1] = a
// }
// if(item.printObject.prints == null){
// item.printObject.prints = [{}]
// }
// })
// this.store.commit('setDesignItemDetail',rv)
// if(rv.others[0].printObject.path == null){
// this.body = false
// }else{
// this.body = true
// }
// this.setImgSize()
// this.generateHighDesignImg = rv.highDesignUrl
// this.designShowPrview = 1
// this.designDetailShow = true
// this.loadingShow = false
// }
// ).catch(rv=>{
// this.loadingShow = false
// })
},
})

View File

@@ -6,25 +6,27 @@
<div class="content-bottom" ref="canvasContent">
<div class="contet">
<div class="canvas" :class="{'active': currentView === 'canvasEditor'}"@click.stop>
<!-- :clothingMinIOPath="selectDetail.minIOPath" 部件选取 -->
<editCanvas v-if="canvasLoad" :config="canvasConfig"
:title="t('CanvasTitle.ModifyItem')"
@canvasInit="editSketchCanvasInit"
is-edit
:clothingImageUrl="selectDetail.path"
:clothingImageUrl2="selectDetail.layersObject[0].maskUrl"
:clothingImageUrl2="selectDetail.maskUrl || selectDetail.layersObject[0].maskUrl"
showFixedLayer
:canvasJSON="canvasJSON"
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
:clothing-image-opts="{
imageMode:'contains',
}"
:hideCanvas="hideCanvas"
:isChangeCanvasSize="false"
:hideCanvas="hideCanvas || !isEditPattern"
ref="editCanvas">
</editCanvas>
<!-- <canvasContent ref="canvasContent"></canvasContent> -->
</div>
<div class="editFrontBack" v-if="currentView === 'redGreenExample'" @click.stop>
<editCanvas v-if="canvasLoad" :config="canvasConfig"
:title="t('CanvasTitle.RedGreen')"
@canvasInit="editFrontBackCanvasInit"
:enabledRedGreenMode="true"
:clothingImageUrl="selectDetail.path"
@@ -34,12 +36,12 @@
:clothing-image-opts="{
imageMode:'contains',
}"
:hideCanvas="hideCanvas"
:hideCanvas="hideCanvas || !isEditPattern"
ref="editCanvasBackFront">
</editCanvas>
</div>
<div class="editSketch" v-if="currentView === 'editSketch'" @click.stop>
<generalMiniCanvas ref="generalMiniCanvas" :btnShow="false" :imgUrl="selectDetail.sketchString || selectDetail.path"></generalMiniCanvas>
<generalMiniCanvas ref="generalMiniCanvas" :isChangeCanvasSize="false" :canvasTitle="t('CanvasTitle.ModifySketch')" :btnShow="false" :imgUrl="selectDetail.sketchString || selectDetail.path"></generalMiniCanvas>
</div>
</div>
@@ -49,9 +51,9 @@
</div>
</div>
<div class="mark_loading" v-show="isShowMark">
<!-- <div class="mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
</div> -->
</div>
</template>
@@ -85,6 +87,7 @@ export default defineComponent({
default:()=>{}
},
},
emits:['update:loadingShow'],
setup(props,{emit}) {
const store = useStore();
const {t} = useI18n();
@@ -116,13 +119,14 @@ export default defineComponent({
getCanvasIfEdit:inject('getCanvasIfEdit')as any,
canvasInstance:null as any,
canvasJSON:'',
hideCanvas: computed(()=>(store.state.Workspace.projectPath !== route.fullPath && props.isEditPattern)),
hideCanvas: computed(()=>(store.state.Workspace.projectPath !== route.fullPath)),
otherData:computed(()=>({
canvasId: store.state.DesignDetail.selectDetail.canvasId,
color: store.state.DesignDetail.selectDetail.color,
printObject: store.state.DesignDetail.selectDetail.printObject,
trims: store.state.DesignDetail.selectDetail.trims,
})),
changeSketchUpdateFrontBack:null as any,//切换sketch后是否需要合成图片进行风格
})
watch(()=>detailData.selectDetail,(newValue,oldValue)=>{
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
@@ -133,38 +137,20 @@ export default defineComponent({
const editFront = (str:any)=>{//编辑前后片
let canvasJSON = '' as any
if(detailData.currentView === 'canvasEditor'){
sessionStorage.setItem('sketchEdit',detailDom.editCanvas.getJSON())
canvasJSON = sessionStorage.getItem('frontBackEdit');
}else if(detailData.currentView === 'redGreenExample'){
sessionStorage.setItem('frontBackEdit',detailDom.editCanvasBackFront.getJSON())
canvasJSON = sessionStorage.getItem('sketchEdit');
}
// detailData.canvasLoad = false
detailData.currentView = str
if(canvasJSON){
// detailData.canvasLoad = true
if(detailData.currentView === 'redGreenExample'){
nextTick(()=>{
if(detailData.currentView === 'redGreenExample'){
detailDom.editCanvas.loadJSON(canvasJSON)
}else{
detailDom.editCanvasBackFront.loadJSON(canvasJSON)
}
setCanvas(detailData.selectDetail.path).then(()=>{
// detailData.canvasLoad = true
})
})
}else{
if(detailData.currentView === 'redGreenExample'){
nextTick(()=>{
setCanvas(detailData.selectDetail.path).then(()=>{
// detailData.canvasLoad = true
})
nextTick(()=>{
setCanvas(detailData.frontBack.front[detailData.imgDomIndex].maskUrl).then(()=>{
// detailData.canvasLoad = true
})
}else{
nextTick(()=>{
setCanvas(detailData.frontBack.front[detailData.imgDomIndex].maskUrl).then(()=>{
// detailData.canvasLoad = true
})
})
}
})
}
}
const updateOtherLayers = (obj:any)=>{
@@ -177,6 +163,7 @@ export default defineComponent({
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
// if(!detailDom.editCanvas)return
return new Promise(async (res,reject)=>{
console.log(detailDom.editCanvas)
await detailDom.editCanvas.exportImage({
isContainFixed:true,
width:props.sketchSize.width,
@@ -184,14 +171,7 @@ export default defineComponent({
}).then((rv)=>{
if(oldSelectDetail?.partialDesign)oldSelectDetail.partialDesign.partialDesignBase64 = rv
})
//包含平铺图层 single+overall模式的图
// await detailDom.editCanvas.exportImage({isContainFixed:true,isPrintTrimsNoRepeat:true,isPrintTrimsRepeat:true,isContainNormalLayer:false}).then((rv)=>{
// oldSelectDetail.undividedLayerWithSinglePrint = rv
// })
//不包含平铺图层overall模式的图
// await detailDom.editCanvas.exportImage({isContainFixed:true,isPrintTrimsNoRepeat:false,isPrintTrimsRepeat:true,isContainNormalLayer:false}).then((rv)=>{
// oldSelectDetail.undividedLayer = rv
// })
await setUndivideLayer()
res('')
})
@@ -215,6 +195,7 @@ export default defineComponent({
// detailData.canvasConfig.height = domHeight
detailData.canvasConfig.width = img.width
detailData.canvasConfig.height = img.height
detailData.canvasConfig.initZoom = true
res('')
}
@@ -263,8 +244,11 @@ export default defineComponent({
}
const frontBackChange = (value:any)=>{
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.path
const frontBackChange = async (value:any)=>{
if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){
await privewDetail()
}
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath || detailData.selectDetail.path
let size = {
...detailData.canvasConfig,
}
@@ -285,7 +269,7 @@ export default defineComponent({
})
}
const editSketchCanvasInit = (value:any)=>{
const editSketchCanvasInit = async (value:any)=>{
detailData.canvasInstance = value
detailData.getCanvasIfEdit.fun = getCanvasLength
detailData.isShowMark = false
@@ -305,14 +289,29 @@ export default defineComponent({
return detailDom?.editCanvas?.getJSON()
}
const saveCanvas = async (canvasData:any)=>{
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData.id);
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData?.id);
await new Promise<void>((resolve, reject) => {
let canvasJSON = JSON.parse(canvasData.canvasJSON)
if(!canvasJSON)return resolve()
// canvasData.canvas.objects.forEach((objectsItem:any) => {
// if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
// });
let blob = new Blob([JSON.stringify(canvasJSON)], { type: "application/json" });
if(!detailDom?.editCanvas)return resolve()
let canvasJSON = detailDom?.editCanvas?.getJSON()
let canvasData = JSON.parse(canvasJSON)
if(!canvasData)return resolve()
function deepProcessObjects(data:any, callback:any) {
if (!Array.isArray(data)) return data;
return data.map(item => {
callback(item)
const processedItem = {...item};
if (processedItem.objects &&
Array.isArray(processedItem.objects) &&
processedItem.objects.length > 0) {
processedItem.objects = deepProcessObjects(processedItem.objects, callback);
}
return processedItem;
});
}
canvasData.canvas.objects = deepProcessObjects(canvasData.canvas.objects,(item:any)=>{
if(item.type == 'image')item.minioUrl = getMinioUrl(item.src)
})
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
let formData = new FormData();
formData.append("file", blob, "data.json");
formData.append("designItemDetailId", detailData.selectDetail.id);
@@ -341,9 +340,14 @@ export default defineComponent({
// },3000)
// }
const canvasLoadJsonSuccess = async ()=>{
let otherData = await props.updateOtherLayers()
let otherData = await props.updateOtherLayers('all','first')
await updateOtherLayers(otherData)
await setUndivideLayer()
if(detailData.changeSketchUpdateFrontBack){
await detailData.changeSketchUpdateFrontBack()
detailData.changeSketchUpdateFrontBack = null
}
setUndivideLayer()
emit('update:loadingShow',false)
}
const setUndivideLayer = async ()=>{
await new Promise<void>(async (resolve, reject) => {
@@ -387,9 +391,6 @@ export default defineComponent({
if(front?.oldMaskUrl)front.maskUrl = front.oldMaskUrl
if(back?.oldImageUrl)back.imageUrl = back.oldImageUrl
if(front?.oldMaskUrl)store.commit('DesignDetail/updataDetailItem',{maskUrl:front.maskUrl})
sessionStorage.removeItem('frontBackEdit');
sessionStorage.removeItem('sketchEdit');
detailData.canvasLoad = false
// privewDetail()
})
@@ -420,7 +421,6 @@ export default defineComponent({
})
}
}
setCanvas(detailData.selectDetail.path).then(()=>{
detailData.canvasLoad = true
})
@@ -429,6 +429,7 @@ export default defineComponent({
return{
...toRefs(detailDom),
...toRefs(detailData),
t,
editFront,
privewDetail,
setFrontBackColor,

View File

@@ -100,12 +100,15 @@ export default defineComponent({
tcxToColor:'',
})
watch(()=>colorData.selectColor,async (newVal,oldVal)=>{
if(newVal.rgba && newVal.rgba?.r){
let data:any = await getColorName(newVal.rgba)
newVal.name = data.name
newVal.tcx = data.tcx
colorData.colorList.list[colorData.selectDetail.id][colorData.colorList.index] = newVal
data.rgba = newVal.rgba
if((newVal.rgba && newVal.rgba?.r != null) || newVal.gradient != null){
let data :any = {}
if(newVal.rgba?.r != null){
data = await getColorName(newVal.rgba)
newVal.name = data.name
newVal.tcx = data.tcx
colorData.colorList.list[colorData.selectDetail.id][colorData.colorList.index] = newVal
data.rgba = newVal.rgba
}
if(newVal.gradient){
data.gradient = newVal.gradient
}
@@ -124,13 +127,12 @@ export default defineComponent({
})
watch(()=>colorData.selectDetail.id,(newVal,oldVal)=>{
if(!newVal)return
console.log(12312)
if(!colorData.colorList?.list?.[newVal]){
colorData.colorList.list[newVal] = []
}else{
return
}
console.log(12312)
colorData.colorList.list[newVal] = []
// if(!colorData.colorList?.list?.[newVal]){
// colorData.colorList.list[newVal] = []
// }else{
// // return
// }
let isNoSelect = false
let pushIndex = 0
for (let index = 0; index < 9; index++) {
@@ -140,14 +142,12 @@ export default defineComponent({
let color = colorData.allBoardData.colorBoards?.[index]
if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue
if(
colorData.allBoardData.colorBoards?.[index] &&
(colorData.allBoardData.colorBoards?.[index] && color?.rgba &&
colorData.selectDetail.color.rgba?.r == color?.rgba?.r &&
colorData.selectDetail.color.rgba?.g == color?.rgba?.g &&
colorData.selectDetail.color.rgba?.b == color?.rgba?.b ||
(JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient)
&& colorData.selectDetail.color.rgba?.r
colorData.selectDetail.color.rgba?.b == color?.rgba?.b) ||
((JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && colorData.selectDetail.color.gradient))
){
console.log(123)
isNoSelect = true
colorData.selectColor = item
colorData.colorList.index = index
@@ -173,19 +173,22 @@ export default defineComponent({
colorData.colorList.list[newVal].push(item)
}
if(!isNoSelect){
let color = colorData.selectDetail.newDetail?.color?.rgba?.r?colorData.selectDetail.newDetail?.color:colorData.selectDetail.color
if(!color?.rgba?.r)return
let item = {
hex:rgbaToHex([color.rgba.r,color.rgba.g,color.rgba.b]),
id:color.id,
rgba:{
r:color.rgba.r,
g:color.rgba.g,
b:color.rgba.b,
},
tcx:color.tcx,
name:color.name,
} as any
let color = colorData.selectDetail.newDetail?.color?.rgba?.r != null?colorData.selectDetail.newDetail?.color:colorData.selectDetail.color
let item:any = {}
if(color?.rgba?.r != null){
item = {
hex:rgbaToHex([color.rgba.r,color.rgba.g,color.rgba.b]),
id:color.id,
rgba:{
r:color.rgba.r,
g:color.rgba.g,
b:color.rgba.b,
},
tcx:color.tcx,
name:color.name,
} as any
}
if(color.gradient){
item.gradient = color.gradient
}

View File

@@ -119,7 +119,7 @@ export default defineComponent({
})
const palletRef = ref(null)
watch(()=>palletData.color_,(newVal:any)=>{
if(!newVal?.rgba?.r)return
if(newVal?.rgba?.r == null)return
if(palletData.color?.gradient?.gradientShow){
palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = {
r:newVal.rgba.r,
@@ -146,7 +146,7 @@ export default defineComponent({
},{deep: true })
const setOperate = ()=>{
if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7'))
palletData.color.rgba = palletData.color?.rgba?.r?palletData.color.rgba:{r:0,g:0,b:0,a:1}
palletData.color.rgba = palletData.color?.rgba?.r != null?palletData.color.rgba:{r:0,g:0,b:0,a:1}
palletData.gradient.selectIndex = 0
palletData.gradient.gradientShow = true
if(!palletData.color.gradient){
@@ -262,7 +262,7 @@ export default defineComponent({
const openPallet = ()=>{
palletData.palletShow = !palletData.palletShow
console.log(props.selectColor,palletData.palletShow)
if(palletData.palletShow && props.selectColor?.rgba?.r){
if(palletData.palletShow && props.selectColor?.rgba?.r != null){
if(props.selectColor.gradient){
palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba
}else{

View File

@@ -40,11 +40,29 @@ export default defineComponent({
setup(props,{emit}) {
const {t} = useI18n();
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({
allBoardData:computed(()=>store.state.UploadFilesModule.allBoardData),
currentList:{
sketch:computed(()=>store.state.UploadFilesModule.allBoardData.sketchboardFiles),
print:computed(()=>store.state.UploadFilesModule.allBoardData.printboardFiles),
sketch:computed(()=>{
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),
models:computed(()=>store.state.Workspace.probjects.model),
},

View File

@@ -76,10 +76,10 @@ export default defineComponent({
selectImgItem(data)
return
}
data.id = id
if(data?.imgUrl)data.url = data.imgUrl
let value = {
data,
id,
}
if(detailData.currentDetailType == 'sketch'){
detailData.selectDetail.sketchString = ''

View File

@@ -53,6 +53,7 @@
</a-slider> -->
<a-popover
trigger="click"
placement="leftTop"
destroyTooltipOnHide
:title="t('Canvas.repeatSetting')"
>
@@ -63,8 +64,8 @@
@inputFillOffset="inputFillOffset"
@inputFillScale="inputFillScale"
:sketchPath="selectDetail.path"
@inputFill_Gap="
(x, y) => inputFill_Gap(x, y)"
@inputFillGap="
(x, y) => inputFillGap(x, y)"
/>
</template>
<div class="btn">
@@ -88,8 +89,8 @@
<img crossOrigin="anonymous" :src="item?.path" :style="{transform:`rotateZ(${item.pattern?.transform?.rotateZ}deg)`}" class="designOpenrtion_imgItme" draggable="false">
</div>
</div>
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg"> -->
<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.path)" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
<img :src="selectDetail.sketchMask" alt="" class="designOpenrtion_sketchMask" ref="sketchMask">
<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))">
@@ -110,7 +111,7 @@
</ul> -->
</div>
<div class="designOpenrtion_pingpu" v-else>
<pingpu :list="printStyleList[type].overall" :width="sketchSize.width" :height="sketchSize.height" ref="pingpuRef" @change-canvas="updateCanvas"></pingpu>
<pingpu :key="selectDetail?.id" :width="sketchSize.width" :height="sketchSize.height" ref="pingpuRef" @change-canvas="updateCanvas"></pingpu>
</div>
</div>
</div>
@@ -159,7 +160,6 @@ export default defineComponent({
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
currentPrintElement:computed(()=>store.state.DesignDetail.currentPrintElement),
systemDesignerPercentage:0,
printStyleList:{
print:{
single:[],
@@ -173,7 +173,6 @@ export default defineComponent({
type:props.type,
imgDomIndex:-1,
direction:'',//判断点的那条边
printZIndex:2,//印花优先级
sketchWH:{
width:0,
height:0,
@@ -207,10 +206,9 @@ export default defineComponent({
elList:[] as any,
selectIndex:0,
})
const setOveralSingle = ()=>{
const setOveralSingle = async ()=>{
setItemPosition()
await setItemPosition()
}
const formatter = (value:any)=>{
return `${value}%`;
@@ -225,6 +223,7 @@ export default defineComponent({
img.onload = ()=>{
let imgScale = img.width / img.height
let zoom = 2
console.log(editPrintElementData.sketchWH)
let width = editPrintElementData.sketchWH.width / zoom
let height = width / editPrintElementData.sketchWH.height
@@ -234,36 +233,54 @@ export default defineComponent({
let sketchH = editPrintElementData.sketchWH.height * editPrintElementData.sketchWH.scale[1]
let x = sketchW / 2 - (sketchW * (width / editPrintElementData.sketchWH.width)/2)
let y = sketchH / 2 -(sketchH * height/2)
if(!editPrintElementData.stateOverallSingle == 'single'){
if(editPrintElementData.stateOverallSingle !== 'single'){
x = sketchW / 2
y = sketchH / 2
}
let location = [x,y]
resolve({scale,location})
}
img.src = item.url
img.src = item.url || item.path
})
}
const addPrintELement = async (data:any)=>{
if(!editPrintElementData.isSketchLoad)return
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 = {
angle:0,
designType:data.designType,
ifSingle:editPrintElementData.stateOverallSingle == 'single',
level2Type:data.level2Type,
location,
location:location,
// location:editPrintElementData.stateOverallSingle == 'single'?location:[0,0],
minIOPath:data.minIOPath || data.originalUrl,
path:data.url,
priority:editPrintElementData.printZIndex,
scale,
priority:printIndex,
scale:editPrintElementData.stateOverallSingle == 'single'?scale:[1,1],
globalCompositeOperation:'',
}
getItemPosition(item)
setItemPosition()
store.commit('DesignDetail/setCurrentPrintElement',null)
}
const previewDetailPrintData = ()=>{
const previewDetailPrintData = (id:any = editPrintElementData.selectDetail?.id)=>{
let data:any = []
let index = 1
let setData = (item:any,index:number)=>{
@@ -276,16 +293,17 @@ export default defineComponent({
}else{
let x = Number(style.left.replace(/px/g,''))
let y = Number(style.top.replace(/px/g,''))
location = [(x*sketchWH[0]) ,(y*sketchWH[1])]
location = item.location
// location = [(x*sketchWH[0]) ,(y*sketchWH[1])]
scale = item.scale
// scale = [item.pattern.style.width/item.pattern.style.height,item.pattern.style.height/item.pattern.style.width]
// location = [item.pattern.style.left,item.pattern.style.top]
}
let value ={
angle : item.pattern.transform.rotateZ,
angle:0,
// angle : !this.overallSingle ? 0:item.pattern.transform.rotateZ,
location : location,
priority:index,
priority:item.priority,
scale: scale,
designType:item.designType,
level2Type:item.level2Type,
@@ -294,24 +312,32 @@ export default defineComponent({
ifSingle:!!item.ifSingle,
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
}
if(editPrintElementData.printStyleList[props.type].single.length>0){
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)=>{
data.push(setData(item,index))
index++
})
console.log(editPrintElementData.printStyleList[props.type].single)
editPrintElementData.printStyleList[props.type].single.forEach((item:any)=>{
data.push(setData(item,index))
index++
})
let value = {
data,
str:props.type
str:props.type,
id:id,
}
console.log('data',value)
store.commit('DesignDetail/setNewDetail',value)
}
const sort = (list:any)=>{
@@ -333,10 +359,9 @@ export default defineComponent({
top = item.location[1] / editPrintElementData.sketchWH.scale[1]
}else{
//overall
editPrintElementData.systemDesignerPercentage = item.scale[0]*1000
left = item.location[0] / editPrintElementData.sketchWH.scale[0]
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 = {
centers:{left:0,top:0},
@@ -354,7 +379,6 @@ export default defineComponent({
},
designOpenrtionBtn:false
}
editPrintElementData.printZIndex++
item.pattern = pattern
if(item.object){
@@ -369,71 +393,77 @@ export default defineComponent({
angle: 0,
flipX: false,
flipY: false,
blendMode: "multiply",
// blendMode: "multiply",
blendMode: "source-over",
gapX: 0,
gapY: 0,
}
if(props.type == 'element'){
item.object.blendMode = 'source-over'
}
}
if(item.ifSingle){
editPrintElementData.printStyleList[props.type].single.push(item)
}else{
}
if(!item.ifSingle){
item.token = Date.now().toString() + (editPrintElementData.printStyleList[props.type].overall.length + '')
// editPrintElementData.printStyleList[props.type].overall = []
editPrintElementData.printStyleList[props.type].overall.push(item)
setTimeout(()=>{
editPrintElementDom.pingpuRef.updataList([
{
action: ACTIONS.ADD,
data: item,
},
]);
})
if(editPrintElementData.stateOverallSingle == 'overall'){
setTimeout(()=>{
editPrintElementDom.pingpuRef.updataList([
{
action: ACTIONS.ADD,
data: item,
},
]);
})
}
}
}
const setPosition = ()=>{
nextTick(()=>{
let img = new Image
img.onload = ()=>{
// let sketchScale = editPrintElementData.selectDetail.layersObject[0].scale
let sketchScale = [1,1]
let scaleX = img.width * sketchScale[0] / editPrintElementDom.sketchImg.offsetWidth
let scaleY = img.height * sketchScale[1] / editPrintElementDom.sketchImg.offsetHeight
const setPosition = async ()=>{
await new Promise<void>((resolve, reject) => {
nextTick(()=>{
let img = new Image
img.onload = ()=>{
// let sketchScale = editPrintElementData.selectDetail.layersObject[0].scale
let sketchScale = [1,1]
let scaleX = img.width * sketchScale[0] / editPrintElementDom.sketchImg.offsetWidth
let scaleY = img.height * sketchScale[1] / editPrintElementDom.sketchImg.offsetHeight
editPrintElementData.sketchWH = {
width:editPrintElementDom.sketchImg.offsetWidth,
height:editPrintElementDom.sketchImg.offsetHeight,
scale:[scaleX,scaleY],
editPrintElementData.sketchWH = {
width:editPrintElementDom.sketchImg.offsetWidth,
height:editPrintElementDom.sketchImg.offsetHeight,
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
let state = true
// editPrintElementData.stateOverallSingle = 'single'
let arr:any = editPrintElementData.selectDetail.newDetail?.print || editPrintElementData.selectDetail.printObject.prints
if(props.type == 'element'){
arr = editPrintElementData.selectDetail.newDetail?.element || editPrintElementData.selectDetail.trims.prints
}
if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
}
if(arr && arr.length > 0){
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
img.src = editPrintElementData.selectDetail.path
})
})
}
// watch(()=>editPrintElementData.selectDetail?.id,(newVal)=>{
// if(!newVal)return
@@ -448,9 +478,10 @@ export default defineComponent({
addPrintELement(newVal)
}
})
watch(()=>((editPrintElementData.selectDetail?.id)),(newVal)=>{
watch(()=>((editPrintElementData.selectDetail?.id)),(newVal,oldVal)=>{
if(!newVal)return
editPrintElementData.isSketchLoad = false,
if(oldVal)previewDetailPrintData(oldVal)
editPrintElementData.isSketchLoad = false
editPrintElementData.printStyleList[props.type] = {
single:[],
overall:[],
@@ -463,14 +494,21 @@ export default defineComponent({
setPosition()
},{immediate: true,})
watch(()=>editPrintElementData.stateOverallSingle,(newVal)=>{
let arr = editPrintElementData.printStyleList[props.type][newVal]
previewDetailPrintData()
let arr:any = editPrintElementData.selectDetail.newDetail?.print || editPrintElementData.selectDetail.printObject.prints
if(props.type == 'element'){
arr = editPrintElementData.selectDetail.newDetail?.element || editPrintElementData.selectDetail.trims.prints
}
if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
}
if(arr.length > 0){
editPrintElementData.imgDomIndex = 0
if(newVal == 'overall'){
editPrintElementData.printStyleList[props.type].single = []
editPrintElementData.printStyleList[props.type].overall = []
arr.forEach((item:any,index:number) => {
item.id_ = index
getItemPosition(item)
});
}
}else{
editPrintElementData.imgDomIndex = -1
}
@@ -499,7 +537,6 @@ export default defineComponent({
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])
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 = {
scale:scale,
rotateZ:rotateZ?rotateZ:0,
@@ -633,7 +670,6 @@ export default defineComponent({
top:editPrintElementDom.imgDom.offsetTop+'px',
height:editPrintElementDom.imgDom.offsetHeight+'px',
width:editPrintElementDom.imgDom.offsetWidth+'px',
// zIndex:editPrintElementData.printZIndex
}
document.removeEventListener('mousemove',sizeMouseMove)
document.removeEventListener('touchmove',sizeTouchmove)
@@ -785,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();
}
}
@@ -816,6 +853,7 @@ export default defineComponent({
collItemSize.elList.forEach((elItem:any)=>{
let clothesIndex = arr.findIndex((item:any)=>item.uniqueId == elItem.uniqueId)
arr[clothesIndex].pattern.style.zIndex = elItem.sort
arr[clothesIndex].priority = elItem.id.split('_')[0]
// let clothesId = editPrintElementData.designDetail.clothes[clothesIndex].id
// editPrintElementData.designDetail.clothes[clothesIndex].priority = elItem.sort
// let frontIndex = editPrintElementData.frontBack_.front.findIndex((item:any)=>item.id == clothesId)
@@ -836,7 +874,6 @@ export default defineComponent({
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
arr.forEach((item,index) => {item.uniqueId = `${Date.now()}_${index}`});
const sortedArray = [...arr].sort((a, b) => a.priority - b.priority);
const sortMap = {} as any;
sortedArray.forEach((item, index) => {
@@ -847,7 +884,8 @@ export default defineComponent({
el: elArr[i],
// sort: elArr.length - i -1,
sort: sortMap[arr[i].priority],
index: i,
id: `${arr[i].priority}_${Date.now() + i}`,
// index: i,
uniqueId:arr[i]?.uniqueId || 99999,
});
}
@@ -872,11 +910,14 @@ export default defineComponent({
}
} else if (item.action === ACTIONS.SELECT) {
overallSetIndex(obj)
} else if(item.action === ACTIONS.DELETE){
navDelete(obj)
}
})
}
const inputFillAngle = (angle:any)=>{
let arr = editPrintElementData.printStyleList[props.type].overall
console.log(angle)
arr[editPrintElementData.imgDomIndex].angle = angle
editPrintElementDom.pingpuRef.updataList([
{
@@ -895,7 +936,7 @@ export default defineComponent({
action: ACTIONS.UPDATE,
token: arr[editPrintElementData.imgDomIndex].token,
key: 'location[0]',
value: offset.left,
value: location[0],
},
]);
editPrintElementDom.pingpuRef.updataList([
@@ -903,7 +944,7 @@ export default defineComponent({
action: ACTIONS.UPDATE,
token: arr[editPrintElementData.imgDomIndex].token,
key: 'location[1]',
value: offset.top,
value: location[1],
},
]);
// editPrintElementData.overallDetail.offsetX = offset.left
@@ -911,7 +952,6 @@ export default defineComponent({
}
const inputFillScale = (scale:any)=>{
let arr = editPrintElementData.printStyleList[props.type].overall
console.log(arr,scale,editPrintElementData.imgDomIndex)
arr[editPrintElementData.imgDomIndex].scale = [scale,scale]
editPrintElementDom.pingpuRef.updataList([
{
@@ -922,7 +962,7 @@ export default defineComponent({
},
]);
}
const inputFill_Gap = (x:any,y:any)=>{
const inputFillGap = (x:any,y:any)=>{
let arr = editPrintElementData.printStyleList[props.type].overall
arr[editPrintElementData.imgDomIndex].object.gapX = x
arr[editPrintElementData.imgDomIndex].object.gapY = y
@@ -982,7 +1022,7 @@ export default defineComponent({
inputFillAngle,
inputFillOffset,
inputFillScale,
inputFill_Gap,
inputFillGap,
overallSetIndex,
}
},
@@ -1100,9 +1140,8 @@ export default defineComponent({
.habit_System_Designer {
align-items: center;
display: flex;
justify-content: flex-end;
margin-top: 1.8rem;
margin-right: .8rem;
margin-left: .8rem;
.ant-slider-track,
.ant-slider-rail {
@@ -1152,7 +1191,7 @@ export default defineComponent({
border-radius: 1rem;
overflow: hidden;
&.active{
border: 2px solid #B4B4B4;
border: 2.5px solid #B4B4B4;
}
> img{
width: 100%;
@@ -1196,20 +1235,22 @@ export default defineComponent({
// width: 100%;
// max-height: 70%;
width: max-content;
overflow-y: auto;
overflow-x: hidden;
&.active{
flex-direction: row;
}
&::-webkit-scrollbar {
display: none;
}
.designOpenrtion_imgMask{
width: auto;
height: auto;
width: 100%;
height: 100%;
min-width: 60%;
overflow-y: auto;
overflow-x: hidden;
// max-height: 80%;
position: relative;
&::-webkit-scrollbar {
display: none;
}
>img{
z-index: 2;
position: relative;
@@ -1222,7 +1263,7 @@ export default defineComponent({
top: 0;
left: 0;
pointer-events: none;
height: 100%;
width: 100%;
}
}
.designOpenrtion_sketch_mask{

View File

@@ -1,6 +1,5 @@
<template>
<div class="repeat-setting">
{{ }}
<div class="repeat-setting" v-if="!mask">
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.angle") }}</span>
<angle-tool
@@ -17,7 +16,7 @@
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${scale}%`"
:tipFormatter="(v) => `${Number(scale)?.toFixed(0)}%`"
:value="scale"
@input="inputFillScale"
/>
@@ -26,28 +25,28 @@
<div class="repeat-setting-item">
<span class="label">Gap X</span>
<slider
:min="0"
:min="1"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapX"
@input="(e) => emit('inputFill_Gap', e, gapY)"
@change="(e) => emit('changeFill_Gap', e, gapY)"
@input="(e) => emit('inputFillGap', e, gapY)"
@change="(e) => emit('changeFillGap', e, gapY)"
/>
</div>
<p></p>
<div class="repeat-setting-item">
<span class="label">Gap Y</span>
<slider
:min="0"
:min="1"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapY"
@input="(e) => emit('inputFill_Gap', gapX, e)"
@change="(e) => emit('changeFill_Gap', gapX, e)"
@input="(e) => emit('inputFillGap', gapX, e)"
@change="(e) => emit('changeFillGap', gapX, e)"
/>
</div>
<p></p>
@@ -85,13 +84,35 @@
const scale = computed(() => {
// let scaleValue = 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(() => {
let index = sketchWH.value[0] > sketchWH.value[1]?0:1;
return sketchWH.value[index] / printWH.value[index] * scale.value / 5;
});
const printWH = ref([0,0])
const sketchWH = ref([0,0])
const mask = ref(false)
const offset = ref([0,0])
const sketchSize:any = async ()=>{
let img = new Image();
let size = [0,0];
img.src = props.sketchPath;
console.log(props.sketchPath)
await new Promise((resolve, reject) => {
img.onload = () => {
size = [img.width, img.height]
resolve([img.width, img.height]);
}
img.onerror = reject;
});
return size
}
const printSize:any = async ()=>{
let img = new Image();
let size = [0,0];
img.src = props.sketchPath;
console.log(props.sketchPath)
await new Promise((resolve, reject) => {
img.onload = () => {
size = [img.width, img.height]
@@ -102,9 +123,12 @@
return size
}
watch (() => props.object.path || props.object.location, async () => {
let size = await sketchSize();
offset.value[0] = props.object.location[0] / size[0] * 100;
offset.value[1] = props.object.location[1] / size[1] * 100;
mask.value = true
sketchWH.value = await sketchSize();
printWH.value = await printSize();
offset.value[0] = props.object.location[0] / sketchWH.value[0] * 100;
offset.value[1] = props.object.location[1] / sketchWH.value[1] * 100;
mask.value = false
},{immediate: true})
const gapX = computed(() => props.object.object?.gapX || 0);
const gapY = computed(() => props.object.object?.gapY || 0);
@@ -115,13 +139,12 @@
"changeFillOffset",
"inputFillScale",
"changeFillScale",
"inputFill_Gap",
"changeFill_Gap",
"inputFillGap",
"changeFillGap",
]);
const inputFillScale = (e) => {
const scale = e / 100;
console.log(scale)
emit("inputFillScale", scale);
emit("inputFillScale", scale.toFixed(2));
};
const inputOffset = async (e:any)=>{
emit('inputFillOffset', {...e,size: await sketchSize()})
@@ -132,6 +155,7 @@
.repeat-setting {
user-select: none;
width: 228px;
overflow: hidden;
> .title {
line-height: 35px;
font-size: 14px;

View File

@@ -128,7 +128,10 @@ export default defineComponent({
getDetailListDom.position?.updataPosition?.()
getDetailListDom.modelNav?.setItemPosition?.()
getDetailListDom.position?.updateRect?.()
},500)
},200)
}
const updateRect = ()=>{
getDetailListDom.position?.updateRect?.()
}
const setBack = ()=>{
showDesignImgDetail(getDetailListData.isEditPattern.value)
@@ -156,6 +159,7 @@ export default defineComponent({
oppositeRevocation,
mousedownDesignImg,
setBack,
updateRect,
}
},

View File

@@ -9,7 +9,7 @@
@click="selectDetailItem(item,index)">
<div class="iconList">
<i class="fi fi-rr-add" :class="{ active:item.scope == 'sys'}" @click.stop="sketchSystemToLibrary(item)"></i>
<i class="fi fi-rr-trash" @click.stop="deleteDetailItem(item?.id)"></i>
<i v-if="probjects?.httpType !== 'SINGLE_DESIGN'" class="fi fi-rr-trash" @click.stop="deleteDetailItem(item?.id)"></i>
</div>
<img :src="item.path" alt="">
<div class="type">{{ getTypeLang(item.type) }}</div>
@@ -41,6 +41,7 @@ export default defineComponent({
const store = useStore();
const {t} = useI18n()
const detailData = reactive({
probjects:computed(()=>store.state.Workspace.probjects),
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
frontBack_:computed(()=>store.state.DesignDetail.frontBack),
designDetail:computed(()=>store.state.DesignDetail.designDetail),
@@ -102,6 +103,7 @@ export default defineComponent({
}
}).then((rv)=>{
if(rv)store.commit('DesignDetail/setDesignColthes',item.id)
console.log(JSON.parse(JSON.stringify(item)),'==========')
})
}
const deleteDetailItem = (id:number)=>{

View File

@@ -0,0 +1,705 @@
<template>
<div class="molepositon" :class="{active:!imgDesignImg}">
<div class="designOpenrtion_imgMask" v-if="frontBack?.body?.path" :style="frontBack?.body?.style">
<div class="designOpenrtion_print" v-for="item,index in frontBack.back" :style="frontBack.front[index].style">
<img :style="item.imageUrl?'':'display:none;'" :src="item.imageUrl" alt="">
</div>
<img class="perview_img" @load="setPrintSize()" ref="detailBody" :key="designDetail.designItemId" :src="frontBack?.body?.path" :style="'width:'+ frontBack?.body?.layersObject?.[0].imageSize?.[0] +';height:' + frontBack?.body?.layersObject?.[0].imageSize?.[0] +';'">
<!-- <div class="detail_modal_item_front" ref="target" v-for="item,index in frontBack.front" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="item.style">
<img :src="item.imageUrl" alt="">
</div> -->
<div class="detail_modal_item_front" :ref="el => { setElementRef(el, index) }" v-for="item,index in frontBack.front" :class="{'active':item.id == selectDetail?.id}" :style="item.style">
<img :src="item.imageUrl" alt="">
</div>
<div ref="moveableContainer" class="moveableContainer"></div>
</div>
<div class="designOpenrtion_imgMask" v-if="!frontBack?.body?.path">
<div class="designOpenrtion_print">
<img v-if="frontBack.back?.[0].imageUrl" :src="frontBack.back?.[0].imageUrl" style="object-fit: cover;" alt="">
</div>
<div class="detail_modal_item_front" style="position: relative;">
<img :src="frontBack.front?.[0].imageUrl || selectDetail?.path" style="object-fit: cover;" alt="">
</div>
<!-- <img @load="setSelectSketch()" :src="designDetail?.currentFullBodyView || selectDetail?.undividedLayer" style="object-fit: cover;" alt=""> -->
</div>
</div>
<div class="molepositon imgDesignImg" :class="{active:imgDesignImg}">
<div class="designOpenrtion_imgMask" style="width: 100%;height: 100%;">
<div class="detail_modal_item_front">
<img
style="object-fit: cover;"
:style="observerWH.width > 0?{width:observerWH.width+'px',height:observerWH.height+'px'}:{width:'100%',height:'auto','object-fit': 'contain'}"
:src="designDetail.designItemUrl" alt="">
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,computed,inject,watch,nextTick,createVNode,toRefs, reactive, onUnmounted} from 'vue'
// import setDesignItem from '@/component/Detail/setDesignItem2.vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { useI18n } from 'vue-i18n'
import { getMousePosition } from "@/tool/mdEvent";
import { KeyValueDB } from "@/tool/indexedDB";
import Vue3Moveable from 'vue3-moveable';
import Moveable from 'moveable';
import { parse } from 'vue/compiler-sfc';
import { scale } from 'echarts/types/src/scale/helper.js';
export default defineComponent({
components:{
},
props:{
imgDesignImg:{
default:false,
type:Boolean,
}
},
emits:['addSketch'],
setup(props,{emit}) {
const {t} = useI18n()
const store = useStore();
const detailData = reactive({
frontBack:computed(()=>store.state.DesignDetail.frontBack),
designDetail:computed(()=>store.state.DesignDetail.designDetail),
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
isEditPattern:inject('isEditPattern') as any,
singleOveral:inject('singleOveral') as any,
detailBody:null as any,
observer:null as any,
observerWH:{
width:0,
height:0,
},
})
const selectItem = reactive({
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
imgDomIndex:-1,
printZIndex:store.state.DesignDetail.printZIndex,
imgDom:null as any,
direction:'',
})
watch(()=>detailData.frontBack?.body?.path,(newVal)=>{
setPrintSize()
})
const setPrintSize = ()=>{
nextTick(()=>{
let sacle = 0
const img = new Image();
let dom = document.querySelector('.molepositon .perview_img') as any
if(!detailData.frontBack?.body?.path || !dom)return
img.onload = () => {
//监听模特图片宽度设置整体图片宽度
if (detailData.observer) {
detailData.observer.disconnect()
}
detailData.observerWH.width = dom.width
detailData.observerWH.height = dom.height
detailData.observer = new ResizeObserver((entries) => {
if(entries[0].contentRect.width == 0)return
detailData.observerWH.width = Math.floor(entries[0].contentRect.width)
detailData.observerWH.height = Math.floor(entries[0].contentRect.height)
})
detailData.observer.observe(dom)
if(detailData.designDetail.clothes.length == 0){
store.commit('DesignDetail/addDesignColthes')
emit('addSketch')
return
}
if(!detailData.selectDetail?.id){
let item = detailData.designDetail.clothes.reduce((max, current) => {
return current.priority > max.priority ? current : max;
});
store.commit('DesignDetail/setDesignColthes',item.id)
}
// resolve(img)
sacle = dom.parentNode.offsetWidth / img.width
detailData.frontBack.front.forEach((item:any,index:number) => {
for (const key in item.style) {
if(key == 'zIndex')return
let value = item.style[key]
if(typeof value !== 'number'){
value = value.replace('px','')
item.style[key] = value
}else{
item.style[key] = value*sacle+'px'
}
// item.style[key] = value*sacle+'px'
}
for (const key in detailData.frontBack.back[index].style) {
if(key == 'zIndex')return
if(key == 'transform')return
let value = detailData.frontBack.back[index].style[key]
if(typeof value !== 'number'){
value = value.replace('px','')
detailData.frontBack.back[index].style[key] = value
}else{
detailData.frontBack.back[index].style[key] = value*sacle+'px'
}
// detailData.frontBack.back[index].style[key] = value*sacle+'px'
}
});
setTimeout(() => {
initMoveableForSelected()
},500);
};
img.src = detailData.frontBack?.body?.path;
})
}
const getDetailListDom = reactive({
libraryList:null as any,
moveableContainer:null as any,//控件层
})
const elementRefs = ref([]) as any;
const moveableInstance = ref(null) as any;
const setElementRef = (el, index) => {
elementRefs.value[index] = el;
};
const updateRect = ()=>{
setTimeout(() => {
if(moveableInstance.value)moveableInstance.value.updateRect()
}, 200);
}
const initMoveableForSelected = () => {
// 销毁旧的实例
if(selectItem.imgDomIndex == -1)return
if (moveableInstance.value) {
moveableInstance.value.destroy();
}
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
if (!selectedEl) return;
if(!selectedEl.style.left)return
moveableInstance.value = new Moveable(getDetailListDom.moveableContainer, {
target: selectedEl,
draggable: true,
scalable: true,
rotatable: true,
keepRatio: false, // 等比缩放
snappable: true,
snapThreshold: 5,
edge: false,
});
let startPosition = {//记录初始位置
left: 0,
top: 0,
}
moveableInstance.value.on('scaleStart', ({ target, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror){
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
}
});
moveableInstance.value.on('rotateStart', ({ target, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror){
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
}
});
moveableInstance.value.on('dragStart', ({ target, clientX, clientY }) => {
startPosition = {
left:parseFloat(selectedEl.style.left.replace('px','')) || 0,
top:parseFloat(selectedEl.style.top.replace('px','')) || 0,
}
});
// 拖拽
moveableInstance.value.on('drag', ({ target, beforeTranslate }) => {
let x = startPosition.left + beforeTranslate[0]
let y = startPosition.top + beforeTranslate[1]
detailData.frontBack.front[selectItem.imgDomIndex].style.left = x + 'px'
detailData.frontBack.front[selectItem.imgDomIndex].style.top = y + 'px'
});
const updateElementTransform = (element, rotateDeg = null) => {
const currentTransform = element.style?.transform || '';
// 1. 提取当前的所有rotate
const currentRotates = (currentTransform.match(/rotate[XYZ]?\([^)]+\)/g) || []);
// 2. 获取除镜像和rotate外的其他所有变换
let otherTransforms = currentTransform
.replace(/scaleX\(-1\)|scaleY\(-1\)/g, '') // 移除镜像
.replace(/rotate[XYZ]?\([^)]+\)/g, '') // 移除rotate
.replace(/\s+/g, ' ')
.trim();
// 3. 构建新transform
const transforms = [];
// 镜像部分
if (element.mirror.x) transforms.push('scaleX(-1)');
if (element.mirror.y) transforms.push('scaleY(-1)');
if (otherTransforms) transforms.push(otherTransforms);
if (rotateDeg !== null) {
transforms.push(`rotate(${rotateDeg}deg)`);
} else if (currentRotates.length > 0) {
transforms.push(...currentRotates);
}
element.style.transform = transforms.join(' ').trim();
};
moveableInstance.value.on('scale', ({ target, delta, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
const width = parseFloat(frontStyle.style.width);
const height = parseFloat(frontStyle.style.height);
let left = parseFloat(frontStyle.style.left) || 0;
let top = parseFloat(frontStyle.style.top) || 0;
let rotation = 0;
// 获取原始比例
const originalRatio = width / height;
if (frontStyle.style.transform) {
const transform = frontStyle.style.transform;
const match = transform.match(/rotate\(([-\d.]+)deg\)/);
if (match) {
rotation = parseFloat(match[1]);
}
}
// 根据旋转角度重新计算控制点的方向
function getAdjustedCorner(originalCorner, rotationAngle) {
const angleRad = rotationAngle * (Math.PI / 180);
const cosA = Math.cos(angleRad);
const sinA = Math.sin(angleRad);
const newX = originalCorner.x * cosA - originalCorner.y * sinA;
const newY = originalCorner.x * sinA + originalCorner.y * cosA;
const threshold = 0.5;
return {
x: Math.abs(newX) > threshold ? (newX > 0 ? 1 : -1) : 0,
y: Math.abs(newY) > threshold ? (newY > 0 ? 1 : -1) : 0
};
}
if (rotation !== 0) {
direction = getAdjustedCorner({x: direction[0], y: direction[1]}, rotation);
direction = [direction.x, direction.y];
}
// 判断是否是对角线方向(需要等比缩放)
const isDiagonal = Math.abs(direction[0]) === 1 && Math.abs(direction[1]) === 1;
// 处理轴缩放,包含镜像翻转逻辑
const processAxis = (axis, val, deltaVal, dir, originalPosition, originalSize, keepRatio = false, otherAxisResult = null) => {
let newVal = val * deltaVal;
const mirrorKey = axis === 'width' ? 'x' : 'y';
const isWidth = axis === 'width';
// 检查是否需要镜像翻转当值小于等于0时
if (newVal <= 0) {
frontStyle.mirror[mirrorKey] = !frontStyle.mirror[mirrorKey];
newVal = Math.abs(newVal);
updateElementTransform(frontStyle);
// 镜像翻转后,位置需要根据原始锚点调整
if (dir === -1) {
// 从左上/右上缩放时,位置保持不变
return {
newVal,
adjustPos: originalPosition,
shouldFlip: true
};
} else {
// 从左下/右下缩放时,位置需要调整
const newPosition = originalPosition + (originalSize - newVal) * (frontStyle.mirror[mirrorKey] ? -1 : 1);
return {
newVal,
adjustPos: newPosition,
shouldFlip: true
};
}
}
const shouldMove = (!frontStyle.mirror[mirrorKey] && dir === -1) ||
(frontStyle.mirror[mirrorKey] && dir === 1);
if (keepRatio && otherAxisResult) {
newVal = isWidth ?
otherAxisResult.newVal * originalRatio :
otherAxisResult.newVal / originalRatio;
}
let adjustPos;
if (shouldMove) {
adjustPos = originalPosition - (newVal - originalSize);
} else {
adjustPos = originalPosition;
}
return {
newVal,
adjustPos,
shouldFlip: false
};
};
// 自由缩放
const widthResult = processAxis('width', width, delta[0], direction[0], left, width);
const heightResult = processAxis('height', height, delta[1], direction[1], top, height);
frontStyle.style.left = widthResult.adjustPos + 'px';
frontStyle.style.top = heightResult.adjustPos + 'px';
frontStyle.style.width = widthResult.newVal + 'px';
frontStyle.style.height = heightResult.newVal + 'px';
// }
});
// 旋转
moveableInstance.value.on('rotate', ({ target, beforeRotate }) => {
let frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
// 确保镜像状态存在
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
const { x: isMirroredX, y: isMirroredY } = frontStyle.mirror;
// 计算实际旋转角度
let actualRotate = beforeRotate;
// 关键逻辑当镜像状态不同时一个true一个false旋转方向反转
if (isMirroredX !== isMirroredY) {
actualRotate = -beforeRotate;
}
// 确保角度在 0-360 度范围内
actualRotate = actualRotate % 360;
// 如果角度为负数,转换为正数
if (actualRotate < 0) {
actualRotate += 360;
}
// 确保角度在 [0, 360) 范围内
actualRotate = ((actualRotate % 360) + 360) % 360;
updateElementTransform(frontStyle, actualRotate.toFixed(2));
});
// 调整大小
moveableInstance.value.on('resize', ({ target, width, height }) => {
// console.log(width, height)
// detailData.frontBack.front[selectItem.imgDomIndex].style.width = width
// detailData.frontBack.front[selectItem.imgDomIndex].style.height = height
});
moveableInstance.value.on('dragEnd', ({ target, clientX, clientY }) => {
startPosition = {
left:0,
top:0,
}
upDataDetail()
});
moveableInstance.value.on('scaleEnd', () => {
upDataDetail()
});
moveableInstance.value.on('rotateEnd', () => {
upDataDetail()
});
};
watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{
if(!newValue && newValue?.id == oldValue?.id)return
selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
initMoveableForSelected()
},{immediate: true,})
const setRevocation = async ()=>{
let frontBack = JSON.parse(JSON.stringify(detailData.frontBack))
let revocation:any = JSON.parse((await KeyValueDB.get("revocation") as any) || '[]')
revocation.push({designData:null,position:frontBack})
KeyValueDB.set('revocation', JSON.stringify(revocation));
}
const upDataDetail = async ()=>{
//同步到selectDetail数据中
// getDetailListData.designDetail
let {scale,offset,priority,transpose,rotate,position,imageSize} = await getSubmitData(selectItem.selectDetail)
selectItem.selectDetail.layersObject[0].scale = scale
selectItem.selectDetail.layersObject[1].scale = scale
selectItem.selectDetail.layersObject[0].offset = offset
selectItem.selectDetail.layersObject[1].offset = offset
selectItem.selectDetail.layersObject[0].priority = priority
selectItem.selectDetail.layersObject[1].priority = priority
selectItem.selectDetail.layersObject[0].rotate = rotate
selectItem.selectDetail.layersObject[1].rotate = rotate
selectItem.selectDetail.layersObject[0].transpose = transpose
selectItem.selectDetail.layersObject[1].transpose = transpose
selectItem.selectDetail.layersObject[0].position = position
selectItem.selectDetail.layersObject[1].position = position
selectItem.selectDetail.layersObject[0].imageSize = imageSize
selectItem.selectDetail.layersObject[1].imageSize = imageSize
setRevocation()
}
const sort = (arr:any)=>{
arr.sort((a:any, b:any) => {
var a_num = a.style.zIndex;
var b_num = b.style.zIndex;
return a_num - b_num;
});
return arr
}
const getSubmitData = async (value:any)=>{
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
if(!detailData.frontBack?.body?.layersObject?.[0]?.imageSize){
return{
scale:value.layersObject[0].scale,
offset:value.layersObject[0].offset,
priority:value.layersObject[0].priority,
}
}
let ratio = detailData.frontBack.body.layersObject[0].imageSize[0]/parentNode.width
let scale = 0
let dom:any = document.querySelector('.molepositon .perview_img')
const img = new Image();
img.src = detailData.frontBack?.body?.path;
await new Promise<void>((resolve, reject) => {
img.onload = () => {
scale = dom.parentNode.offsetWidth / img.width
resolve()
};
})
// let arr:any = sort(detailData.frontBack.front)
let arr:any = sort(JSON.parse(JSON.stringify(detailData.frontBack.front)))
let num = 10
arr.forEach((item:any)=>{
item.priority = num++
})
let data:any = {
scale:null,
offset:null,
priority:'',
maskUrl:'',
maskMinioUrl:'',
position:null,
imageSize:null,
}
let state = false
for (let index = 0; index < arr.length; index++) {
if(value.id == arr[index].id){
state = true
let y = ((arr[index]?.style?.top.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[0])
let x = ((arr[index]?.style?.left.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[1])
let positionX = Number((arr[index]?.style?.left.replace(/px/g,'')/scale)).toFixed(2)
let positionY = Number((arr[index]?.style?.top.replace(/px/g,'')/scale)).toFixed(2)
let imageSizeW = Number((arr[index]?.style?.width.replace(/px/g,'')/scale)).toFixed(2)
let imageSizeH = Number((arr[index]?.style?.height.replace(/px/g,'')/scale)).toFixed(2)
let scaleWidth = arr[index]?.imageSize?Number(((arr[index]?.style?.width.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[0]/arr[index].scale[0])).toFixed(2)):1
let scaleHeight = arr[index]?.imageSize?Number(((arr[index]?.style?.height.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[1]/arr[index].scale[1])).toFixed(2)):1
// let widthScale = (arr[index].style.width.replace(/px/g,'')/arr[index].style.height.replace(/px/g,'')).toFixed(2)
let transformStr = arr[index]?.style?.transform
let scaleX = transformStr.match(/scaleX\(([-\d.]+)\)/)
let scaleY = transformStr.match(/scaleY\(([-\d.]+)\)/)
let rotate = transformStr.match(/rotate\(([-\d.]+)deg\)/);
data.transpose = [parseFloat(scaleX?.[1] || 1),parseFloat(scaleY?.[1] || 1)]
data.rotate = parseFloat(rotate?.[1] || 0)
data.scale = [scaleWidth,scaleHeight]
let top = y == 0 ? value.layersObject[0].offset[1]:y+value.layersObject[0].offset[1]
let left = x == 0 ? value.layersObject[0].offset[0]:x+value.layersObject[0].offset[0]
data.offset = [left?left:0,top?top:0]
data.position = [positionY,positionX]
data.imageSize = [imageSizeW,imageSizeH]
// data.offset = [left?left:0,top?top:0]
data.maskUrl = arr[index].maskUrl
data.maskMinioUrl = arr[index].maskMinioUrl
// data.priority = arr[index].style.zIndex
data.priority = arr[index].priority
arr[index].similarity = true
// item.offset = [(arr[index]?.style?.left.replace(/px/g,'')*ratio).toFixed(0),(i?.style?.top.replace(/px/g,'')*ratio).toFixed(0)]
break
}
}
if(!state){
data.scale = [1,1]
data.offset = [0,0]
data.priority = 10+arr.length
}
return data
}
const deleteNav = ()=>{
}
const updataPosition = ()=>{
let url = detailData.frontBack?.body?.path
let sacle = 0
const img = new Image();
img.onload = () => {
let dom:any = document.querySelector('.molepositon .perview_img')
// resolve(img)
sacle = dom.parentNode.offsetWidth / img.width
detailData.frontBack.front.forEach((item:any,index:number) => {
for (const key in item.style) {
if(key == 'zIndex')return
if(key == 'transform')return
item.style[key] = item.style[key]*sacle+'px'
}
for (const key in detailData.frontBack.back[index].style) {
if(key == 'zIndex')return
if(key == 'transform')return
detailData.frontBack.back[index].style[key] = detailData.frontBack.back[index].style[key]*sacle+'px'
}
});
};
img.src = url;
}
onUnmounted(()=>{
if (detailData.observer) {
detailData.observer.disconnect()
}
if (moveableInstance.value) {
moveableInstance.value.destroy();
}
})
return{
...toRefs(detailData),
...toRefs(selectItem),
...toRefs(getDetailListDom),
setElementRef,
setPrintSize,
deleteNav,
getSubmitData,
getMousePosition,
updataPosition,
updateRect,
}
},
directives:{
detailBody:{
mounted (el,data:any) {
let sacle = 0
const img = new Image();
img.onload = () => {
// resolve(img)
sacle = el.parentNode.offsetWidth / img.width
data.instance.frontBack.front.forEach((item:any,index:number) => {
for (const key in item.style) {
if(key == 'zIndex')return
item.style[key] = item.style[key]*sacle+'px'
}
for (const key in data.instance.frontBack.back[index].style) {
if(key == 'zIndex')return
data.instance.frontBack.back[index].style[key] = data.instance.frontBack.back[index].style[key]*sacle+'px'
}
});
};
img.src = data.value;
},
updated (el,data:any) {
let sacle = 0
const img = new Image();
img.onload = () => {
// resolve(img)
sacle = el.parentNode.offsetWidth / img.width
data.instance.frontBack.front.forEach((item:any,index:number) => {
for (const key in item.style) {
if(key == 'zIndex')return
item.style[key] = item.style[key].replace(/px/g,'')*sacle+'px'
}
for (const key in data.instance.frontBack.back[index].style) {
if(key == 'zIndex')return
data.instance.frontBack.back[index].style[key] = data.instance.frontBack.back[index].style[key].replace(/px/g,'')*sacle+'px'
}
});
};
img.src = data.value;
}
}
},
provide() {
return {
}
},
})
</script>
<style lang="less" scoped>
.molepositon{
// width: 30rem;
// width: calc(66 * .470rem);
width: calc(66 * .457rem);
height: 66rem;
display: flex;
flex-direction: column;
// margin: auto 0;
// padding-top: 3rem;
position: relative;
display: none;
&.active{
display: flex;
z-index: 2;
align-items: center;
justify-content: center;
}
&.imgDesignImg{
> .designOpenrtion_imgMask{
.detail_modal_item_front{
display: flex;
align-items: center;
justify-content: center;
img{
// height: auto;
}
}
}
}
.moveableContainer{
:deep(.moveable-origin){
opacity: 0;
}
:deep(.moveable-control){
border-radius: 0;
}
:deep(.moveable-rotation-control){
border-radius: 50%;
}
}
> .designOpenrtion_imgMask{
width: auto;
height: auto;
position: relative;
// height: 100%;
display: flex;
align-items: center;
justify-content: center;
>img{
z-index: 2;
position: relative;
width: 100%;
height: auto;
// height: 100%;
// object-fit: contain;
}
>div{
position: absolute;
top: 0;
}
.detail_modal_item_front,.designOpenrtion_print{
z-index: 2;
height: 100%;
width: 100%;
pointer-events: none;
&.active{
pointer-events: auto;
}
img{
width: 100%;
// height: ;
height: 100%;
float: left;
user-select:none;
-webkit-user-drag: none;
}
.modal_imgItem{
position: absolute;
overflow: hidden;
top: 0;
}
}
.designOpenrtion_print{
z-index: 1 !important;
}
}
}
</style>

File diff suppressed because one or more lines are too long

View File

@@ -1,142 +1,175 @@
<template>
<div class="eventsDetail_page" :class="{active:isScroll}">
<div class="eventsDetail_title ">
<div class="eventsDetail_page" :class="{ active: isScroll }">
<div class="eventsDetail_title">
<div class="modal_title_text" @click="setBack">
<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 class="eventsDetail_content">
<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 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 class="detail-btn" v-if="eventsDetail.id === 3" @click="openDetail">
{{ $t("event.detail") }}
</div>
</div>
<div class="modal_title_text" v-for="item in eventsDetail.textList">
<div class="modal_title_text content" v-for="item in eventsDetail.textList">
<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 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
class="eventsDetail_content_right_btn"
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 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>
</div>
</div>
</template>
<script lang="ts">
import { LoadingOutlined } from "@ant-design/icons-vue";
import { defineComponent,h ,toRefs,ref,reactive,onMounted,nextTick,provide,computed} from 'vue'
import { LoadingOutlined } from "@ant-design/icons-vue"
import {
defineComponent,
h,
toRefs,
ref,
reactive,
onMounted,
nextTick,
provide,
computed
} from "vue"
// import RobotAssist from "@/component/HomePage/RobotAssist.vue";
import { Https } from "@/tool/https";
import { message, Upload, Modal } from "ant-design-vue";
import fullScreenImg from '@/component/HomePage/fullScreenImg.vue'
import { useRouter } from 'vue-router';
import { useI18n } from "vue-i18n";
import generalMenu from "@/component/HomePage/generalMenu.vue";
import eventData from "@/assets/json/events.json";
import eventDataCn from "@/assets/json/events_cn.json";
import { useStore } from "vuex";
import { Https } from "@/tool/https"
import { message, Upload, Modal } from "ant-design-vue"
import fullScreenImg from "@/component/HomePage/fullScreenImg.vue"
import { useRouter } from "vue-router"
import { useI18n } from "vue-i18n"
import generalMenu from "@/component/HomePage/generalMenu.vue"
import eventData from "@/assets/json/events.json"
import eventDataCn from "@/assets/json/events_cn.json"
import { useStore } from "vuex"
export default defineComponent({
components: {
components: {
generalMenu,
fullScreenImg,
},
props:{
isScroll:{
type:Boolean,
default:true,
},
fullScreenImg
},
setup() {
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) => {
props: {
isScroll: {
type: Boolean,
default: true
}
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')
}
let openButton = (data:any,index:number)=>{
if(filter.loadingShow[index]){
}
let openButton = (data: any, index: number) => {
if (filter.loadingShow[index]) {
return
}
filter.loadingShow[index] = true
Https.axiosGet(data.https).then(
(rv: any) => {
if(rv){
Https.axiosGet(data.https)
.then((rv: any) => {
if (rv) {
message.success(data.success)
filter.loadingShow[index] = false
}
}
).catch(res=>{
filter.loadingShow[index] = false
});
})
.catch((res) => {
filter.loadingShow[index] = false
})
}
onMounted (()=>{
const { t, locale } = useI18n();
const currentLocale = locale.value;
let eventLangData:any
if(currentLocale == 'ENGLISH'){
const openDetail = () => {
let language = locale.value === "ENGLISH" ? "en" : "zh"
let url = `https://aida-global-design-awards.com.hk/${language}`
window.open(url, "_blank")
// router.push("/award/index")
}
onMounted(() => {
const currentLocale = locale.value
let eventLangData: any
if (currentLocale == "ENGLISH") {
eventLangData = eventData
}else{
} else {
eventLangData = eventDataCn
}
eventLangData.eventsItem.forEach((item:any)=>{
if(item.id == router.currentRoute.value.query.eventId){
filter.eventsDetail = item;
eventLangData.eventsItem.forEach((item: any) => {
if (item.id == router.currentRoute.value.query.eventId) {
filter.eventsDetail = item
}
})
})
return {
return {
...toRefs(filter),
likeFile,
setBack,
openButton,
}
},
directives:{
detailText:{
mounted (el,binding) {
openDetail
}
},
directives: {
detailText: {
mounted(el, binding) {
el.innerHTML = binding.value
}
}
},
async mounted(){
},
async mounted() {}
})
</script>
<style lang="less">
.eventsDetail_page {
min-height: 100%;
width: 100%;
width: 100%;
padding: 0 6rem;
padding-top: 5rem;
&.active{
&.active {
display: flex;
flex-direction: column;
height: 100%;
.eventsDetail_content{
.eventsDetail_content {
overflow-y: auto;
width: 100%;
}
@@ -146,7 +179,7 @@ export default defineComponent({
min-height: auto;
padding-bottom: 10rem;
}
.eventsDetail_title{
.eventsDetail_title {
display: flex;
padding: 2rem 0rem;
align-items: center;
@@ -154,21 +187,21 @@ export default defineComponent({
top: 0;
z-index: 222;
background: #fff;
.modal_title_text{
.modal_title_text {
cursor: pointer;
display: flex;
margin-bottom: 0;
}
.modal_title_text:hover .eventsDetail_title_text{
.modal_title_text:hover .eventsDetail_title_text {
text-decoration: underline;
}
i{
i {
display: flex;
align-items: center;
margin-right: 1rem;
}
}
.eventsDetail_content{
.eventsDetail_content {
border-top: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
@@ -176,59 +209,69 @@ export default defineComponent({
@media (max-width: 768px) {
flex-direction: column;
}
.eventsDetail_content_left,.eventsDetail_content_right{
.eventsDetail_content_left,
.eventsDetail_content_right {
width: 50%;
@media (max-width: 768px) {
width: 100%;
}
}
.eventsDetail_content_left{
.eventsDetail_content_left {
width: 40%;
max-height: 60rem;
@media (max-width: 768px) {
width: 100%;
}
.ant-image{
.ant-image {
// height: auto;
height: 100%;
}
.eventsDetail_content_left_img{
.eventsDetail_content_left_img {
width: 100%;
cursor: zoom-in;
}
}
.eventsDetail_content_right{
.modal_title_text{
letter-spacing: .4rem;
.eventsDetail_content_right {
.modal_title_text {
letter-spacing: 0.4rem;
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;
&.active{
&.active {
display: flex;
justify-content: space-between;
}
li{
li {
width: 48%;
}
em{
em {
// font-family: auto;
}
a{
a {
display: inline;
}
}
.eventsDetail_content_right_btn_box{
.eventsDetail_content_right_btn_box {
display: flex;
justify-content: space-evenly;
.eventsDetail_content_right_btn{
.eventsDetail_content_right_btn {
}
}
}
.modal_title_text:last-child{
.modal_title_text:last-child {
}
.modal_title_text:last-child::after{
.modal_title_text:last-child::after {
content: "";
display: block;
border-top: 3px solid;
@@ -237,4 +280,17 @@ export default defineComponent({
}
}
}
</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;
}
</style>

View File

@@ -271,7 +271,7 @@ export default defineComponent({
},
selectColor:{
handler(newVal,oldVal){
if(typeof newVal?.rgba?.r !== 'number' && typeof newVal?.rgba?.r !== 'string'){
if(newVal?.rgba?.r == null){
this.colorList[this.selectIndex] = {}
return
}
@@ -388,7 +388,7 @@ export default defineComponent({
//选择不同的色块
selectColorItem(index,color){
let hex
if(color?.rgba?.r){
if(color?.rgba?.r != null){
hex = this.rgbaToHex([color.rgba.r,color.rgba.g,color.rgba.b,color.rgba.a?color.rgba.a:1])
}else{
hex = '#FFFFFF'
@@ -402,7 +402,7 @@ export default defineComponent({
if(this.driver__.driver){
driverObj__.moveNext()
}
if(color?.rgba?.r){
if(color?.rgba?.r != null){
this.selectColor = color
this.selectColor.hex = hex
}

View File

@@ -853,9 +853,7 @@ export default defineComponent({
level2Type = this.sketchboardList?.[0]?.categoryValue
? this.sketchboardList[0].categoryValue
: ''
if (this.workspace.styleName) {
sloganText = `${this.workspace.styleName},${sloganText}`
}
sloganText = `${this.workspace.styleName || 'all'},${sloganText}`
} else if (this.upload.level1Type == 'Printboard') {
level2Type = this.scene?.value
if (level2Type == 'Slogan' && this.searchPictureName == '') {
@@ -925,7 +923,9 @@ export default defineComponent({
},
onCancel() {}
})
}
}else{
this.fileList = this.fileList.filter((item: any) => item.imgUrl)
}
})
},
setGenerate(dataList: any) {

View File

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

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